项目所需依赖:
<?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>
<groupId>com.transaction</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- springboot 整合mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- alibaba的druid数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.自定义注解:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExtTransaction {
}
//////////////////////////////////////////
//定义切点
import com.transaction.annotation.ExtTransaction;
import com.transaction.utils.TransactionUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
// 定义切面可以让事务注解可以生效
@Aspect
@Component
public class AopExtTransaction {
@Autowired
private TransactionUtils transactionUtils;
@Pointcut("execution(public * com.transaction.service.*.*(..))")
public void rlAop() {
}
// 使用异常通知 接受回滚事务
@AfterThrowing("rlAop()")
public void afterThrowing(JoinPoint point) {
// 获取当前事务状态
TransactionStatus transaction = transactionUtils.gteTransactionStatus();
if (transaction != null)
// transactionUtils.rollback(transaction);
//获取当前线程的事务进行回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
// 事务底层原理 采用那些通知?环绕和异常即可 注意单例线程安全问题
// 可以使用环绕通知对方法进行开启事务和提交事务 异常通知当程序抛出异常的情况下,进行回滚
@Around("rlAop()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// 1.判断方法上面是否有加上事务注解
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
ExtTransaction extTransaction = methodSignature.getMethod().getDeclaredAnnotation(ExtTransaction.class);
if (extTransaction == null) {// 方法上面没有加上注解执行原有方法
return pjp.proceed();
}
// 2.如果方法上加上事务直接的 开启或者是提交事务 proceed();执行原有方法
TransactionStatus transactionStatus = transactionUtils.begin();
Object proceed = pjp.proceed();// 执行原有方法
transactionUtils.commit(transactionStatus);
return proceed;
}
}
3.dao层和业务层
@Insert("INSERT INTO `rbac_db`.`user` (`name`, `age`) VALUES (#{name}, #{age}) ")
Integer addUser(User user);
////////////////////////////////////////////
@Service
public class UserServiceImpl {
@Autowired
UserMapper userMapper;
@Autowired
TransactionUtils transactionUtils;
@ExtTransaction
public Integer addUser(User user) {
System.out.println("开始事务");
// transactionUtils.begin();
System.out.println("开始添加数据到数据库");
Integer integer = userMapper.addUser(user);
int i = integer / 0;
System.out.println("-----------"+integer+"----------");
return i;
}
经测试,在加了@ExtTransaction注解的方法发生异常后会自动回滚。