Un texto con su profundo entendimiento de los principios de la primavera de transacciones

Los principales asuntos básicos de la primavera

El resorte es, de hecho, la naturaleza del soporte de base de datos de transacción para transacciones, no hay soporte de base de datos de transacción, el resorte es incapaz de proporcionar capacidades de transacción. Para la operación de base de datos JDBC puro, que desea utilizar los servicios, puede seguir estos pasos:

  1. La obtención de una conexión con conexión = DriverManager.getConnection ()

  2. con.setAutoCommit abierto transacción (verdadero / falso);

  3. realizar CRUD

  4. Confirmar la con.commit transacción transacción / rollback () / con.rollback ();

  5. Cierre la conexión conn.Close ();

Después de usar las capacidades de gestión de transacciones de la primavera, podemos escribir ningún código de tiempo en el paso 2 y 4, pero se hace automáticamente por Spirng. Entonces, ¿cómo abrir la primavera después de la transacción antes de escribir y ABM y el cierre de la sesión es? Para resolver este problema, se puede entender los principios de gestión de transacciones de primavera para lograr un todo.

Lo que sigue es una descripción breve, el modo de anotación como un ejemplo:

  1. Abra la unidad de anotación de archivo de configuración, en las clases y métodos pertinentes que identifican @Transactional anotaciones.

  2. primavera cuando empieza a análisis sintáctico generará bean relevante, esta vez tendrá que ver las clases y métodos notas relacionadas, y generar un proxy para estas clases y los métodos, y los parámetros de configuración basándose en la @Transaction inyección, por lo tanto el agente para nosotros para resolver asuntos relacionados con el (normal abierta confirmar la transacción, la transacción se revierte anormal).

  3. La transacción de bienes cometer y la capa de base de datos de rollback se logra mediante el registro de binlog o rehacer.

mecanismo de transacción de la primavera

Todas las tecnologías de acceso a datos tienen el procesamiento de transacciones, estas técnicas proporciona una API para permitir la transacción, la transacción se ha comprometido a la realización de la manipulación de datos, de datos o revierte cuando se produjo el error.

mecanismo de transacción de la primavera con un mecanismo unificado para la transacción de manejar el procesamiento de diferentes tecnologías de acceso a datos. mecanismo de transacción de resorte proporciona una interfaz de PlatformTransactionManager, diferentes transacciones utilizando diferentes interfaz de tecnología de acceso de datos, como se muestra en la Tabla.

Datos de la tecnología de acceso e Implementación

La tecnología de acceso a datos realización
JDBC DataSourceTransactionManager
JPA JapTransactionManager
Hibernar HibernateTransactionManager
JDO JdoTransactionManager
transacciones distribuidas JtaTransactionManager

Código define el administrador de transacciones en el programa son los siguientes:

@Bean
public PlatformTransactionManager transactionManager() {

    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setDataSource(dataSource());
    return transactionManager;
}

transacción declarativa

soporte de transacciones declarativa Spring, los usuarios pueden seleccionar el método requiere el uso de una transacción utilizando anotaciones, que utiliza anotación @Transactional en los programas de métodos que este método requiere soporte de transacciones. Esta es una realización de la operación a base de AOP.

@Transactional
public void saveSomething(Long  id, String name) {
    //数据库操作
}

De particular interés aquí es que este comentario @Transactional del paquete org.springframework.transaction.annotation lugar javax.transaction.

Hay dos tipos de AOP aplicación de proxy:

  • jdk es la interfaz del agente, no debe existir métodos privados en la interfaz, no será interceptada;

  • cglib es una subclase, método privado sigue sin aparecer en la subclase, no puede ser interceptada.

Java proxy dinámico.

En particular, los siguientes cuatro pasos:

  1. InvocationHandler implementando la interfaz para crear su propio procesador de llamadas;

  2. Para crear una clase de proxy dinámico mediante la especificación de un conjunto de objetos de interfaz y ClassLoader como la clase Proxy;

  3. constructor de la clase proxy dinámico se obtiene por la reflexión, el único tipo de parámetro es un tipo de interfaz de procesador de llamada;

  4. Mediante la creación de objeto constructor instancia de clase proxy dinámico configurado para llamar al manejador se pasa como un parámetro.

agente GCLIB

cglib (Biblioteca de generación de código) es un potente de alto rendimiento, bibliotecas generación de código, de alta calidad. Se puede extender en tiempo de ejecución clases Java e implementar interfaces Java.

  • cglib encapsulados asm, generar dinámicamente una nueva clase (subclase) en tiempo de ejecución.

  • cglib de AOP, JDK interfaces de la representación deberá basarse, cglib no tienen esta limitación.

El principio de distinción:

java proxy dinámico utilizando la reflexión para generar una clase de proxy anónimo que implementa la interfaz de llamada InvokeHandler antes de llamar a un método específico de procesar. El ASM dinámica de proxy cglib el uso de paquetes de código abierto, la clase de proxy archivos de clases de objetos cargados en, procesados ​​mediante la modificación de un código de bytes subclase.

  1. Si implementa el objeto de destino de la interfaz, se utilizará el JDK de proxy dinámico AOP implementaciones por defecto

  2. Si el objeto de destino implementa la interfaz, se puede forzar el uso de CGLIB lograr AOP

  3. Si el objeto de destino no implementa las interfaces debe ser utilizado biblioteca CGLIB, primavera automáticamente entre proxies dinámicos de JDK y convertir por CGLIB

Si la clase no es un método directo para ir dentro de la agencia, esta vez por el mantenimiento de su propia instancia de un proxy.

@Service
public class PersonServiceImpl implements PersonService {
    @Autowired
    PersonRepository personRepository;

    // 注入自身代理对象,在本类内部方法调用事务的传递性才会生效
    @Autowired
    PersonService selfProxyPersonService;

    /**
     * 测试事务的传递性
     *
     * @param person
     * @return
     */
    @Transactional
    public Person save(Person person) {
        Person p = personRepository.save(person);
        try {
            // 新开事务 独立回滚
            selfProxyPersonService.delete();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            // 使用当前事务 全部回滚
            selfProxyPersonService.save2(person);
        } catch (Exception e) {
            e.printStackTrace();
        }
        personRepository.save(person);

        return p;
    }

    @Transactional
    public void save2(Person person) {
        personRepository.save(person);
        throw new RuntimeException();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void delete() {
        personRepository.delete(1L);
        throw new RuntimeException();
    }
}

propiedades de propagación de transacción primavera

La propagación de la llamada primavera transacción de la propiedad se define cuando hay múltiples transacciones simultáneas, el resorte debe ser cómo tratar con el comportamiento de estos asuntos. Estos atributos definen constantes específicas TransactionDefinition explican en la siguiente tabla:

Nombre constante constante explicó
PROPAGATION_REQUIRED Apoyar la transacción actual, si no hay ninguna transacción, creamos un nuevo negocio. Esta es la elección más común, sino también la propagación de las transacciones de incumplimiento de la primavera.
PROPAGATION_REQUIRES_NEW Nueva transacción, si existe la transacción actual, la transacción actual en espera. La nueva transacción y la transacción pendiente no tiene nada que hacer, son dos operaciones separadas, la transacción exterior se deshace después de la falla, los resultados no pueden hacer retroceder la ejecución de la transacción transacción interior, interno no logra lanzar una excepción, la transacción externa la captura, el procesamiento puede no ser rollback
PROPAGATION_SUPPORTS Apoyar la transacción actual, si no hay ninguna transacción se ejecuta de una manera no transaccional.
PROPAGATION_MANDATORY Apoyar la transacción actual, si no hay ninguna transacción, una excepción.
PROPAGATION_NOT_SUPPORTED Realizar operaciones de una manera no transaccional, si existe la transacción actual, puso la transacción actual en espera.
PROPAGATION_NEVER Realizado de una manera no transaccional, si existe la transacción actual, se inicia una excepción.
PROPAGATION_NESTED Si hay una transacción activa, ejecute en una transacción anidada. Si no hay ninguna transacción activa, pulse ejecutar propiedad requerida. Utiliza una transacción separada, la transacción tiene múltiples puntos de guardado se pueden revertir. Rollback asuntos internos no afectarán a los asuntos externos. Sólo la aparición de administrador de transacciones DataSourceTransactionManager.

nivel de aislamiento de la base de datos

Niveles de aislamiento El valor del nivel de aislamiento Los problemas causados
Lectura no confirmada 0 Conducir a la lectura sucia
Comprometidos lectura 1 Prevenir las lecturas sucias, permite irrepetible lee y lectura fantasma
Repetible-Lee 2 Prevenir las lecturas sucias, lectura no repetible, permitiendo lectura fantasma
serializable 3 Lectura transacción serializado sólo se puede ejecutar uno por uno, para evitar lecturas sucias, lectura no repetible, lectura fantasma. Eficiencia lenta, el uso de precaución

Sucia leer: un conjunto de datos de transacción eran adiciones y supresiones, pero no presentó, otra transacción puede leer datos sin compromiso. En este momento, si la primera transacción se revierte, a continuación, la segunda transacción para asistir a los datos sucios.

No repetible de lectura: ha habido dos operaciones de lectura en una transacción, entre una primera operación de lectura y una segunda operación, un conjunto de datos de transacción modificados adicionalmente, esta vez los dos leer datos son inconsistentes.

La magia de lectura: la primera operación de una serie de datos realizar ediciones masivas, añadir un segundo de datos de transacciones en este rango, se pierde cuando la primera transacción para modificar los datos nuevos.

resumen:

Cuanto mayor sea el nivel de aislamiento, más se puede garantizar la integridad y la consistencia de los datos, pero el impacto en el rendimiento concurrente también es mayor.

La mayor parte de la base de datos de nivel de aislamiento predeterminado es leído Commited, como SqlServer, Oracle

nivel de aislamiento predeterminado pocas base de datos: Lectura repetible por ejemplo: MySQL InnoDB

nivel de aislamiento de la primavera

constante explicación
ISOLATION_DEFAULT Este es un nivel de aislamiento predeterminado PlatfromTransactionManager, utilice el nivel de aislamiento de base de datos por defecto. Además nivel JDBC aislamiento y cuatro, respectivamente.
ISOLATION_READ_UNCOMMITTED Este es el nivel de aislamiento de transacción más bajo, que promete otra carga de transacciones y se puede ver las transacciones sin confirmar estos datos. Este nivel de aislamiento tendrá lecturas sucias, no repetibles y las lecturas fantasma.
ISOLATION_READ_COMMITTED Después de una transacción para asegurar que los datos presentados con el fin de ser modificados para leer otra transacción. Otra transacción no puede leer las transacciones no confirmadas.
ISOLATION_REPEATABLE_READ Esto evita el aislamiento de transacciones a nivel de las lecturas sucias, lecturas no repetibles. Sin embargo, se puede producir la lectura fantasma.
ISOLATION_SERIALIZABLE Este es el más caro, pero el costo del nivel de aislamiento más confiable. La transacción se procesa como una ejecución secuencial.

Las transacciones anidadas

通过上面的理论知识的铺垫,我们大致知道了数据库事务和spring事务的一些属性和特点,接下来我们通过分析一些嵌套事务的场景,来深入理解spring事务传播的机制。

假设外层事务 Service A 的 Method A() 调用 内层Service B 的 Method B()

PROPAGATION_REQUIRED(spring 默认)

如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。

假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。

这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。

PROPAGATION_REQUIRES_NEW

比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。

那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。

他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。

PROPAGATION_SUPPORTS

假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。

PROPAGATION_NESTED

现在的情况就变得比较复杂了, ServiceB.methodB() 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢? ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:

a、捕获异常,执行异常分支逻辑

void methodA() {

        try {

            ServiceB.methodB();

        } catch (SomeException) {

            // 执行其他业务, 如 ServiceC.methodC();

        }

    }

这种方式也是嵌套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点。

b、 外部事务回滚/提交 代码不做任何修改, 那么如果内部事务(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), 外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback

另外三种事务传播属性基本用不到,在此不做分析。

总结

对于项目中需要使用到事务的地方,我建议开发者还是使用spring的TransactionCallback接口来实现事务,不要盲目使用spring事务注解,如果一定要使用注解,那么一定要对spring事务的传播机制和隔离级别有个详细的了解,否则很可能发生意想不到的效果。

Spring Boot 对事务的支持

通过org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration类。我们可以看出Spring Boot自动开启了对注解事务的支持 Spring

只读事务(@Transactional(readOnly = true))的一些概念

  • 概念:从这一点设置的时间点开始(时间点a)到这个事务结束的过程中,其他事务所提交的数据,该事务将看不见!(查询中不会出现别人在时间点a之后提交的数据)。

@Transcational(readOnly=true) 这个注解一般会写在业务类上,或者其方法上,用来对其添加事务控制。当括号中添加readOnly=true, 则会告诉底层数据源,这个是一个只读事务,对于JDBC而言,只读事务会有一定的速度优化。

而这样写的话,事务控制的其他配置则采用默认值,事务的隔离级别(isolation) 为DEFAULT,也就是跟随底层数据源的隔离级别,事务的传播行为(propagation)则是REQUIRED,所以还是会有事务存在,一代在代码中抛出RuntimeException,依然会导致事务回滚。

  • 应用场合:

  1. 如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持SQL执行期间的读一致性;

  2. 如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询SQL必须保证整体的读一致性,否则,在前条SQL查询之后,后条SQL查询之前,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态,此时,应该启用事务支持。

【注意是一次执行多次查询来统计某些信息,这时为了保证数据整体的一致性,要用只读事务】

References:

  1. http://www.codeceo.com/article/spring-transactions.html

  2. http://www.cnblogs.com/fenglie/articles/4097759.html

  3. https://www.zhihu.com/question/39074428/answer/88581202

  4. http://blog.csdn.net/andyzhaojianhui/article/details/51984157

发布了50 篇原创文章 · 获赞 1706 · 访问量 222万+

Supongo que te gusta

Origin blog.csdn.net/zl1zl2zl3/article/details/105372909
Recomendado
Clasificación