@Problema de invalidación transaccional cuando diferentes métodos del mismo tipo se llaman entre sí

Este artículo tiene como objetivo explorar el impacto de las llamadas de métodos mutuos en la validez de las anotaciones de transacciones de Spring en la misma clase.

suponer

La clase A tiene dos métodos a y b:
el método a es modificado por public, y el método b será llamado cuando se ejecute;
el método b es modificado por private, y operará en la base de datos cuando se ejecute.

Escenas

escena 1

El método a llama al método b, el método a no tiene decoración de anotación de transacción, en este momento, no importa si el método b tiene decoración de anotación de transacción o no, la transacción no será válida;

escena 2

El método a llama al método b, y el método a está decorado con anotaciones de transacciones, luego la transacción del método a tendrá efecto y la excepción lanzada en el método b también se revertirá. En este momento, si el método b está decorado con anotaciones de transacciones, la transacción del método b dejará de ser válida.

Análisis de causa

Al llamar a métodos de otras clases desde el exterior, si el método de destino se modifica con la anotación de transacción, cuando Spring escanea el bean, generará una clase de proxy envuelta para el método que contiene @Transactional, y usará AOP para iniciar la transacción antes que el se ejecuta el método Confirmar/revertir transacciones después de la ejecución. Sin embargo, las llamadas a métodos entre clases no siguen esta lógica, por lo que no habrá objetos proxy y las transacciones no se iniciarán.

Solución

  1. Agregue la transacción del método principal: cuando el método a en la clase A llama al método b, se pueden agregar anotaciones a a para administrar las transacciones comunes del método a y el método b.
  2. Usar transacciones programáticas en métodos:
//引入事务模板
@Autowired
TransactionTemplate transactionTemplate;

//在b方法(被调方法)中使用模板创建并执行语句
transactionTemplate.execute((TransactionCallback<Void>) status -> {
    
    
	// 业务逻辑
	return null;
})
  1. Obtenga el objeto proxy de la clase actual, use el objeto proxy para llamar al método b
    • Inyectarse y usar el objeto inyectado para llamar al método b
    • Obtenga la clase de proxy actual a través del contexto de primavera, use la clase de proxy para llamar al método b
    • Use AopContext para obtener la clase de proxy actual, use la clase de proxy para llamar al método b

extensión

La lógica de las llamadas a métodos entre diferentes clases.

El método a de la clase A llama al método b de la clase B, siempre que el método aob esté configurado con una transacción, la transacción tendrá efecto en este momento.
Si ambos métodos están configurados con transacciones, la forma en que se propagan las dos transacciones depende de las características de propagación de transacciones establecidas. El método predeterminado de transacciones de primavera es OBLIGATORIO (unirse si hay una transacción, crear si no hay transacción), en este caso, si ambos métodos a y b están anotados con @Transactional, porque a llama a b, entonces el método b será añadido a un método ejecutado en la transacción.

función de propagación de transacciones de primavera

REQUERIDO (Se requiere el tipo de propagación de transacción predeterminado de Spring: necesita, depende de, confía): Si no hay transacción actualmente, cree una nueva transacción usted mismo, si hay una transacción actualmente, únase a esta transacción Cuando A llama a B: si no hay transacción en A,
B Si hay una transacción en A, entonces B creará una nueva transacción, si hay una transacción en A, y hay una transacción en B, entonces B se unirá a A y se convertirá en una transacción. En este momento , o todos tienen éxito o ambos fallan. (Si hay 2 SQL en A y 2 SQL en B, entonces estos cuatro SQL se convertirán en un SQL, todos tendrán éxito o todos fallarán)

SOPORTES (soportes: soporte; soporte): actualmente hay una transacción, luego únase a la transacción actual, si no hay transacción, se ejecutará en un método no transaccional Si hay una transacción en A, entonces la transacción
del El método B se agregará a la transacción A para convertirse en una transacción (éxito en conjunto, falla en conjunto), si no hay transacción en A, entonces B se ejecutará en un modo no transaccional (se confirmará directamente después de la ejecución);

OBLIGATORIO (obligatorio: obligatorio): si hay una transacción actual, únase a la transacción actual, y si la transacción actual no existe, se lanzará una excepción.
Si hay una transacción en A, la transacción del método B se agrega a la transacción de A para convertirse en una transacción (éxitos juntos, fallan juntos); si no hay transacción en A y hay una transacción en B, entonces B arrojar directamente una excepción, lo que significa que B debe ejecutarse dentro de una transacción para admitir la reversión

REQUIRES_NEW (requires_new: requiere nuevo): Crea una nueva transacción, si hay una transacción actual, suspende la transacción.
B creará una nueva transacción, y las transacciones A y B no interferirán entre sí. Cuando tengan problemas y reviertan, solo revertirán sus propias transacciones;

NOT_SUPPORTED (no admitido: no admitido): Ejecutado de manera no transaccional. Si hay una transacción actualmente, el
destinatario B suspenderá la transacción actual y se ejecutará de manera no transaccional (enviar directamente). Transacción, A será suspendido (no ejecutado, esperar a que B termine de ejecutarse, volver); A y B tienen una excepción y necesitan retroceder, sin afectarse mutuamente

NEVER (nunca: nunca): Si no existe ninguna transacción actualmente, se ejecutará de manera no transaccional; si la hay, se lanzará una excepción. Es decir, B nunca se ejecuta de manera transaccional.
A no puede tener una transacción. De lo contrario, B se ejecutará de manera no transaccional. Si A tiene una transacción, se lanzará una excepción directamente.

NESTED (anidado: anidado) transacción anidada: si la transacción actual existe, se ejecutará en la transacción anidada, de lo contrario, la operación de REQUERIDO es la misma (abrir una transacción)
Si no hay transacción en A, entonces B crea una transacción para ejecutar, si A también hay una transacción en él, entonces B anidará la transacción en él

artículo de referencia

https://blog.csdn.net/ChineseSoftware/article/details/127602310
https://blog.csdn.net/single_0910/article/details/121561725
https://blog.csdn.net/dayuiicghaid/article/details/ 125260092
https://blog.csdn.net/hellozhxy/article/details/109753711

Supongo que te gusta

Origin blog.csdn.net/Ka__ze/article/details/131087408
Recomendado
Clasificación