Declarative transaction control

Programming transaction control related objects

Programming is to write code by using Java API. Declarative is to configure some things in the way of configuration

PlatformTransactionManager

The PlatformTransactionManager interface is the transaction manager of spring. It provides our common methods of operating transactions, that is, how transactions are controlled

methodexplain
TransactionStatus getTransaction(TransactionDefination defination)Gets the status information of the transaction
void commit(TransactionStatus status)Commit transaction
void rollback(TransactionStatus status)Rollback transaction

Note: PlatformTransactionManager is an interface type, and different Dao layer technologies have different implementation classes. For example, when Dao layer technology is JDBC or mybatis: org.springframework.jdbc.datasource.datasourcetransactionmanager; When Dao layer technology is Hibernate: org.springframework.orm.hibernate5.hibernatetransaction Manager

TransactionDefinition

Maintain transaction attribute information
TransactionDefinition is the transaction definition information object, which contains the following methods

methodexplain
int getIsolationLevel()Gets the isolation level of the transaction
int getPropogationBehavior()Get propagation behavior of transaction
int getTimeout()Get timeout
boolean isReadOnlyRead only
Transaction isolation level

Setting the isolation level can solve the problems caused by transaction concurrency, such as dirty read, non repeatable read and virtual read
Dirty read: a transaction reads uncommitted data from another transaction
Non repeatability: in the same transaction, the data read twice is different
Phantom reading: if one transaction operation (DML) data represents all records and another transaction adds a piece of data, the first transaction cannot query its own modifications.
ISOLATION_DEFAULT default
ISOLATION_ READ_ Uncommitted read (resulting problems: dirty read, non heavy load read, phantom read)
ISOLATION_READ_COMMITTED read has been submitted (resulting problems: no heavy reading, unreal reading)
ISOLATION_REPEATABLE_READ is not repeatable
ISOLATION_SERIALIZABLE serialization can solve all problems

Transaction propagation behavior

Encapsulate some state information and passive information during operation
The problem of transaction uniformity when business methods call business methods. In normal development, the business layer has many methods. When a and B methods call each other, we control their transactions in advance, and the problem of transaction duplication may occur
REQUIRED: if there is no transaction at present, create a new transaction. If there is already a transaction, join it. General selection (default)
SUPPORTS: SUPPORTS the current transaction. If there is no transaction, it will be executed in a non transactional manner (no transaction)
MANDATORY: use the current transaction. If there is no transaction, an exception will be thrown
Requests_new: create a new transaction. If it is currently in a transaction, suspend the current transaction.
NOT_SUPPORTED: perform operations in a non transactional manner. If there is a transaction, suspend the current transaction
NEVER: run in non transaction mode. If there is a transaction, throw an exception
NESTED: if a transaction currently exists, it is executed within a NESTED transaction. If there is no transaction currently, an operation similar to REQUIRED is executed
Timeout: the default value is - 1. There is no timeout limit. If there is, it is set in seconds
Read only: it is recommended to set it as read-only when querying

TransactionStatus

The TransactionStatus interface provides the specific running status of transactions. The methods are described below

methodexplain
boolean hasSavepoint()Store rollback points
boolean isCompleted()Is the transaction complete
boolean isNewTransaction()Is this a new transaction
boolean isRollbackOnly()Whether the transaction is rolled back

Declarative transaction control based on XML

Spring's declarative transaction, as its name suggests, is to process transactions in a declarative manner. The declaration here refers to declaring in the configuration file and using the declarative transaction in the spring configuration file to replace the code transaction.

The role of declarative transactions

1. Transaction management does not invade the developed components. Specifically, business logic objects will not realize that they are in transaction management. In fact, it should be the same, because transaction management is a system level service, not a part of business logic. If you want to change the transaction management plan, you only need to reconfigure it in the definition file
2. When transaction management is not required, the transaction management service can be removed as long as the settings file is modified without changing the code and recompiling, which is very convenient for maintenance
The underlying layer of Spring declarative transaction control is AOP

Implementation of declarative transaction control

Explicit matters of declarative transaction control:
Who is the pointcut? The business approach is enhanced
Who is notification? Transaction enhancement
Configuration aspect weaves transaction enhancements and business methods
0. Write dao layer and service layer

package com.zg.dao.impl;
import com.zg.dao.AccountDao;
import org.springframework.jdbc.core.JdbcTemplate;

public class AccountDaoImpl implements AccountDao {

    private JdbcTemplate jdbcTemplate;
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void out(String outMan, double money) {
        jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
    }

    public void in(String inMan, double money) {
        jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
    }
}

package com.zg.service.impl;


import com.zg.dao.AccountDao;
import com.zg.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String outMan, String inMan, double money) {
        //The transaction needs to be started here
        accountDao.out(outMan,money);
        int i = 1/0;
        accountDao.in(inMan,money);
        //Commit transaction
    }
}

1. Introduce tx namespace, configure transaction enhancement, and configure transaction AOP weaving

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="accountDao" class="com.zg.dao.impl.AccountDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"/>
    </bean>

    <!--The internal method of the target object is the tangent point-->
    <bean id="accountService" class="com.zg.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!--Configure a platform transaction manager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        <!--transactionManager The bottom layer needs to start from dataSource Gets a control for the transaction-->
        <!--jdbc The template is right jdbc Simple encapsulation. The platform manager needs to connect objects when managing transactions connection,connection Injection required from data source dataSource-->
    </bean>

    <!--The namespace of the enhanced transaction for the notification transaction is tx-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes<--tx affair attributs attribute-->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <!--to configure aop Transaction weaving-->
    <aop:config>
        <!--advisor yes Spring Specialized configuration of transaction control-->
        <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.zg.service.impl.*.*(..))"></aop:advisor>
    </aop:config>
</beans>

If the implementation of dao layer is not native jdbc or Mybatis, the platform manager may change accordingly
2. Test transaction control transfer business code

package com.zg.service.impl;


import com.zg.dao.AccountDao;
import com.zg.service.AccountService;

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void transfer(String outMan, String inMan, double money) {
        //The transaction needs to be started here
        accountDao.out(outMan,money);
        int i = 1/0;
        accountDao.in(inMan,money);
        //Commit transaction
    }
}

Configuration of transaction parameters of pointcut method

<!--The namespace of the enhanced transaction for the notification transaction is tx-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

Where, < TX: method > represents the configuration of the transaction parameters of the pointcut method, for example
< TX: attributes > is to set the attribute information of the transaction

<tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" timeout="-1" read-only="false"/>
<--Here because transfer It's enhancement, so it's right transfer Separate transaction configuration. If there are other methods, copy and rewrite. A transaction can configure the attribute parameters belonging to the transaction respectively-->

nam = "*" *: represents any method
name="update *": indicates the method starting with update
Name: pointcut method name
Isolation: isolation level of transaction
Propagation: propagation behavior of transactions
Timeout: timeout
Read only: whether it is readable

Annotation based declarative transaction control

Configuring declarative transaction control using annotations

1. Write dao

package com.zg.dao.impl;
import com.zg.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    public void out(String outMan, double money) {
        jdbcTemplate.update("update account set money=money-? where name=?",money,outMan);
    }

    public void in(String inMan, double money) {
        jdbcTemplate.update("update account set money=money+? where name=?",money,inMan);
    }
}

2. Write service

package com.zg.service.impl;


import com.zg.dao.AccountDao;
import com.zg.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service("accountService")
//You can also add transaction control to the class, which means that all methods in the following class use the specified transaction control parameter
@Transactional(isolation = Isolation.READ_COMMITTED)
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;
    //The principle of proximity is the main principle
    @Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
    public void transfer(String outMan, String inMan, double money) {
        //The transaction needs to be started here
        accountDao.out(outMan,money);
        int i = 1/0;
        accountDao.in(inMan,money);
        //Commit transaction
    }
}

3. Write the application.xml configuration file

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
    <!--Component scan-->
    <context:component-scan base-package="com.zg"/>

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?serverTimezone=UTC"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>


    <!--Configure a platform transaction manager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        <!--transactionManager The bottom layer needs to start from dataSource Gets a control for the transaction-->
        <!--jdbc The template is right jdbc Simple encapsulation. The platform manager needs to connect objects when managing transactions connection,connection Injection required from data source dataSource-->
    </bean>
    <!--Annotation driven transactions-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

Here, if there is no customized aspect class, there is no need to configure it. The pointcut and weaving framework of transaction management have been obtained through the transaction annotation and the information of the class. The underlying aspect class is provided by spring and configured by spring itself

Annotation configuration declarative transaction control resolution

1. @ Transactional modifies classes or methods that need transaction control. The attributes available for annotation are the same as xml configuration methods, such as isolation level, propagation behavior, etc.
2. If annotations are used on a class, all methods under the class are configured with the same set of annotation parameters
3. In terms of methods, different methods can adopt different transaction parameter configurations
4. Annotation driven transaction manager = "transactionmanager" > < / TX: annotation driven >

Keywords: Java Hibernate SSM

Added by Hokus on Tue, 09 Nov 2021 01:11:27 +0200