Primavera de varios tipos de prueba de comprensión de transacciones

  • Propiedades de propagación

    • Preparación ambiental

    • Clase de excepción

    • Llamador

  • para resumir

  • Dirección de Github


Para aprender cosas hay que saber y hacer las cosas juntos. Si solo conoces la teoría y no la has practicado, entonces no serás particularmente sólido. Se estima que la olvidarás en unos días. A continuación, practiquemos juntos para conocer las propiedades de propagación de las transacciones Spring.

Propiedades de propagación

El atributo de propagación define el comportamiento de procesamiento cuando un método de transacción encuentra otro método de transacción. Hay siete tipos de comportamientos, que se definen de la siguiente manera

De hecho, con solo mirar el concepto ya se ha explicado el papel de cada comunicabilidad de manera muy sencilla, en este momento usaremos ejemplos específicos para demostrar el comportamiento de cada atributo comunicable.

En esta demostración, usamos la base de datos H2, que se usa en la memoria, por lo que es correcto para nosotros demostrar el efecto de la transacción. No necesitamos hacer otras configuraciones. Creemos una nueva tabla. Coloque la siguiente declaración en el archivo schema.sql y el programa SpringBoot creará automáticamente dicha tabla en la memoria para nosotros cuando se inicie.

CREATE TABLE FOO (ID INT IDENTITY, BAR VARCHAR(64));

Antes de la demostración, definiremos dos clases FooService y BarService. Usamos los métodos en BarService para llamar a los métodos en FooService.

Preparación ambiental

Antes de realizar la demostración de la transacción, se puede dividir en las siguientes situaciones. Según la permutación y combinación, podemos dibujar las siguientes ocho situaciones

  • Persona que llama: si hay una transacción

  • Persona que llama: ¿Hay alguna excepción?

  • Destinatario: si hay una transacción ** (esto está controlado por el atributo de propagación) ** Por lo tanto, no está en la permutación y combinación

  • Llamado: ¿Hay alguna excepción?

Clase de excepción

RollbackException es una clase de excepción definida por nosotros

@Service
public class BarServiceImpl implements BarService{
    @Autowired
    private FooService fooService;

     // PROPAGATION_REQUIRED演示 无事务
    @Override
    public void testRequiredNoTransactional() throws RollbackException {
        fooService.testRequiredTransactional();
    }
}

Llamador

Defina dos métodos en BarService, uno con transacción y otro sin transacción

// 有事务
@Override
@Transactional(rollbackFor = Exception.class)
public void hasTransactional() throws RollbackException {

}

// 无事务
@Override
public void noTransactional() throws RollbackException {

}

A continuación, estudiaremos los atributos de propagación de transacciones en función de las ocho situaciones definidas anteriormente en Rusia.

PROPAGATION_REQUIRED

Bajo este atributo de propagación, si el destinatario de la llamada crea una nueva transacción depende de si el llamante realiza una transacción.

Para comprender las características de este atributo de propagación, de hecho, nos basta con demostrar dos ejemplos de las ocho situaciones anteriores.

  • En el primer caso, cuando el destinatario de la llamada lanza una excepción, si los datos insertados no se pueden consultar, significa que el destinatario de la llamada ha creado una nueva transacción sin el llamador.

  • En el segundo caso, cuando la persona que llama lanza una excepción, si los datos insertados no se pueden consultar, significa que la persona que llama se ha unido a la transacción actual cuando la persona que llama tiene una transacción.

Veamos primero un ejemplo del método de la clase del destinatario.

@Service
public class FooServiceImpl implements FooService {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    // REQUIRED传播属性-被调用者有异常抛出
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void testRequiredHasException() throws RollbackException {
        jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ("+Global.REQUIRED_HAS_EXCEPTION+")");
        throw new RollbackException();
    }

    // REQUIRED传播属性-被调用者无异常抛出
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public void testRequiredNoException() throws RollbackException {
        jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ("+Global.REQUIRED_NO_EXCEPTION+")");
    }
}

A continuación, miramos un ejemplo del método de llamada.

@Service
public class BarServiceImpl implements BarService{
    @Autowired
    private FooService fooService;

    // 有事务
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void hasTransactional() throws RollbackException {
        // 调用者有事务,抛异常  被调用者无异常
        fooService.testRequiredNoException();
        throw new RollbackException();
    }

    // 无事务
    @Override
    public void noTransactional() throws RollbackException {
        // 调用者无事务,不抛异常  被调用者有异常
        fooService.testRequiredHasException();
    }
}

En este punto, consultamos cuándo se llama al programa

String noException = Global.REQUIRED_NO_EXCEPTION;
String hasException = Global.REQUIRED_HAS_EXCEPTION;

try {
    barService.noTransactional();
}catch (Exception e){
    log.info("第一种情况 {}",
            jdbcTemplate
                    .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='"+hasException+"'", Long.class));
}

try {
    barService.hasTransactional();
}catch (Exception e){
    log.info("第二种情况 {}",
            jdbcTemplate
                    .queryForObject("SELECT COUNT(*) FROM FOO WHERE BAR='"+noException+"'", Long.class));
}

Ver el registro impreso

2019-10-16 13:02:04.142  INFO 11869 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 13:02:04.143  INFO 11869 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

Vemos que no hemos encontrado los datos correspondientes, lo que indica que los datos se han retrotraído. En este punto, debemos entender que la oración respalda la transacción actual, si no, cree una nueva transacción.

PROPAGATION_SUPPORTS

Si la persona que llama tiene una transacción depende completamente de la persona que llama. Si la persona que llama tiene una transacción, habrá una transacción, y si la persona que llama no tiene una transacción, no habrá transacción.

A continuación, usaremos los dos ejemplos anteriores para demostrar

  • El primer caso: si el destinatario de la llamada lanza una excepción, si los datos aún se pueden consultar, significa que la transacción no se ha revertido, lo que indica que el destinatario de la llamada no tiene transacción.

  • El segundo caso: si la persona que llama lanza una excepción, si no se pueden encontrar los datos, significa que los dos métodos están en una transacción

El siguiente sigue siendo un ejemplo de demostración.

El destinatario simplemente reemplaza el atributo de propagación en la anotación @Transactional con Propagation.

// SUPPORTS传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void testSupportsHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// SUPPORTS传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS)
public void testSupportsNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_NO_EXCEPTION+"')");
}

La persona que llama es la misma que la llamada de ejemplo anterior, vemos directamente el efecto de ejecución

2019-10-16 13:50:27.738  INFO 12174 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 1
2019-10-16 13:50:27.741  INFO 12174 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

Vimos que los datos se encontraron en el primer caso, lo que indica que el destinatario no tiene transacción en el primer caso. En este punto, debemos entender que esta oración es compatible con la transacción actual, si no, no se ejecutará de manera transaccional.

PROPAGATION_MANDATORY

Estos dos ejemplos todavía se utilizan para demostración.

  • El primer caso: debido a que la persona que llama no tiene una transacción, se debe lanzar una excepción bajo este atributo de propagación.

  • El segundo caso: la transacción de la persona que llama y la transacción de la persona que llama son la misma

El siguiente es el ejemplo de código del destinatario

// MANDATORY传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void testMandatoryHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// MANDATORY传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY)
public void testMandatoryNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.SUPPORTS_NO_EXCEPTION+"')");
}

La persona que llama es la misma que la llamada de ejemplo anterior, vemos directamente el efecto de ejecución

2019-10-16 13:58:39.178 ERROR 12317 --- [           main] c.e.t.t.TransactionApplication           : org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
2019-10-16 13:58:39.276  INFO 12317 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 13:58:39.281  INFO 12317 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0

Descubrimos que, como especulamos, significa que el destinatario de la llamada no creará una nueva transacción por sí mismo. En este momento, debemos entender que esta oración es compatible con la transacción actual, y si no hay ninguna transacción actualmente, lanzamos una excepción.

PROPAGATION_REQUIRES_NEW

Bajo este atributo de propagación, independientemente de si la persona que llama tiene una transacción, la persona que llama creará una nueva transacción.

  • El primer caso: la persona que llama no tiene transacción, la persona que llama creará una nueva transacción, por lo que no se pueden encontrar datos

  • El segundo caso: la persona que llama tiene una transacción, la persona que llama creará una nueva transacción, por lo que la persona que llama lanza una excepción sin afectar a la persona que llama, por lo que se pueden encontrar los datos

A continuación, demostramos el código.

Llamado

// REQUIRES_NEW传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void testRequiresNewHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.REQUIRES_NEW_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// REQUIRES_NEW传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void testRequiresNewNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.REQUIRES_NEW_NO_EXCEPTION+"')");
}

El ejemplo de la persona que llama es el mismo que el anterior, veamos directamente la ejecución

2019-10-16 16:29:20.296  INFO 15553 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 16:29:20.298  INFO 15553 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 1

Descubrimos que es lo mismo que nuestra inferencia, lo que indica que los asuntos de la persona que llama y los asuntos de la persona que llama no tienen ninguna relación. En este punto, debemos entender esta oración, independientemente de si hay una transacción actualmente, se iniciará una nueva transacción.

PROPAGATION_NOT_SUPPORTED

Independientemente de si la persona que llama tiene una transacción, la persona que llama no se ejecuta de manera transaccional

Los mismos dos ejemplos

  • El primer caso: el destinatario de la llamada no tendrá una transacción, luego se pueden encontrar los datos correspondientes después de que se lanza la excepción

  • El segundo caso: cuando la persona que llama tiene una transacción, la persona que llama también se ejecutará en un entorno sin transacciones, por lo que aún podemos encontrar los datos.

A continuación, verifique nuestra suposición

// NOT_SUPPORTED传播属性-被调用者有异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void testNotSupportHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NOT_SUPPORTS_HAS_EXCEPTION+"')");
    throw new RollbackException();
}

// NOT_SUPPORTED传播属性-被调用者无异常抛出
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED)
public void testNotSupportNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NOT_SUPPORTS_NO_EXCEPTION+"')");
}

Luego vea el resultado de la ejecución

2019-10-16 16:38:35.065  INFO 15739 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 1
2019-10-16 16:38:35.067  INFO 15739 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 1

Podemos ver que los datos se encontraron en los dos últimos casos. Según el efecto de demostración, esta oración debe entenderse. No se admite la transacción. Si hay una transacción actualmente, la transacción se suspenderá y no se ejecutará como una transacción.

PROPAGATION_NEVER

Si la persona que llama tiene una transacción, la persona que llama lanzará una excepción

No lo demostraré. Creo que todos entenderán que podemos encontrar los datos en el primer caso. En el segundo caso, debido a que la persona que llama está realizando una transacción, se lanzará una excepción.

PROPAGATION_NESTED

Bajo este atributo de propagación, la transacción de la persona que llama es un subconjunto de la transacción de la persona que llama.

Centrémonos en las características de las propiedades de propagación de NESTED

Con respecto a la relación entre transacciones anidadas, podemos demostrarlo con los siguientes tres ejemplos.

  • El primer caso: si no se pueden encontrar los datos, significa que la persona que llama iniciará una nueva transacción si la persona que llama no tiene ninguna transacción

  • El segundo caso: si no se encuentran datos, significa que los asuntos externos pueden afectar los asuntos internos.

  • El tercer caso: si se encuentran los datos, significa que los asuntos internos no afectan los asuntos externos.

A continuación, escribimos un código específico.

// NESTED传播属性-回滚事务
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testNestedHasException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_HAS_EXCEPTION+"')");
   // TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    throw new RollbackException();
}

// NESTED传播属性-不回滚事务
@Override
@Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED)
public void testNestedNoException() throws RollbackException {
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_NO_EXCEPTION+"')");
}

Entonces la próxima persona que llame será un poco diferente

@Override
@Transactional()
public void hasTransactionalNoException() throws RollbackException {
    // NESTED传播属性 - 调用者有事务,不抛异常  被调用者有异常
    jdbcTemplate.execute("INSERT INTO FOO (BAR) VALUES ('"+Global.NESTED_HAS_EXCEPTION_TWO+"')");
    fooService.testNestedHasException();
}

Luego ejecuta el efecto

2019-10-16 18:01:06.387  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第一种情况 0
2019-10-16 18:01:06.389  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第二种情况 0
2019-10-16 18:01:06.390  INFO 17172 --- [           main] c.e.t.t.TransactionApplication           : 第三种情况 1

Se puede ver que la esencia de las transacciones anidadas es que la capa externa afecta a la capa interna y la capa interna no afecta a la capa externa. Y REQUIRES_NEW no se afectan entre sí.

para resumir

Hasta ahora, todos hemos analizado los siete atributos de la comunicación. Desde el principio hasta el final de este artículo, nos hemos encontrado con algunos pozos. Algunos de ellos no se conocen en absoluto si no los practicas tú mismo, así que aún recomiendo lectores que lean este artículo. En el futuro, practicaré y demostraré varias situaciones por mí mismo. Solo así podré familiarizarme con ellas.

Dirección de Github

"

https://github.com/modouxiansheng/Doraemon

Supongo que te gusta

Origin blog.csdn.net/qq_39809613/article/details/106994709
Recomendado
Clasificación