
一、前言
spring事务分为编程式事务和声明式事务。编程式事务需要自己手动开启,提交,回滚事务,声明式事务则是添加自带的Transactional注解就 ok,正常情况下就不用关心事务的操作了。
声明式事务优点:
声明式事务帮助我们节省了很多代码,他会自动帮我们进行事务的开启、提交以及回滚等操作,把程序员从事务管理中解放出来。
声明式事务管理使用了 AOP 实现的,本质就是在目标方法执行前后进行拦截。 在目标方法执行前加入或创建一个事务,在执行方法执行后,根据实际情况选择提交或是回滚事务。
使用这种方式,对代码没有侵入性,方法内只需要写业务逻辑就可以了。
声明式事务缺点:
声明式事务有一个局限,那就是他的最小粒度要作用在方法上。
也就是说,如果想要给一部分代码块增加事务的话,那就需要把这个部分代码块单独独立出来作为一个方法。
但是,正是因为这个粒度问题,本人并不建议过度的使用声明式事务。
首先,因为声明式事务是通过注解的,有些时候还可以通过配置实现,这就会导致一个问题,那就是这个事务有可能被开发者忽略。
事务被忽略了有什么问题呢?
首先,如果开发者没有注意到一个方法是被事务嵌套的,那么就可能会再方法中加入一些如RPC远程调用、消息发送、缓存更新、文件写入等操作。
二、编程式事务编写
1.导入依赖
mysql mysql-connector-java5.1.47 com.alibaba druid1.1.10
@Autowired
DataSourceTransactionManager dataSourceTransactionManager;
private TransactionStatus transaction;
public TransactionStatus transactionBegin(){
System.out.println("自定义事务开启");
transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
return transaction;
}
public void TransactionalCommit(){
System.out.println("自定义事务提交");
dataSourceTransactionManager.commit(transaction);
}
public void rollback(){
System.out.println("自定义事务回滚");
dataSourceTransactionManager.rollback(transaction);
}
2.建表语句
CREATE TABLE `pe_user` ( `id` varchar(40) NOT NULL COMMENT 'ID', `username` varchar(255) NOT NULL COMMENT '用户名称', `password` varchar(255) DEFAULT NULL COMMENT '密码', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.测试代码
public void add() {
TransactionStatus transactionStatus = null;
try{
transactionStatus = transactionalUtil.transactionBegin();
userMapper.insertUser("1232143243","dong","123");
String aa = "18.239563";
int i = Integer.parseInt(aa);
System.out.println("插入user"+"dong" );
userMapper.insertUser("sdsdwere120","ergouzi","456");
transactionalUtil.TransactionalCommit();
}catch (Exception e){
transactionalUtil.rollback();
}
}
三、声明式事务
1.复用编程式事务代码
2.自定义声明式事务注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
public @interface MyTransaction {
Propagation propagation() default Propagation.REQUIRED;
Class extends Throwable>[] rollbackFor() default {};
}
3.AOP切面编写
@Component
@Aspect
public class MyTransactionAop {
@Autowired
TransactionalUtil transactionalUtil;
private TransactionStatus transactionStatus;
@AfterThrowing(value = "execution(* com.dong.studyaop.service..*.*(..))",throwing = "e")
public void afterThrowing(JoinPoint joinPoint,Exception e) throws Exception {
//1.捕获到的异常是否属于配置的类型
if (transactionStatus !=null){
transactionalUtil.rollback();
}
}
@Around("execution(* com.dong.studyaop.service..*.*(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
//1.获取方法上的注解
MyTransaction annotation = getAnnotation(proceedingJoinPoint);
//2.开启事务
begin(annotation);
//3.执行目标对象的方法
proceedingJoinPoint.proceed();
//4.提交事务
commit();
}
private void commit() {
if (transactionStatus !=null){
transactionalUtil.TransactionalCommit();
}
}
private TransactionStatus begin(MyTransaction annotation) {
if (annotation ==null){
return null;
}
transactionStatus = transactionalUtil.transactionBegin();
return transactionStatus;
}
private MyTransaction getAnnotation(JoinPoint proceedingJoinPoint) throws NoSuchMethodException {
//1.获取代理对象的方法
String name = proceedingJoinPoint.getSignature().getName();
Class> aClass = proceedingJoinPoint.getTarget().getClass();
Class[] parameterTypes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();
//2.由代理对象获取目标对象的方法
Method method = aClass.getMethod(name, parameterTypes);
MyTransaction annotation = method.getAnnotation(MyTransaction.class);
return annotation;
}
4.测试代码
@Service
public class UserServiceImpl {
@Resource
UserMapper userMapper;
@Autowired
TransactionalUtil transactionalUtil;
@MyTransaction
public void add() {
userMapper.insertUser("1232143243","dong","123");
String aa = "18.239563";
int i = Integer.parseInt(aa);
System.out.println("插入user"+"dong" );
userMapper.insertUser("sdsdwere120","ergouzi","456");
}
public void update() {
}
}