处理并发问题-锁

转自:小魏的博客(https://blog.csdn.net/u014034934/article/details/60127392)

多个事务并发运行时的并发问题

  • 第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖 脏读:一个事务读到另一个事务未提交的数据
    虚读:一个事务读到另一个事务已提交的新插入的数据 不可重复读:一个事务读到另一个事务已提交的更新数据。

  • 第二类丢失更新:不可重复读中的特例,一个事务覆盖另一个事务的更新数据

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
数据库锁的基本原理
1.事务执行select语句时,要先获得共享锁,insert,delete等更新语句时,要先获得独占锁。
2.第二个事务执行select语句时,要先获得共享锁,执行更新语句时要获得独占锁。要根据资源上锁的类型,来决定是否等待第一个事务释放对资源的锁定,还是马上获得锁。
这里写图片描述

锁的多粒度性及自动锁的升级
数据库中能够锁定的资源有:数据库,表,区域(锁定数据库的特定区域),页面(锁定数据库的特定页面),键值(带有索引的行数据),行(当行数据)
锁的粒度越大,事务的隔离性越高,事务之间的并发性能越低。一般数据库都会把锁自动升级,就是多个低级锁来升级成高级锁,来降低系统负荷。

锁的类型及兼容性

  • 共享锁:用于读数据操作,它是非独占的,允许其他事务同时读取锁定的资源,但不允许更新。

    1.执行select时,加锁。
    2.默认情况下,数据读取后就解除了共享锁,例如select * from a.先锁定第一行,读取,释放,锁定第二行。读取释放。
    3.如果资源上被放置了共享锁,还能放置共享锁和更新锁。
    4,具有良好的并发性能
    
  • 独占锁:也加排他锁,锁定的资源不能读取也不能修改。

    1.更新操作语句时,加锁,如果有了独占锁,就无法在放置。
    2.事务结束释放锁。
    3.不与其他锁兼容。
    4.并发性能差,只允许一个事务锁定特定的数据,其他事务必须等到释放锁后才能操作这些数据。
    
  • 更新锁:在更新操作的初始化阶段锁定可能要被修改的资源。可以避免共享锁造成的死锁问题。

update  a set xx=xx where a.name='hello'

先获得共享锁,然后升级为独占锁。有两个事务时,同时获得共享锁,然后要升级共享锁,但是独占锁要等待其他事务释放共享锁,所以所有的事务都等待了,就造成了死锁。

     1. update语句时分配更新锁
     2. 读取数据后执行更新操作时,把更新锁升级为独占锁。
     3. 更新锁和共享锁兼容,但是只能有一个更新锁。
     4. 允许其他事务同时读锁定的资源,但是不允许修改。

死锁及其防止办法

死锁是指多个事务分别锁定了一个资源,又试图请求锁定对方已经锁定的资源,那么所有的事务就会等待别的事务释放锁。
        1.合理安排表的访问顺序。
        2.使用短事务
        3.如果对一致性要求不高,可以允许脏读,脏读不需要加锁,可以避免锁冲突。
        4.可能的话,错开访问相同资源的时间,防止锁冲突。
        5.尽可能使用事务隔离级别低的事务

数据库的事务隔离级别

1.Serializable:串行化
2.RepeatAble Read:可重复读
3.Read Commit:读已提交数据
4.Read Uncommit:读未提交数据。
这里写图片描述

串行化:一个事务完全看不到其他事务对数据的更新。
可重复读:可以看到其他事务已提交的新插入的数据,看不到对已有记录的更新。
读已提交数据:可以看到插入的记录,也可以看到已提交更新的记录
读未提交数据:可以看到插入的记录,也可以未提交的更新记录

在程序中采用悲观锁
悲观锁:应用程序显示的为资源加锁。悲观锁假定当前资源会被同时访问,先加锁,可以防止不可重复读和丢失更新。
乐观锁:假定资源没有竞争,完全让数据库隔离级别来操作数据。

悲观锁的两种实现方式
1.显式的指定独占锁来锁定资源。select … for update就可以指定独占锁。
2.在数据库中指定一个表明状态的字段,为Y表示锁定,为N表示没锁定。

Hibernate版本控制来实现乐观锁
1.使用<version>:表中有一个version字段

<class>
<id>
<version name="" column/>//必须紧跟id
</class>

hibernate执行update语句时,先根据缓存中对象的version去匹配数据库

update xxx set version=1 where xxx and version=0

然后version加一,更新到session,因为其他事务得到的对象还是原来的,是游离对象,多以其他事务再执行上面的语句会报StaleObjectStateException.有两种方式处理:

  • 1)自动撤销事务
  • 2)通知用户数据被修改了,是否继续事务,还是撤销事务

还可以使用跟version一样,只是这个是时间,version是数字加1。timestamp可能比version不安全,因为可能两个事务的时间是一样的。

2.对游离对象进行版本检查

session.lock(对象,LockMode.READ)

lock设定为LockMode.READ,则马上进行版本检查,不会计划执行语句。数据库没有匹配到就包StaleObjectStateException。update()方法不会马上检查,会计划执行一条语句。等到清理缓存时,如果数据库没有匹配到就包StaleObjectStateException。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值