A consistent model of things

  • One of the core problems solved by Spring’s unified transaction model is that no matter what data access method you use, Hibernate, MyBatis, JDBC, your Service layer code is the same, there is no need to make any changes.
  • Spring works well together using either JTA or DataSource transactions.

The transaction abstracts the core interface

PlatformTransactionManager transaction manager

  • Package path org. Springframework. Transaction. PlatformTransactionManager
/** * Returns the currently active transaction or creates a new transaction, depending on the specified propagation behavior. * @param definition propagation behavior * @return TransactionStatus TransactionStatus * @throws TransactionException superclass of all transaction exceptions */ TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; /** * commit the transaction * @param status TransactionStatus * @throws TransactionException superclass for all transaction exceptions */ void commit(TransactionStatus status) throws  TransactionException; /** * transaction rollback * @param status TransactionStatus * @throws TransactionException superclass for all transaction exceptions */ void rollback(TransactionStatus status) throws TransactionException;Copy the code

TransactionDefinition Basic information about a transaction, such as timeout, isolation level, propagation properties, and so on

public interface TransactionDefinition {

    /** * (1) Transaction propagation features: * Support the current transaction; If not, a new transaction is created. * Is generally the default setting for things */
    int PROPAGATION_REQUIRED = 0;

    /** * (2) Transaction propagation features: * Support current transaction; If no transaction exists, it is executed nontransactionally. * It defines a transaction scope that can be applied to synchronization. As a result, Use {PROPAGATION_SUPPORTS} with care, especially if you don't rely on {PROPAGATION_REQUIRED} or {PROPAGATION_REQUIRES_NEW} * for the same resource Within {PROPAGATION_SUPPORTS} (this may cause synchronization conflicts at runtime) *@see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#SYNCHRONIZATION_ON_ACTUAL_TRANSACTION
     */
    int PROPAGATION_SUPPORTS = 1;

    /** * (3) Transaction propagation features: * Support the current transaction; If no current transaction exists, an exception is thrown * PROPAGATION_MANDATORY transaction synchronization is always driven by surrounding transactions. * /
    int PROPAGATION_MANDATORY = 2;

    /** * (4) Transaction propagation features: * Create a new transaction, if the current transaction exists, suspend the current transaction. *@see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_REQUIRES_NEW = 3;

    /** * (5) Transaction propagation features: * Create a new transaction, if the current transaction exists, suspend the current transaction. * Actual transaction pauses do not work out of the box on all transaction managers. * This is especially true for {@linkOrg. Springframework. Transaction. The jta. JtaTransactionManager}, * it requires {@codeJavax.mail. Transaction. TransactionManager} is available on the * please note that in {@codeTransaction synchronization cannot occur within the PROPAGATION_NOT_SUPPORTED} range. Existing synchronization will be paused and resumed as appropriate. *@see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
     */
    int PROPAGATION_NOT_SUPPORTED = 4;

    /** * (6) Transaction propagation features: * Does not support current transaction; An exception is thrown if the current transaction exists. * Transaction synchronization in {@code* Unusable within the PROPAGATION_NEVER} range. * /
    int PROPAGATION_NEVER = 5;

    /** * (7) transaction propagation features: * If the current transaction exists, execute in a nested transaction, otherwise behave like {@link# PROPAGATION_REQUIRED}. * The actual creation of nested transactions only applies to a particular transaction manager. *@see org.springframework.jdbc.datasource.DataSourceTransactionManager
     */
    int PROPAGATION_NESTED = 6;


    /** * The higher the isolation level, the greater the data integrity and consistency, but the greater the impact on concurrency performance. * For most applications, setting the isolation level of the database system to Read Committed is a priority. * It avoids dirty reads and has good concurrency performance. Although it can cause concurrent problems such as unrepeatable reads, phantom reads, and type ii missing updates, * In the rare cases where such problems may occur, it can be controlled by applications using pessimistic or optimistic locking. * * Spring also provides an identifier: ISOLATION_DEFAULT. Indicates that the default isolation level of the back-end database is used. * The default transaction isolation level for most databases, such as Sql Server and Oracle, is Read COMMITTED. * MySQL's default isolation level is Repeatable Read. * /
    /** * Transaction isolation level * Uses the default isolation level of the underlying data store. * All other levels correspond to the JDBC isolation level. *@see java.sql.Connection
     */
    int ISOLATION_DEFAULT = -1;

    /** * Transaction isolation level * Read Uncommitted * Allows dirty reads, but does not allow lost updates. If one transaction has already started writing data, the other transaction is not allowed to write data at the same time, * but other transactions are allowed to read data on this row. This isolation level can be achieved through exclusive write locks. *@see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
     */
    int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;

    /** * Transaction isolation level * Read Committed * Allows unrepeatable reads, but does not allow dirty reads. This can be done with "instant shared read locks" and "exclusive write locks". * A transaction reading data allows other transactions to continue to access the row, but an uncommitted write transaction prevents other transactions from accessing the row. *@see java.sql.Connection#TRANSACTION_READ_COMMITTED
     */
    int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;

    Repeatable Read /** * Transaction isolation level * Repeatable Read * Forbids non-repeatable and dirty reads, but sometimes phantom data may occur. This can be done with "shared read locks" and "exclusive write locks". * A transaction that reads data disallows a write transaction (but allows a read transaction), and a write transaction disallows any other transaction. *@see java.sql.Connection#TRANSACTION_REPEATABLE_READ
     */
    int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;

    /** * Transaction isolation level * Serializable provides strict transaction isolation. It requires serialized execution of transactions, which can only be executed one after another, not concurrently. * Transaction serialization cannot be achieved by "row-level locking" alone. Some other mechanism must be used to ensure that newly inserted data is not accessed by the transaction that just performed the query. *@see java.sql.Connection#TRANSACTION_SERIALIZABLE
     */
    int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
    /** * Use the default timeout of the underlying transaction system, or use none if timeout is not supported. * /
    int TIMEOUT_DEFAULT = -1;


    /** * returns propagation behavior. Must return in {@linkTransactionDefinition} {defined on this interface *@codeOne of the PROPAGATION_XXX} constants. *@returnCommunication behavior@see #PROPAGATION_REQUIRED
     * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()
     */
        int getPropagationBehavior(a);

    /** * Returns the isolation level. * must return in {@link{defined on the TransactionDefinition} interface@codeISOLATION_XXX} one of the constants. * These constants are designed to match {@linkMatch the value of the same constant on java.sql.Connection}.@link# PROPAGATION_REQUIRED} or {@link#PROPAGATION_REQUIRES_NEW}, * because it only applies to newly started transactions. If you want to participate in with a different isolation level of the existing transaction isolation level declaration, * please consider the transaction manager "validateExistingTransactions" mark on the switch to "true". * * Note that transaction managers that do not support custom isolation levels are given {@linkAny level other than #ISOLATION_DEFAULT} throws an exception. *@returnIsolation Level *@see #ISOLATION_DEFAULT
     * @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setValidateExistingTransaction
     */
    int getIsolationLevel(a);

    /** * returns transaction timeout. * Must return the number of seconds, or {@link# TIMEOUT_DEFAULT}. * designed for {@link# PROPAGATION_REQUIRED} or {@link#PROPAGATION_REQUIRES_NEW} is used because it only applies to newly started transactions * Note that timeout transaction managers are not supported in given {@linkAny timeout other than #TIMEOUT_DEFAULT} will throw an exception. *@returnTransaction timeout */
    int getTimeout(a);

    /** * returns whether to optimize as a read-only transaction. * Returns whether to optimize for a read-only transaction. * The read-only flag applies to any transaction context, whether supported by an actual resource transaction * ({@link #PROPAGATION_REQUIRED} / {@link#PROPAGATION_REQUIRES_NEW}) * Still operate non-transactionally at the resource level ({@link# PROPAGATION_SUPPORTS}). * In the latter case, the flag only applies to managed resources within the application, such as Hibernate {@codeThe Session}. * This is just a hint of the actual trading subsystem. < I > does not necessarily </ I > cause a write access attempt to fail. * Transaction managers that cannot interpret read-only prompts will < I > not </ I > throw an exception when requesting a read-only transaction. *@returnIf the transaction is to be optimized to read only, then {@code true}
     * @see org.springframework.transaction.support.TransactionSynchronization#beforeCommit(boolean)
     * @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
     */
    boolean isReadOnly(a);

    /** * returns the name of this transaction. Can be a {@codeNull}. * This will be used as the transaction name (such as WebLogic) to be displayed in the transaction monitor. * For Spring's declarative transactions, the public name will be {@codeFully qualified class name + ". + method name} (default). *@returnTransaction name *@see org.springframework.transaction.interceptor.TransactionAspectSupport
     * @see org.springframework.transaction.support.TransactionSynchronizationManager#getCurrentTransactionName()
     */
    @Nullable
    String getName(a);
}
Copy the code

TransactionStatus Some information about the status of a transaction, such as whether it is a new transaction and whether it has been marked for rollback

public interface TransactionStatus extends SavepointManager.Flushable {

    /** * returns whether the current transaction is a new transaction; Otherwise, you will participate in an existing transaction, or you may not run in the actual transaction first. * /
    boolean isNewTransaction(a);

    /** * Returns whether this transaction carries savepoints internally, that is, whether it has been created as a nested transaction based on savepoints. * This method is mainly for diagnostic purposes, and {@link#isNewTransaction} used together. * To programmatically handle custom savepoints, use {@linkSavepointManager} provides operations *@see #isNewTransaction()
     * @see #createSavepoint()
     * @see #rollbackToSavepoint(Object)
     * @see #releaseSavepoint(Object)
     */
    boolean hasSavepoint(a);

    /** * Set transaction rollback only. This would indicate to the transaction manager that the only possible outcome of the transaction might be a rollback, as an alternative to throwing an exception, * which would in turn trigger a rollback. This is mainly used for {@linkOrg. Springframework. Transaction. Support. TransactionTemplate} or {*@linkOrg. Springframework. Transaction. The interceptor. TransactionInterceptor}, * which actually commit/rollback decision made by the container. *@see org.springframework.transaction.support.TransactionCallback#doInTransaction
     * @see org.springframework.transaction.interceptor.TransactionAttribute#rollbackOn
     */
    void setRollbackOnly(a);

    /** * Returns whether the transaction has been marked for rollback only (by the application or by the transaction infrastructure) */
    boolean isRollbackOnly(a);

    /** * Flush the underlying session to the data store if applicable: for example, all affected Hibernate/JPA sessions. * In fact, this is just a hint that if the underlying transaction manager does not have the concept of flush, it might do nothing. * The refresh signal can be applied to either primary resource or transaction synchronization, depending on the underlying resource. * /
    @Override
    void flush(a);

    /** * returns whether the transaction has completed, that is, whether it was committed or rolled back. *@see PlatformTransactionManager#commit
     * @see PlatformTransactionManager#rollback
     */
    boolean isCompleted(a);
}
Copy the code

Four characteristics of transactions

Atomicity

All operations of the transaction are either all successful or all rolled back.

Consistency

Always transition from one consistent state to another consistent state.

Isolation

When multiple transactions execute concurrently, the execution of one transaction should not affect the execution of other transactions

“Durability”

Changes made to the database by committed transactions should be permanently stored in the database.If before operation (transaction has not been submitted) server outage or power outage, then restart the database, data status should be zhang SAN: 100, li si: 100 if after the operation (transaction has been submitted) server outage or power outage, then restart the database, data status should be zhang SAN: 0, li si: 200

What are dirty reads, phantom reads, and unrepeatable reads

Dirty read

At this isolation level, all transactions can see the results of other Uncommitted transactions. This isolation level is rarely used in real-world applications because its performance is not much better than other levels. Reading uncommitted data is also known as Dirty reads.At point 5, when transaction A queries the data again, transaction B does not commit the transaction, but the new data is also detected by transaction A. This is dirty reading.

Non-repeatable read (virtual read)

Read Committed is the default isolation level of most database systems (e.g. Sql Server, Oracle, but not MySQL, MySQL defaults Repeatable Read). It satisfies a simple definition of isolation: a transaction can only see the changes made by committed transactions. This isolation level also supports what is called Nonrepeatable Read, because other instances of the same transaction may have new COMMITS in the process of that instance, so the same SELECT may return different results.Before time point 6, the two query results at time points 3 and 5 in transaction A are consistent. After transaction B submitted the transaction, transaction A was queried again at 7 time points and the newly added data was queried. In transaction A, multiple queries with inconsistent results are called “unrepeatable reads.”

Phantom read

A transaction in one thread reads data from an INSERT submitted by another thread.

Isolation level

Check the TransactionDefinition comment in the source code

Programmatic transaction

The easiest way to declare things is to inject them manually

	@Autowired
	private TransactionTemplate transactionTemplate;
Copy the code

A simple example

	transactionTemplate.execute(new TransactionCallbackWithoutResult() {
		@Override
		protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
		    / / write SQL
               
			// transactionStatus.setRollbackOnly();}});Copy the code

TransactionCallbackWithoutResult: no return value using TransactionCallback: returns a value to use

Declarative transaction

An overview of the

Spring’s declarative transaction management is underpinned by AOP. The essence is to intercept before and after the method, then create or join a transaction before the target method starts, and commit or roll back the transaction after the target method is executed.

Declarative transaction’s biggest advantage is not need to programmatically manage transactions, so there is no need for doping in the business logic code transaction management code, just in the configuration file to do related business rule statement (or) by means of equivalent based on annotations, and business rules can be applied to the business logic. Because transaction management itself is a classic piece of crosscutting logic, that’s where AOP comes in. The Spring development team is aware of this and provides simple and powerful support for declarative transactions.

Declarative transactions are used in development not only because of their simplicity, but also because they keep the pure business code from being contaminated and greatly facilitate later code maintenance.

The only disadvantage of declarative transactions compared to programmatic transactions is that the fineness of the latter applies only to the method level, not to the code block level as programmatic transactions can. But even if there is such a need, there are many workarounds, such as separating the blocks of code that need transaction management into methods.

Declarative transaction management also has two common approaches:

  • XML configuration files based on and namespaces;
  • Based on the @Transactional annotation.
  • Add @ EnableTransactionManagement Stringboot need to start the class

The configuration can be as follows: @EnableTransactionManagement(mode = AdviceMode.PROXY,proxyTargetClass=true,order = Ordered.LOWEST_PRECEDENCE ) – ProxyTargetClass: whether a class-based proxy – mode: whether the transaction management function is implemented using JDK dynamic proxy or AspectJ. -order: aop interception order, default lowest priority, this advantage is that their own AOP interception can be above this

@ Transactional properties

The website address

  • Value Applies to the following scenarios: In a system that needs to access multiple data sources or databases, multiple transaction managers must be configured
  • REQUIRED_NEW: Internal transactions run independently and can be rolled back or committed independently in their respective scopes. External transactions are not affected by the rollback state of internal transactions.
  • ESTED transactions, which are administered on a single transaction basis, provide multiple savepoints. This multiple savepoints mechanism allows changes to an internal transaction to trigger a rollback of an external transaction. An external transaction can continue to transact after being mixed, even if some operations have been mixed. Since this setting is based on JDBC savepoints, it only works with JDBC mechanisms.
  • RollbackFor: allows checked exceptions to be rolled back; That is, roll back something that should not be rolled back.
  • NoRollbackFor: ignores non-check exceptions. That is, do not roll back what should be rolled back.

The sample

Make a @transactional. At the interface or class declaration. The Transactional // class annotation can override the @Transactional // class level annotation that applies to all public methods in the class

@Transactional
public class TestServiceBean implements TestService {} 
Copy the code

Add @transactional (Propagation = Propagation.NOT_SUPPORTED) to methods that do not need things

2. Add annotations to the method

Behavior of thing transmission

  • @Transactional(propagation=Propagation.REQUIRED)

If there is a transaction, join it, if not, create one (default)

  • @Transactional(propagation=Propagation.NOT_SUPPORTED)

The container does not open transactions for this method

  • @Transactional(propagation=Propagation.REQUIRES_NEW)

Regardless of whether a transaction exists, a new transaction is created, the original transaction is suspended, the new execution completes, and the old transaction continues

  • @Transactional(propagation=Propagation.MANDATORY)

Must be executed within an existing transaction, otherwise an exception is thrown

  • @Transactional(propagation=Propagation.NEVER)

Must be executed in a transaction that does not exist, otherwise an exception is raised (as opposed to Propagation.Mandatory)

  • @Transactional(propagation=Propagation.SUPPORTS)

If another bean calls this method and declares a transaction in another bean, use a transaction. If the other bean does not declare a transaction, then no transaction is required.

Transaction timeout setting:

  • Transactional(timeout=30) // The default is 30 seconds

Transaction isolation level:

  • @Transactional(isolation = Isolation.READ_UNCOMMITTED)

Reading uncommitted data (dirty read, non-repeatable read) is basically not used

  • @Transactional(isolation = Isolation.READ_COMMITTED)

Read committed data (unrepeatable reads and phantom reads occur)

  • @Transactional(isolation = Isolation.REPEATABLE_READ)

Repeatable reading (phantom reading may occur)

  • @Transactional(isolation = Isolation.SERIALIZABLE)

serialization