Aop Based Handwritten spring transactions (declarative transactions)

1, Foreword

    spring transactions are divided into programmatic transactions and declarative transactions. Programming transactions need to be manually started, committed and rolled back. Declarative transactions are ok by adding their own Transactional annotations. Under normal circumstances, you don't need to care about the operation of transactions.

Declarative transaction benefits:

Declarative transaction helps us save a lot of code. It will automatically help us open, commit and rollback transactions, freeing programmers from transaction management.

Declarative transaction management is implemented using AOP, and its essence is to intercept before and after the execution of the target method. Add or create a transaction before the execution of the target method. After the execution of the method, choose to commit or rollback the transaction according to the actual situation.

In this way, the code is not intrusive, and only business logic needs to be written in the method.

Disadvantages of declarative transactions:

One limitation of declarative transaction is that its minimum granularity should act on methods.

That is, if you want to add transactions to a part of the code block, you need to separate this part of the code block as a method.

However, because of this granularity problem, I do not recommend excessive use of declarative transactions.

First of all, because declarative transactions are annotated and sometimes implemented through configuration, this will lead to a problem that this transaction may be ignored by developers.

What's the problem with transactions being ignored?

First, if the developer does not notice that a method is nested by transactions, some operations such as RPC remote call, message sending, cache update, file writing, etc. may be added to the method.

2, Programming transaction writing

1. Import dependency

<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>
 @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;

    private TransactionStatus transaction;

    public TransactionStatus transactionBegin(){
        System.out.println("Custom transaction on");
        transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
        return transaction;
    }

    public void TransactionalCommit(){
        System.out.println("Custom transaction commit");
        dataSourceTransactionManager.commit(transaction);
    }

    public void rollback(){
        System.out.println("Custom transaction rollback");
        dataSourceTransactionManager.rollback(transaction);
    }

2. CREATE TABLE statement

CREATE TABLE `pe_user` (
  `id` varchar(40) NOT NULL COMMENT 'ID',
  `username` varchar(255) NOT NULL COMMENT 'User name',
  `password` varchar(255) DEFAULT NULL COMMENT 'password',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

3. Test code

 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("insert user"+"dong" );
                userMapper.insertUser("sdsdwere120","ergouzi","456");
                transactionalUtil.TransactionalCommit();
            }catch (Exception e){
                transactionalUtil.rollback();
            }
    }

3, Declarative transaction

1. Reuse programmatic transaction code

2. Custom declarative transaction annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Transactional
public @interface MyTransaction {

    Propagation propagation() default Propagation.REQUIRED;

    Class<? extends Throwable>[] rollbackFor() default {};
}

3.AOP section preparation

@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. Whether the caught exception belongs to the configured type
        if (transactionStatus !=null){
            transactionalUtil.rollback();
        }
    }

    @Around("execution(* com.dong.studyaop.service..*.*(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //1. Get annotation on method
        MyTransaction annotation = getAnnotation(proceedingJoinPoint);
        //2. Start transaction
        begin(annotation);
        //3. Method of executing target object
        proceedingJoinPoint.proceed();
        //4. Submission of services
        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. Method of obtaining proxy object
        String name = proceedingJoinPoint.getSignature().getName();
        Class<?> aClass = proceedingJoinPoint.getTarget().getClass();
        Class[] parameterTypes = ((MethodSignature) proceedingJoinPoint.getSignature()).getParameterTypes();
        //2. Method of obtaining target object from proxy object
        Method method = aClass.getMethod(name, parameterTypes);
        MyTransaction annotation = method.getAnnotation(MyTransaction.class);
        return annotation;
    }

4. Test code

@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("insert user"+"dong" );
            userMapper.insertUser("sdsdwere120","ergouzi","456");
    }

    public void update() {

    }


}

Tags: Java AOP

Posted on Wed, 29 Sep 2021 15:29:58 -0400 by sarathi