Talk about how to program and implement transaction management in Spring

Keywords: Spring JDBC SQL log4j

Spring provides the template class org. spring framework. transaction. support. Transaction Template for programmable transaction management, which can meet the needs of some special occasions.

Transaction Template is thread-safe, so you can share Transaction Template instances in multiple classes to achieve transaction management.

Transaction Template inherits DefaultTransaction Definition, so it also has a variety of ways to set transaction attributes:

The main methods of the TransactionTemplate class are:

Method Explain
public void setTransactionManager(PlatformTransactionManager transactionManager) Set up the transaction manager.
public <T> T execute(TransactionCallback<T> action) In the Transaction Callback callback interface, write data access logic code that needs to be executed transactionally.

The Transaction Callback interface defines only one method, doInTransaction (Transaction Status). Spring also defines an abstract class, TransactionCallback WithoutResult, for scenarios where only execution is required but no results are returned.

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

    <!-- Scanning class packages containing annotation definitions-->
    <context:component-scan base-package="net.deniro.xxx.transaction"/>

    <!-- data source-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
          destroy-method="close"
          p:driverClassName="com.mysql.jdbc.Driver"
          p:url="jdbc:mysql://127.0.0.1:3306/xxx"
          p:username="root"
          p:password="xxx"/>

    <!-- JDBC Template-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
          p:dataSource-ref="dataSource"
            />

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

    <!-- Transaction template -->
    <bean id="TransactionTemplate"
          class="org.springframework.transaction.support.TransactionTemplate"
          p:transactionManager-ref="transactionManager"/>

</beans>

Class User:

public class User {
    private long id;
    private String name;

    public User(String name) {
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }


}

UserDao class:

@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;


    /**
     * Save account number
     *
     * @param user
     * @throws SQLException
     */
    public void save(User user) {
        String sql = "insert into t_user(user_name) values(?)";
        jdbcTemplate.update(sql, user.getName());

        String sql2 = "insert into t_log(user_name) values(?)";
        jdbcTemplate.update(sql2, user.getName());
    }

}

In order to test whether the transaction is valid, the first SQL here is correct, and the second SQL is wrong (the table cannot be found).

UserService class:

@Service
public class UserService {

    @Autowired
    private UserDao userDao;


    @Autowired
    private TransactionTemplate template;


    public void save(final User user) {
        template.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                userDao.save(user);
            }
        });
    }
}

Unit testing:

public class UserServiceTest {

    ApplicationContext context;

    @BeforeMethod
    public void setUp() throws Exception {
        context = new ClassPathXmlApplicationContext("spring.xml");
    }

    @Test
    public void test() {
        UserService userService = (UserService) context.getBean("userService");
        final User user = new User("deniro");
        userService.save(user);
    }
}

To see Spring's transaction log, we can modify the log4j transaction configuration to DEBUG:

log4j.logger.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
log4j.logger.org.springframework.transaction.interceptor=DEBUG
log4j.logger.org.springframework.transaction=DEBUG

Operation result analysis:

Spring first creates a new transaction.

When the second SQL statement is executed, an exception is thrown; Spring performs a rollback operation. Explain that the transaction is valid. O()~

Posted by umer on Sat, 06 Apr 2019 18:57:30 -0700