MySQL Spring框架下事务的挂起工作原理简述
在开发和设计应用程序时,保证数据的一致性和完整性是最为重要的问题之一。事务(transaction)机制被广泛应用在关系型数据库中,目的是保证对多个数据库操作的统一性和原子性。Spring框架提供了非常好的支持和管理事务的能力,它使用声明式的方式定义事务操作,同时也支持编程式管理,使得事务功能的实现变得更加便捷和灵活。
在Spring框架中,事务的挂起功能是非常有用的。例如,当应用程序调用外部的系统(比如Web服务)时,外部的系统可能需要很长时间才能返回响应结果,这个时候应用程序需要保持数据库事务的一致性,但又不能一直阻塞,因此需要挂起当前事务并进行其他任务,待外部系统返回结果时再恢复原有的事务状态。Spring框架通过提供
“`@Transactional“`注解的一些特性来实现这一功能。
阅读更多:MySQL 教程
Spring事务的注解特性
1. propagation属性
“`propagation“`属性定义了事务如何在方法间传递,一共有7种处理方式。
- REQUIRED:如果当前存在事务,则把方法嵌入其中执行,否则开启一个新的事务。
- SUPPORTS:如果当前存在事务,则把方法嵌入其中执行,否则不执行事务处理。
- MANDATORY:如果当前存在事务,则把方法嵌入其中执行,否则抛出异常。
- REQUIRES_NEW:开启一个新的事务来执行方法,如果当前存在事务则挂起它。
- NOT_SUPPORTED:不执行事务处理,如果一个事务已经存在则挂起它。
- NEVER:不执行事务处理,如果当前存在事务则抛出异常。
- NESTED:如果当前存在事务,则在事务内部创建一个嵌套事务,否则与
“`REQUIRED“`的处理方式相同。
2. timeout属性
“`timeout“`属性定义了事务在多长时间内恢复之前,如果超时则回滚事务。
3. rollbackFor属性
“`rollbackFor“`属性定义了可以抛出哪些类型的异常来使得事务回滚。
Spring的事务挂起机制
对于一个开启事务的方法,如果需要在某个阶段挂起事务,可以使用
“`TransactionSynchronizationManager“`类提供的方法来实现。
@Service
public class MyService {
@Autowired
private MyDAO myDAO;
@Autowired
private PlatformTransactionManager transactionManager;
@Transactional
public void doSomeBusinessService() throws InterruptedException {
// 执行一些业务逻辑
// 挂起事务
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
// 调用外部服务
ExternalService service = new ExternalService();
service.doSomeExtenralWork();
// 恢复事务
transactionManager.commit(transactionStatus);
// 继续完成剩余的业务逻辑
}
}
从上面的示例代码可以看出,在方法的开始处,使用
“`DefaultTransactionDefinition“`类创建了一个新的事务定义,再使用“`transactionManager.getTransaction()“`方法开启事务并获得一个事务状态,这个方法会返回当前事务的状态,我们可以保存在一个变量中以便稍后恢复这个事务。在执行一些业务逻辑后,如果需要挂起事务,可以直接调用“`TransactionSynchronizationManager“`类的“`suspend()“`方法,这个方法会挂起当前线程的事务状态。
@Service
public class ExternalService {
public void doSomeExternalWork() throws InterruptedException {
// 执行一些耗时的任务,模拟外部系统调用
Thread.sleep(5000);
}
}
在外部服务中,模拟了一个需要执行5秒钟的任务,这个任务会占用当前线程5秒钟,这个时间可能会很长,如果直接阻塞在这里等待,会对应用程序的性能产生影响。因此,Spring框架提供了
“`waitForTransactionToComplete()“`方法,可以让方法在事务完成前一直处于等待状态。
@Service
public class MyService {
@Autowired
private MyDAO myDAO;
@Autowired
private PlatformTransactionManager transactionManager;
@Transactional
public void doSomeBusinessService() throws InterruptedException {
// 执行一些业务逻辑
// 挂起事务
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
// 调用外部服务
ExternalService service = new ExternalService();
service.doSomeExtenralWork();
TransactionSynchronizationManager.waitForTransactionToComplete(transactionStatus);
// 恢复事务
transactionManager.commit(transactionStatus);
// 继续完成剩余的业务逻辑
}
}
在上面的示例中,调用
“`ExternalService“`类的“`doSomeExternalWork()“`方法时,使用了“`TransactionSynchronizationManager“`类的“`waitForTransactionToComplete()“`方法来等待事务完成,这个方法在执行时将一直阻塞等待当前事务的完成。
当外部系统返回响应结果后,需要恢复之前挂起的事务状态,可以直接调用
“`TransactionSynchronizationManager“`类的“`resume()“`方法即可。在恢复的时候注意,需要使用之前获取的事务状态变量版本来恢复。
@Service
public class MyService {
@Autowired
private MyDAO myDAO;
@Autowired
private PlatformTransactionManager transactionManager;
@Transactional
public void doSomeBusinessService() throws InterruptedException {
// 执行一些业务逻辑
// 挂起事务
TransactionStatus transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
// 调用外部服务
ExternalService service = new ExternalService();
service.doSomeExtenralWork();
TransactionSynchronizationManager.waitForTransactionToComplete(transactionStatus);
// 恢复事务
transactionManager.commit(transactionStatus);
transactionStatus = transactionManager.getTransaction(new DefaultTransactionDefinition());
TransactionSynchronizationManager.resume(transactionStatus);
// 继续完成剩余的业务逻辑
}
}
在上面的代码示例中,恢复时需要重新获取一个新的事务状态,并将其绑定到当前线程上,在恢复之后就可以继续执行剩余的业务逻辑了。
总结
在Spring框架中,事务的挂起功能对于应用程序来说是非常有用的。通过使用
“`TransactionSynchronizationManager“`类提供的方法,我们可以挂起和恢复事务状态,以便处理一些需要较长时间等待的操作,同时又保证了数据的一致性和完整性。在使用这个功能的时候,需要注意事务的传递机制和使用“`waitForTransactionToComplete()“`方法等待事务的完成。