PHP套模板做网站/个人网站规划书模板
文章目录
- 事务分类
- 基于Aop实现编程式事务
- 测试
- 基于Aop实现spring声明式事务
- 基于Spring AOP事务
- 测试
- 基于Aop实现类似@Transactional注解
- 1. 实现自定义注解
- 2. 基于aop实现事务回滚提交
- 3. 测试
- 补充说明
事务分类
- 编程式事务:在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法(自己手动控制事务)
- 声明式事务:在方法头加入事务注解或者在xml配置开启编程式事务,简单来说就是把事务交由spring容器管理
基于Aop实现编程式事务
事务管理核心类: DataSourceTransactionManager或PlatformTransactionManager,这里使用DataSourceTransactionManager
TransactionUtils
@Component
@Scope("prototype")
//设置为原型,防止多线程操作引起的事务问题
public class TransactionUtils {@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;//开启事务public TransactionStatus begin() {TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());return transactionStatus;}//提交事务public void commit(TransactionStatus transactionStatus) {dataSourceTransactionManager.commit(transactionStatus);}//回滚事务public void rollback(TransactionStatus transactionStatus) {dataSourceTransactionManager.rollback(transactionStatus);}
}
测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MybatisApplication.class)
public class SpringbootTest {
@AutowiredTransactionUtils transactionUtils;@AutowiredUserDao userDao;@Testpublic void addUserTest() {TransactionStatus transactionStatus = null;try {User user = new User("12365987", "6666", "女", "小奏");//开启事务transactionStatus = transactionUtils.begin();userDao.addUser(user);//模拟发生异常int i = 1 / 0;//第二次插入数据库userDao.addUser(user);//提交事务transactionUtils.commit(transactionStatus);} catch (Exception e) {e.printStackTrace();//回滚事务if (transactionStatus != null) {transactionStatus.rollbackToSavepoint(transactionStatus);}}}
}
如果发生异常,事务会自动回滚,数据库不会插入数据
这手动开启事务的方法比较麻烦,必须每个方法自己手动开启事务
基于Aop实现spring声明式事务
基于Spring AOP事务
@Component
@Aspect
@Slf4j
public class AopTransaction {private static final String POINT_CUT = "execution(* com.mybatis.service.UserService.addUser(..))";//定义切面@Pointcut(POINT_CUT)private void pointcut(){}@AutowiredTransactionUtils transactionUtils;/*环绕通知* 方法执行前后执行** */@Around("pointcut()")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {//调用方法之前log.info("开启事务");TransactionStatus transactionStatus = transactionUtils.begin();//代理调用方法proceedingJoinPoint.proceed();log.info("提交事务");transactionUtils.commit(transactionStatus);}//异常通知@AfterThrowing("pointcut()")public void afterTrowing() {log.info("回滚事务");//获取当前事务并回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}
UserServiceImpl
@Service("userService")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Overridepublic void addUser(User user) {userDao.addUser(user);//模拟发生异常int i = 1/0;userDao.addUser(user);}
}
测试
UserController
@RestController
public class UserController {@AutowiredUserService userService;@GetMapping("/adduser")public void addUser() {User user = new User("12365987", "6666", "女", "小奏");userService.addUser(user);}
}
查看控制台及数据库
数据库也没有数据写入
基于Aop实现类似@Transactional注解
1. 实现自定义注解
WhTransaction
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WhTransaction {
}
- @Target说明了注解可使用的地方,Target有如下几个参数
- CONSTRUCTOR:用于描述构造器
- FIELD:用于描述域
- LOCAL_VARIABLE:用于描述局部变量
- METHOD:用于描述方法
- PACKAGE:用于描述包
- PARAMETER:用于描述参数
- TYPE:用于描述类、接口(包括注解类型) 或enum声明
- @Retention作用是定义注解保留多久,RetentionPolicy.RUNTIME表示会在class字节码文件中存在,在运行时可以通过反射获取到
2. 基于aop实现事务回滚提交
AopTransaction
@Component
@Aspect
@Slf4j
public class AopTransaction {private static final String POINT_CUT = "execution(* com.mybatis.service..*.*(..))";//定义切面@Pointcut(POINT_CUT)private void pointcut(){}@AutowiredTransactionUtils transactionUtils;/*环绕通知* 方法执行前后执行** */@Around("pointcut()")public void around(ProceedingJoinPoint pjp) throws Throwable {//1.获取代理对象的方法//获取方法名称String methodName = pjp.getSignature().getName();//获取目标对象Class<?> classTarget = pjp.getTarget().getClass();//获取目标对象类型Class<?>[] par = ((MethodSignature) pjp.getSignature()).getParameterTypes();//获取目标对象方法Method objmethod = classTarget.getMethod(methodName, par);//2.获取该方法上是否加注解WhTransaction whTransaction = objmethod.getDeclaredAnnotation(WhTransaction.class);//3. 如果存在事务注解则开启事务TransactionStatus transactionStatus = null;if (whTransaction != null) {log.info("开启事务");transactionStatus = transactionUtils.begin();}//4. 调用目标代理对象方法pjp.proceed();//5. 判断该方法是否有注解if (whTransaction != null) {//6.如果存在注解,提交事务log.info("提交事务");transactionUtils.commit(transactionStatus);}}//异常通知@AfterThrowing("pointcut()")public void afterTrowing() {log.info("回滚事务");//获取当前事务并回滚TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();}
}
3. 测试
UserServiceImpl
@Service("userService")
public class UserServiceImpl implements UserService {@Autowiredprivate UserDao userDao;@Override@WhTransactionpublic void addUser(User user) {userDao.addUser(user);//模拟发生异常int i = 1/0;userDao.addUser(user);}}
补充说明
- 事务失效:spring事务是基于aop异常通知实现的,所以如果有有异常一定不能try,只能throws,不然异常通知就捕获不到,无法完成事务回滚
- 这里实现spring事务没有考虑spring事务的传播行为