Enterprise Distribution Micro Service Cloud Springcloud springboot MyBatis (17) transaction management in Spring boot

Source: Internet
Author: User
Tags sql error

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:

@RunWith (Springjunit4classrunner.class) @SpringApplicationConfiguration (application.class) public class applicationtests {@Autowiredprivate userrepository userrepository; @Testpublic void Test () throws Exception {// Create 10 records Userrepository.save (New User ("AAA")), Userrepository.save (New User ("BBB")), Userrepository.save (new User ("CCC"), Userrepository.save ("DDD", +), Userrepository.save ("EEE", 50)); Userrepository.save (New User ("FFF")), Userrepository.save (New User ("GGG"), Userrepository.save ("HHH"); Userrepository.save ("III"), Userrepository.save (New User ("JJJ", 100));//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.

@Entitypublic class User {    @Id    @GeneratedValue    private 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.

Create 10 records Userrepository.save (New User ("AAA")), Userrepository.save (New User ("BBB")), Userrepository.save (new User ("CCC"), Userrepository.save ("DDD", +), Userrepository.save ("EEE", 50)); 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", 100));

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

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 ' name ' at row 12016-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---[           main] O.h . Engine.jdbc.spi.SqlExceptionHelper   : Data too long for column ' name ' at row 1org.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 .

@Test @transactionalpublic 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),

2016-05-27 10:35:32.210 WARN 5672---[main] o.h.engine.jdbc.spi.sqlexceptionhelper:sql error:1406, SQLSt ate:220012016-05-27 10:35:32.210 ERROR 5672---[main] o.h.engine.jdbc.spi.sqlexceptionhelper:data Truncat Ion:data too long for column ' name ' at row 12016-05-27 10:35:32.213 WARN 5672---[main] o.h.engine.jdbc.spi. Sqlexceptionhelper:sql Warning code:1406, sqlstate:hy0002016-05-27 10:35:32.213 WARN 5672---[main] o.h           . Engine.jdbc.spi.SqlExceptionHelper:Data too long for column ' name ' at row 12016-05-27 10:35:32.221 INFO 5672---[  Main] o.s.t.c.transaction.transactioncontext:rolled back transaction for test 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 = ' [] ', ACTI Veprofiles = ' {} ', propertysourcelocations = ' {} ', propertysourceproperties = ' {} ', Contextloader = ' org.springframework. Boot.test.SpringApplicationContextLoader ', parent = [NULL]].

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:

Public interface UserService {        @Transactional    User 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:

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:

@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:

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:

@Transactional (propagation = propagation.required)

  

Source Source

Enterprise Distribution Micro Service Cloud Springcloud springboot MyBatis (17) transaction management in Spring boot

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.