Spring -- declarative transaction

Posted by ready2drum on Thu, 23 Dec 2021 22:37:06 +0100

Spring - declarative transactions

Our journey is the sea of stars, not the dust of the world

Declarative transaction

Review transactions

  • Transaction is very important in the project development process. It involves the problem of data consistency, which should not be careless!
  • Transaction management is a necessary technology in enterprise application development to ensure data integrity and consistency.

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

Transaction four attribute ACID

  1. atomicity

    • A transaction is an atomic operation, which consists of a series of actions. The atomicity of a transaction ensures that the actions either complete or fail to work at all
  2. consistency

    • Once all transaction actions are completed, the transaction is 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. Persistence

    • 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

test

Copy the above code into a new project

In the previous case, we added two methods to the UserMapper interface, delete and add users;

//Add a user
int addUser(User user);

//Delete user by id
int deleteUser(int id);

mapper file, we deliberately write delete wrong, test!

<insert id="addUser" parameterType="User">
insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
</insert>

<delete id="deleteUser" parameterType="int">
deletes from user where id = #{id}
</delete>

Write the implementation class of the interface. In the implementation class, we operate a wave

public class UserDaoImpl extends SqlSessionDaoSupport implements UserMapper {

   //Add some operations
   public List<User> selectUser() {
       User user = new User(12,"Xiao Ming","123456");
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       mapper.addUser(user);
       mapper.deleteUser(12);
       return mapper.selectUser();
  }

   //newly added
   public int addUser(User user) {
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       return mapper.addUser(user);
  }
   //delete
   public int deleteUser(int id) {
       UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
       return mapper.deleteUser(id);
  }

}

test

import com.qifei.mapper.UserMapper;
import com.qifei.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTranscationTest {
    public static void main(String[] args) {
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application.xml");
        UserMapper userMapperImpl = classPathXmlApplicationContext.getBean("userMapperImpl", UserMapper.class);
        for (User user : userMapperImpl.selectUser()) {
            System.out.println(user);
        }
    }
}

Error reporting: sql exception. delete is written incorrectly

Result: insertion succeeded!

No transaction management; We want them to succeed only when they succeed. If there is a failure, they will all fail. We should need affairs!

In the past, we all needed to manage affairs manually, which was very troublesome!

However, Spring provides us with transaction management, and we only need to configure it;

Transaction management in Spring

Spring defines an abstraction layer on top of different transaction management APIs, so that developers can use spring's transaction management mechanism without understanding the underlying transaction management API. Spring supports programmatic transaction management and declarative transaction management.

Programming transaction management

  • Embed transaction management code into business methods to control transaction commit and rollback
  • Disadvantages: additional transaction management code must be included in each transaction operation business logic

Declarative transaction management

  • Generally, it works better than programmatic transactions.
  • The transaction management code is separated from the business method to realize the transaction management in a declarative way.
  • Transaction management is regarded as a crosscutting concern and modularized through aop method. Spring supports declarative transaction management through the Spring AOP framework.

Using Spring to manage transactions, pay attention to the constraint import of header file: tx

<?xml version="1.0" encoding="UTF8"?>
<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">

Transaction manager

  • No matter which transaction management strategy (programmatic or declarative) Spring uses, the transaction manager is required.
  • Spring's core transaction management abstraction encapsulates a set of technology independent methods.

JDBC transaction

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
       <property name="dataSource" ref="dataSource" />
</bean>

After configuring the transaction manager, we need to configure the notification of transactions

<!--Configure transaction notifications-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
       <!--What methods are configured and what transactions are used,Configure propagation properties of transactions-->
       <tx:method name="add" propagation="REQUIRED"/>
       <tx:method name="delete" propagation="REQUIRED"/>
       <tx:method name="update" propagation="REQUIRED"/>
       <tx:method name="search*" propagation="REQUIRED"/>
       <tx:method name="get" read-only="true"/>
       <tx:method name="*" propagation="REQUIRED"/>
   </tx:attributes>
</tx:advice>

spring transaction propagation feature:

Transaction propagation behavior is how transactions propagate among multiple transaction methods when they call each other. spring supports seven transaction propagation behaviors:

  • propagation_ Requisited: if there is no transaction at present, create a new transaction. If there is already a transaction, join it. This is the most common choice.
  • propagation_supports: supports the current transaction. If there is no current transaction, it will be executed in a non transaction method.
  • propagation_mandatory: use the current transaction. If there is no current transaction, an exception will be thrown.
  • propagation_required_new: create a new transaction. If there is a current transaction, suspend the current transaction.
  • propagation_not_supported: perform operations in a non transactional manner. If there is a transaction, suspend the current transaction.
  • propagation_never: execute the operation in a non transactional manner. If the current transaction exists, an exception will be thrown.
  • propagation_nested: if a transaction currently exists, it is executed within a nested transaction. If there is no transaction at present, the and propagation are executed_ Required similar operations

The default transaction propagation behavior of Spring is PROPAGATION_REQUIRED, which is suitable for most situations.

Assuming that ServiveX#methodX() works in a transaction environment (that is, they are enhanced by Spring transactions), assuming that there is the following call chain in the program: service1 #method1 () - > service2 #method2 () - > service3 #method3 (), then the three methods of the three service classes work in the same transaction through the transaction propagation mechanism of Spring.

For example, the methods we just mentioned are called, so they will be placed in a group of transactions!

Configure AOP

Import aop header file!

<!--to configure aop Weaving transaction-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.qifei.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

Test

Delete the data just inserted and test again!

public class SpringTranscationTest {
    public static void main(String[] args) {
        ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("application.xml");
        UserMapper userMapperImpl = classPathXmlApplicationContext.getBean("userMapperImpl", UserMapper.class);
        for (User user : userMapperImpl.selectUser()) {
            System.out.println(user);
        }
    }
}

application.xml

<?xml version="1.0" encoding="UTF8"?>
<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">

    <import resource="springbeans.xml"/>

    <bean id="userMapperImpl" class="com.qifei.mapper.UserMapperImpl">
        <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>

    <!--to configure JDBC affair-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!--Configure transaction notifications-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--What methods are configured and what transactions are used,Configure propagation properties of transactions-->
            <tx:method name="add" propagation="REQUIRED"/>
            <tx:method name="delete" propagation="REQUIRED"/>
            <tx:method name="update" propagation="REQUIRED"/>
            <tx:method name="search*" propagation="REQUIRED"/>
            <tx:method name="get" read-only="true"/>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!--to configure aop Weaving transaction-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.qifei.mapper.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

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.qifei.pojo"/>
    </typeAliases>

</configuration>

springbeans.xml

<?xml version="1.0" encoding="UTF8"?>
<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">

    <!--DataSource:Replace with data source Mybatis Configuration of
    We use data sources: org.springframework.jdbc.datasource.DriverManagerDataSource-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8"/>
        <property name="username" value="root"/>
        <property name="password" value="111111"/>
    </bean>

    <!--to configure sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
        <property name="mapperLocations" value="classpath:com/qifei/mapper/*.xml"/>
    </bean>

</beans>

Topics: Java MySQL Mybatis Spring