python – 在什么时候抛出MySQL主键错误?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了python – 在什么时候抛出MySQL主键错误?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4289字,纯文字阅读大概需要7分钟。
内容图文
![python – 在什么时候抛出MySQL主键错误?](/upload/InfoBanner/zyjiaocheng/893/5402718e0c704344b05dc12c4c08a411.jpg)
如果我有一个批量插入语句,如:
INSERT INTO TABLE VALUES (x,y,z),(x2,y2,z2),(x3,y3,z3);
并且x2违反了主键,是在处理x3之前或之后抛出的错误?
具体来说,我在使用Python和PyMySQL的try-catch块中有一堆批量插入,如:
conn = myDB.cursor()
try:
conn.execute("INSERT INTO TABLE VALUES (x,y,z),(x2,y2,z2),(x3,y3,z3);")
except pymysql.Error as msg:
print("MYSQL ERROR!:{0}".format(msg)) #print error
我想确保如果批处理插入中的一个元组失败,从而打印错误,同一批处理中的其余元组仍然会被处理.
我的动机是我在两台服务器上传输大量数据.在服务器1中,数据存储在日志文件中,并且它被插入到服务器2上的MySQL中.一些数据已经存在于服务器2上的MySQL中,因此存在许多故障.但是,如果我不使用批量插入,并且每个(数百万)记录都有一个单独的INSERT INTO,那么事情似乎运行得慢得多.所以我遇到麻烦:使用批量插入,重复的失败会炸毁整个语句,没有批量插入,这个过程需要更长的时间.
解决方法:
MySQL处理多个插入(或更新)语句的方式因表引擎和服务器SQL模式而异.
虽然只有表引擎对于你在这里要求的关键约束非常重要,但了解更大的图片非常重要,所以我会花时间添加一些额外的细节.如果您赶时间,请随时阅读下面的第一部分和最后一部分.
表引擎
对于像MyISAM这样的非事务性表引擎,您可以轻松地最终执行部分更新,因为每次插入或更新都是按顺序执行的,并且在遇到错误行并且语句被中止时无法回滚.
但是,如果您使用像InnoDB这样的事务表引擎,那么除了中止语句之外,插入或更新语句期间的任何约束违规都将触发回滚到该点所做的任何更改.
SQL模式
当您没有违反键约束时,server SQL mode变得很重要,但是您尝试插入或更新的数据不符合您要放入的列的定义.例如:
>插入一行而不为每个NOT NULL列赋值
>将’123’插入使用数字类型定义的列(而不是123)
>更新CHAR(3)列以保存值’four’
在这些情况下,如果严格模式生效,MySQL将抛出错误.但是,如果严格模式不起作用,它通常会“修复”您的错误,这可能会导致各种潜在的有害行为(仅举两个例子,请参见MySQL ‘Truncated incorrect INTEGER value’和mysql string conversion return 0).
威尔罗宾逊,危险!
非交易表和严格模式存在一些潜在的“陷阱”.你没有告诉我们你正在使用哪个表引擎,但是目前编写的this answer显然是使用非事务表,重要的是要知道它会如何影响结果.
例如,请考虑以下语句集:
SET sql_mode = ''; # This will make sure strict mode is not in effect
CREATE TABLE tbl (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
val INT
) ENGINE=MyISAM; # A nontransactional table engine (this used to be the default)
INSERT INTO tbl (val) VALUES (1), ('two'), (3);
INSERT INTO tbl (val) VALUES ('four'), (5), (6);
INSERT INTO tbl (val) VALUES ('7'), (8), (9);
由于严格模式不起作用,因此插入所有九个值并将无效字符串强制转换为整数应该不足为奇.服务器足够聪明,可以将’7’识别为数字但不识别’two’或’four’,因此它们会转换为default value for numeric types in MySQL:
mysql> SELECT val FROM tbl;
+------+
| val |
+------+
| 1 |
| 0 |
| 3 |
| 0 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+------+
9 rows in set (0.00 sec)
现在,尝试使用sql_mode =’STRICT_ALL_TABLES’再次执行此操作.长话短说,第一个INSERT语句将导致部分插入,第二个将完全失败,第三个将默默强制’7’到7(如果你问我,这似乎不是非常“严格”,但它是documented behavior而不是那么不合理).
但等等,还有更多!尝试使用sql_mode =’STRICT_TRANS_TABLES’.现在你会发现第一个语句抛出警告而不是错误 – 但第二个语句仍然失败!如果您将LOAD DATA与一堆文件一起使用而某些文件失败而另一些文件没有失败(参见this closed bug report),这可能会特别令人沮丧.
该怎么办
特别是在密钥违规的情况下,重要的只是表引擎是否是事务性的(例如:InnoDB)(例如:MyISAM).如果您正在处理事务表,那么问题中的Python代码将导致MySQL服务器按以下顺序执行操作:
>解析INSERT语句并启动事务.*
>插入第一个元组.
>插入第二个元组(违反键约束).
>回滚事务.
>向pymysql发送错误消息.
*在开始事务之前解析语句是有意义的,但我不知道确切的实现,所以我将这些放在一起作为一步.
在这种情况下,当脚本从服务器收到错误消息并进入except块时,错误元组之前的任何更改都已被反转.
但是,如果您正在处理非事务性表,则服务器将跳过步骤4(以及步骤1的相关部分),因为表引擎不支持transaction statements.在这种情况下,脚本进入except块时,第二个元组已被插入,第二个元组已被炸毁,您可能无法轻易确定成功插入了多少行,因为如果最后一个插入或更新语句引发错误,则the function that normally does that返回-1.
应严格避免部分更新;他们更难以解决而不仅仅是确保你的陈述完全成功或完全失败.在这种情况下,the documentation suggests:
To avoid [a partial update], use single-row statements, which can be aborted without changing the table.
在我看来,这正是你应该做的.在Python中编写一个循环并不困难,只要你是inserting values properly as parameters就不必重复代码而不是硬代码 – 你已经在做了,对吧?对??? >
内容总结
以上是互联网集市为您收集整理的python – 在什么时候抛出MySQL主键错误?全部内容,希望文章能够帮你解决python – 在什么时候抛出MySQL主键错误?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。