Declarative transaction

What is a transaction?

Transaction is to treat a series of actions as an independent unit of work, which are either completed or ineffective.

Attribute ACID of transaction:

1. Atomicity: a transaction is an atomic operation consisting of a series of actions. The atomicity of a transaction ensures that the actions are either completed or ineffective

2. consistency: once all transaction actions are completed, the transaction will be committed. Data and resources are in a consistent state that meets business rules

3. isolation: multiple transactions may process the same data at the same time, so each transaction should be isolated from other transactions to prevent data corruption

4. durability: once the transaction is completed, no matter what error occurs in the system, the result will not be affected. Typically, the result of a transaction is written to persistent storage

Case:

In the IDEA project, in order to more clearly show the advantages of declarative transactions, the case is divided into two parts. First, show the situation without configuring declarative transactions, and then show the situation after configuring declarative transactions:

Declarative transaction not configured:

UserMapper.java

import com.hui.pojo.User;
import java.util.List;

public interface UserMapper {
    public List<User> selectUser();

    public int insertUser(User user);

    public int deleteUser(int id);
}

UserMapper.xml (note that the deletes in the delete tag here is wrong, and pay attention to the final running result)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hui.mapper.UserMapper">
    <select id="selectUser" resultType="User">
        select * from mybatis.users;
    </select>
    <insert id="insertUser" parameterType="User">
        insert into mybatis.users values(#{id},#{name},#{age})
    </insert>
    <delete id="deleteUser" parameterType="int">
        deletes from mybatis.users where id=#{id}
    </delete>
</mapper>

UserMapperImpl.java (pay attention to the selectUser method, insert first, then delete, and then query)

import com.hui.pojo.User;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import java.util.List;

public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper {
    @Override
    public List<User> selectUser() {
        User user=new User(6,"petty thief",456);
        UserMapper mapper=getSqlSession().getMapper(UserMapper.class);
        mapper.insertUser(user);
        System.out.println("delete");
        mapper.deleteUser(5);
        return mapper.selectUser();
    }

    @Override
    public int insertUser(User user) {
        System.out.println("insert");
        return getSqlSession().getMapper(UserMapper.class).insertUser(user);
    }

    @Override
    public int deleteUser(int id) {
        return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
    }
}

User.java

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private int age;
    public User(){}
    public User(int id,String name,int age){
        this.id=id;
        this.name=name;
        this.age=age;
    }
}

mybatis-config.xml

<?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">
<configuration>
    <typeAliases>
        <package name="com.hui.pojo"/>
    </typeAliases>
</configuration>

spring-dao.xml

<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">
    <!--Focus on connection processing with database-->
    <!--DataSource: use spring Data source replacement for Mybatis Configuration of c3p0  dbcp  druid(Use here spring Provided JDBC)   This module was originally mybatis Configuration in configuration file-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
    </bean>

    <!--to configure sqlSessionFactory,relation MyBatis,So is this one mybatis Connection database to write-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <!--binding MyBatis configuration file-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/><!--Associated mybatis Configuration file for-->
        <property name="mapperLocations" value="classpath:com/hui/mapper/UserMapper.xml"/><!--Register the mapper. This step was also in mybatis In the total configuration file, the last<mappers>-->
    </bean>

    <!--SqlSessionTemplate: Replace the original sqlSession,It is used because it is thread safe-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--Only constructor injection can be used sqlSessionFactory,Because it doesn't set method(Focus on source code)-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    
</beans>

applicationContext.xml (general 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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="spring-dao.xml"/>
    <bean id="userMapper" class="com.hui.mapper.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

Test class
MyTest.java

import com.hui.mapper.UserMapper;
import com.hui.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserMapper mapper=context.getBean("userMapper",UserMapper.class);
        List<User> users=mapper.selectUser();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

Operation results:

Detailed error information:
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'deletes from mybatis.users where id=5' at line 1

Database result: the insertion is still successful!!!

The submitted data is inconsistent with the real results. Introducing declarative transactions -- >

Configure declarative transactions:
I manually deleted the data that was successfully inserted into the database just now. Only modify spring Dao Content in XML.

spring-dao.xml

<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">
    <!--Focus on connection processing with database-->
    <!--DataSource: use spring Data source replacement for Mybatis Configuration of c3p0  dbcp  druid(Use here spring Provided JDBC)   This module was originally mybatis Configuration in configuration file-->
    <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="password" value="123456"/>
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
    </bean>

    <!--to configure sqlSessionFactory,relation MyBatis,So is this one mybatis Connection database to write-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="datasource"/>
        <!--binding MyBatis configuration file-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/><!--Associated mybatis Configuration file for-->
        <property name="mapperLocations" value="classpath:com/hui/mapper/UserMapper.xml"/><!--Register the mapper. This step was also in mybatis In the total configuration file, the last<mappers>-->
    </bean>

    <!--SqlSessionTemplate: Replace the original sqlSession,It is used because it is thread safe-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <!--Only constructor injection can be used sqlSessionFactory,Because it doesn't set method(Focus on source code)-->
        <constructor-arg index="0" ref="sqlSessionFactory"/>
    </bean>

    <!--Configure declarative transactions-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        <constructor-arg ref="datasource"/>-->
        <property name="dataSource" ref="datasource"/>
    </bean>

    <!--combination AOP Implement transaction placement-->
    <!--Configure transaction Notifications:-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--Set which methods to configure transactions for name=" "-->
        <!--Configure the propagation characteristics of transactions: new -->
        <tx:attributes>
<!--            <tx:method name="selectUser" read-only="true"/>-->
<!--            <tx:method name="insertUser" propagation="REQUIRED"/>-->
<!--            <tx:method name="deleteUser" propagation="REQUIRED"/>-->
            <tx:method name="*" propagation="REQUIRED"/><!--Generally, all methods need to deal with transactions-->
        </tx:attributes>
    </tx:advice>

    <!--Configure transaction entry-->
    <aop:config>
        <!--breakthrough point-->
        <aop:pointcut id="txPointCut" expression="execution(* com.hui.mapper.*.*(..))"/>
        <!--Cut into something-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
</beans>

Operation results:

Error details:
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'deletes from mybatis.users where id=5' at line 1

Database result: failed to insert information. There is no record with id=6

This is the advantage of declarative transaction, which can ensure the consistency of data.
Set usermapper After changing the delete in XML to delete, it can run normally.

Correct operation results:

Console:

Database:

The record with id=5 was also deleted successfully.

Keywords: Java Mybatis Spring

Added by amandas on Sat, 19 Feb 2022 12:43:32 +0200