reference resources
https://blog.csdn.net/hepei120/article/details/78058468
https://blog.csdn.net/yangquanwa/article/details/88578357
1, @ Transactional failed
@There are many scenarios for Transactional failure. There are many articles under the research of interest. This paper focuses on the scenario of calling Spring transaction annotation @ Transactional failure inside the class.
Phenomenon 1
There is no doubt that the latest data can be queried after updating in a transaction.
code
@Autowired private TestMapper testMapper; @Transactional public void testTransactional() { System.out.println("1.====:" + testMapper.selectById(1).toString()); updateTestById("Sima cylinder 5"); System.out.println("2.====:" + testMapper.selectById(1).toString()); } public void updateTestById(String name) { TestEntity entity = new TestEntity(); entity.setId(1); entity.setName(name); testMapper.updateById(entity); }
Execute testTransactional()
output
Phenomenon 2
Update in a transaction, and add the transaction propagation behavior propagation.requirements in the query method_ New means that a new transaction is enabled regardless of whether the transaction exists or not.
code
@Autowired private TestMapper testMapper; @Transactional public void testTransactional() { System.out.println("1.====:" + testMapper.selectById(1).toString()); updateTestById("Sima cylinder 5"); System.out.println("2.====:" + get().toString()); } public void updateTestById(String name) { TestEntity entity = new TestEntity(); entity.setId(1); entity.setName(name); testMapper.updateById(entity); } @Transactional(propagation = Propagation.REQUIRES_NEW) public TestEntity get() { return testMapper.selectById(1); }
Execute testTransactional()
output
analysis
Transaction isolation level
The transaction isolation levels from weak to strong are: READ_UNCOMMITTED(Uncommitted read),READ_COMMITTED(Submit (read) REPEATABLE_READ(Repeat) and SERIALIZABLE(Serial read).
Data problem
-
Dirty read:
Dirty read refers to a transaction that allows reading data that has not been committed by other running transactions. This happens mainly because it is not locked. -
Non repeatable:
It refers to reading the same data multiple times in a transaction. When this transaction is not finished, another transaction also accesses the same data. Then, between the two data reads in the first transaction, the data read in the first transaction may be different due to the modification of the second transaction. In this way, the data read twice in a transaction is different, so it is called non repeatable reading. (i.e. the same data content cannot be read)
For example, an editor reads the same document twice, but between reads, the author rewrites the document. When the editor reads the document the second time, the document has changed. The original read is not repeatable. This problem can be avoided if editors can read the document only after the author has completed writing.
To allow repeatable reads, the current transaction must maintain a read shared lock. -
Unreal reading:
Phantom read refers to A phenomenon that occurs when A transaction does not occur serially. It is that transaction A reads the new data submitted by transaction B. For example, the first transaction modifies all data in A table, while the second transaction inserts A new data into the table. Then the user who operates the first transaction will find that there are no modified data rows in the table, just like an illusion. The solution to unreal reading is to add range lock or table lock.
Problems with different isolation levels
Segregated sector | Dirty reading | Non repeatable reading | Unreal reading |
---|---|---|---|
READ_UNCOMMITTED | allow | allow | allow |
READ_COMMITTED | Not allowed | allow | allow |
REPEATABLE_READ | Not allowed | Not allowed | allow |
SERIALIZABLE | Not allowed | Not allowed | not allow |
The default transaction isolation level of MySQL is REPEATABLE_READ. The default transaction isolation level for ORACLE, SQL Server, DB2, and PostgreSQL is READ_COMMITED
According to the default transaction isolation level of MySQL, repeatable_ Normally, read should not have dirty reads, that is, it should not read data not committed by other transactions, but now it is read. WHY???
Continue to look at phenomenon 3
Phenomenon 3
Update in a transaction, and add the transaction propagation behavior propagation.requirements in the query method_ New means that a new transaction is enabled regardless of whether the transaction exists or not.
code
@Service public class TestServiceImpl extends ServiceImpl<TestMapper, TestEntity> implements ITestService { @Autowired private TestMapper testMapper; @Autowired private TestServiceImpl2 testServiceImpl2; @Transactional public void testTransactional() { System.out.println("1.====:" + testMapper.selectById(1).toString()); updateTestById("Sima cylinder 5"); System.out.println("2.====:" + testServiceImpl2.get().toString()); } public void updateTestById(String name) { TestEntity entity = new TestEntity(); entity.setId(1); entity.setName(name); testMapper.updateById(entity); } } @Service public class TestServiceImpl2 extends ServiceImpl<TestMapper, TestEntity> implements ITestService { @Autowired private TestMapper testMapper; @Transactional(propagation = Propagation.REQUIRES_NEW) public TestEntity get() { return testMapper.selectById(1); } }
Execute testTransactional()
output
analysis
Do you see any difference between the code of phenomenon 2 and phenomenon 3? Different from calling get(), 2 is this.get(), 3 is testServiceImpl2.get(), and 3 extracts the get() method.
Why is @ transactional (propagation = propagation. Requirements_new) in 2 invalid?
reason
Spring transactions are implemented based on AOP, that is to proxy the class identified by @ Transactional, create the proxy class when creating the object, and add transaction processing before and after executing the method in the proxy class, which is equivalent to @ Around. When we execute a method that requires a transaction, it is executed by the called proxy class. However, other transaction methods of this class are called inside the method through this.get(), and the target class is obtained instead of the proxy class, so the propagation.requirements of the get() method_ New is invalid and does not create a new transaction or execute in a transaction.
conclusion
Transactions are based on proxy classes