Spring Transaction learning II. Spring Transaction management

Posted by basil on Sun, 27 Feb 2022 02:40:32 +0100

Spring Transaction learning II. Spring Transaction management

Record the learning of Spring and database things. The learning of Spring things here is in the form of full annotation

Mind map:

1. Configure transaction manager

In the configuration of Spring annotation starting things, if you want to enable things, you need to configure the thing manager. Just as different databases need different drivers, there are also many kinds of transaction managers in Spring. DataSourceTransactionManager is the transaction manager used by JDBC operation database

First introduce the Jar package of Spring things:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.12</version>
</dependency>

Register the transaction manager as a bean and submit it to the Spring container for management:

/**
  * Configure database data source
  */
@Bean
@Primary//The function of this annotation is that if an interface has multiple implementation classes, the implementation class marked with @ Primary has a higher level and takes precedence
public DataSource druidDataSource(){
    DruidDataSource druidDataSource = new DruidDataSource();
    druidDataSource.setUrl(url);
    druidDataSource.setUsername(userName);
    druidDataSource.setPassword(password);
    return druidDataSource;
}

/**
  * Add Spring transaction support
  */
@Bean
public DataSourceTransactionManager jdbcTransactionManager(DataSource dataSource){
    //The transaction manager is related to the data source
    DataSourceTransactionManager jdbcTransactionManager = new DataSourceTransactionManager();
    jdbcTransactionManager.setDataSource(dataSource);
    return jdbcTransactionManager;
}

There are many transaction managers, among which Mybatis enables the JDBC transaction manager, and other framework transaction managers include:

It can be seen from the inheritance tree of DataSourceTransactionManager that it implements the PlatformTransactionManager interface, which represents the platform related transaction manager. In Spring, TransactionManager is an empty interface, and the top-level interface of the transaction manager is PlatformTransactionManager

Inheritance tree:

The PlatformTransactionManager interface defines three methods in total,

TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;//Gets the transaction, which also sets the data properties
void commit(TransactionStatus status) throws TransactionException;//Commit transaction
void rollback(TransactionStatus status) throws TransactionException;//Rollback transaction

Through these three methods, we can ensure the atomicity of Spring when operating the database

If you want to test Spring things, we can have a simple chestnut. Here is to set the insertion check of fields in the database, because mysql8 constraint constraints are not supported in versions below 0.15, so the sql script here is Oracle script. Mysql8. Constraints can be used for above 0.15

create table account
(
   accountid int primary key ,
   balance   numeric(10,2)
);
--  Time and date type  date
create table oprecord
(
   id int primary key ,
   accountid int,
   opmoney numeric(10,2),
   optime date
);

alter table oprecord 
  add constraint fk_oprecord_accountid
     foreign key(accountid) references account(accountid);
     
alter table account
   add constraint ck_account_balance
   check(balance>=0);
 -- Generate primary key with sequence  
 create sequence seq_account;
 create sequence seq_oprecord;
   
 insert into account(accountid,balance) values(seq_account.nextval,100);
 insert into account(accountid,balance) values(seq_account.nextval,1000);
 
 -- oracle Work on Constraints,  Throw exception ->  mybatis  (dao Annotation of layer  @Repository-> take exception Conversion exception RuntimeException )  -> biz   
 --   ->  spring Do business management -> spring Affairs management meeting bu Exception caught (  RuntimeException work ) -> Transactions can be completed automatically rollback()
 insert into account(accountid,balance) values(seq_account.nextval,-10);
 
 commit;


select * from account;
select * from oprecord;

Then we insert an illegal piece of data into the constrained table:

public Integer openAccount(double money) {
        String sql = "insert into account values(default,?)";
        KeyHolder keyHolder = new GeneratedKeyHolder();
        jdbcTemplate.update(connection -> {
            PreparedStatement psmt = connection.prepareStatement(sql, new String[]{"accountid"});
            psmt.setString(1,String.valueOf(money));
            return psmt;
        },keyHolder);
        //To return the account number of the user after opening an account
        return Objects.requireNonNull(keyHolder.getKey()).intValue();
}

@Test
public void testOpen() throws Exception {
    Account open = accountBiz.open(-10.0);
    System.out.println(open);
}

Then an error will be reported:

org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [update account set balance = ? where accountid = ?]; SQL state [HY000]; error code [3819]; Check constraint 'account_chk_1' is violated.; nested exception is java.sql.SQLException: Check constraint 'account_chk_1' is violated.

Looking at the error message, you can see that it throws an Exception org springframework. jdbc. Uncategorized sqlexception. By viewing its inheritance structure, you can find that this Exception actually inherits from RuntimeException. In the following section of the error message, it is written that this Exception is nested with a nested exception. In fact, after adding the @ Repository annotation in Spring, the Exception will be packaged as a RuntimeException and thrown. The advantage of this is that there is no need to catch too many try catch es in the business code, After the transaction is enabled, the transaction can catch exceptions and roll back data (the transaction can only catch RuntimeException exceptions)

When we check the database, we can find that even if an exception is thrown, Spring will still submit the data without enabling things

2. Enable things

After configuring the class transaction manager, you need to add the @ EnableTransactionManagement annotation in the configuration class to indicate that the transaction is enabled, and then enable the transaction through the @ Transactional annotation in the corresponding Service layer. There are many configurations in the @ Transactional annotation, as follows:

The meanings and default values of these configurations are respectively (transaction manager is a transaction manager added for itself. Mybatis is based on JDBC and can configure DataSourceTransactionManager)

Add the annotation @ transactional (transactionmanager = "JDBC transactionmanager") in the business layer to enable things. If you test again, you will find that after the database throws an exception, Spring will roll back the data so that illegal data cannot be submitted

3. Default configuration of @ Transactional annotation

@Transactional annotations also have some default configurations, corresponding to the characteristics of things in the database:

You can see the function and default attributes of each configuration in detail in the comments of the source code. There are seven levels of Propagation, namely:

Topics: Java Spring