SpringBoot Foundation: declarative transactions and faceted transactions and programmatic transactions

Keywords: Java Android Apache Programmer architecture

preface

Transaction is one or more database operations that need to ensure atomicity, isolation, consistency and persistence at the same time

This article will explain the implementation methods of two transactions in springBoot, programming transaction configuration and declarative transaction configuration, as well as aspect transactions. Of course, before that, we will talk about some basic things: the four characteristics of transactions, the isolation level of transactions, and the propagation behavior of transactions

Four characteristics of transactions (ACID)

  1. Atomicity: all operations in a transaction are inseparable in the database, either all or none
  2. Consistency: for several transactions executed in parallel, the execution result must be consistent with the result of serial execution in a certain order
  3. Isolation: the execution of a transaction is not disturbed by other transactions. The intermediate results of transaction execution must be transparent to other transactions
  4. Persistence: for any committed transaction, the system must ensure that the changes made to the database by the transaction are not lost

Open transaction

@EnableTransactionManagement

SpringBoot declarative transaction

Declarative transaction @ Transactional can be used on classes or public methods. If it is used on classes, transactions will be enabled for all public methods. If there are transactions on classes and methods, transactions on methods will take effect

Can be used on classes

@Transactional(rollbackFor=Exception.class)
public class TransactionServiceImpl implements TransactionService {
}

It is more used in methods

@Override
@Transactional(rollbackFor=Exception.class)
public void t1(Student one) {
}

@Parameters for Transactional

Some of its parameters are used when using @ Transactional

parameter

effect

value

When multiple transaction managers are configured, you can use this attribute to specify which transaction manager to select

transactionManager

When multiple transaction managers are configured, you can use this attribute to specify which transaction manager to select

propagation

Propagation behavior of transactions. The default value is Propagation.REQUIRED

isolation

The isolation level of the transaction. The default value is Isolation.DEFAULT

timeout

The timeout of the transaction. The default value is - 1. If the time limit is exceeded but the transaction has not completed, the transaction will be rolled back automatically

readOnly

Specifies whether the transaction is read-only. The default value is false; To ignore methods that do not require transactions, such as reading data, you can set read only to true

rollbackFor

Used to specify exception types that can trigger transaction rollback. Multiple exception types can be specified

rollbackForClassName

Used to specify exception types that can trigger transaction rollback. Multiple exception types can be specified

noRollbackFor

Throw the specified exception type, do not roll back the transaction, or specify multiple exception types

noRollbackForClassName

Throw the specified exception type, do not roll back the transaction, or specify multiple exception types

value is the same as transactionManager. rollbackFor and rollbackForClassName are the same. noRollbackFor and noRollbackForClassName are the same

Isolation level of transaction

Isolation level is used in isolation

parameter

Transaction isolation level

Dirty reading

Non repeatable reading

Unreal reading

READ_UNCOMMITTED

Read uncommitted

yes

yes

yes

READ_COMMITTED

Read committed

no

yes

yes

REPEATABLE_READ

Repeatable read

no

no

yes

SERIALIZABLE

serializable

no

no

no

Propagation of transactions

Propagation will use this propagation script

Communication behavior

explain

REQUIRED

If there is a transaction, join it. If there is no transaction, create a new transaction

SUPPORTS

If a transaction currently exists, join the transaction; If no transaction currently exists, it continues to run in a non - transactional manner

MANDATORY

If a transaction currently exists, join the transaction; Throw an exception if no transaction currently exists

REQUIRES_NEW

Recreate a new transaction. If there is a current transaction, pause the current transaction

NOT_SUPPORTED

Run in a non - transactional manner. If a transaction currently exists, suspend the current transaction

NEVER

Run in a non - transactional manner and throw an exception if a transaction currently exists

NESTED

It has the same effect as REQUIRED

SpringBoo programmatic transaction

Inject TransactionTemplate where needed

@Autowired 
private TransactionTemplate transactionTemplate;

Then use it in your code

@Override
  public final void save2() {
   transactionTemplate.execute((status)->{
            mapper.saveStudent(newOne());
            mapper.saveStudent(newOne());
            return Boolean.TRUE;
        });
  }

These two mappers. Savestudent (newone()); Executed in one transaction

SpringBoo faceted programmatic transactions

This method is based on AOP function, so it needs to be added

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

Write configuration class

@Aspect
@Configuration
public class MyTransactionConfig {

    /**
     * Configure method expiration time, default - 1, never timeout
     */
    private final static int TX_METHOD_TIME_OUT = 10;

   /**
     * The global transaction location configures where transactions are required
     * Configure pointcut expressions
     */
    private static final String POITCUT_EXPRESSION = "execution(* zdc.enterprise.service.impl.*.*(..))";

    @Autowired
    private PlatformTransactionManager platformTransactionManager;


    @Bean
    public TransactionInterceptor txadvice() {

        /*Read only things, do not update and delete, etc*/
        /*Transaction management rules*/
        RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
        /*Set whether the current transaction is read-only. true is read-only*/
        readOnlyRule.setReadOnly(true);
        /* transactiondefinition Define the isolation level of transactions;
         *If a transaction currently exists, join the transaction; If there are currently no transactions, continue to run in a non transactional manner.*/
        readOnlyRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);

         /*Add, delete and modify transaction rules*/
        RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
        /*Execute pointcut rollback after throwing an exception. It is recommended to customize the exception*/
        requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        /*PROPAGATION_REQUIRED:The transaction isolation is 1. If there is a current transaction, join the transaction; If there is no current transaction, a new transaction is created. This is the default. */
        requireRule.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        /*Set the transaction expiration time, which exceeds 10 seconds*/
        requireRule.setTimeout(TX_METHOD_TIME_OUT);

        /** Configure transaction management rules
         nameMap Declare a method name that needs to manage a transaction
         Here we use addTransactionalMethod and setNameMap
         */
        Map<String, TransactionAttribute> nameMap = new HashMap<>();
        nameMap.put("add*", requireRule);
        nameMap.put("save*", requireRule);
        nameMap.put("insert*", requireRule);
        nameMap.put("update*", requireRule);
        nameMap.put("delete*", requireRule);
        nameMap.put("remove*", requireRule);

        /*During batch operation*/
        nameMap.put("batch*", requireRule);
        nameMap.put("get*", readOnlyRule);
        nameMap.put("query*", readOnlyRule);
        nameMap.put("find*", readOnlyRule);
        nameMap.put("select*", readOnlyRule);
        nameMap.put("count*", readOnlyRule);

        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        source.setNameMap(nameMap);

        TransactionInterceptor transactionInterceptor = new TransactionInterceptor(platformTransactionManager, source);

        return transactionInterceptor;
    }

    /**
     * Set tangent = tangent pointcut + notification TxAdvice
     * @return
     */
    @Bean
    public Advisor txAdviceAdvisor() {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(POITCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txadvice());
    }
}

With this aspect configuration class, don't use @ Transactional on the class or each method. Of course, the prefix of the method name should match the setting  
The parameters of RuleBasedTransactionAttribute are roughly the same as those of @ Transactional. There are detailed comments in it, but there is no more explanation

END

The granularity of faceted transactions is the coarsest. If the method names do not match, it is easy to leak methods. The granularity of declarative transactions is medium, but problems will occur in case of large transactions. The granularity of programming transactions is the smallest. You can consider using it at special times

Posted by Skyphoxx on Tue, 30 Nov 2021 13:34:46 -0800