有人能通过真实的例子解释@Transactional注释中的隔离和传播参数是用于什么吗?
基本上,我应该在什么时候以及为什么选择更改它们的默认值。
有人能通过真实的例子解释@Transactional注释中的隔离和传播参数是用于什么吗?
基本上,我应该在什么时候以及为什么选择更改它们的默认值。
当前回答
我们可以为此添加:
@Transactional(readOnly = true)
public class Banking_CustomerService implements CustomerService {
public Customer getDetail(String customername) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateCustomer(Customer customer) {
// do something
}
}
其他回答
你可以这样用:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public EventMessage<ModificaOperativitaRapporto> activate(EventMessage<ModificaOperativitaRapporto> eventMessage) {
//here some transaction related code
}
你也可以用这个东西:
public interface TransactionStatus extends SavepointManager {
boolean isNewTransaction();
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
}
我们可以为此添加:
@Transactional(readOnly = true)
public class Banking_CustomerService implements CustomerService {
public Customer getDetail(String customername) {
// do something
}
// these settings have precedence for this method
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateCustomer(Customer customer) {
// do something
}
}
事务表示数据库的一个工作单元。具有自己的txns(或没有txn)的多个服务中的事务行为称为事务传播。事务隔离定义了当两个事务并发作用于同一个数据库实体时的数据库状态。
TransactionDefinition接口,该接口定义了与spring兼容的事务属性。@Transactional注释描述方法或类上的事务属性。
@Autowired
private TestDAO testDAO;
@Transactional(propagation=TransactionDefinition.PROPAGATION_REQUIRED,isolation=TransactionDefinition.ISOLATION_READ_UNCOMMITTED)
public void someTransactionalMethod(User user) {
// Interact with testDAO
}
传播(复制):用于事务间的关系。(类似于Java线程间通信)
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
| value | Propagation | Description |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
| -1 | TIMEOUT_DEFAULT | Use the default timeout of the underlying transaction system, or none if timeouts are not supported. |
| 0 | PROPAGATION_REQUIRED | Support a current transaction; create a new one if none exists. |
| 1 | PROPAGATION_SUPPORTS | Support a current transaction; execute non-transactionally if none exists. |
| 2 | PROPAGATION_MANDATORY | Support a current transaction; throw an exception if no current transaction exists. |
| 3 | PROPAGATION_REQUIRES_NEW | Create a new transaction, suspending the current transaction if one exists. |
| 4 | PROPAGATION_NOT_SUPPORTED | Do not support a current transaction; rather always execute non-transactionally. |
| 5 | PROPAGATION_NEVER | Do not support a current transaction; throw an exception if a current transaction exists. |
| 6 | PROPAGATION_NESTED | Execute within a nested transaction if a current transaction exists. |
+-------+---------------------------+------------------------------------------------------------------------------------------------------+
隔离:隔离是数据库事务的ACID(原子性、一致性、隔离性、持久性)属性之一。隔离决定了事务完整性如何对其他用户和系统可见。它用于资源锁定,即并发控制,确保在给定的点上只有一个事务可以访问资源。
锁定感知:隔离级别决定持有锁的持续时间。
+---------------------------+-------------------+-------------+-------------+------------------------+
| Isolation Level Mode | Read | Insert | Update | Lock Scope |
+---------------------------+-------------------+-------------+-------------+------------------------+
| READ_UNCOMMITTED | uncommitted data | Allowed | Allowed | No Lock |
| READ_COMMITTED (Default) | committed data | Allowed | Allowed | Lock on Committed data |
| REPEATABLE_READ | committed data | Allowed | Not Allowed | Lock on block of table |
| SERIALIZABLE | committed data | Not Allowed | Not Allowed | Lock on full table |
+---------------------------+-------------------+-------------+-------------+------------------------+
阅读感悟:出现以下3种主要问题:
脏读:从另一个tx(事务)中读取未提交的数据。 不可重复读取:从另一个tx读取已提交的更新。 幻影读取:从另一个tx读取已提交的insert和/或delete
下面的图表显示了哪个事务隔离级别可以解决哪些并发问题:
+---------------------------+--------------+----------------------+----------------+
| Isolation Level Mode | Dirty reads | Non-repeatable reads | Phantoms reads |
+---------------------------+--------------+----------------------+----------------+
| READ_UNCOMMITTED | X | X | X |
| READ_COMMITTED (Default) | solves | X | X |
| REPEATABLE_READ | solves | solves | X |
| SERIALIZABLE | solves | solves | solves |
+---------------------------+--------------+----------------------+----------------+
为例子
我已经用不同的传播模式运行了outerMethod, method_1和method_2。
下面是不同传播模式的输出。
外部方法
@Transactional
@Override
public void outerMethod() {
customerProfileDAO.method_1();
iWorkflowDetailDao.method_2();
}
Method_1
@Transactional(propagation=Propagation.MANDATORY)
public void method_1() {
Session session = null;
try {
session = getSession();
Temp entity = new Temp(0l, "XXX");
session.save(entity);
System.out.println("Method - 1 Id "+entity.getId());
} finally {
if (session != null && session.isOpen()) {
}
}
}
Method_2
@Transactional()
@Override
public void method_2() {
Session session = null;
try {
session = getSession();
Temp entity = new Temp(0l, "CCC");
session.save(entity);
int i = 1/0;
System.out.println("Method - 2 Id "+entity.getId());
} finally {
if (session != null && session.isOpen()) {
}
}
}
OuterMethod -没有事务 传播。mandatory) - Method_2 -仅事务注释 method_1将抛出不存在事务的异常
OuterMethod -没有事务 Method_1 -仅事务注释 方法2 -传播。mandatory) 输出:method_2将抛出不存在事务的异常 输出:method_1将保存数据库中的记录。
OuterMethod -带有事务 Method_1 -仅事务注释 方法2 -传播。mandatory) 输出:method_2将记录保存在数据库中。 输出:method_1将保存数据库中的记录。 方法1和方法2都使用了Main Outer现有事务
OuterMethod -带有事务 传播。mandatory) Method_2 -仅事务注释并抛出异常 输出:没有记录保存在数据库中意味着回滚完成。
OuterMethod -带有事务 方法1 -传播。requires_new) Method_2 - Propagation.REQUIRES_NEW)并抛出1/0异常 输出:method_2将抛出异常,因此method_2记录不被保存。 输出:method_1将保存数据库中的记录。 输出:method_1没有回滚
事务隔离和事务传播虽然相关,但显然是两个完全不同的概念。在这两种情况下,通过使用声明式事务管理或编程式事务管理在客户端边界组件上自定义默认值。每个隔离级别和传播属性的详细信息可以在下面的参考链接中找到。
事务隔离
对于给定的两个或多个正在运行的事务/到数据库的连接,一个事务中的查询所做的更改如何以及何时对另一个事务中的查询产生影响/可见。它还涉及到将使用哪种数据库记录锁定将此事务中的更改与其他事务隔离,反之亦然。这通常是由参与事务的数据库/资源实现的。
.
事务传播
In an enterprise application for any given request/processing there are many components that are involved to get the job done. Some of this components mark the boundaries (start/end) of a transaction that will be used in respective component and it's sub components. For this transactional boundary of components, Transaction Propogation specifies if respective component will or will not participate in transaction and what happens if calling component already has or does not have a transaction already created/started. This is same as Java EE Transaction Attributes. This is typically implemented by the client transaction/connection manager.
参考:
Spring事务管理 Wiki事务隔离(数据库系统) 关于事务隔离级别的Oracle Java EE事务属性(传播) Spring框架事务传播