在执行SQL语句的时候,某些业务要求,一系列操作必须全部执行,而不能仅执行一部分。 例如,一个转账操作:
CREATE TABLE `jwentest` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`balance` int(3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8
update jwentest set balance = balance - 10 where id=1;
update jwentest set balance = balance + 10 where id=2;
这两条SQL语句必须全部执行,或者,由于某些原因,如果第一条语句成功,第二条语句失败,就必须全部撤销。这种把多条语句作为一个整体进行操作的功能,被称为数据库事务。数据库事务可以确保该事务范围内的所有操作都可以全部成功或者全部失败。如果事务失败,那么效果就和没有执行这些SQL一样,不会对数据库数据有任何改动。
-- 事务commit成功
BEGIN;
update jwentest set balance = balance - 10 where id=1;
update jwentest set balance = balance + 10 where id=2;
COMMIT;
-- 事务回滚
BEGIN;
update jwentest set balance = balance - 10 where id=1;
update jwentest set balance = balance + 10 where id=2;
ROLLBACK;
重新开个查询窗口,逐步执行事务,在新开窗口查看到的数据和现有窗口查看到的数据,进行对比
-- 窗口A
BEGIN;
update jwentest set balance = balance - 10 where id=1;
update jwentest set balance = balance + 10 where id=2;
select * from jwentest; -- 查看数据,发现数据update成功
-- 切到窗口B
select * from jwentest; -- 查看数据,发现数据没有update
-- 切到窗口A
COMMIT;
-- 切到窗口B
select * from jwentest;
在事务处理的过程中,该mysql连接(或者说进程)把数据库表lock住了 同理ROLLBACK操作一次:
-- 窗口A
BEGIN;
update jwentest set balance = balance - 10 where id=1;
update jwentest set balance = balance + 10 where id=2;
select * from jwentest; -- 查看数据,发现数据update成功
-- 切到窗口B
select * from jwentest; -- 查看数据,发现数据没有update
-- 切到窗口A
ROLLBACK;
-- 切到窗口B
select * from jwentest;
异常case,可以讨论下
BEGIN;
update jwentest set balance = balance - 10 where id=1;
INSERT INTO `test`.`jwentest`(`id`, `balance`) VALUES (1, 1000); --Duplicate entry '1' for key 'PRIMARY'
COMMIT;
按照对事务的理解,一起成功一起失败,上面的case应该是update不成功,因为第二个sql语句是肯定失败的 ,但执行完发现: 在本窗口,数据update了的,而在其他窗口来看,其实没有update成功了的,因为事务lock住了 事务失败是程序检测到错误主动调用rollback 你忽略了错误继续调用commit那成功执行的sql就保存了 还有其他异常case:可参考: https://www.cnblogs.com/jkko123/p/10184532.html
可不可报错了后自动回滚呢 ? 可以,需要设置,请参考: https://www.cnblogs.com/ajianbeyourself/p/6956417.html
SELECT
table_name,
`engine`
FROM
information_schema.TABLES
WHERE
table_name = 'jwentest';
-- 查看lock的超时时间
show variables like 'innodb_lock_wait_timeout';
set innodb_lock_wait_timeout = 120;
-- 查看process
SELECT * from information_schema.`PROCESSLIST` where DB='test' ORDER BY TIME desc;
-- kill process
kill 12323
select * from information_schema.innodb_trx;
select * from information_schema.innodb_locks;
select * from information_schema.innodb_lock_waits;
# -*- coding: utf-8 -*-
# @Time : 2020/6/15 17:59
# @Author : jwen
# @File : demo1.py
import pymysql
if __name__ == "__main__":
print("start")
# 打开数据库连接
db = pymysql.connect("host", "root", "password", "test")
# 使用 cursor() 方法创建一个游标对象 cursor
cursor = db.cursor()
try:
print("update db ...")
# 使用 execute() 方法执行 SQL 查询
sql1 = "update jwentest set balance = balance - 10 where id=1;"
cursor.execute(sql1)
# insert错误
sql2 = "INSERT INTO `test`.`jwentest`(`id`, `balance`) VALUES (1, 1000);"
# sql2 = "update jwentest set balance = balance + 10 where id=2;"
cursor.execute(sql2)
db.commit()
print("commit success")
except Exception as e:
print(e)
print("rollbacking...")
db.rollback()
# 关闭数据库连接
db.close()
第三方调用不要放在事务中,再调用offer-sync的时候确保DB update成功了并释放了锁
高并发下的话。。问题有没有解决呢 ? 并发调用apply接口修改同一份数据,第二次等待lock超时?
如果没有指定隔离级别,数据库就会使用默认的隔离级别。在MySQL中,如果使用InnoDB,默认的隔离级别是Repeatable Read。
https://www.liaoxuefeng.com/wiki/1177760294764384/1179611198786848 https://segmentfault.com/a/1190000015314171 https://blog.csdn.net/java__project/article/details/100137526 https://cloud.tencent.com/developer/article/1356959 https://www.cnblogs.com/jkko123/p/10184532.html