千家信息网

如何使用JPA加锁机制

发表于:2024-09-29 作者:千家信息网编辑
千家信息网最后更新 2024年09月29日,这篇文章主要介绍"如何使用JPA加锁机制",在日常操作中,相信很多人在如何使用JPA加锁机制问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何使用JPA加锁机制"的疑惑
千家信息网最后更新 2024年09月29日如何使用JPA加锁机制

这篇文章主要介绍"如何使用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注解)

    @Entitypublic 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将线程沉睡,测试事务的提交性

    @RestControllerpublic 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

    @Servicepublic 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 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加锁机制"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

    乐观 事务 数据 机制 悲观 字段 数据库 方法 学习 控制 对象 级别 问题 不对 实体 更多 类型 语句 冲突 帮助 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 河北职业软件开发诚信企业 梦幻转回原来服务器 福建顶点软件开发工程师 地理信息服务器安全等级 深圳单机版外贸软件开发 中毒后浏览器代理服务器没反应 软件开发项目前期工作 网络安全文明小讲师手抄报 其他软件开发属于什么行业分类 通信网络技术举例说明 万州区一站式软件开发服务公司 ccna网络安全 西安天迅网络技术有限公司 服务器湖里 数据库的运用与java结合 网络安全性短信 开发联机游戏一定要服务器吗 行业软件开发用什么语言 陕西数据库通用多路锁控板方案 电脑密钥激活无法连接激活服务器 软件开发管理工程师证书 绝地求生bp服务器 服务器导轨拆除 软件开发专业前途如何 企业应该用什么数据库服务器 数据库如何快速定位到数据记录 网络安全是一盘大棋 昆明市软件开发的学校 ctf网络安全大赛排名kk 营山网络安全保卫大队
    0