true transaction transacciones requires_new framework example español ejemplo spring transactions

spring - transaction - Primavera @ Propagación transaccional de solo lectura



spring transaction propagation (4)

En primer lugar, dado que Spring no hace la persistencia en sí misma, no puede especificar qué significa exactamente readOnly exactamente. Este atributo es solo una sugerencia para el proveedor, el comportamiento depende, en este caso, de Hibernate.

Si especifica readOnly como true , el modo de descarga se establecerá como FlushMode.NEVER en la sesión de hibernación actual, lo que FlushMode.NEVER que la sesión FlushMode.NEVER la transacción.

Además, se llamará a setReadOnly (verdadero) en la conexión JDBC, que también es una sugerencia para la base de datos subyacente. Si su base de datos lo admite (lo más probable es que lo haga), esto tiene básicamente el mismo efecto que FlushMode.NEVER . FlushMode.NEVER , pero es más fuerte ya que ni siquiera puede vaciar manualmente.

Ahora veamos cómo funciona la propagación de transacciones.

Si no establece explícitamente readOnly en true , tendrá transacciones de lectura / escritura. Dependiendo de los atributos de la transacción (como REQUIRES_NEW ), a veces su transacción se suspende en algún momento, se inicia una nueva y finalmente se confirma, y ​​luego se reanuda la primera transacción.

OK, ya casi estamos allí. Veamos qué trae a readOnly en este escenario.

Si un método en una transacción de lectura / escritura llama a un método que requiere una transacción readOnly , el primero debería suspenderse, porque de lo contrario se produciría un vaciado / confirmación al final del segundo método.

A la inversa, si llama a un método desde una transacción readOnly que requiere lectura / escritura , nuevamente, el primero se suspenderá, ya que no se puede vaciar / confirmar, y el segundo método lo necesita.

En los casos readOnly-to-read-Only , y read / write-to-read / write , la transacción externa no necesita ser suspendida (a menos que especifique la propagación de lo contrario, obviamente).

Estoy experimentando con el uso del patrón de comando para permitir que mi capa web funcione con entidades de Hibernación en el contexto de una sola transacción (evitando así las excepciones de carga lenta). Sin embargo, ahora estoy confundido con cómo debo lidiar con las transacciones.

Mis comandos llaman a los métodos de capa de servicio que están anotados con @Transactional . Algunos de estos métodos de capa de servicio son de solo lectura, por ejemplo, @Transactional(readOnly=true) , y algunos son de lectura / escritura.

Mi capa de servicio expone un controlador de comandos que ejecuta los comandos que se le pasan en nombre de la capa web.

@Transactional public Command handle( Command cmd ) throws CommandException

Supongo que estoy en lo cierto al hacer transaccional el método handle() del controlador de comandos. Aquí es donde entra la confusión. Si la implementación de un comando hace llamadas a múltiples métodos de la capa de servicio, no hay forma de que el controlador de comandos sepa si las operaciones a las que se llama dentro del comando serán de solo lectura, lectura / escritura o una combinación de los dos.

No entiendo cómo funciona la propagación en este ejemplo. Si readOnly=true que hacer que el método handle() readOnly=true , entonces, ¿qué sucede si el comando llama a un método de capa de servicio que se anota con @Transactional(realOnly=false) ?

Apreciaría una mejor comprensión de esto y agradecería sus comentarios ...

Andrés


Llamar a readOnly = false desde readOnly = true no funciona ya que la transacción anterior continúa.

En su ejemplo, el método handle () en su capa de servicio está iniciando una nueva transacción de lectura-escritura. Si el método de manejo a su vez llama a los métodos de servicio que anotaron solo lectura, el de solo lectura no tendrá efecto ya que participará en la transacción de lectura-escritura existente.

Si es esencial que esos métodos sean de solo lectura, puede anotarlos con Propagation.REQUIRES_NEW, y luego iniciarán una nueva transacción de solo lectura en lugar de participar en la transacción de lectura-escritura existente.

Este es un ejemplo práctico: CircuitStateRepository es un repositorio JPA de datos de primavera.

BeanS llama a una transacción = Bean1 de solo lectura, que realiza una búsqueda y llama a una transacción = lectura-escritura Bean2 que guarda un nuevo objeto.

  • Bean1 inicia un tx de solo lectura.

31 09: 39: 44.199 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager - Creando una nueva transacción con el nombre [nz.co.vodafone.wcim.business.Bean1.startSomething]: PROPAGATION_REQUIRED, ISOLATION_DEFAULT, readOnly; ''''

  • El frijol 2 participa en él.

31 09: 39: 44.230 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager - Participando en una transacción existente

Nada está comprometido con la base de datos.

Ahora cambie Bean2 @Transactional anotación @Transactional para agregar propagation=Propagation.REQUIRES_NEW

  • Bean1 inicia un tx de solo lectura.

31 09: 31: 36.418 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager - Creando una nueva transacción con el nombre [nz.co.vodafone.wcim.business.Bean1.startSomething]: PROPAGATION_REQUIRED, ISOLATION_DEFAULT, readOnly; ''''

  • Bean2 comienza una nueva lectura-escritura tx

31 09: 31: 36.449 [pool-1-thread-1] DEBUG osorm.jpa.JpaTransactionManager - Suspendiendo la transacción actual, creando una nueva transacción con el nombre [nz.co.vodafone.wcim.business.Bean2.createSomething]

Y los cambios realizados por Bean2 ahora están comprometidos con la base de datos.

Aquí está el ejemplo, probado con datos de primavera, hibernación y oráculo.

@Named public class BeanS { @Inject Bean1 bean1; @Scheduled(fixedRate = 20000) public void runSomething() { bean1.startSomething(); } } @Named @Transactional(readOnly = true) public class Bean1 { Logger log = LoggerFactory.getLogger(Bean1.class); @Inject private CircuitStateRepository csr; @Inject private Bean2 bean2; public void startSomething() { Iterable<CircuitState> s = csr.findAll(); CircuitState c = s.iterator().next(); log.info("GOT CIRCUIT {}", c.getCircuitId()); bean2.createSomething(c.getCircuitId()); } } @Named @Transactional(readOnly = false) public class Bean2 { @Inject CircuitStateRepository csr; public void createSomething(String circuitId) { CircuitState c = new CircuitState(circuitId + "-New-" + new DateTime().toString("hhmmss"), new DateTime()); csr.save(c); } }


Parece ignorar la configuración de la transacción activa actual, solo aplica la configuración a una nueva transacción:

org.springframework.transaction.PlatformTransactionManager TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException Return a currently active transaction or create a new one, according to the specified propagation behavior. Note that parameters like isolation level or timeout will only be applied to new transactions, and thus be ignored when participating in active ones. Furthermore, not all transaction definition settings will be supported by every transaction manager: A proper transaction manager implementation should throw an exception when unsupported settings are encountered. An exception to the above rule is the read-only flag, which should be ignored if no explicit read-only mode is supported. Essentially, the read-only flag is just a hint for potential optimization.


Por defecto, la propagación de la transacción es REQUERIDA, lo que significa que la misma transacción se propagará de un llamante transaccional a un destinatario transaccional. En este caso también se propagará el estado de sólo lectura. Por ejemplo, si una transacción de solo lectura llamará a una transacción de lectura-escritura, toda la transacción será de solo lectura.

¿Podría usar el patrón Abrir sesión en vista para permitir la carga diferida? De esa manera, su método de manejo no necesita ser transaccional en absoluto.