锁的分类
- 按照数据库性能分为乐观锁和悲观锁(个人觉得乐观锁从严格意义上来说不叫锁,他没有锁定任何数据,只是用了版本号来控制)。
- 按照对数据库的操作类型分为读锁和写锁(都属于悲观锁)。读锁也叫共享锁,针对同一份数据,允许多个读操作,不允许任何写操作(一般在数据迁移的时候用到);写锁也叫排它锁,当前锁没有释放,其它的读写操作都会阻塞。
- 按照对数据库锁的粒度划分为表锁和行锁。表锁偏向使用MyISAM存储引擎,开销相对更小,加锁更快,不会死锁,但是锁的粒度大,更大概率出现锁竞争,所以并发度相对较低。行锁偏向使用InnoDB存储引擎,开销相对更大,加锁慢,会出现死锁,但是加锁的粒度小,锁竞争的概率更低,并发度更高。InnoDB与MyISAM的不同点在:行级锁和支持事物。
事物的属性
事物的ACID属性,这里就不介绍了,网上大把的说明文档,都很详细。
并发事物带来的问题
更新丢失(Lost Update):当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。
脏读(Dirty Reads):一个事务正在对一条记录做修改,在这个事务完成并提交前,这条记录的数据就处于不一致的状态;这时,另一个事务也来读取同一条记录,如果不加控制,第二个事务读取了这些“脏”数据,并据此作进一步的处理,就会产生未提交的数据依赖关系,这种现象被形象的叫做“脏读”。
不可重复读(Non-Repeatable Reads):一个事务在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了改变、或某些记录已经被删除了!这种现象就叫做“不可重复读”。总结为事务A在事物内读取到了事务B提交前后的两次数据,不符合隔离性。
幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。
总结为事务A在事物内读取到了事务B提交前的数据和提交后的新增数据,不符合隔离性。
解决并发事物问题
解决数据库并发事物,数据库内部采用事物隔离级别来解决,隔离的级别与并发的性能紧密相关,性能从高到低依次为:Read uncommitted, Read committed, Repeatable read, Serializable四种级别。MySQL默认的级别为:Repeatable read,可以通过spring注解进行设置,也可以通过SQL命令设置,查看当前数据库的事务隔离级别: show variables like 'tx_isolation'; 设置事务隔离级别:set tx_isolation='REPEATABLE-READ';
各事物隔离级别对脏读、不可重复读、幻读出现的的解决程度如下表: