1 引用tcc-transaction
在服务调用方和提供方项目中需要引用tcc-transaction-spring jar包,如使用maven依赖:
org.mengyun
tcc-transaction-spring
${project.version}
2 加载tcc-transaction.xml配置
启动应用时,需要将tcc-transaction-spring jar中的tcc-transaction.xml加入到classpath中。如在web.xml中配置:
2 加载tcc-transaction.xml配置
启动应用时,需要将tcc-transaction-spring jar中的tcc-transaction.xml加入到classpath中。如在web.xml中配置:
contextConfigLocation
classpath:tcc-transaction.xml
3 设置TransactionRepository
需要为参与事务的应用项目配置一个TransactionRepository,tcc-transaction框架使用transactionRepository持久化事务日志。可以选择FileSystemTransactionRepository、SpringJdbcTransactionRepository、RedisTransactionRepository或ZooKeeperTransactionRepository。
使用SpringJdbcTransactionRepository配置示例如下:
特别提示,dataSource需要单独配置,不能和业务里使用的dataSource复用,即使使用的是同一个数据库。
4 设置恢复策略(可选)
当Tcc事务异常后,恢复Job将会定期恢复事务。在Spring配置文件中配置RecoverConfig类型的Bean来设置恢复策略示例:
com.alibaba.dubbo.remoting.TimeoutException
其中maxRetryCount表示一个事务最多尝试恢复次数,超过将不再自动恢复,需要人工干预,默认是30次。
recoverDuration表示一个事务日志当超过一定时间间隔后没有更新就会被认为是发生了异常,需要恢复,恢复Job将扫描超过这个时间间隔依旧没有更新的事务日志,并对这些事务进行恢复,时间单位是秒,默认是120秒。
cronExpression表示恢复Job触发间隔配置,默认是0 */1 * * * ?。
delayCancelExceptions(1.2.3版中新加的配置)表示系统发生了设置的异常时,主事务不立即rollback,而是由恢复job来执行事务恢复。通常需要将超时异常设置为delayCancelExceptions,这样可以避免因为服务调用时发生了超时异常,主事务如果立刻rollback, 但是从事务还没执行完,从而造成主事务rollback失败。示例中com.alibaba.dubbo.remoting.TimeoutException为底层rpc框架为dubbo,超时异常发生时框架抛出的超时异常类,需要将其加入delayCancelExceptions中。
发布一个Tcc服务方法,可被远程调用并参与到Tcc事务中,发布Tcc服务方法有下面四个约束:
tcc-transaction将拦截加上了@Compensable注解的服务方法,并根据Compensalbe的confirmMethod和cancelMethod获取在CONFRIM阶段和CANCEL阶段需要调用的方法。注解属性tcc-transaction在调用confirmMethod或是cancelMethod时是根据发布Tcc服务的接口类在Spring的ApplicationContext中获取Tcc服务实例,并调用confirmMethod或cancelMethod指定方法。因此如果是使用动态代理的方式实现aop(默认方式),则confirmMethod和cancelMethod需在接口类中声明,如果使用动态字节码技术实现aop(如指定aspectj-autoproxy的proxy-target-class属性为true,在1.2.1版本中,默认已设置为true),则无需在接口类中声明。
tcc-transaction在执行服务过程中会将Tcc服务的上下文持久化,包括所有入参,内部默认实现为将入参使用jdk自带的序列化机制序列化为为byte流,所以需要实现Serializable接口(另外可选择Kryo序列化实现机制,可参考例子)。
例如:
try实现方法:
@Compensable(confirmMethod = "confirmRecord", cancelMethod = "cancelRecord", transactionContextEditor = MethodTransactionContextEditor.class)
public String record(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {
confirm方法:
public void confirmRecord(TransactionContext transactionContext, CapitalTradeOrderDto tradeOrderDto) {
cancel方法:
public void cancelRecord(TransactionContext transactionContext, CapitalTradeOrderDto