暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

在Python中调试SQL

原创 沐言倾心 2022-10-12
853

将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

最后修改时间:2022-10-20 15:19:09
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
2人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论