0108 spring affirm transaction

background

Internet banking and electricity supplier industry, are most concerned about database transactions.

Core Business Explanation
The financial industry - the amount of financial products It does not allow an error
Electricity supplier industry - the amount of commodity trading, commodity stocks It does not allow an error

Facing difficulties:

Highly concurrent guaranteed: data consistency, high performance;

spring treatment of things:

AOP uses technology provides transaction support, declarative transaction code to repeat try-catch-finally addition codes;

Scene two solutions:

Scenes Solution
Inventory deductions, transaction records, account the amount of data consistency Database transaction to ensure consistency
Batch processing part of the task failure does not affect the rollback batch jobs Database transaction propagation behavior

jdbc-processing services

Code

package com.springbootpractice.demo.demo_jdbc_tx.biz;
import lombok.SneakyThrows;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Objects;
import java.util.Optional;
/**
 * 说明:代码方式事务编程 VS 申明式事物编程
 * @author carter
 * 创建时间: 2020年01月08日 11:02 上午
 **/
@Service
public class TxJdbcBiz {
    private final JdbcTemplate jdbcTemplate;

    public TxJdbcBiz(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    @SneakyThrows
    public int insertUserLogin(String username, String note) {
        Connection connection = null;
        int result = 0;
        try {
            connection = Objects.requireNonNull(jdbcTemplate.getDataSource()).getConnection();

            connection.setAutoCommit(false);

            connection.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);

            final PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO user_login(user_name,password,sex,note)  VALUES(?,?,?,?)");

            preparedStatement.setString(1, username);
            preparedStatement.setString(2, "abc123");
            preparedStatement.setInt(3, 1);
            preparedStatement.setString(4, note);

            result = preparedStatement.executeUpdate();

            connection.commit();
        } catch (Exception e) {
            Optional.ofNullable(connection)
                    .ifPresent(item -> {
                        try {
                            item.rollback();
                        } catch (SQLException ex) {
                            ex.printStackTrace();
                        }
                    });
            e.printStackTrace();
        } finally {
            Optional.ofNullable(connection)
                    .filter(this::closeConnection)
                    .ifPresent(item -> {
                        try {
                            item.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    });
        }
        return result;
    }
    private boolean closeConnection(Connection item) {
        try {
            return !item.isClosed();
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }
    @Transactional
    public int insertUserLoginTransaction(String username, String note) {
        String sql = "INSERT INTO user_login(user_name,password,sex,note)  VALUES(?,?,?,?)";
        Object[] params = {username, "abc123", 1, note};
        return jdbcTemplate.update(sql, params);
    }
}

Test code

package com.springbootpractice.demo.demo_jdbc_tx;
import com.springbootpractice.demo.demo_jdbc_tx.biz.TxJdbcBiz;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.TransactionManager;
import org.springframework.util.Assert;
@SpringBootTest
class DemoJdbcTxApplicationTests {
    @Autowired
    private TxJdbcBiz txJdbcBiz;
    @Autowired
    private TransactionManager transactionManager;

    @Test
    void testInsertUserTest() {
        final int result = txJdbcBiz.insertUserLogin("monika.smith", "xxxx");
        Assert.isTrue(result > 0, "插入失败");
    }

    @Test
    void insertUserLoginTransactionTest() {
        final int result = txJdbcBiz.insertUserLoginTransaction("stefan.li", "hello transaction");
        Assert.isTrue(result > 0, "插入失败");
    }

    @Test
    void transactionManagerTest() {
        System.out.println(transactionManager.getClass().getName());
    }
}

Code has a very nasty place, is the try-catch-finally;

flow chart

graph TD A [Start] -> B (open transaction) B -> C {execute SQL} C -> | abnormal | D [transaction rollback] C -> | Normal | E [things Submit] D -> F [release transactional resource] E -> F [release transactional resource] F -> G [end]

AOP process with the overall process is very similar to the use of AOP, you can perform the steps of sql extracted achieve alone, other fixed processes in place to do the notification.

jdbc I use programming code point things!

Affirming transaction

To mark the transaction declarative annotation @Transaction, or can be standard methods in the class;

@Tranaction use position Explanation
The class or interface Class in all public non-static method will enable transaction, the Spring recommendation on implementation classes, aop must otherwise take effect when the agent interface based on the entry into force of
Methodologically This method

@Transaction source code and configuration items

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.transaction.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;

@Target({ElementType.TYPE, ElementType.METHOD})
@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 {};
}

Description:

Attributes Explanation
isolation Transaction isolation level
propagation Propagation behavior
rollbackFor,rollbakcForClassName Which will trigger abnormal transaction rollback
value Transaction Manager
timeout Transaction timeout
readOnly Whether it is read-only transaction
noRollbackFor,noRollbackForClassName What exception does not trigger a transaction rollback

Affairs of the installation process:

springIOC container when activated, will @Transactional annotation parsed configuration information, and then save the transaction definer (TransactionDefinition), and record what kind of needs to initiate a transaction, what strategy to adopt to execute the transaction.

We have to do is mark @Transactional and configuration properties can be;

Process Figure:

graph TD A [Start] -> B (opening and transaction set) B -> C {logic to perform a method} C -> | abnormal | D [transaction rollback] C -> | Normal | E [things submit] D -> F [release transactional resource] E -> F [release transactional resource] F -> G [end]

Using greatly simplified manner;

Code

 @Transactional
    public int insertUserLoginTransaction(String username, String note) {
        String sql = "INSERT INTO user_login(user_name,password,sex,note)  VALUES(?,?,?,?)";
        Object[] params = {username, "abc123", 1, note};
        return jdbcTemplate.update(sql, params);
    }

Transaction Manager

Open transaction, commit, rollback is placed on the transaction manager. TransactionManager;

TransactionManager Code


package org.springframework.transaction;

public interface TransactionManager {
}

This is an empty interface, the actual work is PlatfromTransactionManager;

PlatfromTransactionManager Code:

package org.springframework.transaction;

import org.springframework.lang.Nullable;

public interface PlatformTransactionManager extends TransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;

    void commit(TransactionStatus var1) throws TransactionException;

    void rollback(TransactionStatus var1) throws TransactionException;
}

3 shelves transaction manager comparison:

Shelf Transaction Management Explanation
spring-jdbc DatasourceTransactionManager
jpa JpaTransactionManager
mybatis DatasourceTransactionManager

Code examples point mybatis me!

Transaction isolation level

Scene: electricity supplier industry inventory deductions, time is multithreaded environment deductions stock, for the database, there will be multiple transactions colleagues access to the same records, inconsistent data due this case, the loss is the database updated .

Database transaction 4 properties

That ACID

Characteristics of the transaction English name Explanation
Atomicity Atomic A transaction comprising a plurality of steps A, B, C, is the identification of these atomicity operations ISSUE all succeed or all fail, the third case will not
consistency Consistency After the transaction is completed, all the data in a consistent state
Isolation Isolation Process multiple threads to access the same data, each thread in a different transaction, in order to suppress generation of lost updates, given the isolation level, by providing the barrier properties, can suppress the occurrence of lost updates, where the presence of a selected
Endurance Durability After the transaction, the data will persist, restart after a power failure also can be provided to continue to use the program

Isolation level:

Isolation Levels Explanation problem Concurrent performance
Uncommitted Read [read uncommitted] Further data allows a transaction to read uncommitted transaction, the transaction is not applicable requirements is relatively high, the transaction suitable for less demanding scenario Dirty read (single) Concurrent highest performance
Read Committed [read committed] A transaction can only read another transaction has a data submitted Non-repeatable read (single) Concurrent performance in general
Repeatable read] [read repeated When the transaction will be submitted to determine whether the latest value changes Fantasy reading (in terms of multiple data) Concurrent poor performance
Serialization [serializable] All sql are executed in the order Exactly the same data Concurrent worst performance

Selected based on

Isolation Levels Dirty read Non-repeatable read Phantom read
Uncommitted Read Yes Yes Yes
Read Committed no Yes Yes
Repeatable read no no Yes
Serialization no no no

According to the actual scene allows to set the transaction isolation level;

Isolation level will bring the cost of the lock; optimization:

  1. Optimistic locking,
  2. redis distributed lock,
  3. zk distributed lock;
database Transaction isolation level The default transaction isolation level
mysql Four kinds Repeatable read
oracle Read Committed, serialized Read Committed

springboot configuration application default transaction isolation level: spring.datasource.xxx.default-transaction-isolation = 2

digital The corresponding isolation level
-1 no
1 Uncommitted Read
2 Read Committed
4 Repeatable read
8 Serialization

Transaction propagation behavior

Communication behavior is a policy issue to call the transaction between the approach taken. Scene: a batch in a transaction A task, each individual has a separate transaction is a transaction Bn; subtasks rollback roll back the transaction does not affect the A's;

Source propagation behavior

package org.springframework.transaction.annotation;
import org.springframework.transaction.TransactionDefinition;
public enum Propagation {
	REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
	SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
	MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
	REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
	NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
	NEVER(TransactionDefinition.PROPAGATION_NEVER),
	NESTED(TransactionDefinition.PROPAGATION_NESTED);
	private final int value;
	Propagation(int value) {
		this.value = value;
	}
	public int value() {
		return this.value;
	}
}

Include seven spread configuration properties, are described below:

Propagation behavior Child behavior method in the presence of the parent method affairs The behavior of sub-method transaction does not exist in the parent method
REQUIRED The default propagation behavior, follow, Create a new transaction
SUPPORTS Follow; No transaction, no transaction sub-method
MANDATORY Follow Throw an exception
REQUIRES_NEW Create a new transaction Create a new transaction
NOT_SUPPORTED Pending transaction, run sub-method No transaction, run sub-method
NEVER Throws No execution method affairs sub
NESTED Sub-method exception occurs, roll back the only method of sql child without a parent roll back a transaction methods Exception occurs, roll back only the sub method of sql, nothing to do with the parent method

Three common communication behavior:

  • REQUIRED
  • REQUIRES_NEW
  • NESTED

Code propagation behavior of these three tests:

Code point me!

spring使用了save point的技术来让子事务回滚,而父事务不会滚;如果不支持save point,则新建一个事务来运行子事务;

区别点 RequestNew Nested
传递 拥有自己的锁和隔离级别 沿用父事务的隔离级别和锁

@Transaction自调用失效问题

事务的实现原理是基于AOP,同一个类中方法的互相调用,是自己调用自己,而没有代理对象的产生,就不会用到aop,所以,事务会失效; **解决办法:**通过spring的ioc容器得到当前类的代理对象,调用本类的方法解决; 原创不易,转载请注明出处。

Guess you like

Origin www.cnblogs.com/snidget/p/12168465.html