关于Python的pymssql模块,之前研究时总结了“pymssql默认关闭自动模式开启事务行为浅析”这篇博客,但是在测试过程中又发现了几个问题,下面对这些问题做一些浅析,如有不足或不正确的地方,敬请指出。

1: pymssql的commit函数可以提交两次或多次

Connection.commit():

Commit current transaction. You must call this method to persist your data if you leave autocommit at its default value, which is False

我们知道pymssql模块里面有commit函数表示提交事务,由于某个特殊原因,测试过程中发现执行多次commit都OK,不会报错,如下代码所示。

 

# -*- coding: utf-8 -*-

'''

-------------------------------------------------------------------------------------------

--  Script Name     :   TranTest.py

-------------------------------------------------------------------------------------------

'''

import pymssql

import logging

import os.path

import os

import base64

from cryptography.fernet import Fernet

 

 

 

 

 

key=bytes(os.environ.get('key'),encoding="utf8")

cipher_suite = Fernet(key)

with open('/home/konglb/python/conf/ms_db_conf.bin', 'rb') as file_object:

    for line in file_object:

        encryptedpwd = line

decrypt_pwd = (cipher_suite.decrypt(encryptedpwd))

password_decrypted = bytes(decrypt_pwd).decode("utf-8") #convert to string

env_db_user=os.environ.get('db_user')

db_user=base64.b64decode(bytes(env_db_user, encoding="utf8"))

 

 

dest_db_conn = pymssql.connect(host=os.environ.get('db_host'),

                               user=bytes.decode(db_user),

                               password=password_decrypted,

                               database='master',

                               charset="utf8");

 

sub_cursor = dest_db_conn.cursor(as_dict=True)

 

 

sub_cursor.execute('SELECT COUNT(*) AS RecordNum FROM msdb.dbo.sysmail_account')

result_rows =sub_cursor.fetchone()

 

print(result_rows["RecordNum"])

dest_db_conn.commit()

dest_db_conn.commit()

dest_db_conn.close()

 

 

其实我们用SQL Profile跟踪一下就会知道,多执行一次commit,相当于在SQL Server数据库多执行了一次下面SQL,显然不会出现什么问题,但是也没有什么用处,所以这个应该只提交一次就OK了。这个问题,其实一开始对于我来说还有点震惊。了解过原理后,其实发现也就那么一回事。如果你是驱动的开发者而言,也不可能让第二次commit报错,如果这样的话,那么程序的健壮性就有问题了。

BEGIN TRAN

COMMIT TRAN;

2: pymssql的close函数可以关闭多次?

Connection.close()  :Close the connection

关于pymssql中的close函数表示关闭数据库连接,第一次执行就已经关闭了数据库连接,执行第二次close没有报任何错误,但是如果在连接关闭后,再执行查询之类的操作,就会报“pymssql.InterfaceError: Connection is closed”这类错误,如下所示,简单修改上面代码,就可以测试、验证:

dest_db_conn.commit()
dest_db_conn.close()
sub_cursor.execute('SELECT COUNT(*) AS RecordNum FROM msdb.dbo.sysmail_account')
dest_db_conn.close()

#python TranTest.py 

 

Traceback (most recent call last):

  File "TranTest.py", line 45, in <module>

    sub_cursor.execute('SELECT COUNT(*) AS RecordNum FROM msdb.dbo.sysmail_account')

  File "src/pymssql.pyx", line 448, in pymssql.Cursor.execute

  File "src/pymssql.pyx", line 238, in pymssql.Connection._conn.__get__

pymssql.InterfaceError: Connection is closed.

个人猜测驱动程序已经关闭数据库链接了,第二次执行close函数时,可能驱动底层检测到数据库连接已经关闭,直接退出了,不做任何操作。但是如果数据库连接关闭后,再去执行相关SQL,此时就会报“Connection is closed”这类错误了。

3: 如果忘记提交或回滚事务,那么脚本执行完成后会回滚吗? 什么时候回滚呢? 另外,它会阻塞其它会话吗? 阻塞的时间有多长?

# -*- coding: utf-8 -*-

'''

-------------------------------------------------------------------------------------------

--  Script Name     :   TranTest.py

-------------------------------------------------------------------------------------------

'''

import pymssql

import logging

import os.path

import os

import base64

from cryptography.fernet import Fernet

 

 

 

 

 

key=bytes(os.environ.get('key'),encoding="utf8")

cipher_suite = Fernet(key)

with open('/home/konglb/python/conf/ms_db_conf.bin', 'rb') as file_object:

    for line in file_object:

        encryptedpwd = line

decrypt_pwd = (cipher_suite.decrypt(encryptedpwd))

password_decrypted = bytes(decrypt_pwd).decode("utf-8") #convert to string

env_db_user=os.environ.get('db_user')

db_user=base64.b64decode(bytes(env_db_user, encoding="utf8"))

 

 

dest_db_conn = pymssql.connect(host=os.environ.get('db_host'),

                               user=bytes.decode(db_user),

                               password=password_decrypted,

                               database='master',

                               charset="utf8");

 

sub_cursor = dest_db_conn.cursor(as_dict=True)

 

 

 

sub_cursor.execute("UPDATE TEST SET NAME='KKK' WHERE ID=100")

 

 

#dest_db_conn.commit()

#dest_db_conn.close()

dest_db_conn.close()

为了搞清楚上面这些问题,我修改了上面脚本,执行后,我去查询数据库, 发现即使上面的Python脚本没有提交事务,但是不会阻塞其它会话(其实是因为事务已经回滚了),对应的会话已经不存在了。猜测是因为Python脚本执行完成后,关闭了TCP层的连接而触发底层驱动关闭数据库连接(在关闭数据库连接之前,回滚了没有提交的事务)。

那么怎么验证呢? 很简单,我们使用休眠函数sleep,在关闭数据库联机(dest_db_conn.close()) 前让其休眠100秒,

dest_db_conn = pymssql.connect(host=os.environ.get('db_host'),
                               user=bytes.decode(db_user),
                               password=password_decrypted,
                               database='master',
                               charset="utf8");

sub_cursor = dest_db_conn.cursor(as_dict=True)


sub_cursor.execute("UPDATE TEST SET NAME='KKK' WHERE ID=100")

time.sleep(100)

dest_db_conn.close()

然后在这期间,我们就可以查看会话信息、查看未提交的事务,构造阻塞会话等等。如下所示:

SELECT * FROM sys.sysprocesses WHERE loginame='xxx'

 

DECLARE @tab TABLE

    (

      NAME VARCHAR(100) ,

      value VARCHAR(200)

    );

INSERT  INTO @tab

        EXEC ( 'DBCC OPENTRAN WITH TABLERESULTS'

            );

SELECT  NAME ,

        CAST(value AS DATETIME) startDate ,

        GETDATE() currentDate ,

        DATEDIFF(s, CAST(value AS DATETIME), GETDATE()) diffsecond

FROM    @tab

WHERE   NAME IN ( 'OLDACT_STARTTIME' );

SELECT  spid ,

        blocked ,

        DB_NAME(sp.dbid) AS DBName ,

        program_name ,

        waitresource ,

        lastwaittype ,

        sp.loginame ,

        sp.hostname ,

        A.[text] AS [TextData] ,

        SUBSTRING(A.text, sp.stmt_start / 2,

                  ( CASE WHEN sp.stmt_end = -1 THEN DATALENGTH(A.text)

                         ELSE sp.stmt_end

                    END - sp.stmt_start ) / 2) AS [current_cmd]

FROM    sys.sysprocesses AS sp

        OUTER APPLY sys.dm_exec_sql_text(sp.sql_handle) AS A

WHERE   spid = ( SELECT CASE WHEN ISNUMERIC(value) = 0 THEN -1

                             ELSE value

                        END

                 FROM   @tab

                 WHERE  NAME IN ( 'OLDACT_SPID' )

               );

那么为什么说是Python执行完成后,关闭TCP连接触发了底层驱动做这个事情呢? 你测试时,发现执行完脚本后,都会有一个Audit Logout,如下截图所示,另外,你也可以将上面脚本的休眠函数和关闭数据库连接注释掉,你会发现,即使不关闭数据库连接,Python脚本执行完成后,事务也回滚了,数据库连接也关闭了。其实如果你进行了上面测试,第三个问题已经基本不用回答了。显然已经不言而喻了

#time.sleep(100)
    #dest_db_conn.close()

 

Audit Logout:Records all new disconnect events since the trace started, such as when a client issues a disconnect command

pymssql的Connection相关特性浅析的更多相关文章

  1. 初窥css---选择器及相关特性

    选择器及相关特性 基础选择器 标签选择器 相当于全选,在我看来局限性较大,也没啥意义的感觉,用处不太大 id选择器 有利于对于某个小盒子的部分属性进行改变,但是若是需要改的小盒子很多的话,就会很麻烦 ...

  2. C#中的自定义控件中的属性、事件及一些相关特性的总结(转)

      摘要: C#中的自定义控件中的属性(Property).事件(Event)及一些相关特性(Attribute)的总结 今天学习了下C#用户控件开发添加自定义属性的事件,主要参考了MSDN,总结并实 ...

  3. java8的相关特性

    1,为什么要介绍java8的相关特性? 因为现在的企业大部分已经从java7向java8开始迈进了,用java8的公司越来越多了,java8中的一些知识还是需要了解一些的; java8具有以下特点: ...

  4. LINQ系列:C#中与LINQ相关特性

    1. 匿名类型 通过关键字var定义匿名类型,编译器将根据运算符右侧表达式的值来发出一个强类型. 使用匿名类型时要遵守的一些基本规则: ◊ 匿名类型必须有一个初始化值,而且这个值不能是空值(null) ...

  5. innodb buffer pool相关特性

    背景 innodb buffer pool作为innodb最重要的缓存,其缓存命中率的高低会直接影响数据库的性能.因此在数据库发生变更,比如重启.主备切换实例迁移等等,innodb buffer po ...

  6. hive 桶相关特性分析

    1. hive 桶相关概念     桶(bucket)是指将表或分区中指定列的值为key进行hash,hash到指定的桶中,这样可以支持高效采样工作.     抽样( sampling )可以在全体数 ...

  7. 《C++标准程序库》学习笔记(一)C++相关特性

    抱着本厚厚的<C++标准库>读了几天,想想也该写点关于用法的总结,一来怕今后容易忘记,二来将书上的事例重新敲一遍,巩固对程序库相关知识的了解.今天开第一篇,以后不固定更新.当然,笔者所读为 ...

  8. c++11相关特性

    前言 发现好多情况下都会用到c++11的新特性啊. 所以稍稍总结一下,只会粗略的说,不会详细的讲…… upd.csp-s可能不是c++11标准,请慎用.(博主考试CE后的善意提醒) 1.auto&am ...

  9. [ES6系列-03]ES6中关于参数相关特性详解(参数默认值与参数解构赋值与剩余参数)

    [原创] 码路工人 大家好,这里是码路工人有力量,我是码路工人,你们是力量. 今天总结一下 ES6 中跟参数相关的内容. 欢迎补充斧正.留言交流. 让我们互相学习一起进步. 1. ES6 参数默认值( ...

随机推荐

  1. jq中attr()和prop() 属性的区别

    query1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. 大家都知道有的浏览器只要写disabled,checked就可以了,而有的要 ...

  2. Android 手机端自动化测试框架

    前言: 大概有4个月没有更新了,因项目和工作原因,忙的手忙脚乱,趁十一假期好好休息一下,年龄大了身体还是扛不住啊,哈哈.这次更新Android端自动化测试框架,也想开源到github,这样有人使用才能 ...

  3. linux下安装配置go语言环境

    1,golang中国下载go源码  http://www.golangtc.com/download  请对应系统版本号,linux-amd64.tar.gz为64位系统(推荐) ,linux-386 ...

  4. 02 Pycharm的安装

    一.初试 在官网http://www.jetbrains.com/pycharm安装最新版本的pycharm软件,版本为 2019.2.3,根据网上教程发现安装不了,现在貌似还没破解,退而安装 201 ...

  5. 从xxe-lab来深入学习xxe漏洞

    这几天,想复习一下xxe的知识,于是把以前的一个靶场拿过来玩玩,顺便审计一下代码2333,靶场地址:https://github.com/c0ny1/xxe-lab 首先先练习的是php-xxe: 我 ...

  6. 02-15 Logistic回归(鸢尾花分类)

    目录 Logistic回归(鸢尾花分类) 一.导入模块 二.获取数据 三.构建决策边界 四.训练模型 4.1 C参数与权重系数的关系 五.可视化 更新.更全的<机器学习>的更新网站,更有p ...

  7. 【NOIP2011】选择客栈

    题文: 丽江河边有n 家很有特色的客栈,客栈按照其位置顺序从1 到n 编号.每家客栈都按照某一种色调进行装饰(总共k 种,用整数0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的 ...

  8. 终端 10X 工作法(一)

    目录 1. Terminal 2. Grep 3. Sed 4. Awk 5. Xargs 6. Find 在 github 上面有一个 700 多人 star 的 repo 叫做 Bash-Onel ...

  9. 小白学 Python(2):基础数据类型(上)

    人生苦短,我选Python 引言 前文传送门 小白学 Python(1):开篇 接触一门新的语言,肯定要先了解它的基础数据类型.啥?你问我为啥要先了解基础数据类型? 为了你的生命安全,还是乖乖听我 B ...

  10. HTTP中get和post

    HTTP中get和post的区别 GET - 从指定的资源请求数据. POST - 向指定的资源提交要被处理的数据 GET POST 后退/刷新 无害的 数据会被重新提交 书签 可收藏为书签 不可收藏 ...