JAVA combat articles Simple application of the transaction manager that comes with Spring Programmatic transaction Declarative transaction, annotation declarative transaction, AspectJ annotation transaction

The transaction manager that comes with Spring

1. Programmatic transactions

For details, please refer to the official documentation:
https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/data-access.html#transaction-programmatic
Advantages: no need for spring to proxy, generate proxy objects (reflection), better performance
Disadvantages: transaction management logic must be coupled with business logic, poor reusability and poor scalability
Application scenario: It is suitable for only a few business methods in the project that require transactions.

1.1. Test code:

1.1.1. Generate the xml file configuration of transaction management (TransactionTemplate):

Pay attention to import related packages or dependencies

The following is my maven configuration file: (need to mention)

<dependencies>
    <dependency>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-core</artifactId>
        <version>1.4.0</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>net.sf.ehcache</groupId>
        <artifactId>ehcache-core</artifactId>
        <version>2.6.11</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>1.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.35</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.taglibs</groupId>
        <artifactId>taglibs-standard-spec</artifactId>
        <version>1.2.5</version>
    </dependency>
    <dependency>
        <groupId>org.apache.taglibs</groupId>
        <artifactId>taglibs-standard-impl</artifactId>
        <version>1.2.5</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.41</version>
    </dependency>
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>5.3.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-instrument</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-messaging</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-oxm</artifactId>
        <version>5.3.2</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.6</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>RELEASE</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.0.25</version>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
</dependencies>

OK, let's get started:
Directly on the configuration file code:

Database configuration:

url=jdbc:mysql://localhost:3306/test?useUnicode=true&amp&characterEncoding=utf-8
driver=com.mysql.jdbc.Driver
uName=root
password=123456

xml file configuration:

<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">

<!--1,Load database configuration information -->
<context:property-placeholder
	location="database.properties" /><!--If you don't have a configuration file, remember to create it first. -->
<!--2,datasource data source -->
<bean id="dataSource"
	class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="${driver}" />
	<property name="url" value="${url}" />
	<property name="username" value="${uName}" />
	<property name="password" value="${password}" />
</bean>
<!-- 3,sqlSessionFactory -->
<bean id="sqlSessionFactory"
	class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- alias -->
	<property name="typeAliasesPackage" value="entity"/>
	<!-- mapper XML map -->
	<property name="mapperLocations"
		value="classpath*:mapper/*Mapper.xml"></property>
	<!-- data source -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!--4,mapper the location of the interface -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="mapper"></property>
</bean>
<!-- 1),transaction management(enhance/Notice):  -->
<bean id="txManager" 
	  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
	<property name="dataSource" ref="dataSource"/> 
</bean>
<bean id="transactionTemplate"
	  class="org.springframework.transaction.support.TransactionTemplate ">
	<property name="transactionManager" ref="txManager"/>
</bean>
</beans>

1.1.2. Generate the xml file configuration of the Mapper interface:

<?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:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    ">
<!--  1,Start annotation scan-->
<context:component-scan base-package="change"/>
<!-- 1)Target -->
<bean id="target" class="change.ChangeMoneyImpl_BC"/>
<!-- 2)proxy object instance -->
<bean id="proxy_BC" class="proxy.Proxy_BC"/>
<!--3)acting  -->
<bean  id="changeMoney" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces"  value="change.ChangeMoney"/><!-- Note that this is the interface -->
    <!-- 1)inject target object -->
    <property name="target"  ref="target"/>
    <!-- 2)proxy object instance  -->
    <property name="interceptorNames">
        <array>
            <value>proxy_BC</value>
        </array>
    </property>
</bean>
</beans>

1.1.3, ChangMoney interface and implementation class:

interface:

public interface ChangeMoney {
    boolean giveMoney(int on, int to, int money);
}
/**
*@author Nical
*/
@Component
public class ChangeMoneyImpl_BC implements ChangeMoney {
    @Autowired
    private UserinfoMapper mapper;
    @Autowired
    private TransactionTemplate transactionTemplate;

    class Result{
        boolean result;
    }

    @Override
    public boolean giveMoney(int on, int to, int money) {
        final  Result result =new Result() ;
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                try {
                    giveMoneyOption(on, to, money);
                    System.out.println("=======transaction committed BC=====");
                    //transaction rollback
                    result.result = true;
                }catch (Exception e){
                    System.out.println("=======transaction rolled back BC=====");
                    //transaction rollback
                    transactionStatus.setRollbackOnly();
                    result.result = false;
                }
            }
        });
        return result.result;
    }

    public void giveMoneyOption(int on, int to, int money) throws Exception {
        Userinfo userinfo =mapper .selectByPrimaryKey(on);
        int i=0;
        if (userinfo!=null){
            //Set the balance of the sender
            userinfo.setMoney(userinfo.getMoney()-money);
            //number of rows affected
            i = mapper.updateByPrimaryKey(userinfo);
        }
        //Information of the person being transferred
        Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
        int j=0;
        if (userinfo2!=null){
            //Set the balance of the sender
            userinfo2.setMoney(userinfo2.getMoney()+money);
            //number of rows affected
            j = mapper.updateByPrimaryKey(userinfo2);
        }
        if (i>0&&j>0){
            System.out.println("The transfer was successful! !");
        }else {
            //rollback transaction
            System.out.println("Transfer failed! !");
            throw new Exception("Transfer failed exception");
        }
    }
}

1.1.4. Test class code:

/**
*@author Nical
*/
//Programmatic transactions
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans_proxy_BC.xml","classpath:beans_BC.xml"})
                          //Generate proxy Generate transaction manager (TransactionTemplate)
public class Test_BC {
    //Programmatic transaction, implement transaction manager through aop yourself
    @Autowired
    @Qualifier("changeMoney")
    private ChangeMoney changeMoney;
    @Test
    public void test2(){
        boolean result = changeMoney.giveMoney(1, 3, 300);
        System.out.println(result);
    }
}

1.2. Summary:

We found that when processing transactions, the transaction code is coupled with our business code, and it is very inconvenient, because every time I want to perform a transaction operation, I need to write the business code again, which is very troublesome. Let's take a look at declarative transactions, which solve the above problems very well:

2. Declarative transactions

Pros: Transaction Management is out of business logic and not hard to configure
Disadvantages: need spring for proxy, generate proxy object (reflection), slightly poor performance
Application scenario: a large number of scenarios in the project that require transaction management (commonly used in enterprise development)

Let's go directly to the code:

2.1. Test code:

2.1.1. Generate xml file configuration for transaction management:

XML file configuration

<?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:context="http://www.springframework.org/schema/context"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    https://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd
    ">
<!--1,Load database configuration information -->
<context:property-placeholder
	location="database.properties" />
<!--2,datasource data source -->
<bean id="dataSource"
	class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="${driver}" />
	<property name="url" value="${url}" />
	<property name="username" value="${uName}" />
	<property name="password" value="${password}" />
</bean>
<!-- 3,sqlSessionFactory -->
<bean id="sqlSessionFactory"
	class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- alias -->
	<property name="typeAliasesPackage" value="entity"/>
	<!-- mapper XML map -->
	<property name="mapperLocations"
		value="classpath*:mapper/*Mapper.xml"></property>
	<!-- data source -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!--4,mapper the location of the interface -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="mapper"></property>
</bean>
<!-- 1),transaction management(enhance/Notice):  -->
<bean id="txManager"
	  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
	<property name="dataSource" ref="dataSource"/> 
</bean>
<!-- Step 1: Define a Notification advice -->
<tx:advice id="gmAdvice" transaction-manager="txManager">
	<tx:attributes>
	<!-- This method will use the transaction manager -->
		<tx:method name="giveMoney*"/>
		<!-- Any other method, using read-only transactions
            isolation="DEFAULT"       Transaction isolation level
            propagation="REQUIRED"    Transaction Propagation Features
            timeout="-1"              transaction timeout
            no-rollback-for=""        Specify a runtime exception not to rollback
            rollback-for=""           Specify a runtime exception to roll back
         -->
	</tx:attributes>
</tx:advice>
<!-- Step 2: Embed the notification into the pointcut
   public void   giveMoney(int a){}
   public void  change.ChangeMoneyImpl_SM.giveMoney(..)
 -->
<aop:config>
	<!--  1)Cut-off point-->
	<aop:pointcut id="pointCut" expression="execution(*  change.ChangeMoneyImpl_SM.*(..))" />
	<!-- 2)Embed : Embed the notification into the pointcut-->
	<aop:advisor advice-ref="gmAdvice"  pointcut-ref="pointCut"/>
</aop:config>

2.1.2. Generate the xml file configuration of the Mapper interface:

<?xml version="1.0" encoding="UTF-8"?>

<!--  1,Start annotation scan-->
  <context:annotation-config/>
<context:component-scan base-package="change"/>
<!-- 1)Target -->
<bean id="target_SM" class="change.ChangeMoneyImpl_SM"/>
<!-- 2)hacker -->
<bean id="proxy_SM" class="proxy.Proxy_SM"/>
<!--3)acting  -->

<bean  id="changeMoney_sm" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- interface-->
    <property name="proxyInterfaces"  value="change.ChangeMoney"/>
    <!-- 1)inject target object -->
    <property name="target"  ref="target_SM"/>
    <!-- 2)hacker object  -->
    <property name="interceptorNames">
        <array>
            <value>proxy_SM</value>
        </array>
    </property>
</bean>
</beans>

2.1.3. Implementation class of ChangMoney interface:

/**
*@author Nical
*/
@Component
public class ChangeMoneyImpl_SM implements ChangeMoney {
    @Autowired
    private UserinfoMapper mapper;
    
    @Override
    public boolean giveMoney(int on, int to, int money) {
        boolean result=giveMoneyOption(on,to,money);
        return result;
    }

    public boolean giveMoneyOption(int on, int to, int money)  {
        Userinfo userinfo =mapper .selectByPrimaryKey(on);
        int i=0;
        if (userinfo!=null){
            //Set the balance of the sender
            userinfo.setMoney(userinfo.getMoney()-money);
            //number of rows affected
            i = mapper.updateByPrimaryKey(userinfo);
        }
        //Information of the person being transferred
        Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
        int j=0;
        if (userinfo2!=null){
            //Set the balance of the sender
            userinfo2.setMoney(userinfo2.getMoney()+money);
            //number of rows affected
            j = mapper.updateByPrimaryKey(userinfo2);
        }
        if (i>0&&j>0){
            System.out.println("The transfer was successful! !");
            return true;
        }else {
            //rollback transaction
            System.out.println("Transfer failed! !");
            throw new RuntimeException("Transfer failed exception");
        }
    }
}

2.1.4 ,Test code:

/**
*@author Nical
*/
//declarative transaction
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans_proxy_SM.xml","classpath:beans_SM.xml"})
                             //Generate proxy Generate transaction manager (TransactionTemplate)
public class Test_SM {
    @Autowired
    @Qualifier("changeMoney_sm")
    private ChangeMoney changeMoney;
    @Test
    public void test2(){
        boolean result = changeMoney.giveMoney(1, 3, 300);
        System.out.println(result);
    }
}

2.2 Summary:

We found that the programming style is less intrusive and avoids the coupling of the code. The transaction-related code can be written separately, but is there a simpler way to write it? Yes! The following annotation declares the transaction:

3. Annotating declarative transactions

Advantages: On the basis of the above advantages, you can directly add annotations to the required methods, which is very convenient
Disadvantages: same as above
Application scenario: same as above (methods commonly used in enterprises)

Let's go directly to the code:

3.1. Test code:

3.1.1. Generate xml file configuration for transaction management:

XML file configuration

<?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:context="http://www.springframework.org/schema/context"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    https://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
    https://www.springframework.org/schema/aop/spring-aop.xsd
    ">
<!--1,Load database configuration information -->
<context:property-placeholder
	location="database.properties" />
<!--2,datasource data source -->
<bean id="dataSource"
	class="org.apache.commons.dbcp.BasicDataSource">
	<property name="driverClassName" value="${driver}" />
	<property name="url" value="${url}" />
	<property name="username" value="${uName}" />
	<property name="password" value="${password}" />
</bean>
<!-- 3,sqlSessionFactory -->
<bean id="sqlSessionFactory"
	class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- alias -->
	<property name="typeAliasesPackage" value="entity"/>
	<!-- mapper XML map -->
	<property name="mapperLocations"
		value="classpath*:mapper/*Mapper.xml"></property>
	<!-- data source -->
	<property name="dataSource" ref="dataSource"></property>
</bean>

<!--4,mapper the location of the interface -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
	<property name="basePackage" value="mapper"></property>
</bean>
<!-- 1),transaction management(enhance/Notice):  -->
<bean id="txManager"
	  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 
	<property name="dataSource" ref="dataSource"/> 
</bean>
<!-- Declarative transaction annotation method: Step 1: Open annotation transaction
    proxy-target-class="true"   Specifies that the annotation transaction is to use cglib Dynamic proxy method to achieve
 -->
<tx:annotation-driven  transaction-manager="txManager"/>

3.1.2. Generate the xml file configuration of the Mapper interface:

<?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:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    https://www.springframework.org/schema/context/spring-context.xsd">

<!--  1,Start annotation scan-->
  <context:annotation-config/>
<context:component-scan base-package="change"/>
<!-- 1)Target -->
<bean id="target_ZJSM" class="change.ChangeMoneyImpl_ZJSM"/>
<!-- 2)Proxy instance -->
<bean id="proxy_ZJSM" class="proxy.Proxy_ZJSM"/>
<!--3)acting  -->

<bean  id="changeMoney_zjsm" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- interface-->
    <property name="proxyInterfaces"  value="change.ChangeMoney"/>
    <!-- 1)inject target object -->
    <property name="target"  ref="target_ZJSM"/>
    <!-- 2)Proxy instance  -->
    <property name="interceptorNames">
        <array>
            <value>proxy_ZJSM</value>
        </array>
    </property>
</bean>
</beans>

3.1.3. Implementation class of ChangMoney interface:

/**
*@author  Nical
*/
@Component
public class ChangeMoneyImpl_ZJSM implements ChangeMoney {
    @Autowired
    private UserinfoMapper mapper;
    @Override
    @Transactional
    public boolean giveMoney(int on, int to, int money) {
        boolean result=giveMoneyOption(on,to,money);
        return result;
    }

    public boolean giveMoneyOption(int on, int to, int money)  {
        Userinfo userinfo =mapper .selectByPrimaryKey(on);
        int i=0;
        if (userinfo!=null){
            //Set the balance of the sender
            userinfo.setMoney(userinfo.getMoney()-money);
            //number of rows affected
            i = mapper.updateByPrimaryKey(userinfo);
        }
        //Information of the person being transferred
        Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
        int j=0;
        if (userinfo2!=null){
            //Set the balance of the sender
            userinfo2.setMoney(userinfo2.getMoney()+money);
            //number of rows affected
            j = mapper.updateByPrimaryKey(userinfo2);
        }
        if (i>0&&j>0){
            System.out.println("The transfer was successful! !");
            return true;
        }else {
            //rollback transaction
            System.out.println("Transfer failed! !");
            throw new RuntimeException("Transfer failed exception");
        }
    }
}

2.1.4 , Test class code:

/**
*@author Nical
*/
//Annotating Declarative Transactions
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:beans_proxy_ZJSM.xml", "classpath:beans_ZJSM.xml"})
                             //Generate proxy Generate transaction manager (TransactionTemplate)
public class Test_ZJSM {
    //Programmatic transaction, implement transaction manager through aop yourself
    @Autowired
    @Qualifier("changeMoney_zjsm")
    private ChangeMoney changeMoney;
    @Test
    public void test2(){
        boolean result = changeMoney.giveMoney(1, 3, 300);
        System.out.println(result);
    }
}

3.2. Summary:

Compared with the first two, the annotation method is particularly cool, so it is strongly recommended to master this kind of transaction management method. Here is another method that can handle transaction management. AspectJ and JAVA configure our transaction management

4. AspectJ is aspect-oriented, annotating transactions

4.1. Introduction

AspectJ is an aspect-oriented framework that extends the Java language. AspectJ defines the AOP syntax, and it has a special compiler to generate Class files that comply with the Java byte encoding specification.

4.2. Test code:

4.2.1, AspectJ code:

/*
 * log notifications (join points (pointcuts) + enhancements)
 * @author Nical
 */
@Aspect
@Component
public class LogAspect {
    // 1. Define a pointcut
    @Pointcut("execution(*  change.Impls.ChangeMoneyImpl_Aspect.*(..) )")
    public void pointCut() {}
    
    //2. Advance notice
    @Before("pointCut() ")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("=====I am advance notice=====>"+joinPoint);
    }
   //3.@After cuts in after calling the target method; pointcut expression (specifies which method to cut in)
    @After("pointCut() ")
    public void  afterAdvice(JoinPoint joinPoint) {
        System.out.println("=====I am post notification=====>"+joinPoint);
    }
    
  //4. Surround notification/enhancement (hack)
    //@Around("com.cc.dao.impl.UserDaoImpl2.add(..)")
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("1.Authentication");
        //call the target method
        Object result = joinPoint.proceed();
        System.out.println("1.log marks==>"+result);
        return result;
    }
    
  //5.JoinPoint must appear in the first place in the parameter list
    @AfterReturning(value="pointCut()",returning="result")
    public Object logReturn(JoinPoint joinPoint, Object result){
        System.out.println(""+joinPoint.getSignature().getName()+"Return normally. . .@AfterReturning:operation result:{"+result+"}");
        return result;
    }
    //6. Exception notification
    @AfterThrowing(value="pointCut()",throwing="exception")
    public void logException(JoinPoint joinPoint, Exception exception){
        System.out.println(""+joinPoint.getSignature().getName()+"abnormal. . . Exception information:{"+exception+"}");
    }
}

4.2.2, Bean factory code configured by JAVA annotation:

/*
 * @author Nical
 */
@Configuration
@ComponentScan(value= {"aspect","change.Impls"})
@EnableAspectJAutoProxy//Start aspectJ annotation aop
@EnableTransactionManagement//Start transaction management
public class AspectJConfig {
    
    //1.datasource
    @Bean
    public BasicDataSource getBasicDataSource() {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/test?useUnicode=true&amp&characterEncoding=utf-8");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        return dataSource;
    }
    //2.sqlSessionFactory
    @Bean
    public SqlSessionFactory getSessionFactoryBean() throws Exception {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(getBasicDataSource());
        Resource[] resources = {new ClassPathResource("mapper/UserinfoMapper.xml")};
        sessionFactoryBean.setMapperLocations(resources );
        return sessionFactoryBean.getObject();
    }
    //3.Mapper
    @Bean
    public UserinfoMapper userMapper() throws Exception {
      // when using javaconfig a template requires less lines than a MapperFactoryBean
      SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(getSessionFactoryBean());
      return sqlSessionTemplate.getMapper(UserinfoMapper.class);
    }
    //4. Transaction DataSourceTransactionManager
    @Bean(name = "dataSourceTransactionManager")
    public DataSourceTransactionManager getTransactionManager() {
        DataSourceTransactionManager txManager = new DataSourceTransactionManager();
        txManager.setDataSource(getBasicDataSource());
        return txManager;
    }
}

4.2.3, the implementation class of the interface:

/*
 * @author Nical
 */
@Component
public class ChangeMoneyImpl_Aspect implements ChangeMoney {
    @Autowired
    private UserinfoMapper mapper;
    @Transactional
    @Override
    public boolean giveMoney(int on, int to, int money) {
        boolean result=giveMoneyOption(on,to,money);
        return result;
    }

    public boolean giveMoneyOption(int on, int to, int money)  {
        Userinfo userinfo =mapper .selectByPrimaryKey(on);
        int i=0;
        if (userinfo!=null){
            //Set the balance of the sender
            userinfo.setMoney(userinfo.getMoney()-money);
            //number of rows affected
            i = mapper.updateByPrimaryKey(userinfo);
        }
        //Information of the person being transferred
        Userinfo userinfo2 =mapper .selectByPrimaryKey(to);
        int j=0;
        if (userinfo2!=null){
            //Set the balance of the sender
            userinfo2.setMoney(userinfo2.getMoney()+money);
            //number of rows affected
            j = mapper.updateByPrimaryKey(userinfo2);
        }
        if (i>0&&j>0){
            System.out.println("The transfer was successful! !");
            return true;
        }else {
            //rollback transaction
            System.out.println("Transfer failed! !");
            throw new RuntimeException("Transfer failed exception");
        }
    }
}

4.2.4. Test code:

/*
 * @author Nical
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AspectJConfig.class)
public class AspectJTest {

    @Autowired
    ChangeMoney changeMoney;
    @Test
    public void Test1(){
        changeMoney.giveMoney(1,2,300);
    }
}

5. Summary:

  • In the above methods: the point-cut of programmatic transactions is obvious and troublesome. It is necessary to splicing transaction-related code in the business code. The code reusability is poor, and it is very time-consuming. The declarative transaction solves the problem of code coupling, but at the same time, it is necessary to write The corresponding code, and the annotation transaction perfectly solves the above problems. At the same time, AspectJ and JAVA annotations can completely eliminate the need to write Xml files, which are also recommended. When you use them, pay attention to the distinction.

  • The database objects and mapper files in this article are generated by reverse engineering. If you have any questions, please refer to https://editor.csdn.net/md?articleId=111378661

  • Welcome friends to leave a message, comment, and discuss related issues together. The blogger will reply to you as soon as possible.

Tags: Java Database Mybatis Spring AOP Dynamic Proxy spring-aop

Posted by irkevin on Sat, 30 Apr 2022 15:40:21 +0300