When we want a set of operations to succeed or fail, we tend to consider using transactions to achieve this; the db operation described earlier, mainly on a single-table CURD, focuses on the use of declarative transactions@Transactional s
<!-- more -->
I. Configuration
This article mainly introduces the usage posture of jdbcTemplate with Transaction Note @Transactional. As for JPA, mybatis does not make much difference in actual usage, which will be explained separately later
Create a SpringBoot project, version 2.2.1.RELEASE, use mysql as the target database, store engine select Innodb, transaction isolation level RR
1. Project Configuration
In the project pom.xml file, plus spring-boot-starter-jdbc, a DataSourceTransactionManager bean is injected, providing transaction support
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency>
2. Database Configuration
Go to the spring configuration file application.properties to set up db-related information
## DataSource spring.datasource.url=jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false spring.datasource.username=root spring.datasource.password=
3. Database
Create a new simple table structure for testing
CREATE TABLE `money` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL DEFAULT '' COMMENT 'User name', `money` int(26) NOT NULL DEFAULT '0' COMMENT 'money', `is_deleted` tinyint(1) NOT NULL DEFAULT '0', `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time', `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Update Time', PRIMARY KEY (`id`), KEY `name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;
II. Instructions for use
1. Initialization
In order to reflect the characteristics of transactions, deleting or modifications is an indispensable statement in DML regardless of DDL scenarios, so we need to initialize several data for testing first
@Service public class SimpleDemo { @Autowired private JdbcTemplate jdbcTemplate; @PostConstruct public void init() { String sql = "replace into money (id, name, money) values (120, 'Initialization', 200)," + "(130, 'Initialization', 200)," + "(140, 'Initialization', 200)," + "(150, 'Initialization', 200)"; jdbcTemplate.execute(sql); } }
We use the replace into statement to initialize the data, which is executed after each bean creation, to ensure that the initial data is the same for each subsequent action you take
2. transactional
This annotation can be placed either on a class or on a method; if it is labeled on a class, all public methods of the class support transactions;
If both classes and methods exist, then the annotations on the methods have configuration to override the annotations on the classes
Here is a simple transaction test case
private boolean updateName(int id) { String sql = "update money set `name`='To update' where id=" + id; jdbcTemplate.execute(sql); return true; } public void query(String tag, int id) { String sql = "select * from money where id=" + id; Map map = jdbcTemplate.queryForMap(sql); System.out.println(tag + " >>>> " + map); } private boolean updateMoney(int id) { String sql = "update money set `money`= `money` + 10 where id=" + id; jdbcTemplate.execute(sql); return false; } /** * Run exception causes rollback * * @return */ @Transactional public boolean testRuntimeExceptionTrans(int id) { if (this.updateName(id)) { this.query("after updateMoney name", id); if (this.updateMoney(id)) { return true; } } throw new RuntimeException("Update failed, rollback!"); }
Add the comment @Transactional to the public method where we need to open the transaction, indicating that if the method's internal execution throws a run exception, a transaction rollback will occur
Note the above statement that the transaction will not take effect until the correct call posture is taken; in other words, it will not take effect in some case s
3. Testing
Next, to test whether the above method transaction is valid, we create a new Bean
@Component public class TransactionalSample { @Autowired private SimpleDemo simpleService; public void testSimpleCase() { System.out.println("============ Transaction is working start ========== "); simpleService.query("transaction before", 130); try { // Transactions can work simpleService.testRuntimeExceptionTrans(130); } catch (Exception e) { } simpleService.query("transaction end", 130); System.out.println("============ Transaction is working end ========== \n"); } }
In the call above, the data before and after modification are printed, and if the transaction is working correctly, the two outputs should be identical
The actual output is as follows, verifying that the transaction is valid, and the intermediate operation to modify the name is rolled back
============ Transaction is working start ========== transaction before >>>> {id=130, name=Initialization, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:21.0} after updateMoney name >>>> {id=130, name=To update, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:22.0} transaction end >>>> {id=130, name=Initialization, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:21.0} ============ Transaction is working end ==========
4. Notes
a. Scenarios applicable
When using annotated @Transactional declarative transactions, it mainly uses AOP to encapsulate the logic of the transaction through a proxy, so the scenario where AOP does not take effect also applies to scenarios where the transaction annotation does not take effect
Simply put, the following case s do not work
- Decoration @Transactional on private method, not valid
- Internal call, not valid
- Examples are: an external call to the generic method m of service A, which calls the method m2 in this class that declares a transaction annotated, in which case the transaction does not take effect
b. Exception types
In addition, the comment @Transactional default only works for runtime exceptions, such as the following case s, which throw exceptions but do not work
@Transactional public boolean testNormalException(int id) throws Exception { if (this.updateName(id)) { this.query("after updateMoney name", id); if (this.updateMoney(id)) { return true; } } throw new Exception("Declare Exceptions"); }
If you need it to take effect, you can use the rollbackFor property to specify the type of exception that triggers the rollback
@Transactional(rollbackFor = Exception.class) public boolean testSpecialException(int id) throws Exception { if (this.updateName(id)) { this.query("after updateMoney name", id); if (this.updateMoney(id)) { return true; } } throw new IllegalArgumentException("Parameter Exception"); }
Test the two case s above
public void testSimpleCase() { System.out.println("============ Transaction is not valid start ========== "); simpleService.query("transaction before", 140); try { // Because a non-operational exception was thrown, it will not be rolled back simpleService.testNormalException(140); } catch (Exception e) { } simpleService.query("transaction end", 140); System.out.println("============ Transaction is not valid end ========== \n"); System.out.println("============ Transaction Effective start ========== "); simpleService.query("transaction before", 150); try { // In the comment, specify that all exceptions are rolled back simpleService.testSpecialException(150); } catch (Exception e) { } simpleService.query("transaction end", 150); System.out.println("============ Transaction Effective end ========== \n"); }
The output is as follows, which just validates what was mentioned above
============ Transaction is not valid start ========== transaction before >>>> {id=140, name=Initialization, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:21.0} after updateMoney name >>>> {id=140, name=To update, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:22.0} transaction end >>>> {id=140, name=To update, money=210, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:22.0} ============ Transaction is not valid end ========== ============ Transaction Effective start ========== transaction before >>>> {id=150, name=Initialization, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:21.0} after updateMoney name >>>> {id=150, name=To update, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:22.0} transaction end >>>> {id=150, name=Initialization, money=200, is_deleted=false, create_at=2020-01-19 16:15:21.0, update_at=2020-01-19 16:15:21.0} ============ Transaction Effective end ==========
c. @Transactional Attribute information for annotations
The above is a basic point of knowledge to meet our general business needs, if you need to be advanced, it is necessary to understand the attribute information
The following comes from: [A thorough understanding of Spring @transactional Use] ( https://www.cnblogs.com/xd502djj/p/10940627.html "A thorough grasp of Spring @transactional Use ")
Property Name | Explain |
---|---|
name | When there are multiple TransactionManager s in the configuration file, you can use this property to specify which Transaction Manager to select. |
propagation | The propagation behavior of the transaction, defaulting to REQUIRED. |
isolation | Transaction isolation with DEFAULT as the default. |
timeout | Transaction timeout, default value is -1.If the time limit is exceeded but the transaction has not been completed, the transaction is rolled back automatically. |
read-only | Specifies whether the transaction is read-only and the default value is false; to ignore methods that do not require transactions, such as reading data, you can set read-only to true. |
rollback-for | Used to specify exception types that trigger transaction rollback, and can be separated by commas if more than one exception type needs to be specified. |
no-rollback- for | Throws the exception type specified by no-rollback-for and does not roll back the transaction. |
Please look forward to explaining the use of the above attributes and the circumstances under which declarative transactions will not take effect and new openings will be made.
II. Other
0.Series Blog & Source
Series Blog
- Basic Use of DB in 180926-SpringBoot Advanced Text
- 190407-SpringBoot Advanced JdbcTemplate Data Insertion Use Posture Details
- 190412-SpringBoot Advanced JdbcTemplate Data Query Previous
- 190417-SpringBoot Advanced JdbcTemplate Data Query Next
- Data Update and Delete of 190418-SpringBoot Advanced JdbcTemplate
Source code
- Project: https://github.com/liuyueyi/spring-boot-demo
- Instance source: https://github.com/liuyueyi/spring-boot-demo/blob/master/spring-boot/101-jdbctemplate-transaction
1.A grey Blog
Unlike letters, the above are purely family statements. Due to limited personal abilities, there are unavoidable omissions and errors. If bug s are found or there are better suggestions, you are welcome to criticize and correct them with gratitude.
Below is a grey personal blog, which records all the blogs in study and work. Welcome to visit it
- A Grey Blog Personal Blog https://blog.hhui.top
- A Grey Blog-Spring Thematic Blog http://spring.hhui.top