Preguntas de la entrevista | ¿En qué escenarios fallarán las transacciones de Spring?

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.

imagen

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:

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 ~~

Supongo que te gusta

Origin blog.csdn.net/l1028386804/article/details/124471028
Recomendado
Clasificación