13、JPA乐观锁和悲观锁

JPA乐观锁和悲观锁

JPA中锁有6种:乐观锁有2种,悲观锁3种,另外1种无锁模式 NONE

  1. OPTIMISTIC 和READ锁模式相同,JPA2.0 任然支持READ模式,但是推荐使用OPTIMISTIC
  2. OPTIMISTIC_FORCE_INCREMENT 和WRITE模式相同,推荐使用
  3. PESSIMISTIC_READ 悲观锁,只要事务读实体,实体管理器就锁定当前实体,直到事务提交才释放锁。当多次重复读语句查询数据库时,可以使用。连续多次读,保证中间不会被修改。
  4. PESSIMISTIC_WRITE 只要事务更新实体,实体管理器就会对实体上锁。当多个并发更新事务出现更新失败几率大时,采用此模式。
  5. PESSIMISTIC_FORCE_INCREMENT 当事务读实体时,实体管理器对实体上锁,即使没有修改实体,版本号也会增加。

**JPA2.0 提供多种方法可以指定锁模式,可以尝试EntityManager的lock()和find(),EntityManager.refresh()方法可以恢复实体实例的状态。

Entity 类型定义

@Data
@Entity
public class Student {
    @Id
    @GeneratedValue
    private long id;
    private String name;
    //添加1列用于版本号控制,乐观锁时使用
    @Version
    private long version;

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + "'"+
                '}';
    }
}

悲观锁案例

@Before
    public void add(){
        EntityManager entityManager = JpaUtil.getEntityManager();
        entityManager.getTransaction().begin();

        Student student=new Student();
        student.setName("jake");
        entityManager.persist(student);

        entityManager.getTransaction().commit();
        entityManager.close();
    }
    

    //悲观锁
    @Test
    public void write(){
        EntityManager e1 = JpaUtil.getEntityManager();
        EntityManager e2 = JpaUtil.getEntityManager();
        e1.getTransaction().begin();
        e2.getTransaction().begin();

        //1、PESSIMISTIC_WRITE 悲观锁,写模式不提交事务另一个事务一直等待事务提交后查询
//        Student student = e1.find(Student.class, 1L, LockModeType.PESSIMISTIC_WRITE);
//        System.out.println("student = " + student);
//        //这里会一直等待
//        Student student1 = e2.find(Student.class, 1L, LockModeType.PESSIMISTIC_WRITE);
//        System.out.println("student1 = " + student1);

        //2、PESSIMISTIC_READ 悲观锁,读模式,其他事务也可以读取,而不会等待
        Student student = e1.find(Student.class, 1L, LockModeType.PESSIMISTIC_READ);
        System.out.println("student = " + student);
        Student student1 = e2.find(Student.class, 1L, LockModeType.PESSIMISTIC_READ);
        System.out.println("student1 = " + student1);


        e2.getTransaction().commit();
        e1.getTransaction().commit();
        e2.close();
        e1.close();
    }

乐观锁案例

//乐观锁
    @Test
    public void optimistic(){
        EntityManager e1 = JpaUtil.getEntityManager();
        EntityManager e2 = JpaUtil.getEntityManager();
        e1.getTransaction().begin();
        e2.getTransaction().begin();

        //乐观锁,修改数据时会更新表中的版本,如果版本和更新时版本不一致,则报异常
        Student student = e1.find(Student.class, 1L, LockModeType.OPTIMISTIC);
        student.setName("jake1");
        Student student1 = e2.find(Student.class, 1L, LockModeType.OPTIMISTIC);
        student1.setName("jake2");

        e2.getTransaction().commit();
        //e2 提交事务后,version+1;e1 之前查询的对象版本还是原来的,提交事务时判断本身版本和数据库版本不一致,报异常;
        //javax.persistence.RollbackException: Error while committing the transaction
        e1.getTransaction().commit();
        e2.close();
        e1.close();
    }

控制台打印输出

update Student set name=?, version=? where id=? and version=?
Hibernate: select version from Student where id =?
Hibernate: update Student set name=?, version=? where id=? and version=?
//最后e1提交事务时,发现数据库版本号和当前实体版本号不一致,报异常
javax.persistence.RollbackException: Error while committing the transaction

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值