mysql不得不说的事务问题总结
定义
事务,什么是事务,它是数据库操作的最小工作单元,是作为单个逻辑工作单元的一系列操作;
或者说,事务是一组不可再分割的操作集合。
典型事务场景:
转账
update user_account set balance = balance - 1000 where userID = 3;
update user_account set balance = balance +1000 where userID = 1;
如何开启
begin / start transaction -- 手工
commit / rollback -- 事务提交或回滚
SHOW VARIABLES like 'autocommit'; 查看是否开启自动提交
set session autocommit = on/off; -- 设定事务是否自动开启
JDBC 编程:
connection.setAutoCommit(boolean);
Spring 事务AOP编程:
expression=execution(com.gpedu.dao..(..))
事务的特性(谨记 ACID)
原子性
最小的工作单元,整个工作单元要么一起提交成功,要么全部失败回滚。
一致性
事务中操作的数据及状态的改变是一致的,即写入资料的结果必须完全符合预设的规则,不会因为出现系统意外导致状态不一致。比如上面转账的例子,如果第一个账户减掉1000块钱,那么第二个不可以只加几百块钱,数据必须是对的上的。
隔离性
一个事务所操作的数据在提交之前对其他事务可见性设定,一般设定不可见。
持久性
事务所作的修改会永久保存,不会因为系统意外导致数据的丢失。
事务并发时带来的一些问题
1.脏读
一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条记录的数据处于不一致状态;此时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并做进一步的处理,就会产生未提交的数据依赖。
2.不可重复读
一个事务在读取某些数据后,再次读取以前读过的数据,发现读出来的数据已经发生了变化,或者某些记录已经被删除
3.幻读
一个事务按照相同的检索条件,重新读取以前检索过的数据,却发现其他事务插入了满足查询条件的新数据,该现象就称为“幻读”,表现为新插入数据
4.更新丢失
当两个或者多个事务选择同一行,然后基于最初选定的值进行更新操作时,由于每个事务都不知道其他事务的存在,则会发生丢失更新问题,即最后的更新并覆盖了前一个程序员所做的更改。
针对上面产生的问题解决定义了四种隔离级别
隔离级别
SQL92 ANSI/ISO标准:
http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
Read Uncommitted(未提交读) --未解决并发问题
事务未提交对其他事务也是可见的,会有脏读(dirty read)
Read Committed(提交读) --解决脏读问题
一个事务开始之后,只能看到自己提交的事务所做的修改,但是不可重复读(nonrepeatable read)
Repeatable Read (可重复读) --解决不可重复读问题
在同一个事务中多次读取同样的数据结果是一样的,这种隔离级别未定义解决幻读的问题
Serializable(串行化) --解决所有问题
最高的隔离级别,通过强制事务的串行执行 ,所有的事务都串行指向。
隔离级别是怎么实现的??
通过锁还有MVCC来实现。
见这篇文章: https://www.jianshu.com/p/b32086b9c38d
spring事务的传播性
基本上,在使用spring开发的时候,也需要关注事务传播性。所谓spring 事务的传播属性,就是定义在存在多个事务同时存在的时候,spring 应该如何处理这些事务的行为。这些属性在TransactionDefinition 中定义,具体常量的解释见下表:
xml使用:
注解方式使用:
更详细的,我突然发现了一片文章,整理得更细致。
https://blog.csdn.net/hcmony/article/details/77850183