Prefacio
Mucha gente piensa que la transacción es muy simple, pero a menudo se encuentran con algunas dificultades en el trabajo (especialmente cuando otros métodos de transacción están anidados en el método de transacción), no sabemos la causa del problema y cómo resolverlo de manera efectiva.
Esto necesita analizar el código fuente central de Spring y finalmente encontrar la causa del problema y las ideas de solución con los pies en la tierra.
Anotar el proceso de operación de la transacción
Primero, observe el proceso de ejecución subyacente de las transacciones de Spring
Relación de objeto principal
Uno, relacionado con la configuración de la transacción
TransactionManagementConfigurationSelector: cuando se inicia la transacción de inicio de configuración (EnableTransactionManagement), importe el bean de configuración registrado.
Incluye dos bloques de configuración, AutoProxyRegistrar y ProxyTransactionManagementConfiguration.
AutoProxyRegistrar: Responsable de la configuración de las propiedades relevantes de la transacción de inyección de dependencia y la clase de entrada de transacción de inyección (clase InfrastructureAdvisorAutoProxyCreator);
ProxyTransactionManagementConfiguration: Responsable de inyectar beans relacionados con transacciones, que incluyen:
- Bean de aspecto de transacción (BeanFactoryTransactionAttributeSourceAdvisor)
- TransactionAttributeSource (bean de atributo de configuración de transacción)
- TransactionInterceptor (bean interceptor de transacciones);
2. Relacionado con la interceptación de la operación de transacción
- AopProxy: La interfaz base del proxy dinámico Spring AOP, responsable de definir el comportamiento básico de Proxy;
- MethodInterceptor: La interfaz central interna del interceptor en la cadena de llamadas Spring AOP. Todos los tipos de aspectos eventualmente serán empaquetados en esta interfaz para activar la interceptación unificada;
- TransactionInterceptor: la implementación comercial principal del interceptor de transacciones Spring y la cadena de llamadas AOP eventualmente activarán su método de invocación;
- TransactionManager: la interfaz base administrada por Spring, que se distingue como la interfaz de capa superior de la subinterfaz, y no define las capacidades reales de comportamiento de las transacciones;
- PlatformTransactionManager: hereda TransactionManager, define transacciones y comportamientos básicos;
- AbstractPlatformTransactionManager: Responsable de realizar el comportamiento público y la lógica de implementación general en todo el proceso de gestión y ejecución de transacciones, hereda la interfaz PlatformTransactionManager;
Implementación de código fuente
A continuación, analicemos el código fuente de la transacción Spring en bloques, algunos de los pozos y conclusiones importantes se compartirán en este proceso.
Uno, configuración de transacciones
TransactionManagementConfigurationSelector.selectImports () es responsable de definir la clase de configuración agregada al contenedor de primavera
Este método finalmente se analiza en ConfigurationClassParser y finalmente se instancia en un bean
AutoProxyRegistrar.registerBeanDefinitions () registra InfrastructureAdvisorAutoProxyCreator con beandefinition
ProxyTransactionManagementConfiguration.transactionAdvisor () inyecta el aspecto de la transacción
Dos, creación de transacciones
Uno de los puntos de entrada reales (y cglib): JdkDynamicAopProxy ... invoke ()
Método principal de procesamiento de la cadena de llamadas de aspecto ReflectiveMethodInvocation.proceed ()
TransactionInterceptor.invoke () activa la intercepción de transacciones desde aquí
TransactionAspectSupport.invokeWithinTransaction () realiza el negocio principal de la transacción Spring
TransactionAspectSupport.determineTransactionManager () define el administrador de transacciones especificado
Para el administrador de transacciones, el DataSourceTransactionManager (un administrador de transacciones que puede configurar la fuente de datos) se usa de forma predeterminada, o puede personalizar el administrador de transacciones y luego configurar la fuente de datos.
createTransactionIfNeeded () crea información de transacción TransactionInfo: incluyendo fuente de datos, conexión de transacción (ConnectionHolder), estado de transacción, caché de conexión, etc .;
DataSourceTransactionManager.doGetTransaction () Obtiene el objeto de transacción: contiene el empaquetado de conexión y el almacenamiento en caché
Caché de nivel de subproceso de conexión TransactionSynchronizationManager.getResource (): para garantizar que el subproceso actual obtenga la única conexión de datos
AbstractPlatformTransactionManager.startTransaction () inicia una nueva transacción
Solo cuando newTransaction sea verdadero, Spring hará el envío o la reversión real. Aquí hay un punto muy importante. Aquí no se comprenden claramente muchos pozos de transacciones anidadas.
DataSourceTransactionManager.doBegin () Código fuente del núcleo de la transacción abierta
TransactionSynchronizationManager.bindResource () establece el enlace a nivel de subproceso de la conexión actual y la fuente de datos
Tres, reversión de transacciones
Para las transacciones que no son de programación, la implementación principal de las transacciones Spring es en realidad el paradigma de analizar el compromiso y la reversión de transacciones con try / catch, pero el empaquetado en la confirmación y la reversión es muy particular.
TransactionAspectSupport.completeTransactionAfterThrowing () implementación de reversión de transacciones
En la captura de pantalla anterior, doSetRollbackOnly () en realidad no establecerá el punto de reversión en la conexión, solo una marca (la transacción actual debe revertirse y la marca se usará al confirmar).
Cuatro, compromiso de transacción
La transacción AbstractPlatformTransactionManager.commit () realmente confirma el código fuente aquí
CleanupAfterCompletion () recicla la conexión o reanuda la transacción. Este punto es intrigante: cuando el atributo de propagación de la transacción es Require_New, la conexión anterior se suspenderá temporalmente y luego se creará una nueva conexión; cuando la nueva conexión se confirma o revierte, este método se usa para restaurar la conexión anterior y ¡estado! ! ! !
OK transacción está aquí, comparto algunos dulces sobre subtransacciones anidadas basadas en el código fuente:
- Durante el proceso de transacción anidada, si hay alguna excepción en el medio, siempre que no esté protegida, se lanzará y no se ejecutará el código posterior;
- Siempre que se establezca el atributo de propagación de transacción Require_New, cada método de anotación transaccional se enviará o revertirá por separado;
- Las transacciones anidadas crearán puntos de reversión de puntos de guardado en subtransacciones, excepto la primera anotación transaccional;
- Después de establecer el punto de reversión del punto de guardado, todas las transacciones anteriores al método actual se revertirán durante la reversión; si solo necesita revertir el método actual, agregue try {} catch () {// sin excepción al método de transacción más externo };
- El objeto de cada transacción es diferente, el estado de la transacción puede ser diferente, pero la conexión puede ser la misma;
para resumir
El código fuente de la transacción Spring de hoy se comparte temporalmente aquí. La transacción tiene solo un nivel de transacción es muy simple, pero cuando se anidan múltiples subtransacciones (nivel) (y las propiedades de propagación de la transacción de cada subtransacción pueden ser diferentes) Es una historia diferente.
¡Necesitamos analizar cómo debe fluir cada capa de subtransacciones de acuerdo con la ley del código fuente! ! Por lo tanto, debe familiarizarse con el código fuente de esta pieza, y si encuentra razones complicadas de análisis de transacciones anidadas, entonces el problema no es grande.