持久层使用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. Oracle Data Guard配置

    Oracle Data Guard 的配置在网上有很多资料,但是没有一个完整的,配置下来多少有些问题.在踩了各种坑之后,自己终于配置成功,就想把这过程记录下来. 1   测试环境 主数据库:windo ...

  2. 包建强的培训课程(13):iOS与ReactNative

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  3. Canal学习笔记(客户端)

    前言 最近公司用到Canal来做从MySQL到Tidb的数据同步,用到HA模式Canal,记录一下HA模式的工作原理. Canal的架构模式 Canal是利用binlog日志来做数据同步,canal伪 ...

  4. Javascript高级编程学习笔记(19)—— 对象属性

    面向对象的语言有一个标志,那就是语言中都有类的概念 前面的文章中我提到过ECMAScript中没有类的概念(ES6之前) 所以JS中的对象和其他语言中的对象存在着一些区别 ECMA中对对象的定义如下: ...

  5. 漫谈PHP组件、框架、Composer那些事

    什么是组件 组件是一组打包的代码,是一系列相关的类.接口和Trait,用于帮助我们解决PHP应用中某个具体问题.例如,你的PHP应用需要收发HTTP请求,可以使用现成的组件如guzzle/guzzle ...

  6. Web Components(续)

    概述 之前我们介绍了Web Components的基本概念,现在我们给出一个使用Web Components的实例代码,并且对组件化进行一些思考.记录下来,供以后开发时参考,相信对其他人也有用. 实例 ...

  7. Spark基础-scala学习(七、类型参数)

    类型参数是什么 类似于java泛型,泛型类 泛型函数 上边界Bounds 下边界 View Bounds Context Bounds Manifest Context Bounds 协变和逆变 Ex ...

  8. linux上安装jdk环境

    只在于安装jdk1.6.jdk1.7和jdk1.8,其他版本请绕行,目的在于方便自己和大家以后急于做jdk环境,苦于没有jdk安装包和设置变量的过程,我将安装包均放在云盘中, 需要直接在连接中找即可: ...

  9. [P4886] 快递员

    考虑在树上选个点rt作为根,并且快递中心就选这儿.计算出所有配送的代价(2*两段之和),设他们的最大值为Max.若此时存在下列情况时,可以判定Max已经为最优解. 1)存在代价为Max的配送(u,v) ...

  10. android用OkHttp和okio包通信的坑--气死我了

    今天新建了个项目,想要用用okhttp包来实现Android和tomcat的通信, 于是就根据记忆,把以前可以用的代码复制过来了,然后呢,出现这个.... 图有点大,不知到怎么调小 很莫名其妙,我看了 ...