1.事务的概念:事务是一组相互依赖的操作行为,不可分割,由一组在业务上相互依赖的SQL语句组成。四个字概括:同生共死。
2.多个事务并发时的并发问题:
脏读:A事务读取B事务尚未提交的更改数据,并在这个基础上操作。如 果B事务恰巧回滚,那么A事务读取到的数据是不被承认的。对于两个事务T1,T2。T1读取了已经被T2更改,但是还没有提交的数据,之后T2回滚,T1读取的数据是临时且无效的。
不可重复读:A事务读取B事务已经提交的更新数据。造成A事务在两个时间点读取的数据不一致。对于两个事务T1,T2。T1读取了一个字段,之后T2修改了该字段,然后,T1 再次读取了这个字段,值不一样。
幻象读:A事务读取B事务已经提交的新增数据。该情况一般发生在计算统计数据的事务中。对于两个事务T1,T2。T1从表中读取符合条件的一些记录,同时,T2往表中新增或或者删除了一些记录,然后T1再次以相同的条件查询数据,发现记录数不一致。事务T1读取与搜索条件相匹配的若干行。事务T2以插入或删除行等方式来修改事务T1的结果集,然后再提交。
两者区别:幻象读是指读到了其它事务已经提到的新增或者删除数据,而不可重复读是指读到了其它事务已经提交的更新数据。
幻象读的重点在于新增或者删除—同样的条件,两次读取的记录数不一致。
不可重复读的重点在于修改—同样的条件,两次读取的值不一致。
为了避免这两种情况,采用的策略是不同的。防止读取到更改数据,只需要对操作的数据添加行级锁,防止操作中的数据 发生变化;为了防止读取到新增数据,需要添加表级锁—将整个表数据锁定,防止新增数据。
第一类更新丢失:A事务撤销时,把B事务已经提交的更新数据覆盖了。
第二类更新丢失:A事务覆盖了B事务已经提交的更新数据。
3.隔离级别
1 Read Uncommitted(读未提交数据) 允许事务读取未被其他事务提交的数据,脏读,不可重复读,幻读都会出现
2 Read Committed(读已提交数据) 只允许事务读取已被其他事务提交的数据,不可重复读,幻读会出现
4 Repeatable Read(重复读) 确保事务可以多次从一个字段中读取相同的值,在这个事务执行期间,禁止其他事务对这个字段进行更新。幻读会出现
8 Serializable (串行化读) 确保事务可以多次从一个表中读取相同行,在这个事务执行期间,禁止其他事务对这个表进行新增,修改,删除操作。所有并发问题都可以避免,性能最低。
4.隔离级别的原则:
隔离级别越高,越能保证数据的一致性和完整性,但是对并发性能的影响很大。
对于多数应用程序而言,一般把隔离级别设置为Read Committed,这样可以避免脏读,并且有较好的并发性能。对于不可重复读,幻想读,
串行化读和第二类丢失更新,在适当的场合可以考虑使用乐观锁和悲观锁来处理。
5.默认隔离级别
Oracle支持2种隔离级别,Read Committed,Serializable,默认是Read Committed
MySql支持4种隔离级别,默认的是Repeatable Read
6.乐观锁与悲观锁
悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改数据,所以每次在拿数据的时候都会上锁。这样别人在拿这个数据就会block直到它拿到锁。传统的关系型数据库中就用到了很多这种锁机制,比如行级锁,表级锁等,读锁,写锁,都是在操作之前先上锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改数据,所以不会上锁,但是在更改之前会先判断一下在此期间别人有没有更改这个数据,可以使用版本号等机制。这样做可以提高吞吐量,像数据库中如果提供类似于write_condition这种机制其实都是用的乐观锁。
数据版本:一般是通过为数据库表增加一个“version”版本字段,读取数据时,将此版本号一同读出,在更新数据时,将此版本号加1。此时,将提交数据的版本和数据的版本进行比较,如果当前的版本数据号大于数据库的版本数据号,则进行更新,否则认为该数据过期。
7.一般处理并发问题时的步骤:
(1)开启事务。
(2)申请写权限,也就是给对象(表或记录)加锁。
(3)假如失败,则结束事务,过一会重试。
(4)假如成功,也就是给对象加锁成功,防止其他用户再用同样的方式打开。
(5)进行编辑操作。
(6)写入所进行的逻辑结果。
(7)假如写入成功,则提交事务,完成操作。
(8)假如写入失败,则回滚事务,取消提交。
(9)(7、8)两步操作已经释放了锁定的对象,恢复到操作前的状态。