使用JPA实现乐观锁
来源:互联网 发布:dnf阿里云搭建 编辑:程序博客网 时间:2024/05/01 00:46
乐观锁的概念就不再赘述了,不了解的朋友请自行百度谷歌之,今天主要说的是在项目中如何使用乐观锁,做成一个小demo。
持久层使用jpa时,默认提供了一个注解@Version
先看看源码怎么描述这个注解的
/** * Specifies the version field or property of an entity class that * serves as its optimistic lock value. The version is used to ensure * integrity when performing the merge operation and for optimistic * concurrency control. * * <p> Only a single <code>Version</code> property or field * should be used per class; applications that use more than one * <code>Version</code> property or field will not be portable. * * <p> The <code>Version</code> property should be mapped to * the primary table for the entity class; applications that * map the <code>Version</code> property to a table other than * the primary table will not be portable. * * <p> The following types are supported for version properties: * <code>int</code>, <code>Integer</code>, <code>short</code>, * <code>Short</code>, <code>long</code>, <code>Long</code>, * <code>java.sql.Timestamp</code>. * * <pre> * Example: * * @Version * @Column(name="OPTLOCK") * protected int getVersionNum() { return versionNum; } * </pre> * * @since Java Persistence 1.0 */@Target({ METHOD, FIELD })@Retention(RUNTIME)public @interface 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. */@Controllerpublic 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是一致的。但是从业务角度出发又要保证数据的严格一致性,避免脏读等问题,使用的场景需要斟酌。记得前面一片博文简单介绍了一下行级锁的概念,其实本质上和乐观锁都是想要再数据库层面加锁控制并发,那么什么时候该用乐观锁,行级锁,什么时候得在程序级别加同步锁,又要根据具体的业务场景去判断。找到能够满足自己项目需求的方案,找到性能和可靠性的平衡点,才是一个程序员的价值所在。
- 使用JPA实现乐观锁
- 使用JPA实现乐观锁
- JPA使用乐观锁应对高并发
- JPA中的乐观锁
- JPA乐观锁
- hibernate使用version实现乐观锁
- 使用数据库模拟状态机实现乐观锁
- 使用redis乐观锁实现秒杀
- 使用redis乐观锁实现秒杀
- Hibernate JPA 悲观锁,乐观锁
- Hibernate JPA 悲观锁,乐观锁
- EclipseLink JPA类乐观锁类型说明
- mybatis和JPA实现乐观锁解决并发问题-阿里巴巴JAVA开发手册详细解读
- 乐观锁以及乐观锁的实现
- 乐观锁以及乐观锁的实现
- 乐观锁以及乐观锁的实现
- 秒杀---使用乐观锁实现或cache实现
- activiti乐观锁实现
- [BZOJ1391][Ceoi2008]order(最小割)
- BZOJ 1084: [SCOI2005]最大子矩阵 DP
- 蓝桥杯 算法训练 输出米字形
- Ubuntu 16.04 LTS与windows双系统时间同步解决方法
- Algorithm Review 1 基础排序算法
- 使用JPA实现乐观锁
- flask部署-Ubuntu下使用nginx+uwsgi+supervisor部署flask应用
- NUCLEO-F767ZI以太网初探
- 蓝桥杯 基础练习 数的读法
- 多客户端通信之Select服务器
- 原来微信收藏也是有容量的
- Git学习之路(2)-安装GIt和创建版本库
- React入门笔记
- HTML滚动效果