成都市城乡建设厅官方网站最新国内新闻重大事件
说明:本文介绍如何在Spring Boot项目中,延迟执行某方法,及讨论延迟执行方法的是事务问题。
搭建Demo
首先,创建一个Spring Boot项目,pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.12</version><relativePath/></parent><groupId>com.hezy</groupId><artifactId>delay_thread_demo</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency></dependencies>
</project>
写个接口,打印进入方法时的时间
import com.hezy.service.DelayService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;import java.text.SimpleDateFormat;
import java.util.Date;@RestController
@RequestMapping("/demo")
@Log4j2
public class DemoController {@Autowiredprivate DelayService delayService;@GetMappingpublic String demo() {return "Hello World!";}@GetMapping("/delay1/{time}")public String delay1(@PathVariable Integer time) {log.info("enter delay1...date={} time={}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), time);delayService.delay1(time);return "success";}
}
延迟执行实现
delayService,delay1()实现,如下:
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);/*** 延迟执行* @param time*/public void delay1(Integer time) {scheduler.schedule(() -> {log.info("run delay1...date={} time={}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), time);}, time, TimeUnit.SECONDS);}
就是开了一个线程来执行,可设置延迟时间。启动项目,测试,如下:
(发送请求,响应结果即刻返回)
(控制台可见任务延迟5秒执行)
事务问题
写个实体类
import lombok.Data;@Data
public class User {private Integer id;private String username;private String password;
}
再写个Mapper,里面写个insert()方法
import com.hezy.pojo.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {@Insert("insert into user (id, username, password) values (#{id}, #{username}, #{password})")void insert(User user);
}
新建个延迟方法,delay2(),方法生加声明式注解
,方法内手动制造一个异常
(controller)
@PostMapping("/delay2/{time}")public String delay2(@RequestBody User user, @PathVariable Integer time) {log.info("enter delay2...date={} time={}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), time);delayService.delay2(user, time);return "success";}
(service)
/*** 声明式事务*/@Transactional(rollbackFor = Exception.class)public void delay2(User user, Integer time) {scheduler.schedule(() -> {log.info("run delay2...date={} time={}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), time);userMapper.insert(user);int i = 1 / 0;user.setId(3);userMapper.insert(user);}, time, TimeUnit.SECONDS);}
启动项目,调用方法
控制台没有报错
数据库,插入了一条数据,事务没有控制住
以上说明,声明式事务无法控制延迟执行的方法,并且异常也被线程内捕获了,没有抛出来。
编程式事务
试下编程式事务,手动实现事务,如下:
(controller)
@PostMapping("/delay3/{time}")public String delay3(@RequestBody User user, @PathVariable Integer time) {log.info("enter delay3...date={} time={}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), time);delayService.delay3(user, time);return "success";}
(service)
@Autowiredprivate PlatformTransactionManager transactionManager;/*** 编程式事务*/public void delay3(User user, Integer time) {scheduler.schedule(() -> {TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());try {log.info("run delay3...date={} time={}",new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), time);userMapper.insert(user);// 故意产生异常int i = 1 / 0;user.setId(3);userMapper.insert(user);// 提交事务transactionManager.commit(status);} catch (Exception e) {transactionManager.rollback(status);e.printStackTrace();}}, time, TimeUnit.SECONDS);}
把数据库记录删掉,启动项目,测试
控制台报错
数据库没有插入记录,编程式事务控制住了
总结
本文介绍了在Spring Boot项目中延迟执行方法的实现,以及延迟执行下声明式事务和编程式事务的使用情况。
完整源码:https://github.com/HeZhongYing/delay_thread_demo