事务框架
框架并不提供对事务的实现,但是提供规约,接口如下:
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
如果在类路径中,发现JPA框架,事务的实现将采用JPA提供的方式,如下:
public class JpaTransactionManager
extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
//...
}
其中==AbstractPlatformTransactionManager== 继承 ==PlatformTransactionManager==,如下;
public abstract class AbstractPlatformTransactionManager
implements PlatformTransactionManager, Serializable {
这是spring框架对事务支持的大概方式。
声明式事务
这是框架建议使用的方式,粒度到方法级别(这也是一直被诟病的地方),如下:
public class TransactionTest{
@Transactional(rollbackFor = Exception.class)
public String doFunc(){
try{
//其他业务逻辑
//如果doFunc()函数正常结束,事务自动提交
}
catch(Exception ex){
//如果发生异常,事务会自动回滚
throw new ex;
}
}
}
有几个限制:
- doFunc()方法必须是public才可以,spring认为只有通过外部调用才会触发事务,private只提供内部调用不触发事务;
- @Transactional(rollbackFor = Exception.class)必须指定触发回滚的异常类型,因为默认只有RuntimeException类型异常才会触发回滚
声明式事务最小粒度到方法级别,如果领域划分不清晰,会导致相关事务很大,如果数据库隔离级别设定不合理,将会非常占用资源,所以很多项目中都使用了编程式事务。
编程式事务
在事务框架中介绍了事务实现的大概方式,如果类路径中提供了JPA,spring boot会根据配置文件自动生成JpaTransactionManager的bean,在项目中可以直接使用,如下:
@Autowired
JpaTransactionManager jpaTransactionManager;
注入后既可使用,比较方便。 如果允许,建议把相关内容封装在自定义的公共里面 使用方式也比较简单,如下:
//获取当前事务状态
private TransactionStatus status;
public void beginTransaction()
{
status = jpaTransactionManager.getTransaction(TransactionDefinition.withDefaults());
}
//提交
public void commit()
{
jpaTransactionManager.commit(status);
}
//回滚
public void rollback()
{
jpaTransactionManager.rollback(status);
}
通过上面的简单封装,如下示例调用:
public void add()
{
try
{
this.beginTransaction();
// do something
this.commit();
}
catch (RuntimeException ex)
{
this.rollback();
}
}
大概就这么简单。
针对嵌套事务需要构建还原点,对开发人员要求比较高,项目中并不建议使用。
事务扩展知识
这里提供一个链接,其中对 事务传递、隔离级别做了介绍,有兴趣的朋友可以拜读: