好久没来 testerhome 了,今天刚好解决了一个怎么搜都搜不出解决方案的问题(可能是我搜索问题的姿势不对 hhh~)来社区记录下,希望能帮助到有此困惑的宝宝们!
初衷是想做个业务流程自动回归,涉及到数据库的操作,在此之前都是手动敲 SQL 在 Navicat 里执行,所以想在代码里面一把梭~
然后我啪嗒啪嗒把连接 mysql 的代码写好,开开心心的调试个 select 语句,perfect 通过,不愧是我!
然后我又啪嗒啪嗒把业务流处理逻辑写好,开开心心的 run 起来,结果却不是很开心,在执行到 update 语句时,编辑器抛出一个错误,如下:
pymysql.err.InternalError: (616, 'Proxy ERROR:In non xa transaction, this SQL use a diffent set')
不慌不慌,先上百度谷歌查查看~(PS:补充一下,本座对数据库和 MYSQL 确实不够熟悉,平时也就 select 用得比较多,drop 什么的看情况使用~)但我在百度谷歌深究了很久,一个解决办法都搜不出,太菜了……
根据报错指示,“使用 pymysql 时出现了代理错误:在非 XA 事务中,此 SQL 使用了不同的 SET 集”(已经尽力翻译了)于是我查找了下有关 “XA 事务” 的描述,得出:
XA(eXtended Architecture)是指由 X/Open 组织提出的分布式交易处理的规范。XA 是一个分布式事务协议,由 Tuxedo 提出,所以分布式事务也称为 XA 事务。XA 协议主要定义了事务管理器 TM(Transaction Manager,协调者)和资源管理器 RM(Resource Manager,参与者)之间的接口。其中,资源管理器往往由数据库实现,如 Oracle、DB2、MySQL,这些商业数据库都实现了 XA 接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。XA 事务是基于两阶段提交(Two-phaseCommit,2PC)协议实现的,可以保证数据的强一致性,许多分布式关系型数据管理系统都采用此协议来完成分布式。阶段一为准备阶段,即所有的参与者准备执行事务并锁住需要的资源。当参与者 Ready 时,向 TM 汇报自己已经准备好。阶段二为提交阶段。当 TM 确认所有参与者都 Ready 后,向所有参与者发送 COMMIT 命令。
大家当做拓展知识阅读即可,直接跳过也问题不大~~~
以上得知该数据库是一个分布式数据库,在存在多个 set 时,需要使用到阶段二的提交方式。所以能初步判断,这应该是连接和使用数据库的方式不对~就凭 pymysql 已经是大家多年的好朋友了,应该它自己能搞定自己的问题~(别问我为啥能这么快做初步判断,我靠的第六感~)
有关分布式事务的内容不在这边展开说明,有兴趣的直接翻上面的链接自行学习哦~!
拓展知识时间又到了:MySQL 的 SELECT,INSERT,UPDATE 或 DELETE 都会开启事务。如果 AUTOCOMMIT 设置为 1(默认值),每一个 SQL 语句都被认为是一个完整的事务。 AUTOCOMMIT 设置为 0 时,在随后的一系列语句的作用就像一个事务,直到一个明确的 COMMIT 语句结束。这是我辛辛苦苦搜出的重要线索,重点圈起来,要考!
修改脚本如下:
connection = pymysql.connect(
host=self.dbInfo["host"],
user=self.dbInfo["user"],
password=self.dbInfo["password"],
db=dbName,
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor,
autocommit=True #加上这一句!
)
搞定啦,可以愉快的玩耍啦~!(好像太简单了,有点侮辱智商的感觉,唉…)
在解决问题时,我在公司内部某平台上看到有个同学写了一个 “号称史上最快执行 SQL” 的小工具,也是使用跟我同一个数据库,咦,这个东西可以执行 update 语句喔,于是我开开心心找到这个天才同学让他分享他的代码给我,代码是用 java 写的,用的 JDBC 的连接方式~(果然,java 爸爸就是了不起~)
为了不影响脚本进度,于是我就照仿着 java 的实现方式,用 python 连接 JDBC,试试看能不能实现。简单描述如下:
先安装 jaydebeapi
pip install jaydebeapi -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
下载 mysql-connector-java-5.1.34.jar 包
传送门 - mysql-connector-java-5.1.34.jar 包下载地址(亲测有效)
import jaydebeapi
class JdbcJoin():
def __init__(self):
self.dbInfo = {
"host": "jdbc:mysql://xxx:3306/", #JDBC地址
"user": "admin",
"password": "admin",
"driver": "com.mysql.jdbc.Driver", #jdbc driver
"jar_file": "D:\mysql-connector-java-5.1.34.jar" #jar包位置
}
def connect(self, sql):
conn = jaydebeapi.connect(self.dbInfo["driver"], self.dbInfo["host"], [self.dbInfo["user"], self.dbInfo["password"]], self.dbInfo["jar_file"])
cur = conn.cursor()
cur.execute(sql)
result = cur.fetchall()
print(result)
cur.close()
conn.close()
乍一看,这不就是变相调用 jar 包的方式吗?跟我之前的那一篇 Python 调用 JAVA 包 - 从入门到放弃 不是一个意思吗?唉,说好要一起放弃,结果我却在 N 年后捡回来,555555555,还是要多学习多动脑,这样子在遇到问题时脑袋瓜才不会嗡嗡嗡的~
祝大家工作顺利!