持久层使用jpa时,默认提供了一个注解@Version来实现乐观锁

简单来说就是用一个version字段来充当乐观锁的作用。
先来设计实体类

/**
* Created by xujingfeng on 2017/1/30.
*/
@Entity
@Table(name = "t_student")
public class Student { @Id
@GenericGenerator(name = "PKUUID", strategy = "uuid2")
@GeneratedValue(generator = "PKUUID")
@Column(length = 36)
private String id; @Version
private int version; private String name; //getter()...
//setter()...
}

Dao层

/**
* Created by xujingfeng on 2017/1/30.
*/
public interface StudentDao extends JpaRepository<Student,String>{ @Query("update Student set name=?1 where id=?2")
@Modifying
@Transactional
int updateNameById(String name,String id);
}

Controller层充当单元测试的作用,通过访问一个requestMapping来触发我们想要测试的方法。

/**
* Created by xujingfeng on 2017/1/30.
*/
@Controller
public class StudentController { @Autowired
StudentDao studentDao; @RequestMapping("student.html")
@ResponseBody
public String student(){
Student student = new Student();
student.setName("xujingfeng");
studentDao.save(student);
return "student";
} @RequestMapping("testVersion.html")
@ResponseBody
public String testVersion() throws InterruptedException {
Student student = studentDao.findOne("6ed16acc-61df-4a66-add9-d17c88b69755");
student.setName("xuxuan");
new Thread(new Runnable() {
@Override
public void run() {
studentDao.findOne("6ed16acc-61df-4a66-add9-d17c88b69755");
student.setName("xuxuanInThread");
studentDao.save(student);
}
}).start();
Thread.sleep(1000);
studentDao.save(student);
return "testVersion";
} @RequestMapping("updateNameById.html")
@ResponseBody
public String updateNameById(){
studentDao.updateNameById("xuxuan2","6ed16acc-61df-4a66-add9-d17c88b69755");
return "updateNameById";
}
}

这里面三个方法,主要是我们想用来测试的三个注意点。
第一个方法student.html我们想看看springdata如何对version字段进行增长的。就不贴图了,直接给结论,对于添加了@Version的注解,我们不需要手动去控制,每一次save操作会在原来的基础上+1,如果初始为null,则springdata自动设置其为0。
第二个方法testVersion.html是乐观锁的核心,当多个线程并发访问同一行记录时,添加了@Version乐观锁之后,程序会进行怎么样的控制呢?

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.example.jpa.Student#6ed16acc-61df-4a66-add9-d17c88b69755]

异常信息如上,主线程和新线程获取了同一行记录,并且新线程优先提交了事务,版本号一致,修改成功。等到了主线程再想save提交事务时,便得到一个版本号不一致的异常,那么在项目开发中就应该自己捕获这个异常根据业务内容做对应处理,是重试还是放弃etc…

第三个方法,updateNameById.html是想强调一下,@Query中的update,delete操作是不会触发springdata的相关代理操作的,而是转化为原生sql的方式,所以在项目中使用时也要注意这点。

总结

乐观锁,用在一些敏感业务数据上,而其本身的修饰:乐观,代表的含义便是相信大多数场景下version是一致的。但是从业务角度出发又要保证数据的严格一致性,避免脏读等问题,使用的场景需要斟酌。记得前面一片博文简单介绍了一下行级锁的概念,其实本质上和乐观锁都是想要再数据库层面加锁控制并发,那么什么时候该用乐观锁,行级锁,什么时候得在程序级别加同步锁,又要根据具体的业务场景去判断。找到能够满足自己项目需求的方案,找到性能和可靠性的平衡点,才是一个程序员的价值所在。

出处:http://www.importnew.com/26099.html

【Spring】27、JPA 实现乐观锁@Version注解的使用的更多相关文章

  1. 【进阶之路】Mybatis-Plus中乐观锁@version注解的问题与解决方案

    大家好,我是练习java两年半时间的南橘,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西.知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了 ...

  2. Mybatis-Plus乐观锁Version

    实现原理 取出记录时,获取当前version更新时,带上这个version执行更新时, set version = newVersion where version = oldVersion如果ver ...

  3. spring boot JPA中实体类常用注解

    spring boot jpa中的注解很多,参数也比较多.没必要全部记住,但是经常查看官方文档也比较麻烦,记录一下一些常用的注解.通过一些具体的例子来帮助记忆. @Entity @Table(name ...

  4. 乐观锁-version的使用

    出处:http://chenzhou123520.iteye.com/blog/1863407 乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般 ...

  5. 解决neo4j @Transactional 与Spring data jpa @Transactional 冲突问题,@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate,以及解决@Version失效问题

    之前mybatis特别流行,所以前几个项目都是用@SelectProvider,@InsertProvider,@UpdateProvider,@DeleteProvider 加反射泛型封装了一些通用 ...

  6. mybatis 乐观锁和逻辑删除

    本篇介绍easymybatis如配置乐观锁和逻辑删除. 乐观锁 easymybatis提供的乐观锁使用方式跟JPA一样,使用@Version注解来实现.即:数据库增加一个int或long类型字段ver ...

  7. Spring Data JPA教程, 第三部分: Custom Queries with Query Methods(翻译)

    在本人的Spring Data JPA教程的第二部分描述了如何用Spring Data JPA创建一个简单的CRUD应用,本博文将描述如何在Spring Data JPA中使用query方法创建自定义 ...

  8. 已实现乐观锁功能,FreeSql.DbContext 准备起航

    上回说到 FreeSql.DbContext 的规则,以及演示它的执行过程,可惜当时还不支持"乐观锁",对于更新数据来讲并不安全. FreeSql 核心库 v0.3.27 已提供乐 ...

  9. 初入spring boot(七 )Spring Data JPA

    Spring Data JPA通过提供基于JPA的Repository极大地减少JPA作为数据访问方案的代码量. 1.定义数据访问层 使用Spring Data JPA建立数据访问层十分简单,只需定义 ...

随机推荐

  1. MySQL--Skip GTID CAP

    import os script_file = "./skip_file.sql" def write_script(script_content): file_handle = ...

  2. Linux(Centos平台)RabbitMQ消息中间件服务器搭建

    本篇结合接口测试平台部署来讲,不了解的请先查看我的另一篇文档,HttpRunnerManager接口测试平台部署在服务器上(Centos + python3.6 + Mysql5.7 + uwsgi ...

  3. Python - 关于代码阅读的一些建议

    初始能力 让阅读思路保持清晰连贯,主力关注在流程架构和逻辑实现上,不被语法.技巧和业务流程等频繁地阻碍和打断. 建议基本满足以下条件,再开始进行代码阅读: 具备一定的语言基础:熟悉基础语法,常用的函数 ...

  4. 如何将一个文本内容通过PHP 以表格的方式输入到页面上

    如何将一个文本内容通过PHP 以表格的方式输入到页面上 <?php //读取文本内容 $contents = file_get_contents("names.txt"); ...

  5. java中MD5加密

    MD5加密是一种不可逆(一些网站通过庞大的数据库可以解密一些简单的)的加密算法(其实是信息摘要算法),常用于用户密码,文件上传等 MD5算法具有以下特点: 1.压缩性:任意长度的数据,算出的MD5值长 ...

  6. spark面试总结1

    Spark Core面试篇01 一.简答题 1.Spark master使用zookeeper进行HA的,有哪些元数据保存在Zookeeper? 答:spark通过这个参数spark.deploy.z ...

  7. 给大家一些改善 Python 程序的 91 个建议

    读了一本还不错的书「编写高质量代码改善 Python 程序的 91 个建议」,大多数的建议是真心不错,我虽然写python也有3年多了,但是有些地方确实没去注意过,特地整理了一下,给大家参考. 我已经 ...

  8. 在IT行业获得成功 你只需一项技能[转]

    能同时使用五种编程语言(包括一种机器语言)?不是. 项目管理能力,再高就是获得PMP认证?也不是. 超强的口才和书面沟通能力,正如工作职位中描述的那样?这不是痛点,但可以学习. 我曾经与最好的IT专业 ...

  9. springboot 与 shiro 整合 (简洁版)

    前言: 网上有很多springboot 与 shiro 整合的资料,有些确实写得很好, 对学习shiro和springboot 都有很大的帮助. 有些朋友比较省事, 直接转发或者复制粘贴.但是没有经过 ...

  10. 为什么你作为一个.NET的程序员工资那么低?

    最近看到很多抱怨贴,也许有一定的道理,但是你想过没,为什么大部分.NET程序员工资相对低?我个人是这么看的: 大批半罐子水的程序员,永远被局限在.NET的原始的小圈圈里.前端不会(你放弃了一项很重要的 ...