Hola a todos, soy Glacier~~
En el trabajo diario, si la función de gestión de transacciones de Spring se usa incorrectamente, causará el problema de que las transacciones de Spring no surtan efecto. El problema de que las transacciones de Spring no surtan efecto también es una pregunta que se hace con frecuencia en las entrevistas de salto de trabajo.
Hoy, analicemos qué escenarios harán que las transacciones de Spring surtan efecto.
Nota: Parte del contenido se cita del libro " Comprensión detallada de las transacciones distribuidas: principios y práctica " publicado por Glacier y Cat .
Se incluyen artículos en GitHub y Gitee:
GitHub: https://github.com/sunshinelyz/technology-binghe
Gitee: https://gitee.com/binghe001/technology-binghe
Descripción general de las transacciones de Spring que no surten efecto
En resumen, las transacciones de Spring fallan en varios escenarios específicos, como se muestra en la siguiente figura.
La base de datos no admite transacciones.
El requisito previo para que las transacciones de Spring surtan efecto es que la base de datos conectada admita transacciones. Si la base de datos subyacente no admite transacciones, las transacciones de Spring definitivamente fallarán. Por ejemplo, si la base de datos utilizada es MySQL y se selecciona el motor de almacenamiento MyISAM, las transacciones de Spring fallarán.
Los métodos de transacción no son administrados por Spring
Si la clase en la que se encuentra el método de transacción no se carga en el contenedor Spring IOC, es decir, la clase en la que se encuentra el método de transacción no está administrada por Spring, la transacción de Spring fallará, el ejemplo es el siguiente.
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
No hay una anotación @Service en la clase ProductService y la instancia de Product no se carga en el contenedor Spring IOC, lo que hará que la transacción del método updateProductStockCountById() falle en Spring.
El método no es modificado por público.
Si public no modifica el método en el que se encuentra la transacción, entonces la transacción de Spring no será válida, por ejemplo, como se muestra en el siguiente código.
@Service
public class ProductService {
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRES_NEW)
private void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
Aunque ProductService está marcado con la anotación @Service, el método updateProductStockCountById() está marcado con la anotación @Transactional(propagation = Propagation.REQUIRES_NEW).
Sin embargo, dado que el método updateProductStockCountById() es un método privado interno (modificado con private), la transacción del método updateProductStockCountById() no será válida en Spring en este momento.
Llamadas a métodos en la misma clase
Si los dos métodos en la misma clase son A y B, la anotación de transacción no se agrega al método A, la anotación de transacción @Transactional se agrega al método B y el método A llama al método B, la transacción del método B no será válida. Por ejemplo, como se muestra en el siguiente código.
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
El método submitOrder() y el método updateProductStockCountById() están ambos en la clase OrderService. El método submitOrder() no está marcado con anotaciones de transacciones, y el método updateProductStockCountById() está marcado con anotaciones de transacciones. El método submitOrder() llama a updateProductStockCountById () En este momento, las transacciones del método updateProductStockCountById () se invalidan en Spring.
Administrador de transacciones no configurado
Si el administrador de transacciones de Spring no está configurado en el proyecto, incluso si se usa la función de administración de transacciones de Spring, la transacción de Spring no tendrá efecto.
Por ejemplo, el siguiente código no está configurado en la clase de configuración del proyecto.
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
En este punto, la transacción de Spring no será válida.
El tipo de propagación de transacciones del método no admite transacciones.
Si el tipo de propagación de transacciones del método interno es un tipo de propagación que no admite transacciones, la transacción del método interno no será válida en Spring.
Por ejemplo, como se muestra en el siguiente código.
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRED)
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void updateProductStockCountById(Integer stockCount, Long id){
productDao.updateProductStockCountById(stockCount, id);
}
}
Dado que el tipo de propagación de transacciones del método updateProductStockCountById() NO ES COMPATIBLE y no admite transacciones, la transacción del método updateProductStockCountById() no será válida en Spring.
Excepción capturada incorrectamente
Las excepciones capturadas incorrectamente también pueden hacer que las transacciones de Spring fallen, como se muestra a continuación.
@Service
public class OrderService {
@Autowired
private OrderDao orderDao;
@Autowired
private ProductDao productDao;
@Transactional(propagation = Propagation.REQUIRED)
public void submitOrder(){
//生成订单
Order order = new Order();
long number = Math.abs(new Random().nextInt(500));
order.setId(number);
order.setOrderNo("order_" + number);
orderDao.saveOrder(order);
//减库存
this.updateProductStockCountById(1, 1L);
}
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
try{
productDao.updateProductStockCountById(stockCount, id);
int i = 1 / 0;
}catch(Exception e){
logger.error("扣减库存异常:", e.getMesaage());
}
}
}
El bloque de código try-catch se usa en el método updateProductStockCountById() para capturar la excepción. Incluso si se lanza una excepción dentro del método updateProductStockCountById(), será capturada por el bloque de código catch. En este momento, la transacción del El método updateProductStockCountById() se confirmará sin devolver Rollback, y la transacción del método submitOrder() se confirmará pero no se revertirá, lo que provoca el error de reversión de las transacciones de Spring.
Tipo de excepción de anotación incorrecto
Si se marca el tipo de excepción incorrecto en la anotación @Transactional, la reversión de la transacción Spring no será válida. El ejemplo es el siguiente.
@Transactional(propagation = Propagation.REQUIRED)
public void updateProductStockCountById(Integer stockCount, Long id){
try{
productDao.updateProductStockCountById(stockCount, id);
}catch(Exception e){
logger.error("扣减库存异常:", e.getMesaage());
throw new Exception("扣减库存异常");
}
}
La excepción se captura en el método updateProductStockCountById() y se lanza una excepción de tipo Exception En este momento, la reversión de la transacción del método updateProductStockCountById() no será válida.
¿Por qué falla? Esto se debe a que el tipo de excepción de transacción para la reversión predeterminada en Spring es RuntimeException, y el código anterior genera una excepción de excepción.
De forma predeterminada, la excepción de excepción no se puede capturar en la transacción Spring, por lo que la reversión de la transacción en el método updateProductStockCountById() no será válida.
En este punto, puede especificar manualmente el tipo de excepción de transacción marcado por el método updateProductStockCountById(), como se muestra a continuación.
@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
Aquí, debe tenerse en cuenta que el atributo rollbackFor en la anotación de transacción Spring @Transactional puede especificar la clase de excepción Throwable y sus subclases.
Bien, detengámonos aquí hoy, soy Glacier, hasta la próxima~~
escribir al final
Si desea ingresar a una gran fábrica, desea obtener una promoción y un aumento de salario, o está confundido acerca de su trabajo actual, puede enviarme un mensaje privado para comunicarme, espero que algunas de mis experiencias puedan ayudarlo ~~
Lectura recomendada:
- " La práctica trae verdadero conocimiento: descifrar la arquitectura del sistema seckill más fuerte de toda la red, ¡no todos los seckills son seckills! ! 》
- " De cero a cientos de millones de usuarios, ¿cómo optimizo la base de datos MySQL paso a paso? (colección recomendada)》
- " Utilicé subprocesos múltiples para optimizar aún más el sistema de revisión de datos masivo en el negocio de comercio electrónico de tráfico de miles de millones de niveles, ¡y el rendimiento mejoró en un 200 %! ! (Todo el proceso es seco, se recomienda recolectar)》
- " Utilicé subprocesos múltiples para optimizar el sistema de revisión de datos masivo en el negocio de comercio electrónico de tráfico de mil millones de niveles, ¡y el rendimiento mejoró directamente en un 200%! ! (Todo el proceso es seco, se recomienda recolectar)》
- " ¡Resumí la mejor ruta de aprendizaje para la programación concurrente con 10 imágenes! ! (colección recomendada)》
- " Un bloqueo que es más rápido que los bloqueos de lectura y escritura en escenarios de alta concurrencia, ¡estoy completamente convencido después de leerlo! ! (colección recomendada)》
- ¡ Resumen de la optimización de rendimiento más completa de toda la red! ! (Arreglo de Hematemesis Glaciar, Colección Recomendada)》
- " Después de tres días de jugar a MyBatis, ¡no dudes en preguntar! ! (Arreglo de Hematemesis Glaciar, Colección Recomendada)》
- " Consejo para los que acaban de empezar a trabajar: ¡Si quieres entrar en una gran fábrica, debes dominar estos conocimientos de programación concurrente! ¡Ruta de aprendizaje completa! ! (colección recomendada)》
- " Consejo para aquellos jóvenes y jóvenes que acaban de comenzar a trabajar: ¡si desea ingresar a una gran fábrica, debe dominar estas habilidades básicas! ¡Ruta de aprendizaje completa! ! (colección recomendada)》
- Consejo para los que acaban de empezar a trabajar: ¡ Cuanto antes conozcas las bases de estos ordenadores y sistemas operativos, mejor! ¡El texto largo de 10,000 caracteres es demasiado alto! ! (colección recomendada)》
- " ¡Desarrollé un juego a nivel nacional adecuado para todas las edades en tres días, admite la reproducción de música y ahora abro el código fuente completo y los comentarios (colección recomendada)! ! 》
- " Soy el autor de programación de alta concurrencia más duro de toda la red y el bloguero más destacado de CSDN, ¿estás de acuerdo? (colección recomendada)》
- " Cinco años después de graduarme, de un salario mensual de 3000 a un salario anual de un millón, ¿qué habilidades básicas he dominado? (colección recomendada)》
- " Me hackeé el Wifi de la chica de al lado y me enteré. . . (Todo el proceso de productos secos de combate real, se recomienda recolectar) "
- " No intentes "Panda Burning Incense" a la ligera, no, ¡me arrepiento! 》
- ¡ Día de barrido de tumbas entrenó en secreto a "Panda quemando incienso" y mi computadora "dedicada" a panda! 》
- " 730.000 palabras repletas de nuevas características de Java8, ¡no creo que puedas leerlo! (colección recomendada)》
- " ¿Cómo es desconectar su servidor durante las horas pico de trabajo? 》
- ¡ Resumen de los comandos Linux más completos de toda la red! ! (La más completa de la historia, colección recomendada) "
- "¡ Escribí una herramienta en Python, MySQL perfectamente descifrado! ! (colección recomendada)》
- ¿Por qué la clase SimpleDateFormat no es segura para subprocesos? (con seis soluciones, colección recomendada) "
- Estos tres nuevos índices en MySQL 8 han hecho que MySQL despegue directamente, ¡ni siquiera lo sabes ! ! (colección recomendada)》
- "¡ Después de terminar el código fuente de Spring, abrí este marco de caché distribuido! ! (colección recomendada)》
- "El producto del sistema de picos concurrentes de alto tráfico de 100 millones de niveles está "sobrevendido", ¡solo porque hay estos dos pozos enormes en el contenedor de sincronización JDK utilizado! ! (El registro de pisar el foso, se recomienda coleccionarlo) "
- " Aconseje a los que acaban de empezar a trabajar: ¡Si quieren aprender bien la programación concurrente, deben prestar atención a los pozos de estos contenedores concurrentes! ! (colección recomendada)》
- "La herramienta de generación de informes de la empresa es demasiado difícil de usar. Conseguí una herramienta de Excel en tres días. La encargada de operaciones dijo que era muy fácil de usar y que ahora es de código abierto. ! (colección recomendada)》
- " Consejo para aquellos que acaban de empezar a trabajar: si quieren entrar en una gran fábrica, ¡estas habilidades básicas de programación concurrente son lo que deben dominar! ! (colección recomendada)》
- Entrevistador de Ali: ¿ Cómo resuelve correctamente el sistema de picos de alta concurrencia y tráfico el problema del inventario sobrevendido? (colección recomendada)》
- ¡ Resumen de cinco tipos de datos y escenarios de uso de Redis! ! (incluidos los casos de combate reales completos, se recomienda recopilar)》
De acuerdo, detengámonos aquí hoy, amigos, me gusta, favoritos, comenten y comiencen a caminar con un clic, soy Glacier, nos vemos en el próximo número ~~