Transacciones en Spring
Qué es una transacción
Transacción: Es la unidad de trabajo más pequeña para las operaciones de la base de datos. Es una serie de operaciones que se realizan como una sola unidad lógica de trabajo. Estas operaciones se envían como un sistema como un todo, ya sea ejecutado o no ejecutado; una transacción es un conjunto de operaciones indivisibles (Unidad lógica de trabajo)
En términos simples, una serie de operaciones para lograr un propósito determinado tienen éxito juntas (confirmación de transacción) o fallan juntas (reversión de transacción)
El ejemplo más común es la transferencia de dinero:
Xiao Ming transfiere dinero a Ruhua:
开启事务-------
① 从小明的账户扣除1000元
② 给如花的账户增加1000元
事务提交-------
Cualquier paso del ejemplo anterior hará que la transacción retroceda si hay un problema.
Desde llegar hasta casarse es la sumisión de los asuntos, y la mujer le pide al hombre que la persiga de nuevo. Una vez que los asuntos se revierten ~
Cuatro características del negocio
ACID es la característica básica de la transacción: fórmula (un aislamiento permanente original)
- Atomicidad: Una transacción es una operación atómica que consta de una serie de acciones. La atomicidad de la transacción asegura que las acciones se completen o sean completamente ineficaces.
- Coherencia: después de que se ejecuta la transacción, el estado de la base de datos es coherente con otras reglas comerciales, como el negocio de transferencias, independientemente de si la transacción se ejecuta con éxito o no, la suma de los saldos de las dos cuentas involucradas en la transferencia no debe modificarse.
- Aislamiento: Aislamiento significa que en operaciones concurrentes, se deben aislar diferentes transacciones, de modo que cada transacción concurrente no interfiera entre sí.
- Durabilidad: una vez que la transacción se envía con éxito, todas las operaciones de datos en la transacción deben persistir en la base de datos. Incluso si la base de datos falla inmediatamente después de que se envía la transacción, cuando se reinicia la base de datos, se debe garantizar que los datos se restauren a través de un cierto mecanismo.
Operaciones de transacciones nativas de JDBC
try {
// 设置是否自动提交
connection.setAutoCommit(false)
// 数据库操作 insert,update,delete
connection.commit()
} catch(Exception ex) {
// 回滚
connection.rollback()
} finally {
connection.setAutoCommit(true)
}
Nivel de aislamiento de transacciones
Los niveles de aislamiento de transacción de base de datos son 4, de bajo a alto son: Read uncomomitted(读取未被提交的数据)
, Read committed(读取以被提交的数据)
, Repeatable read(可重复读)
, Serializable(完全隔离)
. Además, en las operaciones concurrentes de transacciones, pueden producirse lecturas sucias, lecturas no repetibles, lecturas fantasma y pérdida de transacciones.
Cuatro niveles de aislamiento
Leer sin compromiso
La lectura no confirmada, como su nombre lo indica, es que una transacción puede leer los datos de otra transacción no confirmada, lo que resultará en lecturas sucias.
Leer comprometido
这种使用的概率比较高,因为很多时候我们就以最后一次读取的为准
Read commit, como su nombre lo indica, es que una transacción no puede leer datos hasta que se confirme otra transacción, lo que provocará lecturas no repetibles.
Lectura repetible
相当于加锁,MySQL的默认级别
La lectura repetida significa que cuando se comienzan a leer los datos (se inicia la transacción), las operaciones de modificación ya no están permitidas y pueden ocurrir lecturas fantasmas.
Serializable
El nivel más alto de aislamiento de transacciones. Bajo el nivel modificado, las transacciones se ejecutan en serie, lo que puede evitar lecturas sucias, lecturas no repetibles y lecturas fantasmas. Sin embargo, este nivel de aislamiento de transacciones es ineficiente y consume el rendimiento de la base de datos, por lo que generalmente no se usa
para resumir
El nivel de aislamiento de transacciones predeterminado de la mayoría de las bases de datos es : Read Committed
, como SqlServer, Oracle
El nivel de aislamiento predeterminado de MySQL es lectura repetible
Posibles problemas
Lectura sucia
读取了未提交的新事务,然后被回滚了
La transacción A lee los datos que aún no se han comprometido en la transacción B. Si la transacción B se revierte, A lee usando los datos incorrectos
No repetible
读取了提交的新事物,指更新操作
La lectura no repetible significa que para ciertos datos en la base de datos, múltiples consultas dentro del alcance de una transacción pero de regreso a diferentes valores, esto se debe al intervalo de consulta, modificado y enviado por otra transacción.
Una solución para resolver la lectura no repetible es ajustar el nivel de aislamiento.
Lectura fantasma
读取了提交的新事物,指增删操作
En la configuración de lectura múltiple de la transacción A, la transacción B realiza nuevas operaciones en los datos, lo que resulta en datos inconsistentes leídos por la transacción A varias veces
Otra comprensión de la lectura fantasma puede ser:
幻读就是指新增了数据记录条数,第一次查询数据记录数为1000,再次查询的时候,变成了1001,这个就是幻读
La diferencia entre lectura no repetible y lectura fantasma
Mucha gente tiende a confundir la lectura no repetible y la lectura fantasma, de hecho, las dos son algo similares. Pero la lectura no repetible se centra en actualizar y eliminar, mientras que la lectura fantasma se centra en insertar
- Lectura no repetible, solo los registros que cumplen las condiciones deben bloquearse
避免不可重复读需要锁行就行
- La lectura fantasma debe bloquear los registros que cumplen las condiciones y su cierre.
避免幻读则需要锁表
Entonces, la mayor diferencia entre la lectura no repetible y la lectura fantasma es cómo resolver los problemas que generan a través del mecanismo de bloqueo.
Transacción perdida
Se pierde el primer tipo de transacción.
称为:回滚丢失
Para el primer tipo de pérdida de transacción, por ejemplo, A y B están ejecutando un dato al mismo tiempo, y luego se ha enviado la transacción B, y luego se revierte una transacción, de modo que la operación de la transacción B se pierde debido a la reversión de una transacción.
El segundo tipo de transacción se pierde
称为:覆盖丢失
Para el segundo tipo de pérdida de transacción, también conocida como pérdida de cobertura, es que A y B ejecutan un dato juntos, y ambos obtienen un dato al mismo tiempo, luego la transacción B se envía primero, pero la transacción A se envía nuevamente, por lo tanto que cubre la transacción B
Cómo Spring configura las transacciones
具体说出一些关键的xml元素
Prepare la hoja de datos:
Clase de entidad:
public class User {
private Integer id;
private String name;
private Integer money;
}
Dao:
Servicio: un escenario de error por defecto
Transacción programática
Transacción de configuración XML: agregue el administrador de transacciones y la configuración de la plantilla del administrador de transacciones en applicationContext.xml
Administrador de transacciones de configuración del modo de anotación y plantilla de administrador de transacciones
Transacción declarativa
基于AspectJ XML方式
Nota: Basado en TransactionProxyFactoryBean, el método proxy es un método más antiguo, no lo describiremos aquí.
Elimine la configuración de la plantilla de gestión de transacciones en applicationContext.xml, que es la siguiente configuración:
<!-- 事务管理的模板 -->
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
Agregar definición de transacción y configuración de AOP
<!--基于AspectJ 申明式事务XML配置方式-->
<!-- 定义一个增强 -->
<tx:advice id="txAdvice"
transaction-manager="transactionManager">
<!-- 增强(事务)的属性的配置 -->
<tx:attributes>
<!-- isolation:DEFAULT ,事务的隔离级别。
propagation:事务的传播行为.
read-only:false,不是只读
timeout:-1
no-rollback-for:发生哪些异常不回滚
rollback-for:发生哪些异常回滚事务
-->
<tx:method name="transfer" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!-- aop配置定义切面和切点的信息 -->
<aop:config>
<!-- 定义切点:哪些类的哪些方法应用增强 -->
<aop:pointcut
expression="execution(* com.dk.beans.service..*.*(..))"
id="mypointcut" />
<!-- 定义切面: -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="mypointcut" />
</aop:config>
Cambiar la clase ejecutiva a la forma original
/**
* 沒有事務的转账的业务
* @param fromName
* @param toName
* @param money
*/
public void transfer(String fromName, String toName, Integer money) {
userDAO.out(fromName, money);// 转出钱
int x = 10;
if(x == 10)
throw new RuntimeException("出错啦!");
userDAO.in(toName, money);// 收入钱
}
Transacción declarativa basada en anotaciones:
configure @EnableTransactionManagement en la clase de configuración para habilitar la transacción. Eliminar @Bane relacionado con la transacción en la clase de anotación
Complete la configuración de la transacción a través de @Transactional por encima de la clase UserService o por encima del método:
@Service
@Transactional
public class UserService {
}
Las transacciones declarativas se pueden configurar según el método correspondiente al inicio de la transacción
<!-- 以insert开头的方法配置事务 -->
<tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/>
Características de propagación de transacciones de primavera
Se refiere a cómo debe proceder el método de transacción cuando otro método de transacción llama a un método de transacción. por ejemplo
public class PersonService {
@Transactional
public void laoda(){
System.out.println("老大的方法");
xiaodi();
}
@Transactional
public void xiaodi(){
System.out.println("小弟方法");
}
}
Es decir, cuando el método del jefe llama al método del hermano menor, ¿qué se debe hacer con los asuntos del hermano menor?
Suponiendo que el método del jefe sea anormal, ¿el hermano menor necesita retroceder?
Suponiendo que el método del hermano menor es anormal, ¿es necesario revertir el método del jefe?
Hacer nada
- PROPAGATION_NEVER: si no hay ejecución de transacción, si hay una excepción, se lanzará
- PROPAGATION_NOT_SUPPORTED: si no hay ejecución no transaccional, si hay una suspensión directa, entonces ejecución no transaccional
- Esto es propenso a estancarse
Dispensable
- PROPAGATION_SUPPORTS: Úselo si lo tiene, olvídelo si no lo tiene
Debe tener aventuras
- PROPAGATION_REQUIRES_NEW: Si hay transacciones nuevas, si hay transacciones originales, se suspenderán las originales. Es decir, las transacciones están completamente aisladas, una transacción no afecta a otras transacciones.
- PROPAGATION_NESTED: Si no es así, cree una nueva transacción; si la hay, anida otras transacciones en la transacción actual. Transacción anidada significa que la transacción externa es anormal y la transacción interna se revierte por completo
- PROPAGATION_REQUIRED: (configuración predeterminada) Si no es así, cree una nueva transacción; si la hay, únase a la transacción actual
- PROPAGATION_MANDATORY: Si no es así, lanza una excepción; si es así, usa la transacción actual.