使用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