Spring Boot 乐观锁加锁失败 - 使用AOP恢复错误
之前写了一些辅助工作相关的Spring Boot怎么使用AOP。这里继续正题,怎么减少Spring Boot 乐观锁加锁报错的情况(基本可以解决)。
1. 包依赖
spring-boot-starter-data-jpa, Spring Boot的JPA starter
h2, H2内存数据库
spring-boot-starter-test,Spring Boot的Junit测试starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>1.2.6.RELEASE</version>
</dependency> <dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.188</version>
<scope>runtime</scope>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>1.2.6.RELEASE</version>
<scope>test</scope>
</dependency>
2. 如何在启用乐观锁?
我用的是JPA, 所以很简单,在实体类加一个字段,并注解@Version。
@Entity
public class Account { //primary key, auto generated
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id; private String name; // enable optimistic locking version control
@Version
private int version; /*omitted getter/setter, but required*/
}
3. 通过AOP实现对RetryOnOptimisticLockingFailureException的恢复
为了减少对代码的侵入,对之前的AOP例子进行少许修改:
- 自定义一个注解,用来标注需要恢复这个错误的接口
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryOnOptimisticLockingFailure { }
- 切入点表达式使用注解,不再使用execution
@Pointcut("@annotation(RetryOnOptimisticLockingFailure)")
public void retryOnOptFailure() {
// pointcut mark
}
@Around("retryOnOptFailure()")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
do {
numAttempts++;
try {
return pjp.proceed();
} catch (OptimisticLockingFailureException ex) {
if (numAttempts > maxRetries) {
//log failure information, and throw exception
throw ex;
}else{
//log failure information for audit/reference
//will try recovery
}
}
} while (numAttempts <= this.maxRetries);
return null;
}
- 在需要对错误进行恢复的RESTFul接口加上恢复标签
至于为什么一定是要在RESTFul接口上加,而不是其他地方(例如service层),是因为Spring Boot的事务管理的上下文是从resource层开始建立的,在service层恢复是无效的,因为数据库的操作依然是在之前失败的事务里,之后再细说吧。
@RestController
@RequestMapping("/account")
public class AccountResource { @Autowired
private AccountService accountService; @RequestMapping(value = "/{id}/{name}", method = RequestMethod.PUT)
@ResponseBody
@RetryOnOptimisticLockingFailure
public void updateName(@PathVariable Integer id, @PathVariable String name) {
accountService.updateName(id, name);
}
}
4. 测试用例
@Test
public void testUpdate() {
new Thread(() -> this.client.put(base + "/1/llt-2", null)).start();
new Thread(() -> this.client.put(base + "/1/llt-3", null)).start(); try {
//waiting for execution result of service
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
5. 测试一下效果如何
- 没有在AccountResource的updateName方法加@RetryOnOptimisticLockingFailure:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [com.leolztang.sb.aop.model.Account] with identifier [1]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.leolztang.sb.aop.model.Account#1]] with root cause org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.leolztang.sb.aop.model.Account#1]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2541)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3285)
- 在AccountResource的updateName方法加@RetryOnOptimisticLockingFailure:
Original:name=[llz-1],version=[0],New:name=[llt-2],version=[1]
Original:name=[llt-2],version=[1],New:name=[llt-3],version=[2]
6. 完整代码
http://files.cnblogs.com/files/leolztang/sb.aop-v2.tar.gz
Spring Boot 乐观锁加锁失败 - 使用AOP恢复错误的更多相关文章
- Spring Boot 乐观锁加锁失败 - 集成AOP
Spring Boot with AOP 手头上的项目使用了Spring Boot, 在高并发的情况下,经常出现乐观锁加锁失败的情况(OptimisticLockingFailureException ...
- spring boot 中@Autowired注解无法自动注入的错误
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/huihuilovei/article/de ...
- spring boot 分布式锁组件 spring-boot-klock-starter
基于redis的分布式锁spring-boot starter组件,使得项目拥有分布式锁能力变得异常简单,支持spring boot,和spirng mvc等spring相关项目 快速开始 sprin ...
- 2020最新的Spring Boot 分布式锁的具体实现(内附代码)
前言 面试总是会被问到有没有用过分布式锁.redis 锁,大部分读者平时很少接触到,所以只能很无奈的回答 "没有".本文通过 Spring Boot 整合 redisson 来实现 ...
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- spring boot 从开发到上线(三)—AOP 异常监控、上报
在做这个项目的期间,看到一篇很有启发性的文章<程序员你为什么这么累>.对于初级程序员来说,拿到需求,第一反应是用什么技术来尽快的完成任务,这本身并没有问题.但长此以往,不仅被需求的更改搞得 ...
- spring boot开发 @autowired注入失败
@autowired注入失败 会出现如下错误提示: 2018-05-28 08:39:41.857 INFO 8080 --- [ restartedMain] org.hibernate.Versi ...
- spring boot下接口调用失败重试方案
背景: 在项目开发中,有时候会出现接口调用失败,本身调用又是异步的,如果是因为一些网络问题请求超时,总想可以重试几次把任务处理掉. 一些RPC框架,比如dubbo都是有重试机制的,但是并不是每一个项目 ...
- Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId
一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...
随机推荐
- Hanoi问题java解法
用什么语言解法都差不多,思路都是一样,递归,这其中只要注重于开始和结果的状态就可以了,对于中间过程,并不需要深究.(我细细思考了一下,还是算了.=_=) 代码其实很简单注重的是思路. 问题描述:有一个 ...
- Unity中关于作用力方式ForceMode的功能注解
功能注解:ForceMode为枚举类型,用来控制力的作用方式,有4个枚举成员,在以下举例中均设刚体质量为m=2.0f,力向量为f=(10.0f,0.0f,0.0f). (1)ForceMode.For ...
- fopen函数和fread函数、fwrite函数
fopen(打开文件) 相关函数 open,fclose 表头文件 #include<stdio.h> 定义函数 FILE * fopen(const char * path,const ...
- jquery validate表单验证插件-推荐
1 表单验证的准备工作 在开启长篇大论之前,首先将表单验证的效果展示给大家. 1.点击表单项,显示帮助提示 2.鼠标离开表单项时,开始校验元素 3.鼠标离开后的正确.错误提示及鼠标移入时的帮 ...
- 数据库 数据库SQL语句一
字符和日期 --字符和日期都要包含在单引号中 --字符大小写敏感,日期格式敏感 --默认的日期格式是DD-MON-RR --查询当前系统时间 SQL> select sysdate from d ...
- [LeetCode] Shuffle an Array 数组洗牌
Shuffle a set of numbers without duplicates. Example: // Init an array with set 1, 2, and 3. int[] n ...
- mysql-5.7.11-winx64.zip 安装配置
1.下载 http://cdn.mysql.com//Downloads/MySQL-5.7/mysql-5.7.11-winx64.zip 2.解压缩zip包: D:\Program Files\m ...
- C语言学习 第十一次作业总结
作业总结 两次的作业,都是和指针有关.从第一次的作业开始,我就多次让同学们思考这个问题:为什么要用指针,为什么在函数的形参中要使用指针.如果能够想明白这2个问题,那么同学们应该会指针的了解就差不多足够 ...
- 百度地图demo
以下代码拷贝成html,直接运行即能看到百度地图 <!DOCTYPE html><html> <head> <meta http-equiv="Co ...
- NCspider项目总结
下午就要答辩了,想把项目经历再总结一下. 项目分三个阶段. 第一阶段,是信息搜集整理阶段 要想法设法从各个门户网站上抓取到新闻和对应的评论数据.首先要分析网站结构. 1. 从哪里找到网站每日发布的所有 ...