数据库事务与并发
概述:事务通过隔离级别控制锁的形式来处理数据的并发问题。
为什么事务能够处理并发问题?
答:事务的特性决定它能够处理并发问题:一致性、隔离性、持久性、原子性
数据的并发有哪些情况?
答:
一、后发生的事务影响前面的事务
1、第一类更新丢失:后发生的事务回滚覆盖了前面提交成功的事务
2、脏读:后发生的事务成功提交覆盖了前面的回滚的事务
3、第二类更新丢失:后发生的事务成功提交覆盖了前面的成功提交的事务
二、后发生的事务受到前面的事务的影响
1、虚读:后一个事务在前后两次读取数据时由于前面的已提交的事务进行了插入操作,
而使数据统计前后不一致。
2、不可重复读:后一个事务在对同一条数据前后两次读取时由于前面的已提交的事务
进行了对这条数据更新操作,而使数据前后不一致。
事务如何处理并发问题?
答:
事务通过锁来处理并发问题一般有两种方式:
悲观锁:通过数据库系统的锁来处理并发
乐观锁:通过应用程序逻辑处理并发
悲观锁的种类有哪些?
答:
一、共享锁:用于读数据操作。
特性:
1、加锁条件:当一个事务执行select语句时数据库系统会为这个事务分配一把共享锁,来锁定被查询的记录。
2、解锁条件:读取完毕则释放共享锁。
3、兼容性:如果数据资源上已经放了共享锁还可放共享锁和更新锁。
4、并发性能:具有良好的并发性能。
二、更新锁:在更新操作的初始化阶段用来锁定可能要被修改的资源,避免使用共享锁造成的死锁问题。
特性:
1、加锁条件:当一个事务执行update语句时,数据库系统会先为事务分配一个更新锁。
2、解锁条件:当读取数据完毕,进行更新操作时将更新锁升级为独占锁。
3、兼容性:与共享锁兼容。一个数据资源上可以有多个共享锁和一个更新锁。
4、允许多个事务同时读锁定的资源,但不允许其它事务修改它。
三、独占锁:修改数据时使用独占锁。
特性:
1、加锁条件:当执行update、delete、insert操作时数据库系统会为数据资源使用独占锁。如果该资源上已经有其它锁
存在时则无法放置独占锁
2、解锁条件:独占锁一直到事务结束才能被解除。
3、兼容性:独占锁不能和其它锁兼容。
4、并发性:并发性能较差。
事务如何控制锁的形式?
答:事务通过事务的隔离级别来控制锁的形式。
事务级别有哪些?并发情况怎样?
答:
隔离级别
是否出现第一类丢失更新
是否出现脏读
是否出现虚读
是否出现不可重复读
是否出现第二类丢失更新
Serializable
否
否
否
否
否
Repeatable Read
否
否
是
否
否
Read Commited
否
否
是
是
是
Read Uncommited
否
是
是
是
是
在应用程序中如何使用乐观锁:
答:一般在数据库表中增加Version或者是TimeStamp字段,根据读取时以及在进行修改操作时Version或者TimeStamp的值不同来控制并发问题。
Hibernate是如何处理并发问题的:
答:
一、Hibernate在读取数据时通过设置锁定模式来控制悲观锁的形式
锁定模式
描述
LockMode.NONE
如果在Hibernate的缓存中存在指定对象,就直接返回该对象的引用;否则就通过Select语句到数据库中加载该对象。这是默认值
LockMode.Read
不管Hibernate的缓存中是否存在指定对象,总是通过select语句到数据库中加载该对象;如果映射文件中设置了版本元素,就执行版本检查,比较缓存中的指定对象是否和数据库中的版本一致。
LockMode.UPGRADE
不管Hibernate的缓存中是否存在指定对象,总是通过select语句到数据库中加载该对象;如果映射文件中设置了版本元素,就执行版本检查,比较缓存中的指定对象是否和数据库中的版本一致。如果数据库系统支持悲观锁就执行select。。。for update语句,如果数据库系统不支持悲观锁,就执行普通的select语句。
LockMode.UPGRADE_NOWAIT
和LockMode.UPGRADE具有同样的功能。此外对于Oracle数据库,执行select。。for update nowait语句。
LockMode.WRITE
当Hibernate向数据库保存或者更新一个对象时,会自动使用此模式。这种模式仅供Hibernate内部使用。
二、Hibernate在映射文件中使用乐观锁处理并发问题
1、<version>元素:此元素指定的字段,每进行一次操作就自动加1,在进行读取和修改操作时如果version值不相同则抛出异常,交给应用程序处理。
2、<timestamp>元素:此元素指定的字段数据,每进行一次操作就更新成当前时间。由于当前时间精确到妙所以在处理并发问题的精确性上没有<version>好。
注意:这两个元素在使用时都要紧跟在<id>元素后面。
3、对于现有的数据库表不包含version或者timestamp字段,要处理并发问题可以在<class>元素上进行如下设置:
<class name=”Account” table=”Accounts” optimistic-lock=”all” dynamic-update=”true”>