Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 543|回复: 0

Hibernate数据丢失更新问题及解决

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-8-29 12:36:08 | 显示全部楼层 |阅读模式

    第一类丢失更新 

        A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来:

     

     

    时间

    取款事务A

    转账事务B

    T1

    开始事务

     

    T2

     

    开始事务

    T3

    查询账户余额为1000元    

     

    T4

     

    查询账户余额为1000元

    T5

     

    汇入100元把余额改为1100元

    T6

     

    提交事务

    T7

    取出100元把余额改为900元

     

    T8

    撤销事务

     

    T9

    余额恢复为1000 元(丢失更新)

     

       

     

     

    A事务在撤销时,“不小心”将B事务已经转入账户的金额给抹去了。 

        第二类丢失更新 

    A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失:   

    时间

    转账事务A

    取款事务B

    T1

     

    开始事务

    T2

    开始事务

                             

    T3

                   

    查询账户余额为1000元    

    T4

    查询账户余额为1000元

                             

    T5

     

    取出100元把余额改为900元

    T6

     

    提交事务           

    T7

    汇入100元

     

    T8

    提交事务

     

    T9

    把余额改为1100 元(丢失更新)

     

      

     

     

        上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元,相反如果转账事务先提交,那么用户账户将损失100元

     

    解决方法:有两种

    第一种:悲观锁(几乎不用,因为效率及慢,影响用户体验) 

      一个典型的倚赖数据库的悲观锁调用:

    select * from account where name="Erica" for update

    这条 sql 语句锁定了 account 表中所有符合检索条件( name="Erica" )的记录。 本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。

    Hibernate 的悲观锁,也是基于数据库的锁机制实现。

    下面的代码实现了对查询记录的加锁:

    String hqlStr = "from TUser as user where user.name='Erica'";

    Query query = session.createQuery(hqlStr);

    query.setLockMode("user",LockMode.UPGRADE); // 加锁

    List userList = query.list();// 执行查询,获取数据

    query.setLockMode 对查询语句中,特定别名所对应的记录进行加锁(我们为TUser 类指定了一个别名"user"),这里也就是对返回的所有 user 记录进行加锁。

    观察运行期 Hibernate 生成的 SQL 语句:

    select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex from t_user tuser0_ where (tuser0_.name='Erica' ) for update

    这里 Hibernate 通过使用数据库的 for update 子句实现了悲观锁机制。

    第二种:乐观锁(建议用)

      1.在对应的JavaBean中添加一个属性,名称可以是任意的。例如:private Integer version; 提供get和set方法

      2.在映射的配置文件中,提供<version name="version"/>标签即可。

      原理:在开启一个事物之前,数据库会自动为你添加一个version字段,默认值为0,当一个用户完成了事物并且更新了数据后,数据库会自动把version字段的值

    改为1,同时,如果另外一个用户也操作这条数据,那么,当他想保存数据的时候,就会出现版本不对的问题,从而修改失败,必须重新修改。这样一来,就可以避免

    丢失更新的问题。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-23 04:13 , Processed in 0.058984 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表