1、事务的并发问题
因为并发事务导致的问题大致有5种,其中两种是更新问题,三种是读问题。
(1)更新问题
● 丢失更新:撤销一个事务时,把其他事务已提交的更新数据也失效了(A和B事务并发执行,A事务执行更新后,提交;B事务在A事务更新后,B事务结束前也做了对该行数据的更新操作,然后回滚,则两次更新操作都丢失了)。
● 覆盖更新:一个事务覆盖另一个事务已提交的更新数据(即A事务更新数据,然后B事务更新该数据,覆盖了A事务更新的数据)。
(2)读问题
● 脏读:读取到另一个事务未提交数据,即脏数据,危害最大;
● 不可重复读:一个事务读到另一个事务已提交的更新数据,导致两次读取不一致;
● 幻读(虚读):对同一张表的两次查询数目不一致,再次查询发现结果集中有以前没有的数据或者以前有的数据消失了,因为另一事务做了增删操作;
附:不可重复读和幻读的区别?
不可重复读是读取到了另一事务的更新;
幻读是读取到了另一事务的插入或删除导致数据不一致(MySQL中无法测试到幻读)。
2、事务的隔离级别
事务中有4个等级隔离级别,在相同数据环境下,使用相同的输入,执行相同的工作,根据不同的隔离级别,可以导致不同的结果。不同事务隔离级别能够解决的数据并发问题的能力也是不同的。
(1)SERIALIZABLE(串行化)
一个事务执行的时候不允许别的事务并发执行,对同一数据的访问是串行的,即让事务排队一个一个的访问,所以就没有了并发现象;是最严格的隔离级别,不会出现以上所有的问题。但是这样性能最差,因此应该避免这种隔离级别。
(2)REPEATABLE READ(可重复读)
一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(所以没有解决幻读问题),但是不能看到其他其他事务对已有记录的更新(解决了不可重复读和脏读问题)。这种隔离级别防止了脏读和不可重复读;不能避免幻影读问题。
性能比SERIALIZABLE好,是mysql的默认隔离级别。(3)READ COMMITTED(读已提交数据)
一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(所以还会导致两次统计数据不一致,所以没有解决幻读问题),而且能看到其他事务已经提交的对已有记录的更新(所以没有解决不可重复读问题)。
性能比REPEATABLE READ好,是Oracle的默认隔离级别。
(4)READ UNCOMMITTED(读未提交数据)
可能出现任何事务并发问题,一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且能看到其他事务没有提交的对已有记录的更新。不能解决脏读问题。
性能最好,但是因为脏读都没有解决,不建议使用。
3、JDBC设置隔离级别
设置隔离级别方法:
<span style="font-size:18px;"> con. setTransactionIsolation(int level)</span>
参数可选值如下:
<span style="font-size:18px;"> Connection.TRANSACTION_READ_UNCOMMITTED
Connection.TRANSACTION_READ_COMMITTED
Connection.TRANSACTION_REPEATABLE_READ
Connection.TRANSACTION_SERIALIZABLE</span>