Spring Data JPA 从入门到精通~@Version处理乐观锁的问题

@Version 处理乐观锁的问题

@Version 乐观锁介绍

我们在研究 Auditing 的时候,发现了一个有趣的注解 @Version,源码如下:

package org.springframework.data.annotation;
/*** Demarcates a property to be used as version field to implement optimistic locking on entities.*/
@Retention(RUNTIME)
@Target(value = { FIELD, METHOD, ANNOTATION_TYPE })
public @interface Version {}

发现它帮我们处理了乐观锁的问题,什么是乐观锁,还有线程的安全性,在另外一本书《Java 并发编程从入门到精通》里面,或者看作者的另外一篇 Chat:Java 多线程与并发编程 · Java 工程师必知必会,作者做了深入的探讨。

对于数据来说,简单理解:在数据库并发操作时,为了保证数据的正确性,我们会做一些并发处理,主要就是加锁。在加锁的选择上,常见有两种方式:悲观锁和乐观锁。

  • 悲观锁:简单的理解就是把需要的数据全部加锁,在事务提交之前,这些数据全部不可读取和修改。
  • 乐观锁:使用对单条数据进行版本校验和比较,来对保证本次的更新是最新的,否则就失败,效率要高很多。在实际工作中,乐观锁不止在数据库层面,其实我们在做分布式系统的时候,为了实现分布式系统的数据一致性,分布式事物的一种做法就是乐观锁。

数据库操作举例说明

悲观锁的做法:

select * from user where id=1 for update;
update user  set name='jack'  where id=1;

通过使用 for update 给这条语句加锁,如果事务没有提交,其他任何读取和修改,都得排队等待。在代码中,我们加事务的 Java 方法就会自然的形成了一个锁。

乐观锁的做法:

select uid,name,version from user where id=1;
update user set name='jack', version=version+1 where id=1 and version=1

假设本次查询 version=1,在更新操作时,带上这次查出来的 Version,这样只有和我们上次版本一样的时候才会更新,就不会出现互相覆盖的问题,保证了数据的原子性。

@Version 用法

在没有 @Version 之前,我们都是自己手动维护这个 Version 的,这样很有可能做什么操作的时候给忘掉。或者是我们自己底层做框架,用 AOP 的思路做拦截底层维护这个 Version 的值。而 Spring Data JPA 的 @Version 就是通过 AOP 机制,帮我们动态维护这个 Version,从而更优雅的实现乐观锁。

(1)实体上的 Version 字段加上 @Version 注解即可。

我们对上面的实体 UserCustomerEntity 改进如下:

@Entity
@Table(name = "user_customer", schema = "test", catalog = "")
public class UserCustomerEntity extends AbstractAuditable {//新增控制乐观锁的字段。并且加上@Version注解@Version@Column(name = "version", nullable = true)private Long version;
......
}

(2)实际调用

userCustomerRepository.save(new UserCustomerEntity("1","Jack"));
UserCustomerEntity uc= userCustomerRepository.findOne(1);
uc.setCustomerName("Jack.Zhang");
userCustomerRepository.save(uc);

我们会发现 Insert 和 Update 的 SQL 语句都会带上 Version 的操作。当乐观锁更新失败的时候,会抛出异常 org.springframework.orm.ObjectOptimisticLockingFailureException。

实现原理关键代码

(1)SimpleJpaRepository.class 里面的 save 方法如下:

public <S extends T> S save(S entity) {if (entityInformation.isNew(entity)) {em.persist(entity);return entity;} else {return em.merge(entity);}
}

(2)如果我们在此处设置一个 debug 断点的话,我们一步一步往下面走会发现进入 JpaMetamodelEntityInformation.class 的关键代码如下:

    @Overridepublic boolean isNew(T entity) {if (!versionAttribute.isPresent()|| versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {return super.isNew(entity);}BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);}

所以到这里,可以看出当我们更新的时候,若实体对象上面有 @Version 注解,那么就一定要带上 version,如果没带上 version 字段的值,只有 ID 字段的值,系统也会认为是新增。相反,如果我们没有 @Version 注解的字段,那么就会以 @ID 字段来判断是否是新增。其实这里我们也明白,省去了传统都需要我们自己去实现的 saveOrUpdate 方法。

(3)其实我们多看看代码,多 debug 几次就会发现,也可以在 @Entity 的类里面覆盖掉 isNew() 方法,这样可以实现自己的 isNew 的判断逻辑。

@Entity
@Table(name = "user")
public class UserEntity  implements Persistable {@Transient   //这个注解表明这个字段不是持久化的@JsonIgnore //json显示的时候我们也可忽略这个字段@Overridepublic boolean isNew() {return getId() == null;}....
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/496303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

人工智能即服务 当人工智能遇到云计算

来源&#xff1a;企业网为了在竞争中保持领先地位&#xff0c;越来越多的企业正在寻求将人工智能技术整合到其应用程序、产品、服务&#xff0c;以及大数据分析方法中。而企业开始使用人工智能技术的最简单和最流行的方法之一是使用基于云计算的人工智能即服务产品。根据调研机…

视频裁剪

用【格式工厂FFSetup190.exe】将视频文件格式专程AVI, 再用视频裁剪工具【SolveigMM AVI Trimmer】裁剪需要的段。 源文件-添加视频文件-填入开始时间和停止时间&#xff08;用三耳确定填写的时间值&#xff09;-按添加按钮-选择目的文件路径及名称-运行。 转载于:https://www.…

三星s9php禁用列表,ADB禁用列表

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼谷歌程序pm uninstall --user 0com.google.android.ext.servicespm uninstall --user 0com.google.android.onetimeinitializerpm uninstall --user 0com.google.android.ext.sharedpm uninstall --user 0com.google.android.confi…

Linux 文件 IO

参考&#xff1a;http://blog.csdn.net/wanxiao009/article/details/5648583 C 和 C 文件操作详解&#xff1a;http://blog.csdn.net/freeking101/article/details/60959624 标准IO与文件IO 的区别&#xff1a;http://blog.csdn.net/big_bit/article/details/51804391 参考…

Spring Data JPA 从入门到精通~默认数据源的讲解

默认数据源 spring.datasource.driver-class-namecom.mysql.jdbc.Driver spring.datasource.urljdbc:mysql://127.0.0.1:3306/test?useSSLfalse spring.datasource.usernameroot spring.datasource.password123456 但是在实际工作中不可能这么简单&#xff0c;因为会用其他数…

国内AI芯片百家争鸣,何以抗衡全球技术寡头

来源&#xff1a;中国科学院自动化研究所 作者&#xff1a;吴军宁如果说 2016 年 3 月份 AlphaGo 与李世石的那场人机大战只在科技界和围棋界产生较大影响的话&#xff0c;那么 2017 年 5 月其与排名第一的世界围棋冠军柯洁的对战则将人工智能技术推向了公众视野。阿尔法狗&am…

zabbix php 5.6 安装配置,CentOS 5.6下Zabbix 1.8.5 服务端安装部署

CentOS 5.6下Zabbix 1.8.5 服务端安装部署CentOS 5.6 x86_64 Zabbix 1.8.5IP:192.168.88.130一、安装LAMP环境依赖包&#xff1a;# yum install MySQL-server mysql-devel libcurl-devel net-snmp-devel php php-gd php-xml php-mysql php-mbstring php-bcmath httpd curl-dev…

Linux系统编程——I/O多路复用select、poll、epoll

参考&#xff1a;https://segmentfault.com/a/1190000003063859 Linux下的I/O复用与epoll详解&#xff1a;https://www.cnblogs.com/lojunren/p/3856290.html 彻底学会 epoll 系列&#xff1a;http://blog.chinaunix.net/uid/28541347/sid-193117-list-1.htm Linux下I/O多路复用…

Spring Data JPA 从入门到精通~AliDruidDataSource的配置

AliDruid 配置方法 &#xff08;1&#xff09;在实际工作中&#xff0c;由于 HikariCP 和 Druid 应该各有千秋&#xff0c;会发现偏向于监控&#xff0c;有很多国内开发 者使用频次最高的 AliDruid&#xff0c;我们来看看看如何配置。 <!--druid--><dependency>&…

励志演讲

王国权励志演讲&#xff08;很有激情&#xff09;转载于:https://www.cnblogs.com/Xredman/archive/2009/07/23/1529186.html

谷歌X实验室的“无用”发明

来源&#xff1a;OFweek人工智能网摘要&#xff1a;作为想要改变世界的科技界钢铁侠&#xff0c;谷歌自诞生起就发明无数。1999年&#xff0c;公司创始人拉里佩奇用导航地图开车载他同事经过一个停车场时突然想到&#xff1a;在线搜索也可以盈利。当时他认为&#xff0c;谷歌能…

php跳一跳小游戏,原生JS实现的跳一跳小游戏完整实例

本文实例讲述了原生JS实现的跳一跳小游戏。分享给大家供大家参考&#xff0c;具体如下&#xff1a;以下说的是闲暇编写的一个小游戏--跳一跳&#xff0c;类似于微信的跳一跳&#xff0c;大体实现功能有&#xff1a;1.先随机生成地图&#xff1b;2.按住按钮释放后完成动作并进行…

windows 快捷键整理

Win10快捷键大全汇总&#xff1a;http://www.pc6.com/infoview/Article_110854.html 电脑键盘快捷键和组合键功能使用大全&#xff1a;http://product.pconline.com.cn/itbk/diy/mouse/1305/3298585.html 键盘上的键都有哪些用途&#xff1a;https://www.gezila.com/tutori…

我想知道怎么求N的N次方

我想知道怎么求N的N次方&#xff0c;这个数据是很大的&#xff0c;但是我要的是这个数据的最高位的数&#xff0c;应该有什么好的方法吧&#xff01; 请大侠们帮帮忙吧&#xff01;&#xff01;&#xff08;N <1000000000&#xff09; 这个问题提出后&#xff0c;fallening同…

Google提出新型学习范式「Deep Memory」,或将彻底改变机器学习领域

图源&#xff1a;pixabay原文来源&#xff1a;arXiv作者&#xff1a;Sylvain Gelly、Karol Kurach、Marcin Michalski、Xiaohua Zhai「雷克世界」编译&#xff1a;嗯~是阿童木呀、KABUDA导语&#xff1a;最近&#xff0c;Google提出了一种称之为Deep Memory的新型学习范式&…

php内容管理器是什么原因,有什么好的php内容管理后台吗?打算试水接单的大三狗提问...

国外优秀的CMS有drupal, joomla, wordpress, typo3drupal最专业&#xff0c;扩展强大&#xff0c;但最难入门&#xff1b;wordpress最简单&#xff0c;模板多&#xff0c;但难以实现高要求&#xff1b;joomla扩展多&#xff0c;入门简单&#xff0c;但后台组织比较混乱&#xf…

网络 IPC 套接字socket

APUE书中所有实例源码下载地址&#xff1a;http://www.apuebook.com apue学习笔记&#xff08;第十六章 网络IPC&#xff1a;套接字&#xff09;&#xff1a;https://www.cnblogs.com/runnyu/p/4648678.html 一起学 Unix 环境高级编程 (APUE) 之 网络 IPC&#xff1a;套接字…

Spring Data JPA 从入门到精通~事务的处理及其讲解

默认 Transactional 注解式事务 &#xff08;1&#xff09;EnableTransactionManagement 正常情况下&#xff0c;我们是需要在 ApplicationConfig 类加上 EnableTransactionManagement 注解才能开启事务管理。通过 DataSource 的研究步骤 spring.factories 里面默认加载 Tran…

ASP.NET MVC V2 Preview 1 发布 期望VS有更好的表现

ASP.NET MVC V2 Preview 1官方首页&#xff1a;http://aspnet.codeplex.com/ 在这里可以下载 以下是网友的转载&#xff0c;介绍的还是比较详细的&#xff1a; 预览版是在.NET 3.5 SP1和VS 2008下工作的&#xff0c;可与ASP.NET MVC 1.0并行安装在同一个机器上&#xff08;即&a…

MC缓存序列化php,PHP serialize()序列化的使用

PHP serialize()序列化的使用可以将数组和对象直接存入数据库中的某一字段。使serialize()是将数组反序列化再存入数据库&#xff0c;序列化话完的数据就是一个字符串。提取的时候&#xff0c;用unserialize()反序列化取&#xff0c;取出来的还是个数组。$arr array(value1,va…