将MySQL与Python一起使用时,您可能希望使用mysqlclient库,这是大多数人所做的且效果甚好。或者,如果您正在使用官方的MySQL 8 Connector/Python包,情况会略有不同,但可能已经在MySQL 8中支持的功能还尚未出现在mysqlclient中。
您的SQL可能是手动编写的,也可能是使用SQL Alchemy,Django或其他包生成的。如果是后者,为了便于交互式调试,查看发送到数据库的实际SQL字符串的方法可能会很有用。
使用 mysqlclient
如果mysqlclient与Python一起使用,则Cursor类内部以该类(github源码)中的_query(self, q)方法将SQL发送到服务器。
该方法_query(self, q)本身会更新cursor的_executed成员,存储发送到服务器的文本查询字符串。但它仅在发送查询后才会这样做。出错时,将引发异常且_executed的更新失败(github源码 )。
若要访问实际的查询字符串,请定义一个类DebugCursor,并使用连接**kwargs指定它。在DebugCursor中,这么做是有必要的。
import MySQLdb
import MySQLdb.cursors
class DebugCursor(MySQLdb.cursors.DictCursor):
def _query(self, q):
print(f"Debug: {q}")
super()._query(q)
db_config = dict(
host="localhost",
user="kris",
passwd="secret",
db="kris",
cursorclass=DebugCursor, # referenced class must be defined before
)
db = MySQLdb.connect(**db_config)
c = db.cursor(()
sql = "select d from testtable where id = 3"
c.execute(sql)
print(c.fetchall())
在类DebugCursor中,我们选择继承ursor。重写_query(self, q)方法,打印查询字符串q,然后调用父类实现。
输出:
$ python3 probe.py
Debug: b'select d from testtable where id = 3'
({'d': 'drei'},)
即使查询字符串无效或包含语法错误,我们也可以使用它来跟踪所有被执行之前的文本SQL。
使用 MySQL Connector/Python
如果您使用Oracle MySQL Connector/Python连接到数据库,则可以在内部使用Cython或协议的Pure Python实现。
这两种实现的行为略有不同。只有Pure Python实现可以在所有情况下轻松调试。因此,请务必使用**kwargs连接指定use_pure=True。
原始SQL语句将在cursor的_executed成员中找到。如果您使用的是多语句,它们将记录在_executed_list中。
我们写为:
import mysql.connector
import mysql.connector.errors
db_config = dict(
host="127.0.0.1",
user="kris",
passwd="geheim",
db="kris",
use_pure=True,
)
db = mysql.connector.connect(**db_config)
c = db.cursor()
print("=== Valid SQL: ")
sql = "select d from testtable where id = 3"
c.execute(sql)
print(f"Debug: {c._executed}")
print(c.fetchall())
print()
print("=== Invalid SQL: ")
sql = "syntaxerror d from testtable where id = 3"
try:
c.execute(sql)
except mysql.connector.errors.ProgrammingError as e:
print(f"Debug: {c._executed}")
print(f"Error: {e}")
输出如下所示:
python3 probe.py
=== Valid SQL:
Debug: b'select d from testtable where id = 3'
[('drei',)]
=== Invalid SQL:
Debug: b'syntaxerror d from testtable where id = 3'
Error: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'syntaxerror d from testtable where id = 3' at line 1
同样,我们可以使用它来跟踪原始SQL并识别实际生成的SQL语法,这样会更容易。这将允许我们选取文本SQL字符串,并以交互方式进行调试。
如果SQL格式不正确,则在不带use_pure=True的情况下运行时,相同的程序将无法正确更新c._executed。它将生成以下输出,这对于调试毫无价值:
$ python3 probe.py
=== Valid SQL:
Debug: b'select d from testtable where id = 3'
[('drei',)]
=== Invalid SQL:
Debug: b'select d from testtable where id = 3'
Error: 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'syntaxerror d from testtable where id = 3' at line 1
请注意,c._executed是怎样做到仍然保存前一个语句,而不是实际出错的语句。
原文标题:Debugging SQL in Python
原文作者:Kristian Köhntopp
原文链接:https://blog.koehntopp.info/2022/03/24/debugging-sql-in-python.html#using-mysqlclient