Spring Series Tutorial 8: Two ways Spring implements transactions

1. Spring Transaction Concepts:

Transactions are a series of actions that, when combined, are a complete unit of work. They must all be completed. If one fails, the transaction rolls back to its original state as if nothing had happened.

Transaction management is an essential technology for enterprise application development to ensure data integrity and consistency.(

Transactions have four characteristics: ACID

  • Atomicity: A transaction is an atomic operation consisting of a series of actions.The atomicity of the transaction ensures that the action is either complete or completely ineffective.

  • Consistency: Once a transaction completes, whether successful or failed, the system must ensure that the business it models is in a consistent state, not a partial completion failure.Data in reality should not be destroyed.

  • Isolation: There may be many transactions that process the same data at the same time, so each transaction should be isolated from other transactions to prevent data corruption.

  • Durability: Once a transaction is completed, no matter what system error occurs, its results should not be affected so that it can recover from any system crash.Typically, the results of a transaction are written to persistent storage.

Take a simple example: For example, Chen Duo transfers money to Chen Polysaccharide, but there are problems in the process of transferring money and problems in the banking system. Then Chen Duo transfers money to Chen Polysaccharide, but Chen Polysaccharide does not receive money?This is embarrassing

So how can I avoid it?Is this a problem?This is the time to use transaction management in our spring

2. Implementing Transaction Management by xml

Step 1, Guide the jar package

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- spring start -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-instrument</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>LATEST</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>LATEST</version>
        </dependency>
        <!-- spring end -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.15</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/aspectj/aspectjrt -->
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.5.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/aspectj/aspectjweaver -->
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.4</version>
        </dependency>


    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

Step 2, Create Mapper interfaces and entity classes

package com.bdqn.zmj.dao;

import com.bdqn.zmj.entity.user;

import java.util.List;

public interface UserMapper {

    List<user> GetList();

    //Outgoing
    void jian();

    //To change into
    void add();
}
package com.bdqn.zmj.entity;

public class user {
    int uid;
    String uname;
    int money;

    //Note that this corresponds to the UserId in the map file, not the uid in this class
    public int getUserId() {
        return uid;
    }

    public void setUserId(int uid) {
        this.uid = uid;
    }

    public String getUserName() {
        return uname;
    }

    public void setUserName(String uname) {
        this.uname = uname;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }
}

Step 3, Create a mybatis mapping file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bdqn.zmj.dao.UserMapper">

    <resultMap id="userMap" type="user">
        <id property="userId" column="uid" />
        <result property="userName" column="uname"/>
        <result property="money" column="money" />
    </resultMap>

    <select id="GetList" resultMap="userMap">
        select * from t_user
    </select>

    <update id="jian">
        update t_user set money = money-500 where uid =1
    </update>
    <update id="add">
        update t_user set money = money +500 where uid =2
    </update>
</mapper>

Step 4, Service Layer Code

package com.bdqn.zmj.service;

import com.bdqn.zmj.dao.UserMapper;
import com.bdqn.zmj.entity.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
/*
* Transactions are typically added to the service layer because the service calls dao
*   When servoce calls multiple dao methods, the transaction is handled as follows
*   Loading the controller layer: How transactions are handled when the controller calls multiple service methods
*
* */
@Service
public class UserService{
    @Autowired
    UserMapper dao;

    public List<user> GetList(){

        return dao.GetList();
    }
    @Transactional
    public void transfer() {
        dao.jian();
        int i = 10/0;
        dao.add();
    }
}

Step 5, ApplicationContext configuration file, mybatis mapping file, Log4J configuration file, database 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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <context:component-scan base-package="com.bdqn.zmj"/>
    <!--Injection Profile-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--Integration of two frameworks: almost all configurations are handed over springļ¼Œbecause spring Integrate specifically-->
    <!--1.data source-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driver}"/>
        <property name="jdbcUrl" value="${url}"/>
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
        <!--Other database connection pool configurations are omitted, such as: number of connections, maximum number of connections...-->
    </bean>

    <!--To configure sqlSessionFactiorBean-->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="mapperLocations" value="com/bdqn/zmj/mapper/*.xml"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--Configure interface scanning-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.bdqn.zmj.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"/>
    </bean>

    <!--Configure Transaction Manager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    //Configuring transaction propagation behavior is how transactions should be passed when a transactional method calls a method without a transaction
    <tx:advice id="txadvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="transfer" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--Configure Faces-->
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.bdqn.zmj..*.*(..))"/>
        <aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/>
    </aop:config>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--With this profile, complete mybatis Connection to database  -->
<configuration>

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <!-- Set Alias for Class -->
    <typeAliases>
        <!-- <typeAlias alias="User" type="com.wu.pojo.User"/> -->
        <!-- Aliases all classes under a package by class name -->
        <!-- This simplifies the amount of code -->
        <package name="com.bdqn.zmj.entity"/>
    </typeAliases>

</configuration>
log4j.rootLogger=info,CONSOLE
#############################################################
# Console Appender
#############################################################
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=info
##log4j.appender.CONSOLE.DatePattern=yyyy-MM-dd
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= %d{yyyy-M-d HH:mm:ss}%x[%5p] %m%n
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/fresh?serverTimezone=UTC
user=root
password=root

Step 6. Writing Test Classes

package com.bdqn.zmj.test;

import com.bdqn.zmj.entity.user;
import com.bdqn.zmj.service.UserService;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public class Testone {
    ApplicationContext context = null;

    @Before
    public void load(){
        context = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    @Test
     //Transaction, the following method has only two states, full execution and none execution
    public void test2(){
        UserService service = context.getBean("userService", UserService.class);
        service.transfer();
    }
}

The data in the database has not changed, operation failed, data rolled back!!!

2. Implementing Transaction Management by Annotation

Just change two places

First, service layer, method plus @Transactional

package com.bdqn.zmj.service;

import com.bdqn.zmj.dao.UserMapper;
import com.bdqn.zmj.entity.user;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
/*
* Transactions are typically added to the service layer because the service calls dao
*   When servoce calls multiple dao methods, the transaction is handled as follows
*   Loading the controller layer: How transactions are handled when the controller calls multiple service methods
*
* */
@Service
public class UserService{
    @Autowired
    UserMapper dao;

    public List<user> GetList(){

        return dao.GetList();
    }
    @Transactional
    public void transfer() {
        dao.jian();
        int i = 10/0;
        dao.add();
    }
}

Step 2, ApplicationContext.xml, leaves only the configuration transaction manager, followed by <tx:annotation-driven />scanning transactions

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

    <context:component-scan base-package="com.bdqn.zmj"/>
    <!--Injection Profile-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--Integration of two frameworks: almost all configurations are handed over springļ¼Œbecause spring Integrate specifically-->
    <!--1.data source-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${driver}"/>
        <property name="jdbcUrl" value="${url}"/>
        <property name="user" value="${user}"/>
        <property name="password" value="${password}"/>
        <!--Other database connection pool configurations are omitted, such as: number of connections, maximum number of connections...-->
    </bean>

    <!--To configure sqlSessionFactiorBean-->
    <bean id="sessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        <property name="mapperLocations" value="com/bdqn/zmj/mapper/*.xml"></property>
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--Configure interface scanning-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.bdqn.zmj.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sessionFactoryBean"/>
    </bean>

    <!--Configure Transaction Manager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--Configuring transaction propagation behavior is how transactions should be passed when a transactional method calls a method without a transaction-->
    <!--<tx:advice id="txadvice" transaction-manager="transactionManager">-->
        <!--<tx:attributes>-->
            <!--<tx:method name="transfer" propagation="REQUIRED"/>-->
        <!--</tx:attributes>-->
    <!--</tx:advice>-->

    <!--&lt;!&ndash;Configure Faces&ndash;&gt;-->
    <!--<aop:config>-->
        <!--<aop:pointcut id="pointcut" expression="execution(* com.bdqn.zmj..*.*(..))"/>-->
        <!--<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut"/>-->
    <!--</aop:config>-->
    <tx:annotation-driven />
</beans>

Both methods can achieve transaction configuration, but if we do not configure the details, we use annotations, xml for more detailed configuration, such as what bank transfers what

Keywords: Programming Spring Mybatis xml log4j

Added by freejellyfish on Sat, 25 May 2019 21:14:34 +0300