Spring thing problem, in a method, you need to update the data of a table and use the latest data, how should you write things annotations?

spring transaction problem, in a method, you need to update the data of a table and use the latest data. How should you write annotations using things?

Aug.17,2021

//ApropagationREQUIRED
public void A(){

 //B,BpropagationREQUIRES_NEW
 B();
 //C,CpropagationREQUIRES_NEW
 C();
}

this should be a problem with the isolation level of database transactions. The default isolation level of the database is repeatable , which means that the operation within the transaction is visible in this transaction, but before committing, the operation does not affect other things, and other things cannot see the operation. The four isolation levels of
database are demonstrated below with mysql database:

create table test (id int not null,name vachar(20),primary key(id));
insert into test (1,'AA');
insert into test (2,'BB');
insert into test (3,'CC');
insert into test (4,'DD');
insert into test (5,'EE');
  • READ UNCOMMITTED uncommitted reads, changes in transactions, even if they are not committed, are visible to other transactions, and the update operation of transaction 1 is visible when transaction 2 is not committed. Under this isolation level, there may be dirty reading, unrepeatable reading, phantom reading, and so on.
//1
//
select @@tx_isolation;
//
set session transaction isolation level READ UNCOMMITTED;
//
set autocommit = off;
//
begin;
// test
select * from test;
// 
update test set name = 'AAAAA' where id = 1;
//test
//
select * from test;
//,
rollback;
  • READ COMMITTED (committed read / non-repeatable read): any changes made by the transaction from the beginning to the commit are not visible to other transactions.

or the above example, the update operation of thing 1 is invisible to thing 2 before it is submitted, and can only be seen after it is submitted. Under this isolation level, there may be unrepeatable readings, phantom readings, and so on.

  • REPEATABLE READ (repeatable): the result of reading the same record multiple times in the same transaction is consistent, and the MySQL default isolation level. There may be phantom reading at this level of isolation.
  • SERIALIZABLE (serialization): transactions are executed serially, read and write locked.

the above four isolation levels reflect the degree of interaction between things. But in the same thing, its update operations are visible to itself. It doesn't exist in the same thing, it's updated above, but it can't be seen below. Unless you are using the propagation characteristics of spring things, you open another thing in the thing, so that in two things, the update of one thing and the other thing cannot be seen.

add:
I wrote an example with SpringBoot . Under the influence of transaction propagation attribute and isolation level, the previous update may occur, but you can't see it later. Here is the code. Pay attention to the comments.
SpringBoot pom.xml the file adds the following dependencies:

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- Use MySQL Connector-J -->

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

main class:

@EnableAutoConfiguration
@ComponentScan
public class SpringBootApplication {
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(SpringBootApplication.class);
        Map<String, Object> defaultMap = new HashMap<String, Object>();
        //
        defaultMap.put("spring.datasource.driverClassName", "com.mysql.jdbc.Driver");
        defaultMap.put("spring.datasource.url", "jdbc:mysql://192.168.1.105:3306/sakila?useUnicode=true&characterEncoding=utf-8");
        defaultMap.put("spring.datasource.username", "root");
        defaultMap.put("spring.datasource.password", "root");
        application.setDefaultProperties(defaultMap);
        ApplicationContext context = application.run(args);

        //1
        SpringTransaction_1 transaction = context.getBean("springTransaction_1", SpringTransaction_1.class);
        transaction.transaction_1();

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            System.out.println("JVM.....");
        }));
    }
}

thing 1:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Service
public class SpringTransaction_1 {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    SpringTransaction_2 springTransaction_2;

    /**
     * 
     *
     * :transaction_1transaction_2transaction_2
     * AOP
     */
    @Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.REPEATABLE_READ)
    public void transaction_1(){
        List<Map<String,Object>> list = jdbcTemplate.queryForList("select * from test");
        System.out.println("initial view in transaction_1");
        list.forEach(System.out::println);
        springTransaction_2.transaction_2();
        list = jdbcTemplate.queryForList("select * from test");
        System.out.println("view in transaction_1 after transaction_2");
        list.forEach(System.out::println);
    }

}

thing 2:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

@Service
public class SpringTransaction_2 {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * @Transactional REQUIREDTransaction1
     * REPEATABLE_READ,transaction_1
     *
     * REQUIRES_NEWREPEATABLE_READ,
     * transaction_1
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW,isolation = Isolation.REPEATABLE_READ)
    public void transaction_2(){
        List<Map<String,Object>> list = jdbcTemplate.queryForList("select * from test");
        System.out.println("initial view in transaction_2");
        list.forEach(System.out::println);
        System.out.println("update record in transaction_2");
        System.out.println("update test set name = 'AB' where id = 1");
        jdbcTemplate.update("update test set name = 'AB' where id = 1");
        System.out.println("view in transaction_2 after update");
        list = jdbcTemplate.queryForList("select * from test");
        list.forEach(System.out::println);
    }
}

output:

transaction_1 begin
initial view in transaction_1
{id=1, name=AB}
transaction_2 begin
initial view in transaction_2
{id=1, name=AB}
update record in transaction_2
update test set name = 'AAAS' where id = 1
view in transaction_2 after update
{id=1, name=AAAS}
transaction_2 end
view in transaction_1 after transaction_2
//transaction_2transaction_1 transaction_1
{id=1, name=AB}
transaction_1 end

the complete code is placed in github

Menu