The transaction

Characteristics of transactions

  • A transaction must be treated as an indivisible, minimal unit of work in which all operations either succeed or fail and are rolled back. It is not possible for a transaction to perform only some of the operations.
  • A transaction must transfer the database from one consistent state to another consistent state. That is, a transaction must be in a consistent state both before and after execution. In the case of transfer, if user A and user B have A total of 5000, then no matter how many transfers are made between user A and user B, the sum of the two users should still be 5000 at the end of the transaction. This is the consistency of the transaction.
  • Isolation Concurrent transactions are isolated from each other, and changes made by one transaction are not visible to other transactions until they are finally committed. For example, if account A has 5000 yuan in deposit and the transfer statement (-500) is executed, the account balance will remain 5000 yuan for other transactions as long as the transaction is not committed.
  • Once transactions are committed, their modifications to the database are permanent and their modified data is not lost even if the system crashes.

Problems with concurrent transactions

  • Multiple transactions change the same row (none committed), and subsequent changes overwrite previous changes.
  • Dirty Reads One transaction can read uncommitted data from another transaction.
  • Non-repeatable Reads (NON-repeatable Reads) execute the same query twice in the same transaction and may get different results. This is because within the query interval, another transaction modifies the record and commits the transaction.
  • Phantom Reads occur when a transaction Reads a record in a range and another transaction inserts a new record in that range. Phantom Reads occur when a previous transaction Reads a record in that range again.

Isolation level

Of the storage engines commonly used by MySQL, only InnoDB supports transactions, so the isolation level here refers to the transaction isolation level under InnoDB.

  • At this isolation level, changes made in a transaction are visible to other transactions even when they are not committed. Update loss is avoided.
  • At this isolation level, a transaction can only see the changes made by the COMMITTED transactions. Updates lost and dirty reads are avoided.
  • REPEATABLE READ Default isolation level of MySQL that ensures that the same record is READ multiple times in the same transaction. Avoid missing updates, dirty reads, unrepeatable reads, and phantom reads.
  • SERIALIZABLE SERIALIZABLE is the highest isolation level and avoids the problems associated with concurrent transactions by forcing transactions to be serialized.
Isolation level Read Data Consistency Update the lost Dirty read Unrepeatable read Phantom read
Read uncommitted At the lowest level, only physically corrupted data can be read x Square root Square root Square root
Reading has been submitted statement-level x x Square root Square root
Repeatable read The transaction level x x x x
serializable The highest level, transaction level x x x x

Spring Transaction Management

The following is the source code of Spring transaction annotations, from which you can see the four properties of Spring transaction management: Propagation, Isolation, Timeout, readOnly.

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}
Copy the code

Transaction propagation behavior

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);

    private final int value;

    private Propagation(int value) {
        this.value = value;
    }

    public int value() {
        returnthis.value; }}Copy the code

Transaction propagation behavior refers to the propagation of transactions between methods. For example, if method B is called from method A:

  • REQUIRED The current transaction is used if A has one, and A new transaction is created if A has none.
  • SUPPORTS uses the current transaction if A has A transaction. Non-transaction execution if A has no transaction.
  • MANDATORY Uses the current transaction if A has one, and throws an exception if A has none.
  • REQUIRES_NEW Creates A new transaction whether or not A has one.
  • NOT_SUPPORTED Executes non-transactionally regardless of whether A has A transaction or not.
  • NEVER Throws an exception if A has A transaction. If A has no transaction, the exception is executed as non-transaction.
  • NESTED creates A transaction if A has no transaction, and NESTED other transactions in the current transaction if A has A transaction. Transaction isolation level
public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);

    private final int value;

    private Isolation(int value) {
        this.value = value;
    }

    public int value() {
        returnthis.value; }}Copy the code

DEFAULT indicates the isolation level of the database.

Transaction timeout

To solve the problem of transaction execution taking too long and consuming too many resources, we can set a timeout time for the transaction. If the transaction execution time exceeds the timeout time, the transaction is rolled back.

Read-only transactions

Some methods that do not require transactions, such as reading data, can be set to read-only transactions, which can significantly improve performance.

Manually managing transactions

Spring uses the TransactionTemplate TransactionTemplate to manage transactions.

(1) DAO layer

Public interface AccountDao {// AccountDao public void out(String outer, Integer money); // Collection public voidin(String inner , Integer money);
}

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

	public void out(String outer, Integer money) {
		this.getJdbcTemplate().update("update account set money = money - ? where username = ?", money,outer);
	}

	public void in(String inner, Integer money) {
		this.getJdbcTemplate().update("update account set money = money + ? where username = ?", money,inner); }}Copy the code

(2) Service layer

Public interface AccountService {// Transfer public void Transfer (String outer,String inner,Integer money); } public class AccountServiceImpl implements AccountService { private AccountDao accountDao; private TransactionTemplate transactionTemplate; public voidsetAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }	
    
    public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
        this.transactionTemplate = transactionTemplate;
    }

    public void transfer(final String outer, final String inner, final Integer money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {

            @Override
            protected void doInTransactionWithoutResult(TransactionStatus arg0) { accountDao.out(outer, money); Int I = 1/0; accountDao.in(inner, money); }}); }}Copy the code

(3) Spring configuration

<beans> <! -- 1, datasource --> < datasource ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="123"></property> </bean> <! Dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
        <property name="dataSource" ref="dataSource"></property> </bean> <! -- 3, service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"></property>
        <property name="transactionTemplate" ref="transactionTemplate"></property> </bean> <! Create transaction template --> <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="txManager"></property> </bean> <! DataSource = 'DataSource'; DataSource = 'DataSource'; DataSource = 'DataSource'"txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>
Copy the code

(4) Test code

@Test
public void demo(){
	String xmlPath = "applicationContext.xml";
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
	AccountService accountService =  (AccountService) applicationContext.getBean("accountService");
	accountService.transfer("jack"."rose", 1000);
}
Copy the code

Spring transaction broker

(1) Service layer

Public interface AccountService {// Transfer public void Transfer (String outer,String inner,Integer money); } public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public voidsetAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void transfer(String outer, String inner, Integer money) { accountDao.out(outer, money); Int I = 1/0; accountDao.in(inner, money); }}Copy the code

(2) Spring configuration file

<beans> <! -- 1, datasource --> < datasource ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123"></property> </bean> <! Dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"></property> </bean> <! -- 3, service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"></property> </bean> <! Service proxy object 4.1 proxyInterfaces 4.2 target target class 4.3 transactionManager transactionManager 4.4 transactionAttributes Prop. key: Determines which methods use the current transaction to configure prop.text: To configure the transaction details format: PROPAGATION, ISOLATION,readOnly, -exception, +Exception Propagation behavior isolation level Read-only Exception Rollback Abnormal submission Example: <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> Default propagation behavior, and isolation level <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> Read-only <prop key="transfer"> PROPAGATION_REQUIRED ISOLATION_DEFAULT, + Java. Lang. ArithmeticException < / prop > have exception thrown submitted - > < bean id ="proxyAccountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<property name="proxyInterfaces" value="org.tx.service.AccountService"></property>
		<property name="target" ref="accountService"></property>
		<property name="transactionManager" ref="txManager"></property>
		<property name="transactionAttributes">
			<props>
				<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> </props> </property> </bean> <! --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>
Copy the code

(3) Test code

@Test
public void demo(){
	String xmlPath = "applicationContext.xml";
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
	AccountService accountService =  (AccountService) applicationContext.getBean("proxyAccountService");
	accountService.transfer("jack"."rose", 1000);
}
Copy the code

Spring + AspectJ

Xml-based Configuration

Public void transfer(String outer,String inner,Integer money) public void transfer(String outer,String inner,Integer money); } public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public voidsetAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void transfer(String outer, String inner, Integer money) { accountDao.out(outer, money); Int I = 1/0; accountDao.in(inner, money); }}Copy the code

(2) Spring configuration file

<beans> <! -- 1, datasource --> < datasource ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
		<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
		<property name="user" value="root"></property>
		<property name="password" value="123"></property> </bean> <! Dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
		<property name="dataSource" ref="dataSource"></property> </bean> <! -- 3, service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"></property> </bean> <! Transaction manager --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property> </bean> <! <tx:advice ID = <tx:advice ID ="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <! < AOP :config> < AOP :advisor advice-ref="txAdvice" pointcut="execution(* org.tx.service.*.*(..) )"/>
	</aop:config>
</beans>
Copy the code

(3) Test code

@Test
public void demo(){
	String xmlPath = "applicationContext.xml";
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
	AccountService accountService =  (AccountService) applicationContext.getBean("accountService");
	accountService.transfer("jack"."rose", 1000);
}
Copy the code

Based on the annotation

(1) @transactional (Propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT) public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public voidsetAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @transactional (Propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT) public void transfer(String outer, String inner, Integer money) { accountDao.out(outer, money); Int I = 1/0; accountDao.in(inner, money); }}Copy the code

(2) Spring configuration file

<beans> <! -- 1, datasource --> < datasource ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
			<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
			<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
			<property name="user" value="root"></property>
			<property name="password" value="123"></property> </bean> <! Dao --> <bean id="accountDao" class="org.tx.dao.impl.AccountDaoImpl">
			<property name="dataSource" ref="dataSource"></property> </bean> <! -- 3, service --> <bean id="accountService" class="org.tx.service.impl.AccountServiceImpl">
			<property name="accountDao" ref="accountDao"></property> </bean> <! Transaction manager --> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
			<property name="dataSource" ref="dataSource"></property> </bean> <! <tx:annotation-driven Transaction-manager ="txManager"/>
</beans>
Copy the code

(3) Test code

@Test
public void demo(){
	String xmlPath = "applicationContext.xml";
	ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
	AccountService accountService =  (AccountService) applicationContext.getBean("accountService");
	accountService.transfer("jack"."rose", 1000);
}
Copy the code

Source:Blog.csdn.net/litianxiang…

Related articles

  • Spring foundation for preparation of handwriting Spring framework
  • Handwritten Spring framework preparation for Spring core AOP

Open Source Project Recommendation

The authors recommend open source projects:

  • Pre Is a RBAC permission management system based on Spring Boot, Spring Security, and Vue
  • Prex based on Spring Cloud, Oauth2, Vue of the front and back end separation of the microservice architecture RBAC permission management system

Concern public number reply open source project can be obtained