2016年/04月/16日
首页回退
spring的事务管理
一直比较好奇spring是如何在数据库连接上实现各种事务传播行为的,最近抽空看了他的源码,做个简单的笔记,spring是一个典型的无状态事务管理框架,在一次请求过程中
事务被界定在业务service的执行边界,这个和数据源配合得很好,可是类似hibernate和jpa的事务会破坏这个抽象,有osiv等问题,发现大量的公司都是采用mybatis或者jdbc template,所以很少有人知道这些问题了.
无框架事务
首先我们看看在不用任何框架的前提下,如果使用原生的jdbc api实现事务代码的编写,jdbc规范是一个典型的API和SPI设计,代码中省去try catch,第一步是加载驱动
如果不关闭自动提交,jdbc的sql每次在连接上执行都会产生一个事务.
jdbc的设计会引入大量的check exception,所以我们必须要写大量的模板代码,spring使用匿名内部类的方法是在内部模拟了类似ruby的代码块闭包行为类优雅的处理了这类问题.
数据库连接是一个昂贵的服务器资源,所以我们要基于连接池技术来优化,使用连接池,我们需要知道另外一个借口DataSource,它可以从应用服务器中通过JNDI查找出来,或者使用第三方的数据源软件.
核心接口
org.springframework.transaction.PlatformTransactionManager
org.springframework.transaction.TransactionDefinition
org.springframework.transaction.TransactionStatus
Datasource事务分析
org.springframework.jdbc.datasource.DataSourceTransactionManager
资源管理
TransactionSynchronizationManager
传播行为的实现
如何实现挂起
陷阱
注解指向Manager
@Transactional注解可以标注在类和方法上,也可以标注在定义的接口和接口方法上。
如果我们在接口上标注@Transactional注解,会留下这样的隐患:因为注解不能被继承,所以业务接口中标注的@Transactional注解不会被业务实现类继承。所以可能会出现不启动事务的情况。所以,Spring建议我们将@Transaction注解在实现类上
@Transactional在配置文件中,默认情况下,会自动使用名称为transactionManager的事务管理器。所以,如果定义的事务管理器名称为transactionManager,那么就可以直接使用
如果我们要程序中使用多个事务管理器(主要是针对多数据源的情况),要在注解上指定事务管理器
异常回滚行为
Spring框架的事务基础架构代码将默认地 只 在抛出运行时和unchecked exceptions时才标识事务回滚。 也就是说,当抛出一个RuntimeException 或其子类例的实例时。(Errors 也一样 - 默认地 - 标识事务回滚。)从事务方法中抛出的Checked exceptions将 不 被标识进行事务回滚
代理的问题
由于Spring事务管理是基于接口代理或动态字节码技术,通过AOP实施事务增强的。对于基于接口动态代理的AOP事务增强来说,由于接口的方法是public的,这就要求实现类的实现方法必须是public的(不能是protected,private等),同时不能使用static的修饰符。所以,可以实施接口动态代理的方法只能是使用“public”或“public final”修饰符的方法,其它方法不可能被动态代理,相应的也就不能实施AOP增强,也即不能进行Spring事务增强了。
基于CGLib字节码动态代理的方案是通过扩展被增强类,动态创建子类的方式进行AOP增强植入的。由于使用final,static,private修饰符的方法都不能被子类覆盖,相应的,这些方法将不能被实施的AOP增强。所以,必须特别注意这些修饰符的使用,以免不小心成为事务管理的漏网之鱼。