1.数据库事务的隔离级别
数据库事务的隔离级别有4个,由低到高依次为Read uncommitted 、Read committed 、Repeatable read 、Serializable ,这四个级别可以逐个解决脏读 、不可重复读 、幻读这几类问题。
1.1. Read UnCommitted(读未提交)
最低的隔离级别。一个事务可以读取另一个事务并未提交的更新结果。
1.2. Read Committed(读提交)
大部分数据库采用的默认隔离级别。一个事务的更新操作结果只有在该事务提交之后,另一个事务才可以的读取到同一笔数据更新后的结果。
1.3. Repeatable Read(重复读)
mysql的默认级别。整个事务过程中,对同一笔数据的读取结果是相同的,不管其他事务是否在对共享数据进行更新,也不管更新提交与否。
1.4. Serializable(序列化)
最高隔离级别。所有事务操作依次顺序执行。注意这会导致并发度下降,性能最差。通常会用其他并发级别加上相应的并发锁机制来取代它。
2.脏读
概念:脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交。
理解:select查询到的数据是update后但并未commit的,如果update语句rollback了,那么读取到的数据就是错的。
对策:此种情况一般发生在隔离级别为“读未提交”的数据库,一般都不会设置成“读未提交”,所以对于实际项目中,大多数情况下不需考虑。
3.不可重复读
概念: 在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据并修改数据。那么,在第一个事务的两次读数据之间。由于另一个事务的修改,那么第一个事务两次读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。
理解:第一次执行select,没有for update,则数据可以被其他用户update。恰好,第二次select之前,该数据被修改,并commit,那么第二次查询到的数据就和第一次有所不同。(注:如果数据库的隔离级别为“重复读”、或“序列化”,那么上面的情况,第二次select和第一次相同)
对策:先select for update(悲观锁),然后比较数据时间戳(乐观锁),如果画面上的时间戳,和select到的时间戳一致,则可以提交update。
4.幻读
概念: 幻读发生在按照两个完全相同的查询条件查询执行时,第二次查询所返回的结果集跟第一个查询不相同。
理解:第一次执行select where 条件,没有for update,则数据可以被其他用户update。恰好,第二次select where 条件之前,按照此查询条件insert了一条,并commit,那么第二次查询到的数据就和第一次有所不同。
对策:select where 条件 for update(范围悲观锁)