La principal investigación en este artículo es la propagación de transacciones de primavera y sus principios de implementación, que se introducen de la siguiente manera.
Spring es actualmente un estándar de facto para el desarrollo de Java, gracias a su conveniencia, funciones completas y fácil de usar. Durante el proceso de desarrollo, operar DB es una operación muy común, y cuando se trata de DB, implica transacciones. Durante el proceso de desarrollo normal de las transacciones, incluso si no lo nota, no habrá efectos secundarios en la ejecución normal del programa. Sin embargo, si se produce una excepción y la transacción no se maneja correctamente, pueden ocurrir resultados inesperados. La primavera ha encapsulado varias operaciones en términos de transacciones, especialmente la aparición de transacciones declarativas, lo que hace que el desarrollo sea más cómodo. Spring expande transacciones y admite la definición de atributos de propagación múltiple, que también es el foco de este artículo.
No hablando estrictamente, una transacción es la abreviatura de múltiples operaciones. Estas operaciones surtan efecto o ninguna de ellas surta efecto (equivalente a no ser ejecutadas). Un proceso de operación general se simplifica de la siguiente manera:
Pruebe {Connection conn = getConnection (); // realizar algunas operaciones de base de datos} Catch (Exception e) {conn.rollback ();} finalmente {conn.close ();}Se pueden ver algunos problemas en el código anterior:
Spring proporciona transacciones declarativas, por lo que no tenemos que prestar atención a la implementación específica de la capa subyacente, y bloquea muchos detalles de implementación diferentes de la capa subyacente. Para respaldar el control fino de las transacciones por múltiples empresas complejas, Spring proporciona los atributos de propagación de las transacciones y combinado con transacciones declarativas, se ha convertido en una importante herramienta de transacción.
En la clase de definición de transacciones, Spring proporciona 6 propiedades de propagación, que se explican con ejemplos simples.
Recordatorio cálido: lo siguiente mencionado que une la transacción actual se refiere al uso de la misma conexión en la parte inferior, pero el objeto de estado de la transacción se puede recrear y no lo afecta. El artículo mencionó que solo hay una transacción en la actualidad, lo que significa que la conexión subyacente se comparte y no le importa cuántos objetos de estado de transacción (Transactionstatus) se crean.
Descripción: Si ya existe una transacción, únase a la transacción. Si no hay transacción, cree una transacción. Este es el valor de atributo de propagación predeterminado.
Veamos un pequeño ejemplo, el código es el siguiente:
@TransactionalPublic Void Service () {ServiceA (); servicioB ();}@transaccionAlservicea ();@transaccionAlserviceB ();ServiceA y ServiceB declaran transacciones. Por defecto, propagation = propagation_required. Durante todo el proceso de llamadas de servicio, solo hay una transacción compartida. Cuando ocurra cualquier excepción, todas las operaciones serán retrocedidas.
Descripción: Si ya existe una transacción, une a la transacción, de lo contrario se crea una llamada transacción vacía (se puede considerar que no es una ejecución de la transacción).
Veamos un pequeño ejemplo, el código es el siguiente:
public void Service () {ServiceA (); tirar nueva runtimeException ();}@transaccional (propagation = propagation.supports) serviceA ();Actualmente no hay transacción cuando ServiceA se está ejecutando, por lo que la excepción lanzada en el servicio no hará que Servicea se regaño.
Echemos un vistazo a otro pequeño ejemplo, el código es el siguiente:
Public void Service () {ServiceA ();}@transaccional (propagation = propagation.supports) serviceA () {do sql 1 1/0; hacer sql 2}Dado que ServiceA no tiene transacciones cuando se ejecuta, en este momento, si la fuente de datos subyacente defaultautOcommit = true, entonces SQL1 es efectivo. Si defaultAutOcommit = false, entonces SQL1 no es válido. Si el servicio tiene la etiqueta @Transactional, ServiceA comparte las transacciones del servicio (ya no confía en el defaultAutOcommit). En este momento, Servicea se retrocede.
Descripción: Actualmente debe existir una transacción, de lo contrario, se lanzará una excepción.
Veamos un pequeño ejemplo, el código es el siguiente:
public void Service () {ServiceB (); ServiceA ();} ServiceB () {do sql} @transactional (propagation = propagation.mandatory) serviceA () {do sql}En este caso, la ejecución del servicio organizará una excepción. Si defaultAutOcommit = true, ServiceB no volverá a retroceder. Si defaultAutOcommit = false, la ejecución de ServiceB no será válida.
Nota: Si actualmente existe una transacción, primero encapsula el contenido relacionado con la transacción actual en una entidad, luego recree una nueva transacción, acepte esta entidad como parámetro y úselo para la recuperación de la transacción. Una declaración más contundente es suspender la transacción actual (no se necesita transacción) y crear una nueva transacción. En este caso, no hay dependencia entre las dos transacciones, y la nueva transacción se puede retirar hacia atrás, pero la transacción externa continúa ejecutándose.
Veamos un pequeño ejemplo, el código es el siguiente:
@TransactionalPublic Void Service () {ServiceB (); intente {ServiceA (); } catch (Exception e) {}} ServiceB () {do sql} @transactional (propagation = propagation.requires_new) serviceA () {do sql 1 1/0; hacer sql 2}Al llamar a la interfaz de servicio, dado que ServiceA usa Requies_new, creará una nueva transacción. Sin embargo, debido a que Servicea lanza una excepción de tiempo de ejecución, Servicea se retrocede. En el método de servicio, se capturan excepciones, por lo que ServiceB se envía normalmente. Tenga en cuenta que el código de captura intente en el servicio es necesario, de lo contrario, el servicio lanzará una excepción, lo que provocará que el servicioB se retire.
Nota: Si actualmente existe una transacción, suspenda la transacción actual, y luego el nuevo método se ejecuta en un entorno sin transacciones y en un entorno sin transacciones de primavera, la confirmación de SQL depende por completo del valor de la propiedad predeterminada.
Veamos un pequeño ejemplo, el código es el siguiente:
@TransactionalPublic Void Service () {ServiceB (); serviceA ();} servicioB () {do sql} @transactional (propagation = propagation.not_supported) serviceA () {do sql 1 1/0; hacer sql 2}Cuando se llama al método de servicio, se lanza una excepción cuando se ejecuta el código 1/0 en el método ServiceA. Dado que ServiceA se encuentra en un entorno libre de transacciones, si SQL1 es efectivo depende del valor de DefaultAutOcommit. Cuando defaultautOcommit = true, SQL1 es efectivo, pero ServiceB se volverá hacia atrás porque el servicio arroja una excepción.
Descripción: Si actualmente una transacción está presente, se lanza una excepción, de lo contrario, el código se ejecuta en un entorno sin transacciones.
Veamos un pequeño ejemplo, el código es el siguiente:
public void Service () {ServiceB (); ServiceA ();} ServiceB () {do SQL} @Transactional (propagation = propagation.never) ServiceA () {do sql 1 1/0; hacer sql 2}Después del ejemplo de ejemplo de ejemplo anterior, si defaultautOcommit = true, el método ServiceB y SQL1 en ServiceA entrarán en vigencia.
Nota: Si actualmente existe una transacción, use la tecnología SavePoint para guardar el estado de transacción actual, y luego la capa subyacente comparte una conexión. Cuando se produce un error dentro de la anidada, volverá al estado de SavePoint por sí solo. Mientras sea una excepción por el exterior, puede continuar cometiendo transacciones externas sin ser perturbadas por el negocio integrado. Sin embargo, si la transacción externa arroja una excepción, toda la transacción grande se volverá hacia atrás.
Nota: El administrador de transacciones de configuración de Spring debe especificar activamente NestedTransActionAllowed = True, como se muestra a continuación:
<bean id = "dataTransactionManager"> <Property Name = "DataSource" ref = "DataDataSource" /> <Property Name = "NestedTransactionAllowed" Value = "True" /> < /bean>
Ver un pequeño ejemplo, el código es el siguiente:
@TransactionalPublic Void Service () {ServiceA (); intente {ServiceB (); } catch (Exception e) {}} ServiceA () {do sql} @transactional (propagation = propagation.nested) serviciob () {do sql1 1/0; hacer sql2}ServiceB es un servicio integrado, y se lanza una excepción de tiempo de ejecución internamente, por lo que ServiceB se remonta. Desde que el servicio obtuvo la excepción, Servicea puede enviarlo normalmente.
Echemos un vistazo a otro ejemplo, el código es el siguiente:
@TransactionalPublic Void Service () {ServiceA (); servicioB (); 1/0;}@transaccional (propagation = propagation.nested) serviceA () {do sql} serviciob () {do sql}Dado que el servicio arroja una excepción, todo el método de servicio se volverá hacia atrás. (Esto es diferente de la propagation_requires_new. Los servicios incrustados en modo anidado se volverán hacia atrás por excepciones de transacciones externas).
Los ejemplos anteriores ilustran varios atributos de propagación proporcionados por las transacciones de primavera se utilizan para satisfacer una variedad de diferentes necesidades comerciales, lo que puede determinar el negocio. A continuación, echemos un vistazo a lo que las dependencias técnicas más importantes de Spring implementan estos atributos de propagación. Esta sección enumera la propagación_requires_new y la propagación.
El siguiente código llame:
@TransactionalPublic Void Service () {ServiceB (); intente {ServiceA (); } catch (Exception e) {}}@transaccional (propagation = propagation.requires_new) serviceA () {do sql 1 1/0; hacer sql 2} serviciob () {do SQL}El esquema de ejecución es el siguiente:
a. Cree un objeto de estado de transacción, obtenga una nueva conexión, restablezca el autocommit, FetchSize, TimeOut y otras propiedades de la conexión
b. Unir la conexión a la variable de threadlocal
do. En espera de la transacción actual, encapsulando el objeto de estado de la transacción actual, la conexión y otra información en un objeto SpendedResources, que puede usarse para la recuperación
d. Cree un nuevo objeto de estado de transacción, vuelva a ascender una nueva conexión, restablezca el autocommit, la obtención de tiempo, el tiempo de espera y otras propiedades de la nueva conexión. Al mismo tiempo, guarde el objeto suspendida para la recuperación de la transacción y une la nueva conexión a la variable de threadlocal (operación de sobrescribencia)
mi. Vea una excepción, retrocede la conexión en ThreadLocal, restaure los parámetros de conexión, cierre la conexión y restaure los recursos suspendidos
F. Envíe la conexión en la variable de ThreadLocal (que hace que se envíe el servicioB), restaure los parámetros de conexión, cierre la conexión y devuelva la conexión a la fuente de datos
Entonces, el resultado de la ejecución del programa es que ServiceA se retrocede y ServiceB se presenta con éxito.
El siguiente código llame:
@TransactionalPublic Void Service () {ServiceA (); intente {ServiceB (); } catch (Exception e) {}} ServiceA () {do sql} @transactional (propagation = propagation.nested) serviciob () {do sql1 1/0; hacer sql2}El esquema de ejecución es el siguiente:
a. Cree un objeto de estado de transacción, obtenga una nueva conexión, restablezca el autocommit, FetchSize, TimeOut y otras propiedades de la conexión
b. Unir la conexión a la variable de threadlocal
do. Marque el uso del objeto de estado de transacción actual, obtenga el objeto de conexión ThreadLocal, guarde el punto de guardado de la conexión actual y se utiliza para la recuperación de excepciones. En este momento, el punto de guardado es el estado después de ejecutar el servicio
d. Obtenga una excepción y use SavePoint en C para la reversión de la transacción, es decir, revertir el estado al estado después de ejecutar ServiceA. Todas las ejecuciones de métodos de servicioB no surtan efecto
mi. Obtenga el objeto de conexión en ThreadLocal, envíe transacciones, restauración de propiedades de conexión, Cerrar conexión
Basado en la fuente de datos subyacente, Spring utiliza ThreadLocal, SavePoint y otros puntos técnicos para realizar una variedad de atributos de propagación de transacciones, lo que facilita la implementación de varios servicios complejos. Solo al comprender el principio de los atributos de propagación podemos controlar mejor las transacciones de resorte. Las transacciones de retroceso de primavera se basan en la captura de excepciones. De manera predeterminada, las transacciones solo se volverán hacia atrás si se lanzan RuntimeException y Error. Por supuesto, se puede configurar. Para obtener más información, puede consultar la anotación @Transactional.
Las transacciones declarativas de Spring nos traen una gran comodidad. Para hacer un buen uso de esta arma, todavía es necesario comprender los principios subyacentes. Este artículo es solo la punta del iceberg de las transacciones de primavera. Los lectores pueden explorar en profundidad sobre esta base.
Lo anterior es todo el contenido de este artículo sobre la propagación de la transacción de primavera y sus principios de implementación. Espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a otros temas relacionados en este sitio. Si hay alguna deficiencia, deje un mensaje para señalarlo. ¡Gracias amigos por su apoyo para este sitio!