1 knowledge review
1.1 transaction characteristics
https://blog.csdn.net/Mr_YanMingXin/article/details/118857302
1.2 isolation level
https://blog.csdn.net/Mr_YanMingXin/article/details/118857302
1.3 dirty reading, unreal reading and non repeatable reading
https://blog.csdn.net/Mr_YanMingXin/article/details/118857302
2 two ways spring uses transactions
2.1 programmatic transactions
Using TransactionalTemplate
@Autowired private UserDAO userDAO; @Autowired private TransactionTemplate transactionTemplate; @Override public void insertUser(User user) { transactionTemplate.execute(new TransactionCallback<Object>() { //Exceptions do not need to be handled, otherwise they will not be rolled back @Override public Object doInTransaction(TransactionStatus status) { userDAO.insertUser(user); return status; } }); }
2.3 declarative transactions
Use @ Transactional annotation
@Transactional(rollbackFor = Exception.class) @Override public int updateUserById(User user) throws Exception { int res = userDAO.updateUserById(user); return res; }
2.4 communication mechanism of affairs
Configuration: @ Transactional(propagation = Propagation.xxx)
public enum Propagation { /** * Support the current transaction. If it does not exist, create a new transaction (Spring's default transaction propagation mechanism) */ REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED), /** * Supports the current transaction. If it does not exist, it will be executed in a non transaction manner */ SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS), /** * Support the current transaction, and throw an exception if it does not exist */ MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY), /** * Create a new transaction. If there is a current transaction, suspend the current transaction */ REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), /** * Execute in a non transactional manner. If there is a current transaction, suspend the current transaction */ NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), /** * Execute in a non - transactional manner, and throw an exception if there is a transaction */ NEVER(TransactionDefinition.PROPAGATION_NEVER), /** * If there is a current transaction, it is executed in a nested transaction. Otherwise, the behavior is like {@ code REQUIRED} */ NESTED(TransactionDefinition.PROPAGATION_NESTED); ... }
- REQUIRED: the default propagation mechanism can meet most business requirements. If there are transactions in the outer layer, the current transaction will be added to the outer layer transaction, one committed and one rolled back. If there is no transaction in the outer layer, create a new transaction to execute.
- REQUES_NEW: the transaction propagation mechanism is to open a new transaction every time and suspend the outer transaction. When the current transaction is completed, the execution of the upper transaction is resumed. If there is no transaction in the outer layer, execute the newly opened transaction.
- SUPPORT: if there is a transaction in the outer layer, the outer layer transaction is added. If there is no transaction in the outer layer, the non transaction method is directly used. Completely dependent on external transactions.
- NOT_SUPPORT: this propagation mechanism does not support transactions. If there is a transaction in the outer layer, it will be suspended. After executing the current code, the outer layer transaction will be restored. No matter whether it is abnormal or not, the current code will not be rolled back.
- NEVER: this propagation mechanism does not support outer transactions, that is, if there are transactions in the outer layer, an exception will be thrown.
- MANDATORY: Contrary to NEVER, an exception is thrown if there is no transaction in the outer layer.
- NESTED: the feature of this propagation mechanism is that it can save state savepoints and roll back the current transaction to a certain point, so as to avoid all NESTED transactions rolling back, that is, rolling back their own. If the sub transaction does not eat the exceptions, it will basically cause all rollback.
2.5 isolation level of transactions
Configuration: @ Transactional(isolation = Isolation.xxx)
ISOLATION_DEFAULT | Use the default isolation level of the back-end database |
---|---|
ISOLATION_READ_UNCOMMITTED | Allow reading of uncommitted changes. It may cause dirty reading, unreal reading or non repeatable reading. |
ISOLATION_READ_COMMITTED | (Oracle default level) allows reading from committed concurrent transactions. Dirty reading can be prevented, but phantom reading and non repeatable reading may still occur. |
ISOLATION_REPEATABLE_READ | (MYSQL default level) the results of multiple reads of the same field are consistent unless the data is changed by the current transaction itself. It can prevent dirty reading and non repeatable reading, but phantom reading can still occur. |
ISOLATION_SERIALIZABLE | Completely obey the isolation level of ACID to ensure that dirty reads, unrepeatable reads and phantom reads do not occur. This is also the slowest of all isolation levels, because it is usually done by completely locking the data table involved in the current transaction. |
2.6 Spring transaction rollback (declarative example)
Configuration: @ Transactional(rollbackFor = Exception.class)
Meaning: the transaction rollback mechanism will be triggered when the exception class specified by rollback for or its derived class occurs
2.6.1 Java exception class inheritance system (part)
By default, the transaction management of the Spring framework only rolls back transactions when uncontrolled exceptions (RuntimeException and Error) occur.
2.6.1 transaction rollback experiment
(1) Using the default configuration, throw a ClassNotFound exception to see whether to roll back
@Transactional @Override public int updateUserById(User user) throws Exception { int res = userDAO.updateUserById(user); throw new ClassNotFoundException(); }
Test:
@Test void contextLoads() { System.out.println("before update "+userService.selectUserById(1)); try { userService.updateUserById(new User(1L, "aaa", "aaa")); } catch (Exception e) { System.err.println("---------Catch exception---------"); System.out.println("after update "+userService.selectUserById(1)); } }
result:
(2) Configure it as exception.class, throw ClassNotFound exception, and check whether to roll back
@Transactional(rollbackFor = Exception.class) @Override public int updateUserById(User user) throws Exception { int res = userDAO.updateUserById(user); throw new ClassNotFoundException(); }
Test:
@Test void contextLoads() { System.out.println("before update "+userService.selectUserById(1)); try { userService.updateUserById(new User(1L, "bbb", "bbb")); } catch (Exception e) { System.err.println("---------Catch exception---------"); System.out.println("after update "+userService.selectUserById(1)); } }
result:
(3) Using the default configuration, throw a NullPointException exception to see whether to roll back
@Transactional @Override public int updateUserById(User user) throws Exception { int res = userDAO.updateUserById(user); throw new NullPointerException(); }
Test:
@Test void contextLoads() { System.out.println("before update "+userService.selectUserById(1)); try { userService.updateUserById(new User(1L, "ccc", "ccc")); } catch (Exception e) { System.err.println("---------Catch exception---------"); System.out.println("after update "+userService.selectUserById(1)); } }
result:
3 bottom layer principle
3.1 general
Spring transaction belongs to the AOP category, which is to conduct transaction processing through the operation of proxy objects on the database, and the underlying layer of spring transaction also needs the support of the database.
Let's debug:
It can be seen that after the transaction is declared, the IOC will use cglib to perform AOP dynamic proxy during initialization, transforming userDAO into a proxy object to operate the transaction
Click enter to see that instead of directly calling the relevant methods of UserDAO, you enter the CglibAopProxy class to proxy the called object
Continue to debug down until an exception occurs
When transaction related information appears, this step is called transaction cleanup
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) { if (txInfo != null) { // Restore previous state txInfo.restoreThreadLocalStatus(); } }
3.2 transaction flow
From this, we can summarize the execution process of Spring transactions