【Spring】27、JPA 实现乐观锁@Version注解的使用
持久层使用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注解的使用的更多相关文章
- 【进阶之路】Mybatis-Plus中乐观锁@version注解的问题与解决方案
大家好,我是练习java两年半时间的南橘,从一名连java有几种数据结构都不懂超级小白,到现在懂了一点点的进阶小白,学到了不少的东西.知识越分享越值钱,我这段时间总结(包括从别的大佬那边学习,引用)了 ...
- Mybatis-Plus乐观锁Version
实现原理 取出记录时,获取当前version更新时,带上这个version执行更新时, set version = newVersion where version = oldVersion如果ver ...
- spring boot JPA中实体类常用注解
spring boot jpa中的注解很多,参数也比较多.没必要全部记住,但是经常查看官方文档也比较麻烦,记录一下一些常用的注解.通过一些具体的例子来帮助记忆. @Entity @Table(name ...
- 乐观锁-version的使用
出处:http://chenzhou123520.iteye.com/blog/1863407 乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据一般 ...
- 解决neo4j @Transactional 与Spring data jpa @Transactional 冲突问题,@CreatedBy,@CreatedDate,@LastModifiedBy,@LastModifiedDate,以及解决@Version失效问题
之前mybatis特别流行,所以前几个项目都是用@SelectProvider,@InsertProvider,@UpdateProvider,@DeleteProvider 加反射泛型封装了一些通用 ...
- mybatis 乐观锁和逻辑删除
本篇介绍easymybatis如配置乐观锁和逻辑删除. 乐观锁 easymybatis提供的乐观锁使用方式跟JPA一样,使用@Version注解来实现.即:数据库增加一个int或long类型字段ver ...
- Spring Data JPA教程, 第三部分: Custom Queries with Query Methods(翻译)
在本人的Spring Data JPA教程的第二部分描述了如何用Spring Data JPA创建一个简单的CRUD应用,本博文将描述如何在Spring Data JPA中使用query方法创建自定义 ...
- 已实现乐观锁功能,FreeSql.DbContext 准备起航
上回说到 FreeSql.DbContext 的规则,以及演示它的执行过程,可惜当时还不支持"乐观锁",对于更新数据来讲并不安全. FreeSql 核心库 v0.3.27 已提供乐 ...
- 初入spring boot(七 )Spring Data JPA
Spring Data JPA通过提供基于JPA的Repository极大地减少JPA作为数据访问方案的代码量. 1.定义数据访问层 使用Spring Data JPA建立数据访问层十分简单,只需定义 ...
随机推荐
- Redis-02.数据类型
Redis中所有数据都是以key-value存储的,value支持的数据类型包括string.hash.list.set.sorted_set 数据类型 string 是redis最基本的类型,一个k ...
- Windows 10 IoT Core 17133 for Insider 版本更新
今天,微软发布了Windows 10 IoT Core 17133 for Insider 版本更新,本次更新只修正了一些Bug,没有发布新的特性.用户可以登录Windows Device Porta ...
- 一篇入门 — Gatling 性能测试手册
介绍 本篇博客,旨在记录学习的要点,所以格式随意, 方便本人日后自考和回忆,有兴趣的朋友可以评论讨论. 原文地址:https://www.cnblogs.com/clockq/p/10539974.h ...
- 使用opencv库编译代码并运行
安装Opencv之后,首先要写一份代码测试一下是否ok. 本文代码图像边沿检测的: #include <opencv2/highgui/highgui.hpp> #include < ...
- Scala - 快速学习05 - 数据结构
1- 数组(Array) 数组一般包括定长数组和变长数组. 可以不指明数组类型,Scala会自动根据提供的初始化数据来推断出数组的类型. 在Scala中,对数组元素的应用,是使用圆括号,而不是方括号. ...
- Oracle nal() 和count(*)的注意点
select count(*) into fhave from tab_ppxuser where name = userstr;和select nvl(hphotourl, '0') into ph ...
- 使用 SonarQube 来分析 .NET Core 项目代码问题
0.介绍 Sonar 是一款开源的代码分析工具,可能有很多人已经用过,本篇文章主要是讲解如何在 Docker 里面安装 Sonar 并且用其来分析 .Net Core 项目. Sonar 是一个用于代 ...
- Android Metro风格的Launcher开发系列第三篇
前言: 各位小伙伴,又到了每周更新文章了时候了,本来是周日能发出来呢,这不是赶上清明节吗,女王大人发话了,清明节前两天半陪她玩,只留给我周一下午半天时间写博客,哪里有女王哪里就有压迫呀有木有!好了闲话 ...
- ES6躬行记(3)——解构
解构(destructuring)是一种赋值语法,可从数组中提取元素或从对象中提取属性,将其值赋给对应的变量或另一个对象的属性.解构地目的是简化提取数据的过程,增强代码的可读性.有两种解构语法,分别是 ...
- 【Apache Pulsar】Apache Pulsar单机环境及Go语言开发环境搭建
0x01 简介 Apache Pulsar是一个开源的分布式发布-订阅消息系统,与Kafka类似,但比后者更加强大.Pulsar最初由Yahoo开发并维护,目前已经成为Apache软件组织的一个孵化子 ...