使用Python采集SQL Server数据库服务器磁盘信息时,遇到了一个错误“CONFIG statement cannot be used inside a user transaction.DB-Lib error message 20018, severity 16”,那么为何遇到这个错误呢? 其实很简单,就是由于SQL Server事务中不容许使用RECONFIGURE,咱们能够简单模拟构造一下这个错误,以下所示:html
BEGIN TRAN
EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE;
COMMIT TRAN;
个人Python脚本中,访问数据库的SQL没有使用事务(没有BEGIN TRAN ... COMMIT TRAN),那么是否pymssql中默认会开启事务呢? 咱们能够构造一个Python脚本访问SQL Server 数据库,而后咱们使用SQL Profile跟踪一下,就基本上能知道是否pymssql会默认开启事务。Python脚本TranTest.py以下所示:python
# -*- 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.close()
以下截图所示,咱们发现pymssql会对任何访问SQL Server的SQL加上BEGIN TRAN,也许眼尖的同窗发现了端倪,SQL Profile捕获的SQL,有BEGIN TRAN,可是没有COMMIT TRAN,这个是由于上面的Python代码中没有提交事务(#dest_db_conn.commit() 注释了)git
修改上面Python代码,在关闭数据库链接前,加上一行代码dest_db_conn.commit(),而后重复上面实验就能看到COMMIT TRAN了,以下所示:github
dest_db_conn.commit()
dest_db_conn.close()sql
那么pymssql中是否能够关闭事务呢? 由于有些普通、简单的查询,根本没有必要使用事务,其实pymmsql的Connection接口实际上是提供了这么一个功能的,官方文档的介绍以下:数据库
Connection object methods服务器
Connection.autocommit(status)app
Where status is a boolean value. This method turns autocommit mode on or off.ide
By default, autocommit mode is off, what means every transaction must be explicitly committed if changed data is to be persisted in the database.测试
You can turn autocommit mode on, what means every single operation commits itself as soon as it succeeds.
A pymssql extension to the DB-API 2.0.
咱们知道,SQL Server在默认状况下数据库链接处于自动提交模式(autocommit mode),每一个SQL命令一旦被执行便提交给数据库,一旦提交就没法回滚。 在数据库中不支持事务的状况下,自动提交模式是惟一支持的模式。 在此类数据库语句仅在提交后能够执行它们并无方法回滚它们;它们所以始终处于自动提交模式.
那么咱们测试一下就会发现autocommit=True的状况下,pymmsql不会自动给SQL加上BEGIN TRAN了(测试期间,犯了个迷糊,弄混了一个前提条件,并且没有充分测试,就作出了一个相反的结论,后续本身一直折腾时才发现这个问题)
修改前代码:
dest_db_conn = pymssql.connect(host=os.environ.get('db_host'),
user=bytes.decode(db_user),
password=password_decrypted,
database='master',
charset="utf8");
修改后代码:
dest_db_conn = pymssql.connect(host=os.environ.get('db_host'),
user=bytes.decode(db_user),
password=password_decrypted,
database='master',
charset="utf8",
autocommit=True);
关于pymssql默认状况下会关闭自动提交模式(autocommit mode)开启事务的行为,必定要当心,若是你SQL脚本里面有DML操做并且忘记加commit时,那么可能形成不少没必要要的阻塞。并且相信不少不明因此的同窗还会一脸懵逼。
参考资料:
https://github.com/pymssql/pymssql/issues/460
http://pymssql.org/en/stable/ref/pymssql.html#connection-object-methods