spring declarative transaction management

Keywords: Database Spring

spring implements transaction management

Transaction is an important part of enterprise application oriented to relational database (RDBMS), which is used to ensure the integrity and consistency of data.

  • ACID attribute of the transaction

Atomicity: a transaction is an inseparable unit of work, and the actions included in the transaction are either done or not done.
Consistency: transactions must ensure that the database changes from one consistency state to another. Consistency and atomicity are closely related.
Isolation: the execution of a transaction cannot be disturbed by other transactions, that is, the operations and data used within a transaction are isolated from other concurrent transactions, and the concurrent transactions cannot disturb each other.
Durability: persistence, also known as permanence, means that once a transaction is committed, its changes to the data in the database are permanent, and other subsequent operations and failures should not have any impact on it.

  • Propagation property of spring transaction propagation

REQUIRED:
Use the current transaction. If there is no transaction, create a new transaction. The sub method must run in a transaction; If there is a transaction, join the transaction as a whole.
For example: if the leader has no food, I have money, I will buy it myself and eat it myself; If some leaders eat, they will share it with you.
SUPPORTS:
If there is a transaction currently, the transaction is used; If there are currently no transactions, no transactions are used.
For example: the leader has no food, and I have no food; Leaders have food, so do I.
MANDATORY:
The propagation property enforces the existence of a transaction. If it does not exist, an exception is thrown
For example: the leader must take care of food. No matter whether there is no food, I don't like it and quit (throw an exception)
REQUIRES_NEW:
If there is a current transaction, suspend the transaction and create a new transaction for your own use; If there is no current transaction, the same as REQUIRED
For example: leaders have food, but I don't want it. I bought it myself and ate it myself
NOT_SUPPORTED:
If there is a transaction, suspend the transaction and run the database operation without the transaction
For example: leaders have food to eat. I'll give you some. I'm too busy. Put it aside and I won't eat
NEVER:
Throw an exception if a transaction currently exists
For example: the leader has food for you. I don't want to eat. I love work. I throw exceptions
NESTED:
If there is a transaction currently, open the sub transaction (nested transaction), and the nested transaction is committed or rolled back independently; If there is no current transaction, the same as REQUIRED. However, if the primary transaction is committed, it will be committed with the secondary transaction. If the primary transaction is rolled back, the child transactions are rolled back together. Conversely, if the child transaction is abnormal, the parent transaction can be rolled back or not.
For example: the leader makes a wrong decision, the boss blames, and the leader suffers with his little brother. If the younger brother makes a mistake, the leader can shirk the responsibility.

  • Transaction isolation level in spring

Isolation default this is the default transaction isolation level of the platform transaction manager. The default transaction isolation level of the database is used / the other four correspond to the transaction isolation level of JDBC
isolation-read_uncommitted
isolation-read_committed
isolation-repeatable-read
isolation-serializable

  • There are two ways of transaction management in Spring:

1) Traditional programmed transaction management, that is, transaction management realized by writing code;
2) Declarative transaction management based on AOP technology.

This paper uses declarative transaction management

  • What is it?

Implemented through AOP, its essence is to intercept before and after the method, then create or join a transaction before the start of the target method, and commit or roll back the transaction according to the execution after the target method is executed.

  • advantage?

There is no need to manage transactions through programming. Business logic code and transaction management code can be well separated.

  • There are two main ways of declarative transaction management:

Declarative transaction management based on XML.
Transaction management through Annotation.

The following describes how to implement declarative transaction management through XML

  • pom dependency
 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.3.5</version>
        </dependency>
        <!--Spring Thing dependence -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.3.5</version>
        </dependency>
  • Spring XML 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:context="http://www.springframework.org/schema/context" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- Turn on scan annotation -->
    <context:component-scan base-package="com.ljw"></context:component-scan>
    <!-- Introduce external properties file -->
    <context:property-placeholder location="classpath:druid.properties"></context:property-placeholder>
    <!-- adopt druid Get data source from connection pool -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--Database driven -->
        <property name="driverClassName" value="${driver}"></property>
        <!--Connecting to the database url -->
        <property name="url" value="${url}"></property>
        <!--User name to connect to the database -->
        <property name="username" value="${user}"></property>
        <!--Password to connect to the database -->
        <property name="password" value="${pwd}"></property>
    </bean>
    <!-- to configure JDBC Template,use JdbcTemplate class -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--By default, you must use the data source to reference the above data source-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- Configure transaction manager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- Write notification: to enhance the transaction (notification), you need to write entry points and details of the specific execution of the transaction -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!-- Add transaction details to pointcut methods, name Represents the method name,*Represents any method name,
            propagation Used to set propagation behavior, read-only Indicates the isolation level. Is it read-only -->
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
        </tx:attributes>
    </tx:advice>
    <!-- aop Write, let Spring Automatically generate proxy for target, need to use AspectJ Expression for -->
    <aop:config proxy-target-class="true">
        <!-- Entry point, execution Defined expression representation com.ljw.service.impl All classes and methods under the package apply the transaction -->
        <aop:pointcut id="point" expression="execution(* com.ljw.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"></aop:advisor>
    </aop:config>
  • bean class
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Goods {
    private Integer goodId;
    private Integer typeId;
    private String goodName;
    private Integer goodNum;
    private Float goodPrice;


    public Goods(Integer typeId, String goodName, Integer goodNum, Float goodPrice) {
        this.typeId = typeId;
        this.goodName = goodName;
        this.goodNum = goodNum;
        this.goodPrice = goodPrice;
    }
  • dao layer implementation
@Controller
public class GoodsDaoImpl implements GoodsDao {
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Override
    public List<Goods> findAll() {
        String sql = "select * from goods";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Goods.class));
    }

    @Override
    public Integer save(Goods goods) {
        String sql = "INSERT INTO goods VALUES(NULL,?,?,?,?)";
        return jdbcTemplate.update(sql,goods.getTypeId(),goods.getGoodName(),goods.getGoodNum(),goods.getGoodPrice());
    }


    @Override
    public Integer update(Goods goods) {
        String sql = "UPDATE goods SET type_id=?,good_name=?,good_num=?,good_price=? WHERE good_id=?";
        return jdbcTemplate.update(sql,goods.getTypeId(),goods.getGoodName(),goods.getGoodNum(),goods.getGoodPrice(),goods.getGoodId());
    }

    @Override
    public Integer delete(Integer id) {
        String sql = "delete from goods where good_id = ?";
        return jdbcTemplate.update(sql,id);
    }
}

  • service layer implementation
@Service
public class GoodsServiceImpl implements GoodsService {
    @Autowired
    GoodsDao goodsDao;
    @Override
    public List<Goods> findAll() {
        return goodsDao.findAll();
    }

    @Override
    public Integer saveAndUpdate(Goods goods,Goods goods2) {
        Integer rows = goodsDao.save(goods);
        Integer rows2 = goodsDao.update(goods2);
        return rows + rows;
    }


    @Override
    public Integer delete(Integer id) {
        return goodsDao.delete(id);
    }

}

  • test
@Test
    public void save() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        GoodsService goodsService = context.getBean("goodsServiceImpl", GoodsServiceImpl.class);
        //Added objects
        Goods goods = new Goods(3, "test88", 2, 2f);
        //Modified object
        Goods goods2 = new Goods(1, 9, "test", 2, 2f);
        int rows = goodsService.saveAndUpdate(goods, goods2);
        System.out.println(rows);
    }

The added and modified methods must be successful at the same time, otherwise the transaction is rolled back

Implementation of declarative transaction management by annotation

  • spring – xml file
 <!-- Configure transaction manager -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- Add transaction by annotation -->
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"></tx:annotation-driven>
  • Only annotate @ Transactional in the service layer implementation
@Transactional
public class GoodsServiceImpl implements GoodsService {
	//towork
}

Posted by Naez on Thu, 16 Sep 2021 11:51:19 -0700