pymssql的Connection相关特性浅析
关于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相关特性浅析的更多相关文章
- 初窥css---选择器及相关特性
选择器及相关特性 基础选择器 标签选择器 相当于全选,在我看来局限性较大,也没啥意义的感觉,用处不太大 id选择器 有利于对于某个小盒子的部分属性进行改变,但是若是需要改的小盒子很多的话,就会很麻烦 ...
- C#中的自定义控件中的属性、事件及一些相关特性的总结(转)
摘要: C#中的自定义控件中的属性(Property).事件(Event)及一些相关特性(Attribute)的总结 今天学习了下C#用户控件开发添加自定义属性的事件,主要参考了MSDN,总结并实 ...
- java8的相关特性
1,为什么要介绍java8的相关特性? 因为现在的企业大部分已经从java7向java8开始迈进了,用java8的公司越来越多了,java8中的一些知识还是需要了解一些的; java8具有以下特点: ...
- LINQ系列:C#中与LINQ相关特性
1. 匿名类型 通过关键字var定义匿名类型,编译器将根据运算符右侧表达式的值来发出一个强类型. 使用匿名类型时要遵守的一些基本规则: ◊ 匿名类型必须有一个初始化值,而且这个值不能是空值(null) ...
- innodb buffer pool相关特性
背景 innodb buffer pool作为innodb最重要的缓存,其缓存命中率的高低会直接影响数据库的性能.因此在数据库发生变更,比如重启.主备切换实例迁移等等,innodb buffer po ...
- hive 桶相关特性分析
1. hive 桶相关概念 桶(bucket)是指将表或分区中指定列的值为key进行hash,hash到指定的桶中,这样可以支持高效采样工作. 抽样( sampling )可以在全体数 ...
- 《C++标准程序库》学习笔记(一)C++相关特性
抱着本厚厚的<C++标准库>读了几天,想想也该写点关于用法的总结,一来怕今后容易忘记,二来将书上的事例重新敲一遍,巩固对程序库相关知识的了解.今天开第一篇,以后不固定更新.当然,笔者所读为 ...
- c++11相关特性
前言 发现好多情况下都会用到c++11的新特性啊. 所以稍稍总结一下,只会粗略的说,不会详细的讲…… upd.csp-s可能不是c++11标准,请慎用.(博主考试CE后的善意提醒) 1.auto&am ...
- [ES6系列-03]ES6中关于参数相关特性详解(参数默认值与参数解构赋值与剩余参数)
[原创] 码路工人 大家好,这里是码路工人有力量,我是码路工人,你们是力量. 今天总结一下 ES6 中跟参数相关的内容. 欢迎补充斧正.留言交流. 让我们互相学习一起进步. 1. ES6 参数默认值( ...
随机推荐
- 死磕 java线程系列之创建线程的8种方式
(手机横屏看源码更方便) 问题 (1)创建线程有哪几种方式? (2)它们分别有什么运用场景? 简介 创建线程,是多线程编程中最基本的操作,彤哥总结了一下,大概有8种创建线程的方式,你知道吗? 继承Th ...
- Django中的表关系实现及操作
表关系的实现 预备知识 ORM的正向操作和反向操作: 1.正向操作:一个模型中定义了一个外键,通过该模型对该外键操作的操作叫做正向操作. 2.反向操作:被外键所关联的模型,通过该模型对外键所在模型 ...
- guava缓存批量获取的一个坑
摘要 Guava Cache是Google开源的Java工具集库Guava里的一款缓存工具,一直觉得使用起来比较简单,没想到这次居然还踩了一个坑 背景 功能需求抽象出来很简单,就是将数据库的查询sth ...
- github项目上传管理
一.完成项目后再在github上面新建仓库然后上传代码文件 1.创建仓库时不初始化README.md文件 touch README.md //此行可忽略 git init //初始化仓库 git ad ...
- 网络请求中的cookie与set-Cookie的交互模式的一些问题解析
首先我们需要思考,很多问题. 1.当很多人访问统一个网服务器,服务器如何来区分不同的用户呢? 答:sessionid,sessionid保证了浏览器和服务器唯一性的通信凭证号码,session保存在服 ...
- java位运算,逻辑运算符
位运算逻辑运算符包括: 与(&),非(~),或(|),异或(^). &: 条件1&条件2 ,只有条件1和条件2都满足, 整个表达式才为真true, 只要有1个为false ...
- MyEclipse10 使用JRebel实现热部署
MyEclipse10 使用JRebel实现热部署 Window --Preferences-Tomcat 6.x-JDK-JVM -noverify -javaagent:D:\JRebel\jre ...
- Oracle11g入门
数据类型 数据类型 表示 数字 number 日期时间 date 字符串 char(长度)/varchar2(长度) 约束条件 名称 约束 唯一 unique 非空约束 not null 主键约束 p ...
- 域渗透-凭据传递攻击(pass the hash)完全总结
总结下PtH具体形式(wmicexec.powershell.msf等) 0x01 PtH攻击原理 && 黄金白银票据 PtH攻击原理 wiki https://en.wikiped ...
- Oier们的幸运数字
题目描述 JerryC对数字痴迷到了一种非正常的境界.每天JerryC都有喜欢的一些数字.第 iii 天JerryC就喜欢Ai−BiA_i-B_iAi−Bi中的数字.但是他觉得这样并不是很有趣,于 ...