温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何使用JPA加锁机制

发布时间:2021-10-15 11:17:33 来源:亿速云 阅读:483 作者:iii 栏目:开发技术

这篇文章主要介绍“如何使用JPA加锁机制”,在日常操作中,相信很多人在如何使用JPA加锁机制问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用JPA加锁机制”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    JPA的加锁机制有两种,乐观锁和悲观锁。

    乐观锁:

    乐观锁的特点在于认为数据冲突或者更新丢失等情况是很少发生的.当发生的时候,抛出异常和回滚就足够解决问题.

    悲观锁:

    悲观锁的逻辑在于认为每次数据操作都很有可能发生冲突,所以一开始就获得记录的锁,再进行记录的操作是解决问题的优先选择.

    一 简述悲观锁的用法

    悲观锁通常是SQL级别的,通过读写时先拿到锁实现,在SQL语句中就会有体现.

    1.1 EntityManager 用法

    return em.createQuery(sql 语句).setLockMode(LockModeType.NONE).getResultList();     //分解写法大概是:     Query query = getSession().createQuery(hql);     query.setLockMode(LockModeType.NONE);

    EntityManager 是一个辅助类,createQuery后返回的就是一个Query对象,然后通过

    setLockMode设置锁的级别即可.

    LockModeType 类型解释
    LockMode.READ事务的隔离级别是Repeatable Read或Serializable时,请求读取数据库记录时自动获得
    LockMode.WRITE请求插入或更新数据库记录时自动获得
    LockMode.OPTIMISTIC乐观锁
    LockMode.OPTIMISTIC_FORCE_INCREMENT乐观锁,通过version控制
    LockMode.PESSIMISTIC_READ与LockMode.PESSIMISTIC_WRITE相同
    LockMode.PESSIMISTIC_WRITE事务开始即获得数据库的锁
    LockMode.PESSIMISTIC_FORCE_INCREMENT事务开始即设置version
    LockMode.NONE取消任何锁,如事务结束后的所有对象,或执行了Session的update()、

    二 乐观锁的详细用法

    乐观锁本篇的主要内容

    实体类是关键 , 乐观锁常用方法是通过version来控制 ,

    • 数据库对应的表中需要有一个字段(名字随意),字段类型设置成BigInt即可

    • 业务不对该字段进行控制,字段的控制交由系统处理

    • 每一次修改都会导致version递增

    • 当出现同时获得该记录的对象且均需要修改时,当第一个已经提交事务,version字段发生改变,后面提交的事务发现version版本不对,则无法提交,抛出异常

    实体类(注意其中的@Version注解)

    @Entity public class User {     @Id     @GeneratedValue     private Long id;     private String username;     private String userdesc;     @Version     private Long version;     public User() {     }     public User(String username, String userdesc) {         this.username = username;         this.userdesc = userdesc;     }     public Long getId() {         return id;     }     public void setId(Long id) {         this.id = id;     }     public String getUsername() {         return username;     }     public void setUsername(String username) {         this.username = username;     }     public String getUserDesc() {         return userdesc;     }     public void setUserDesc(String userdesc) {         this.userdesc = userdesc;     }     public Long getVersion() {         return version;     }     public void setVersion(Long version) {         this.version = version;     } }

    controller中通过sleep将线程沉睡,测试事务的提交性

    @RestController public class UserController {     private Logger logger = LoggerFactory.getLogger(getClass());     @Autowired     UserService userService;     @PostMapping("/changeone")     @Transactional     public String changeone() {         User user = userService.findUser("gang");         try {             logger.info("修改1 before:user--{}--Versdion:{}", user.getUserDesc(), user.getVersion());             Thread.sleep(25000);             user.setUserDesc("修改1");             logger.info("修改1 :user--{}--version:{}", user.getUserDesc(), user.getVersion());         } catch (InterruptedException e) {             e.printStackTrace();         } catch (Exception e) {             logger.info("eeeeeeeeeeeeee");             e.printStackTrace();         }         return "true";     }     @PostMapping("/changetwo")     @Transactional     public String changetwo() {         User user = userService.findUser("gang");         try {             logger.info("修改2 before:user--{}--version:{}", user.getUserDesc(), user.getVersion());             Thread.sleep(30000);             user.setUserDesc("修改2");             logger.info("修改2:user--{}--version:{}", user.getUserDesc(), user.getVersion());         } catch (InterruptedException e) {             e.printStackTrace();         } catch (Exception e) {             logger.info("eeeeeeeeeeeeee");             e.printStackTrace();         }         return "true";     }     @PostMapping("/changethree")     @Transactional     public String changethree() {         User user = userService.findUser("gang");         logger.info("修改3 before:user--{}--version:{}", user.getUserDesc(), user.getVersion());         user.setUserDesc("修改3");         logger.info("修改3 :user--{}--version:{}", user.getUserDesc(), user.getVersion());         return "true";     }     @PostMapping("/newuser")     @Transactional     public String newuser() {         logger.info("save user");         User user = new User();         user.setUserDesc("第一次创建");         user.setUsername("gang");         userService.saveUser(user);         return "true";     } }

    以及service及repository

    @Service public class UserService {     @Autowired     UserRepository userRepository;     public User findUser(String username){         return userRepository.findByUsername(username);     }     public void saveUser(User user){         userRepository.save(user);     } } UserRepository  public interface UserRepository extends JpaRepository<User,Long> {     User findByUsername(String username); }

    总结

    使用很简单,version是自动增长的,唯一的缺点是抛出的异常不易捕获,捕获的方法:

    @Resource     private UserTransaction rtc;      try {             rtc.begin();             User user = userService.findUser("gang");             user .setDesc("异常捕获");              rtc.commit();         } catch (OptimisticLockException e) {             throw new OptimisticLockException ();         } catch (Exception e) {             throw new Exception ();         }

    注意其中的 rtc.begin(); 以及 rtc.commit();

    不同于@Transaction,这种是手动的提交方法

    到此,关于“如何使用JPA加锁机制”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    jpa
    AI