Transactional Transactional in SpringBoot series
When we want a set of operations that will either all succeed or all fail, we tend to consider transactions to do this; Before the introduction of the db operation, mainly lies in the single table CURD, this article will mainly introduce the use of declarative transaction @ Transactional position
I. the configuration
Mybatis uses JPA as a Transactional annotation. Mybatis uses jdbcTemplate as a Transactional annotation. Mybatis uses JPA as a Transactional annotation
Create a SpringBoot project with version 2.2.1.RELEASE, use mysql as the target database, select Innodb as the storage engine, and set transaction isolation level to RR
1. Project configuration
In pom project. The XML file, plus the spring – the boot – starter – JDBC, will inject a DataSourceTransactionManager bean, provides 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>
Copy the code
2. Configure the database
Go to the Spring configuration file application.properties and set up db related information
# # the DataSource spring. The DataSource. Url = JDBC: mysql: / / 127.0.0.1:3306 / story? useUnicode=true&characterEncoding=UTF-8&useSSL=false spring.datasource.username=root spring.datasource.password=Copy the code
3. The database
Create a simple table structure for testing
CREATE TABLE `money` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT ' ' COMMENT 'Username'.`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;
Copy the code
II. Instructions
1. Initialization
In order to reflect the characteristics of transactions, without considering DDL, add, delete or modify statements in DML are indispensable, so we need to initialize several data for testing
@Service
public class SimpleDemo {
@Autowired
private JdbcTemplate jdbcTemplate;
@PostConstruct
public void init(a) {
String sql = "Replace into money (id, name, money) values (120, 'initialize ', 200)," +
"(130, 'initialize ', 200) +
"(140, 'initialize ', 200)," +
"(150, 'initialize ', 200)"; jdbcTemplate.execute(sql); }}Copy the code
We use the Replace into statement to initialize the data, which is executed each time the bean is created, ensuring that the initial data is the same each time you perform subsequent operations
2. transactional
This annotation can be placed on a class or a method; If it’s annotated on a class, then all the public methods of that class support transactions;
Annotations on the method are configured to override annotations on the class if they exist on both classes and methods
Here is a simple transaction test case
private boolean updateName(int id) {
String sql = "Update money set 'name' =' 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;
}
/** * Rollback occurred due to an exception@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!");
}
Copy the code
Add the @Transactional annotation to the public method where we need to open the transaction to indicate that the method is properly called and that a transaction rollback occurs if a run exception is thrown from within the method
Note the above statement, the correct call posture, the transaction will take effect; In other words, in some cases, it doesn’t work
3. The test
Next, to test whether the method transaction above works, we create a new Bean
@Component
public class TransactionalSample {
@Autowired
private SimpleDemo simpleService;
public void testSimpleCase(a) {
System.out.println("============ transaction working fine start ==========");
simpleService.query("transaction before".130);
try {
// The transaction will work
simpleService.testRuntimeExceptionTrans(130);
} catch (Exception e) {
}
simpleService.query("transaction end".130);
System.out.println("============ transaction working end ========== \n"); }}Copy the code
In the above call, the data before the modification is printed and the data after the modification is printed, and if the transaction is working properly, the two outputs should be consistent
The actual output is as follows, verifying that the transaction is in effect and that the intermediate operation to change the name is rolled back
= = = = = = = = = = = = affairs work normally 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= updateMoney, 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} = = = = = = = = = = = = affairs work normally end = = = = = = = = = =Copy the code
4. Precautions
A. Application scenario
When using the @Transactional Transactional annotation, AOP is used to encapsulate the Transactional logic through proxies, so scenarios where AOP does not work are also applicable to scenarios where the Transactional annotation does not work
Briefly, in the following cases, annotations do not take effect
- Private method decorates
@Transactional
And don’t take effect - Internal call, not valid
- For example, an external call to the normal method M of service A calls the method M2 declared with transaction annotations in this class. Under normal circumstances, the transaction does not take effect
B. Exception type
In addition, the @Transactional annotation defaults only to runtime exceptions, such as the case below, which throws an exception but does not take effect
@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("Declaration exception");
}
Copy the code
If you want it to work, you can specify the type of exception that triggers the rollback using the rollbackFor property
@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("Abnormal parameter");
}
Copy the code
Test the two cases above
public void testSimpleCase(a) {
System.out.println("============ transaction not effective start ==========");
simpleService.query("transaction before".140);
try {
// Because it is a non-running exception, it will not be rolled back
simpleService.testNormalException(140);
} catch (Exception e) {
}
simpleService.query("transaction end".140);
System.out.println("============ transaction invalid end ========== \n");
System.out.println("============ transaction effective start ==========");
simpleService.query("transaction before".150);
try {
// Specify that all exceptions are rolled back in the annotation
simpleService.testSpecialException(150);
} catch (Exception e) {
}
simpleService.query("transaction end".150);
System.out.println("============ transaction effective end ========== \n");
}
Copy the code
The output is as follows, which validates what was proposed above
= = = = = = = = = = = = will not commence transaction 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= updateMoney, money=200, is_deleted=false, create_at=2020-01-19 16:15:22.0, update_at=2020-01-19 16:15:22.0} transaction end >>>> {id=140, name= update, money=210, is_deleted=false, create_at = 2020-01-19 16:15:21. 0, Update_at = 2020-01-19 16:15:22. 0} = = = = = = = = = = = = will not commence transaction 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= updateMoney, 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 = = = = = = = = = =Copy the code
Attribute information for the C.@Transactional annotation
The above contents are relatively basic knowledge points, enough to meet our general business needs. If you need to advance, it is necessary to understand the attribute information
Get a thorough understanding of the use of @Transactional in Spring
The property name | instructions |
---|---|
name | When you have multiple transactionmanagers in a configuration file, you can use this property to specify which TransactionManager to select. |
propagation | The propagation behavior of the transaction, which defaults to REQUIRED. |
isolation | The isolation degree of a transaction is DEFAULT. |
timeout | Timeout period for a transaction. Default value is -1. If the time limit is exceeded but the transaction has not completed, the transaction is automatically rolled back. |
read-only | Specifies whether the transaction is read-only. 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 | Specifies the type of exception that can trigger transaction rollback. If more than one exception type needs to be specified, separate the exception types by commas. |
no-rollback- for | Throw the exception type specified by no-rollback-for without rolling back the transaction. |
For more information on the use of the above attributes and the circumstances under which declarative transactions will not take effect, stay tuned.
II. The other
Series of blog posts & source code
Series of blog posts
- 180926- Basic use of SpringBoot advanced DB
- 190407-SpringBoot Advanced JdbcTemplate data insert position details
- 190412-SpringBoot Advanced JdbcTemplate data query first
- 190417-SpringBoot Advanced JdbcTemplate data query next
- 190418-SpringBoot Advanced JdbcTemplate data update and delete
The source code
- Project: github.com/liuyueyi/sp…
- Example source: github.com/liuyueyi/sp…
1. An ashy Blog
As far as the letter is not as good, the above content is purely one’s opinion, due to the limited personal ability, it is inevitable that there are omissions and mistakes, if you find bugs or have better suggestions, welcome criticism and correction, don’t hesitate to appreciate
Below a gray personal blog, record all the study and work of the blog, welcome everyone to go to stroll
- A grey Blog Personal Blog blog.hhui.top
- A Grey Blog-Spring feature Blog Spring.hhui.top