Transaction management for Springboot

Source: Internet
Author: User
Tags sql error

Transaction management in Spring bootOriginal2016-05-27SuphingSpring Bootbe watched 29,955 times What is a transaction?

When we develop an enterprise application, one operation for the business person is actually a combination of multi-step operation to read and write data. Because the data operation in the sequential execution of the process, any one step operation can be an exception, the exception will cause subsequent operations can not be completed, because the business logic is not completed correctly, before the successful operation of the data is not reliable, you need to fallback in this case.

The purpose of a transaction is to ensure that every operation of the user is reliable, and that every step of the transaction must be executed successfully, as long as there is an exception to the state in which the transaction begins to operate.

Transaction management is one of the most common features of the spring framework, and in most cases we need to use transactions when we develop our applications using spring boot.

Quick Start

In spring boot, when we use SPRING-BOOT-STARTER-JDBC or SPRING-BOOT-STARTER-DATA-JPA dependencies, The framework automatically injects Datasourcetransactionmanager or Jpatransactionmanager, respectively, by default. So we don't need any extra configuration to use @transactional annotations for transactions.

We use common sense for the basic engineering of the chapter3-2-2 as an example of using SPRING-DATA-JPA to access the database.

In this sample project (if the data access method is not known, you can read the article first), we introduced the SPRING-DATA-JPA, and created the user entity and the user's data access object Userrepository, The unit test cases for data reading and writing using Userrepository are implemented in the Applicationtest class as follows:

123456789101112131415161718192021222324252627 @RunWith (Springjunit4classrunner.class)@SpringApplicationConfiguration (Application.class)public class applicationtests { @Autowiredprivate userrepository userrepository;@Testpublic void Test() throws Exception { //Create 10 RecordsUserrepository.save (New User ("AAA", Ten)); Userrepository.save (New User ("BBB", + )); Userrepository.save (New User ("CCC", +) ); Userrepository.save (New User ("DDD", +) ); Userrepository.save (New User ("EEE", ( )); Userrepository.save (New User ("FFF") ; Userrepository.save (New User ("GGG", + )); Userrepository.save (New User ("HHH") ; Userrepository.save (New User ("III", +) ); Userrepository.save (New User ("JJJ", +) ); //Omit some subsequent validation actions}  }

As you can see, in this unit test case, using the Userrepository object to create a continuous 10 user entities into the database, let's artificially make some exceptions and see what happens.

By defining the Name property of the user, the length of the user is 5, so that an exception can be triggered by creating a long Name property on the object.

12345678910111213141516 @Entity public class User { @Id@GeneratedValueprivate Long Id; @Column (nullable = false, length = 5)  private String name; @Column (nullable = false)  private Integer age; //Omit constructors, getter, and setter }

Modify the statement that created the record in the test case to have a record name longer than 5, as follows: The user object named Hhhhhhhhh will throw an exception.

123456789101112 //Create 10 RecordsUserrepository.save (New User ("AAA", Ten)); Userrepository.save (New User ("BBB", + )); Userrepository.save (New User ("CCC", +) ); Userrepository.save (New User ("DDD", +) ); Userrepository.save (New User ("EEE", ( )); Userrepository.save (New User ("FFF") ; Userrepository.save (New User ("GGG", + )); Userrepository.save (New User ("hhhhhhhhhh") ; Userrepository.save (New User ("III", +) ); Userrepository.save (New User ("JJJ", +) );

Executing the test case, you can see that the console throws the following exception, the Name field is very long:

123456 2016-05-27 10:30:35.948 WARN 2660---[main ] O.h.engine.jdbc.spi.sqlexceptionhelper:sql error:1406, sqlstate:220012016-05-27 10:30:35.948 Error 2660---[main] O.h.engine.jdbc.spi.sqlexceptionhelper:data truncation:data too long for column 2016-05-27 10:30:35.951 WARN 2660---[main] O.h.engine.jdbc.spi.sqlexceptionhelper:sql Warning code:1406, sqlstate:hy0002016-05-27 10:30:35.951 WARN 2660---[ma In] o.h.engine.jdbc.spi.sqlexceptionhelper:data too long for column ' name ' at row 1  org.springframework.dao.dataintegrityviolationexception:could not execute statement; SQL [n/a]; Nested exception is org.hibernate.exception.DataException:could not execute statement

In the database, a record of name from AAA to GGG is created, with no records for Hhhhhhhhhh, III, JJJ. And if this is a case where you want to guarantee integrity, the AAA to GGG Record wants to be rolled back at the time of the exception, so it's very simple to use a transaction to get it back, and we just need to add annotations to the test function @Transactional .

1234567 @Test @Transactional public void Test() throws Exception { //Omit testing contents }

To execute the test case again, you can see that the rollback log is output in the console (rolled back transaction for test context),

1234567 2016-05-27 10:35:32.210 WARN 5672---[main] o.h.engine.jdbc.spi.sqlexceptionhelper:sql error:1406, sqlstate:22001201 6-05-27 10:35:32.210 ERROR 5672---[main] o.h.engine.jdbc.spi.sqlexceptionhelper:data truncation:data too longFor column ' name ' at row 1 2016-05-27 10:35:32.213 WARN 5672---[main] o.h.engine.jdbc.spi.sqlexceptionhelper:sql Warning code:1406, sqlstate:h y0002016-05-27 10:35:32.213 WARN 5672---[main] o.h.engine.jdbc.spi.sqlexceptionhelper:data too longFor column ' name ' at row 1 2016-05-27 10:35:32.221 INFO 5672---[main] o.s.t.c.transaction.transactioncontext:rolled back transactionForTest context [[email protected]TestClass = Applicationtests,testinstance = [email protected], testmethod = [email protected], testexception = Org.springframework.dao.DataIntegrityViolationException:could not execute statement; SQL [n/a]; Nested exception is org.hibernate.exception.DataException:could not execute statement, mergedcontextconfiguration = [[ Email protected] testclass = applicationtests, locations = ' {} ', Classes = ' {class com.didispace.Application} ', contextinitializerclasses = ' {} ', propertysourcelocations = ' {} ', propertysourceproperties = ' Org.springframework.boot.test.SpringApplicationContextLoader ', parent = [NULL]]. Org.springframework.dao.DataIntegrityViolationException:could not execute statement; SQL [n/a]; Nested exception is org.hibernate.exception.DataException:could not execute statement

Looking at the database, the user table will not have AAA to GGG users data, the successful implementation of automatic rollback.

This is mainly done through unit tests that demonstrate how to use @Transactional annotations to declare a function to be managed by a transaction, usually in order to ensure that the data between each test is independent, the annotations are used @Rollback so that each unit test can be rolled back at the end. When it comes to developing business logic, we typically use the service layer interface @Transactional to configure the transaction management of each business logic, such as:

1234567 public Interface userservice { @TransactionalUser login(String Name, String password); }
Detailed Business

In the example above we used the default transaction configuration to meet some basic transaction requirements, but when our project is more complex (for example, there are multiple data sources, etc.), we need to specify a different transaction manager when declaring a transaction. The transaction management configuration for different data sources can be found in the settings in Spring boot multi-data source configuration and use. When declaring a transaction, you only need to specify the configured transaction manager name through the Value property, for example: @Transactional(value="transactionManagerPrimary") .

In addition to specifying a different transaction manager, you can also control the isolation level and propagation behavior of transactions, which are explained in detail below:

# # # Isolation LEVEL

Isolation level refers to the degree of isolation between several concurrent transactions, including dirty reads, repeated reads, and Phantom reads, which are primarily relevant to our development time.

We can see that the org.springframework.transaction.annotation.Isolation enumeration class defines five values that represent the isolation level:

1234567 public enum Isolation {DEFAULT (-1),read_uncommitted (1),read_committed (2), Repeatable_read (4),SERIALIZABLE (8);}
    • DEFAULT: This is the default value, which indicates the default isolation level for using the underlying database. For most databases, this is usually the value: READ_COMMITTED .
    • READ_UNCOMMITTED: This isolation level indicates that one transaction can read data that has been modified by another transaction but has not yet been committed. This level does not prevent dirty reads and non-repeatable reads, so this isolation level is rarely used.
    • READ_COMMITTED: This isolation level indicates that a transaction can only read data that has been committed by another transaction. This level prevents dirty reads, which is the recommended value in most cases.
    • REPEATABLE_READ: This isolation level indicates that a transaction can repeatedly execute a query multiple times throughout the process, and that each returned record is the same. These new records are ignored even if there are new data that satisfies the query between multiple queries. This level protects against dirty reads and non-repeatable reads.
    • SERIALIZABLE: All transactions are executed one after the other, so that there is absolutely no possibility of interference between transactions, that is, this level prevents dirty reads, non-repeatable reads, and Phantom reads. However, this will severely affect the performance of the program. This level is not normally used.

Specify method: By using isolation property settings, for example:

1 @Transactional (isolation = isolation.default)
Propagation behavior

The so-called transaction propagation behavior is that if a transaction context already exists before the current transaction is started, there are several options to specify the execution behavior of a transactional method.

We can see that the org.springframework.transaction.annotation.Propagation enumeration class defines 6 enumeration values that represent propagation behavior:

123456789 public enum propagation {REQUIRED (0),SUPPORTS (1), MANDATORY (2), Requires_new (3),not_supported (4),never (5),NESTED (6);
    • REQUIRED: If a transaction is currently present, the transaction is joined and a new transaction is created if there is no current transaction.
    • SUPPORTS: If a transaction is currently present, the transaction is joined, and if there is no transaction, it will continue to run in a non-transactional manner.
    • MANDATORY: If a transaction is currently present, the transaction is joined and an exception is thrown if there is no current transaction.
    • REQUIRES_NEW: Creates a new transaction and suspends the current transaction if a transaction is currently present.
    • NOT_SUPPORTED: Runs in a non-transactional manner, suspending the current transaction if a transaction is currently present.
    • NEVER: Runs in a non-transactional manner and throws an exception if a transaction is currently present.
    • NESTED: Creates a transaction to run as a nested transaction for the current transaction if there is currently a transaction, which is equivalent to if there is no current transaction REQUIRED .

Specify method: By using propagation property settings, for example:

1 @Transactional (propagation = propagation.required)

Complete Example Chapter3-3-1

Transaction management for Springboot

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.