环境:SpringBoot2.4.3 + Spring Retry + JPA + MySQL + JDK8
- 相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- 配置文件
spring:
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/testjpa?serverTimezone=GMT%2B8&useSSL=false
username: root
password: ******
type: com.zaxxer.hikari.HikariDataSource
hikari:
minimumIdle: 10
maximumPoolSize: 200
autoCommit: true
idleTimeout: 30000
poolName: MasterDatabookHikariCP
maxLifetime: 1800000
connectionTimeout: 30000
connectionTestQuery: SELECT 1
- 实体类及DAO
@Entity
@Table(name = "t_account")
public class Account {
@Id
private Long id;
private String userId;
private BigDecimal money;
}
public interface AccountDAO extends JpaRepository<Account, Long> {
Account findByUserId(String userId);
}
- Service类
@Service
public class AccountService {
@Resource
private AccountDAO accountDAO ;
@Transactional
@Retryable(value = {InvalidParameterException.class})
public Account save(Account account) {
System.out.println(Thread.currentThread().getName()) ;
if (account.getId() == 0) {
System.out.println("save retry...") ;
throw new InvalidParameterException("无效参数") ;
}
return accountDAO.saveAndFlush(account) ;
}
// 当重试了指定的次数后将会回调此方法
@Recover
public Account recoverSave(Exception e) {
System.out.println("............." + e.getMessage()) ;
return null ;
}
}
@Retryable注解说明:
- recover:指定兜底/补偿的方法名。如果不指定,默认对照 @Recover 标识的,第一入参为重试异常,其余入参和出参一致的方法;这里是通过@Recover注解对照指定。
- interceptor:指定方法切面 bean,org.aopalliance.intercept.MethodInterceptor 实现类
- value / include:可重试的异常类型,如果value和include都为空,那么会对所有的异常进行重试;
- exclude:和 include 相反,指出哪些异常不需要重试;
- label:可以指定唯一标签,用于统计;
- stateful:默认false。重试是否是有状态的;
- maxAttempts:最大的重试次数,默认为3;
- backoff:指定 @Backoff,回退策略;@Backoff属性如下:
这里可以指定重试的策略,比如:延迟多久进行重试。
- listeners:监听器,指定 org.springframework.retry.RetryListener 实现 bean。下面有示例演示。
开启重试功能@EnableRetry
@Configuration
@EnableRetry
public class RetryConfig {
}
测试:
@Resource
private AccountService accountService ;
@Test
public void testSave() {
Account account = new Account() ;
account.setId(0L) ;
account.setMoney(BigDecimal.valueOf(1000)) ;
account.setUserId("1") ;
accountService.save(account) ;
}
控制台输出:
默认进行了3次重试。
@Retryable注解属性listeners的使用
@Retryable(value = {InvalidParameterException.class}, stateful = false, listeners = {“accountRetryListener”})
定义监听器:
public class AccountRetryListener implements RetryListener {
@Override
public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
System.out.println("open invoke...") ;
return false;
}
@Override
public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("close invoke...") ;
}
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback,
Throwable throwable) {
System.out.println("onError invoke...") ;
throwable.getStackTrace() ;
}
}
这里的open方法如果返回false,那么将不会进行重试。
执行结果:
基于编程式重试
自定义RetryTemplate
@Configuration
@EnableRetry
public class RetryConfig {
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate template = RetryTemplate.builder()
.maxAttempts(3) // 重试次数
.fixedBackoff(1000) // 以固定的时间间隔重试(1000ms)
.retryOn(InvalidParameterException.class) // 当发生InvalidParameterException异常时进行重试
.build();
return template ;
}
}
public class AccountService {
@Resource
private AccountDAO accountDAO ;
@Resource
private RetryTemplate retryTemplate ;
@Transactional
public Account update(Account account) {
return retryTemplate.execute(context -> {
if (account.getId() == 0) {
System.out.println("update retry...") ;
throw new InvalidParameterException("无效参数") ;
}
return accountDAO.saveAndFlush(account) ;
}, context -> {
System.out.println("重试结束...") ;
return null ;
}) ;
}
}
测试:
@Test
public void testUpdate() {
Account account = new Account() ;
account.setId(0L) ;
account.setMoney(BigDecimal.valueOf(1000)) ;
account.setUserId("1") ;
accountService.update(account) ;
}
执行结果
完毕!!!
给个关注+转发呗,谢谢
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/80022.html