MYSQL:基础——事务处理
MYSQL:基础——事务处理
事物处理
什么是事物处理
试想我们实现一个销售结算的业务,这个完整的操作大致需要执行3条SQL语句:
UPDATE MS_GOODS SET quantity = quantity - 5 WHERE id = '1001' AND quantity >=5; --库存-5 UPDATE MS_WALLET SET money = money - 500 WHERE userid = 'admin' AND money >=500; --客户资产-500 INSERT INTO MS_DETAIL; --插入订单记录
如果这三条语句执行期间某一条语句出现问题都将导致错误后果,甚至造成不可挽回的损失。所以,这三条语句应该一起执行,即为一个原子操作,要么都成功,要么都失败!怎样让其成为一个原子操作呢,这就引入了事务的概念。事务是一个序列操作,其中的操作要么都执行,要么都不执行,一个事务为一个原子操作。
在MySQL中,手动开启事务的代码如下:
BEGIN; -- 或START TRANSACTION; UPDATE MS_SALE SET quantity = quantity - 5 WHERE id = '1001' AND quantity >=5; UPDATE MS_WALLET SET money = money - 500 WHERE userid = 'admin' AND money >=500; INSERT INTO MS_DETAIL; COMMIT;
更改默认的提交行为
在 MySQL 命令行的默认设置下,事务都是自动提交的,即执行 SQL 语句后就会马上执行 COMMIT 操作。因此要显式地开启一个事务务须使用命令 BEGIN 或 START TRANSACTION,或者执行命令 SET AUTOCOMMIT=0,用来禁止使用当前会话的自动提交。
SET AUTOCOMMIT = 0 -- 关闭自动提交 SET AUTOCOMMIT = 1 -- 打开自动提交
RollBack和Commit
开启事务后,如果我修改了一些数据,发现数据修改错误,可以执行rollback命令来使数据回滚到事务开始前的状态;当然如果事务内的代码执行没有问题,我们可以执行commit,让修改真正生效。
BEGIN; UPDATE... INSERT... DELETE... --发现修改错误 ROLLBACK; --回滚到修改前的状态 BEGIN; UPDATE... INSERT... DELETE... --修改的没毛病 COMMIT; --使修改生效
如果直接调用ROLLBACK,会使是事务内的所有操作失效,但是如果设置保留点的话,可以使数据更加灵活的恢复到保留点时的状态。
BEGIN; UPDATE... INSERT... INSERT... INSERT... SAVEPOINT MYPOINT DELETE... ROLLBACK TO MYPOINT; --回滚到delete前的状态
事物的隔离级别
事物的隔离级别主要关于多个事务访问同一数据时,MySQL的处理策略。主要有RU、RC、RR、Serializable四种,并且执行效率依次降低。
read uncommitted(读取未提交数据)
将事务隔离级别设置为read uncommitted,即便是事务没有commit,但是我们仍然能读到未提交的数据,这是所有隔离级别中最低的一种。事务B可以访问到事务A还没提交的数据,这种情况称之为脏读。
read committed(可以读取其他事务提交的数据)
当我们将当前会话的隔离级别设置为read committed的时候,当前会话只能读取到其他事务提交的数据,未提交的数据读不到。
repeatable read(可重读)
这是MySQL默认的隔离级别,在同一个事务中查询结果必须保持一致。事务A查询数据后,如果其他事务B新增了一条数据D并提交,但是事务A再查是查不到新增的数据D的,此时事务A插入数据D是会报错的,因为实际上数据D已经插入到数据库中了,这种情况也称之为幻读。
serializable(串行化)
当我们将当前会话的隔离级别设置为serializable的时候,其他会话对该表的写操作将被挂起。串行化是隔离级别中最严格的,但是这样做势必对性能造成影响。所以在实际的选用上,我们要根据当前具体的情况选用合适的。
参考资料
- https://draveness.me/mysql-transaction
- https://juejin.im/post/5b977e56e51d450e9c553cef
- https://www.jianshu.com/p/4e3edbedb9a8