Abstract: When ordering take-out food, you only need to consider how to buy it. When choosing a trip, you just have to think about the destination; When paying by phone, you just need to make sure your balance is adequate. But what you don’t know is that this intelligence is backed up by billions of dollars of data, and that’s the power of databases. So behind the huge data will be involved in data security issues, then how to solve these accidents and conflicts?

This article is shared from huawei cloud community “How Spring uses” declarative transaction “to protect hundreds of millions of data security?

What is affair management?

Understanding declarative transactions starts with its basic concepts. So what is a transaction?

In the large-scale project development of JavaEE, it is necessary to ensure the integrity and consistency of data in the face of large scale data, so there is the concept of database transaction, so it is also an essential technology for enterprise project application development.

A transaction can be thought of as a set of database operations that are logically closely related and combined into a single entity (unit of work). All or none of these operations are performed.

At the same time transactions have four very critical properties (ACID) :

1. Atomicity: The meaning of “atom” is “indivisibility”. Atomicity refers to the fact that multiple operations involved in a transaction are logically indispensable. The atomicity of a transaction requires that all operations in a transaction either execute or none of them.

2. Consistency: Consistency refers to data consistency. Specifically, all data is in a consistent state that meets service rules. The consistency principle requires that no matter how many operations are involved in a transaction, the data must be correct before and after the transaction. If one or more operations fail during a transaction, all other operations must be undone to restore the data to the state before the transaction was executed. This is called rollback.

3. Isolation: During the actual operation of an application, transactions are usually executed concurrently, so it is likely that many transactions will process the same data at the same time. Therefore, each transaction should be isolated from other transactions to prevent data corruption. The principle of isolation requires that multiple transactions execute concurrently without interfering with each other.

Durability: Durability requires that modifications to data persist permanently after transactions complete, unaffected by system errors or other contingencies. Normally, changes made by transactions to data should be written to persistent storage.

Therefore, transaction control should satisfy these four attributes as much as possible. Since the purpose of transaction control is to be able to roll back transactions in the event of data processing accidents, what are the common types of errors and how should you handle them?

Second, the use of declarative transaction details

Declarative transactions have the advantage over programmatic transactions in that they separate transaction management code from business methods and implement business management in a declarative manner.

The fixed pattern of transaction management code, as a crosscutting concern, can be modularized through an AOP approach to declarative transaction management with the help of the Spring AOP framework.

Spring defines an abstraction layer on top of the different transaction management apis, which can be configured to enable application developers to use Spring’s transaction management mechanism without having to understand the underlying implementation details of the transaction management API.

Spring also supports both programmatic and declarative transaction management.

So how do you use declarative transactions in Spring?

1. Main implementation of transaction manager

Spring abstracts a whole set of transaction management mechanisms from different transaction management apis, making transaction management code independent of a particular transaction technology. In this way, we only need to configure transaction management without understanding the underlying implementation. This is one of the benefits of using declarative transactions.

The core of the Spring transaction management abstract is PlatformTransactionManager. It encapsulates a set of technology-independent methods for transaction management. Regardless of which of Spring’s transaction management strategies (programmatic or declarative) are used, a transaction manager is required.

The transaction manager can be declared in the Spring IOC container as a plain bean. The three transaction managers we use in Spring are:

DataSourceTransactionManager: in the application needs to handle only one data source, and through JDBC access.

2. JtaTransactionManager: Use JTA(Java TransactionAPI) for transaction management on JavaEE application server

3. HibernateTransactionManager: use Hibernate framework to access the database

They are all PlatformTransactionManager subclasses, inheritance diagram is as follows:

Now that we have a basic understanding of how declarative transactions work, let’s take a look at how to actually configure declarative transactions using Spring.

2. Annotation-based declarative transaction configuration

I DataSourceTransactionManager class as an example to tell everyone the implementation process of declarative transaction, friends can realize the operation, there is one problem remember message communication with me.

(1) Configure the data source

Since it is the operation of the database, then the first step must be to configure the data source, about the data source configuration I believe friends should be familiar with, is not familiar with friends can read my last article about Spring. Spring JDBC Persistence Layer framework “family bucket” tutorial

I used the example of importing an external data profile, so here I need to import an external file using the **** tag and assign a value to the property using “${}” :

The code is as follows:

<! - connect the external configuration file -- > < context: the property - placeholder location = "classpath: jdbcconfig. Properties" / > <! - connect to the database - > < bean id = "pooldataSource" class = "boPooledDataSource com.mchange.v2.c3p0.Com" > < property name = "user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl"  value="${jdbc.jdbcurl}"></property> <property name="driverClass" value="${jdbc.driverclass}"></property> </bean>Copy the code

Create JdbcTemplate

Since it is the operation of the database, and is in the Spring framework, then the use of the spring database operation framework must also be essential, about the jdbcTemplate framework technical point detailed use I also in the last article and we explained, friends can learn up!

Here we declare the jdbcTemplate class directly in the IOC bean and set the data source as the data source for the first step.

The code is as follows:

<! In order to build a jdbcTemplate - > < bean id = "jdbcTemplate" class = "org. Springframework. JDBC. Core. JdbcTemplate" > < property name="dataSource" ref="pooldataSource"></property> </bean>Copy the code

(3) Conduct transaction control

Now that the data source is configured and the database operations are complete, it’s time for today’s topic of transaction control

We know that transaction control itself is based on aspect programming to achieve, so when configuring transaction control, we need to import the corresponding JAR package:

  • Spring aop — 4.0.0. RELEASE. The jar

  • com.springsource.net.sf.cglib-2.2.0.jar

  • com.springsource.org.aopalliance-1.0.0.jar

  • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

Here’s a sidebar, or interview question: What are the advantages of using a transaction manager?

The use of transaction control can save the amount of code usually written for transaction control. When transaction control is carried out, if any error occurs during the execution of a transaction, other operations will not be modified and the atomicity of the transaction will be maintained.

Here we use DataSourceTransactionManager classes to configure transaction manager.

To do this, declare an instance of the class in the ioc bean tag, set the ID, and assign the DataSource attribute to the DataSource.

The code is as follows:

<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <! </ dataSource ="dataSource" ></ dataSource >Copy the code

The transaction manager has been configured. Next is the most important step! Turn the transaction manager on, because how do I use it if I don’t turn it on?

(4) Enable annotation-based transaction control

The main function of enabling annotation-based transaction control is to add annotations to methods and classes to enable automatic packet scanning. Enabling annotation-based transaction control requires the introduction of tx expressions, which use the annotation-driven tag to enable transaction control for the executing transaction manager.

The code is as follows:

<! - 3, open the annotation-based transaction control - > < tx: annotation - driven transaction - manager = "dataSourceTransactionManager" / > <! Add transaction control to the method and add corresponding annotations.Copy the code

The next step is to add annotations to the method to add transaction control

Classes that operate on the database first usually belong to the business logic layer, so we add the **@service annotation ** for that class to implement package scanning, and then the Transactional annotation **@Transactional for methods that require Transactional control to tell Spring that the method is Transactional. When an operation in this method fails, all other operations on the database in this method are rolled back. 台湾国

The code is as follows:

@Service public class BookService { @Autowired BookDao bookDao; @transactional public void buyBook(String username,String isbn) {public void buyBook(String username,String isbn) { bookDao.updateStockFromBookStock(isbn); int price = bookDao.getPriceFromBook(isbn); bookDao.updateBalanceFromAccount(username, price); System.out.println(" [" +username + "]) ); }}Copy the code

Declarative transaction configuration based on XML

Explained the use annotations above us how to configure declarative transaction, then configure declarative transaction there is another way, is in the XML file configuration, and they at the time of declaration data sources are the same, here I would say, after I only said it in the configuration data source, how to use the XML declaration transaction manager and the transaction method.

(1) Configure the transaction aspect

Spring provides a transaction manager (transaction aspect), so first we need to configure this transaction aspect.

<aop:config> <aop:pointcut expression="execution(* com.spring.service.*.*(..) )" id="txpoint"/> <! -- Transaction suggestions; Advice-ref: point to the transaction manager configuration --> < AOP :advisor advice-ref="myAdvice" pointcut-ref="txpoint"/> </aop:config>Copy the code

(2) Configure the transaction manager

To configure the transaction manager, use the TX: Advice tag, where the property transaction-Manager =”transactionManager” specifies which transaction manager to configure. Once this is done, we need to configure the transaction method in this tag

<! Transaction-manager ="transactionManager" --> < advice ID ="myAdvice" transaction-manager="dataSourceTransactionManager"> </tx:advice>Copy the code

(3) Specify the transaction method

We need to add the tx: Method tag to the TX: Advice tag to tell Spring which methods are transactional (the transaction aspect will slice the transaction method according to our pointcut expression). At the same time, the various parameters that transactions can use can be declared in tx:method

The code is as follows:

<! Transaction-manager ="transactionManager" --> < advice ID ="myAdvice" transaction-manager="dataSourceTransactionManager"> <! <tx: Attributes > <! Pointcut expressions simply say that the transaction manager should access these methods, --> <! <tx:method name="*"/> <! <tx:method name="buyBook" Propagation ="REQUIRED" timeout="-1"/> <! <tx:method name="get*" Read -only="true"/> </tx:attributes> </tx:advice>Copy the code

Now that the initial use of declarative transactions is complete, when do you use annotation-based transaction managers and when do you use XML-based transaction managers

Note: It is correct to use annotations as well as annotations, annotations for important transactions and configuration for unimportant transactions.

You think this is the end of it? But this is just the beginning, because transaction control must be performed in conjunction with multiple situations.

3. Communication behavior of transaction

When a transaction method is called by another transaction method, you must specify how the transaction should propagate. For example, a method may continue to run in an existing transaction, or it may start a new transaction and run in its own transaction.

The propagation behavior of ** transactions can be specified in the propagation attribute of the @Transactional annotation. **Spring defines seven types of propagation behavior.

Their corresponding functions are shown in the following table:

Let me mention two of the most commonly used communication behaviors.

REQUIRED: The current transaction shares one transaction with the previous large transaction

When a transaction uses REQUIRED, the transaction’s attributes are integrated into the larger transaction, so attributes imposed on methods do not take effect independently, such as timeout.

When a transaction uses REQUIRES_NEW, the attributes of the transaction can be adjusted

REQUIRES_NEW: The current transaction always uses a new transaction. If there are already transactions, the transaction will be suspended, and the suspended transaction will continue to run after the current transaction commits

Principle: REQUIRED, the connection of the previous transaction is passed to this method for use.

REQUIRES_NEW is the method that uses the new connection directly

Fourth, transaction isolation level

1. Database transaction concurrency

When we operate on the data in the database, there is often not only one person in the operation, that is to say, there may be concurrent execution of transactions, so since there is concurrent execution, there must be a problem of concurrent processing.

So what are the common transaction concurrency problems? For example, Transaction01 and Transaction02 are executed concurrently:

(1), dirty reading

Dirty read refers to the read of dirty data. Generally speaking, the read data is invalid. The following operation example:

1. Transaction01 Changes the AGE value of a record from 20 to 30.

2. Transaction02 reads the updated value of Transaction01:30.

3. The AGE value is restored to 20 after Transaction01 is rolled back.

4. Transaction02 reads 30 as an invalid value.

At this point, the Transaction02 transaction has a dirty read

(2) Do not read repeatedly

When the same transaction reads data repeatedly, the two read data are inconsistent.

Look at the following example:

1. Transaction01 reads the AGE value 20.

2. Transaction02 Change the AGE value to 30.

3. Transaction01 reads the AGE value 30 again, which is different from the first read.

When Transaction01 reads different data, it will not know which data to use when Transaction01 processes the transaction. This is called unrepeatable reads.

(3) Magic reading

Hearing this name is not feel very magical, how can there be magic? Phantom reading actually means that the two readings are inconsistent

Look at the following example:

1. Transaction01 reads part of the STUDENT table.

2. Transaction02 inserts new rows into STUDENT table.

3. Transaction01 read the STUDENT table and there are some extra rows.

When Transaction01 reads the table for the second time, it finds more data in the table than before, which is a phantom read.

2. Isolation level analysis of transactions

So how do we solve the three concurrency problems we mentioned above? This is where the isolation level of transactions is used, because these problems are caused by concurrent execution, and therefore the database system must have the ability to isolate the individual transactions running concurrently so that they do not interact with each other and avoid various concurrency problems.

The degree to which a transaction is isolated from other transactions is called the isolation level. The SQL standard defines multiple transaction isolation levels, which correspond to different interference levels. The higher the isolation level, the better the data consistency, but the weaker the concurrency.

There are four common isolation levels:

1. READ UNCOMMITTED: Allows Transaction01 to READ UNCOMMITTED changes in Transaction02.

2. READ COMMITTED: Transaction01 can only READ changes COMMITTED by Transaction02.

REPEATABLE READ Ensures that Transaction01 can READ the same value from a field multiple times, i.e. other transactions are not allowed to update this field during Transaction01 execution.

4. Serialization: SERIALIZABLE ensures that Transaction01 can read the same row from a table multiple times, and prevents other transactions from adding, updating, or deleting the table while Transaction01 is executing. Can avoid any concurrency problems, but performance is very poor.

However, not all of these isolation levels solve all of the above concurrency problems, and their ability to solve concurrency problems is as follows:

Different databases also support different isolation levels. Take MySQL and Oracle for example:

3. Specify the isolation level for the method

We’ve talked about transaction concurrency and the isolation levels that should be used to address it, so how to add isolation levels to transaction methods. There are two ways to do this.

(1) Specify isolation levels based on annotations

Specifying the transaction isolation level based on annotations allows you to set the isolation level in the @Transactional attribute when the @Transactional annotation declaratively manages transactions. This gives the transaction method the isolation level.

@Transactional(readOnly=true,isolation=Isolation.READ_UNCOMMITTED)
	public int getPrice(String isbn) {
		return bookDao.getPriceFromBook(isbn);
	}
Copy the code

(2) Specify isolation level based on XML

This approach allows you to declare the isolation level for a method in an XML configuration file if no annotations are used, and specify the isolation attribute in the TX: Method element in the Spring 2.x transaction notification. * * is as follows:

<tx:advice id="myAdvice" transaction-manager="dataSourceTransactionManager"> <! <tx: Method name="buyBook" Propagation ="REQUIRED" Isolation ="READ_COMMITTED"/> </tx:attributes> </tx:advice>Copy the code

An exception that triggers transaction rollback

We just said that rollback occurs when an error occurs, so can we specify that rollback occurs only when a specific error occurs? Of course you can.

1. The default rollback is abnormal

By default:

The system rolls back RuntimeException or Error caught, but does not roll back compile-time exceptions caught.

But now we can specify a rollback only if one or more errors occur through an attribute.

2. Set rollback for specific exceptions

Setting specific exceptions for rollback can also be declared in annotations or in XML

(1) Set rollback through annotations

A Transactional annotation setting rollback, also under the @Transactional annotation, has two attributes:

  • RollbackFor property: Specifies the type of exception that must be rolled back when encountered

  • NoRollbackFor attribute: Specifies the type of exception that will not be rolled back when encountered

When multiple values are set, use curly braces {} to expand them, separated by commas.

As follows:

@Transactional(propagation=Propagation.REQUIRED,rollbackFor={IOException.class,SQLException.class},
noRollbackFor={ArithmeticException.class,NullPointerException.class})
public void updatePrice(String isbn,int price) {
    bookDao.updatePrice(isbn, price);
}
Copy the code

(2) Rollback through XML Settings

In Spring 2.x transaction notifications, you can specify rollback rules in the **tx:method** element. If there is more than one exception, separate it with a comma.

<! Transaction-manager ="transactionManager" --> < advice ID ="myAdvice" transaction-manager="dataSourceTransactionManager"> <! <tx:method name="get*" Read -only="true" rollback-for=" java.io.ioException, java.sql.SQLException" no-rollback-for="java.langArithmeticException"/> </tx:attributes> </tx:advice>Copy the code

The timeout and read-only properties of the transaction

Because transactions can acquire locks on rows and tables, long transactions consume resources and have an impact on overall performance.

If a transaction only reads data but does not modify it, the database engine can optimize the transaction. ReadOnly =true readOnly=true

So two attributes are introduced:

Timeout transaction attribute: How long a transaction can remain in place before forced rollback. This prevents long running transactions from hogging resources. Use the attribute timeout

Read-only transaction property: Indicates that the transaction reads data but does not update data, which helps the database engine optimize the transaction. Use the attribute readOnly

Both properties can also be set via annotations or XML.

1. Annotations set timeout and read-only

To set timeouts and rollbacks via annotations, use the Timeout and readOnly attributes under the @Transactional annotation

ReadOnly: read-only. The parameter is Boolean. Type, set the transaction to read-only (only query operations can be performed; operations that modify the database will not be performed). When optimizing a transaction, use readOnly=true to increase query speed and ignore transaction-related operations

Timeout: indicates a Timeout. The parameter is int (in seconds). The transaction is automatically terminated and rolled back after the specified execution time.

Timeout error: when * * TransactionTimedOutException: Transaction timed out * * :

Example code is as follows:

@Transactional(timeout=3,readOnly=false,propagation=Propagation.REQUIRES_NEW) public void buyBook(String username,String  isbn){ bookDao.updateStockFromBookStock(isbn); int price = bookDao.getPriceFromBook(isbn); bookDao.updateBalanceFromAccount(username, price); System.out.println(" [" +username + "]) ); }Copy the code

2. Set timeout and read-only XML

In Spring 2.x transaction notifications, timeout and read-only attributes can be specified in the tx: Method element, again using the timeout and readOnly attributes.

The code is as follows:

<! Transaction-manager ="transactionManager" --> < advice ID ="myAdvice" transaction-manager="dataSourceTransactionManager"> <! <tx:method name="get*" Read -only="true" timeout="3"/> </tx:attributes> </tx:advice>Copy the code

Write at the end

The tutorial on using the declarative transaction manager in Spring is not complete until now, but there are many details that need to be discovered in actual development.

Click to follow, the first time to learn about Huawei cloud fresh technology ~