#前言
在之前的spring+dubbo进行分布式项目搭建时,在面对被@Transactionnal()注解的事务服务时,dubbo是不能将其注册成服务者的。
查阅资料后发现大致原因:是因为我们一般的service发布dubbo服务时,dubbo能够扫描到类上dubbo的@service注解,并为其生成代理,而当我们使用@Transactionnal注解时,将会采用cglib为service生成代理,生成的类为原service的子类,而bubbo并没有允许子类继承父类的注解,因此就扫描不到这个注解并生成代理了。
解决方法可参考博客:http://blog.csdn.net/verne_feng/article/details/53022088
#背景
在事务成功注册上之后,远程多数据库跨服务跨库回滚成为亟待解决的难题。参考大量资料后发现,这是一个通用的世界性难题,而向阿里腾讯一些大团队,他们应用的也无非是使用以下两中方式结合使用:
1、使用各种MQ消息中间件进行事务代理,涉及事务问题多采用两段式或三段式提交,并尽量将事务拆分成本地事务串行。
2、使用本地消息库进行消息存储,因为消息中间件具有一定的不可靠性,所以使用本地库作为一种弥补。
首先呢,通过多方调研,我们不可否认,上述做法具有其特定的优越性。因为从大数据量、高并发以及亿级用户压力角度来讲。上述方式也许是唯一一种比较可行的方式。
但结合我们的实际环境和需求,上述方式并不能解决我们对事务的完整回滚操作。后经过调研发现DUBBO LCN可以完成这项使命。DUBBO LCN是将我们的事务进行标注,形成一个事务组,当我们需要回滚的时候,控制事务组回滚即可。这样将一个个子事务的回滚交给其所在的数据库,由数据库单独执行回滚。可行性很高。
当然,同样站在用户压力角度看,我猜想LCN可能并不能承受很高的压力,因为每次我们都需要标注事务,形成事务组,当事务链又多又长的时候,其性能可以想象,肯定高不了。但是站在我们当前的小站点来说,当用户压力并不足以造成巨大的影响时,使用LCN将是我们的首选。因为其简洁明了,只需要在本地事务上将本地事务标注为tx-manager事务,添加或生成事务组即可。
#配置
在明白了LCN的背景及其作用域后,我们开始配置环境。
1、下载工具
首先,你可以参考官网,官网有更详细的讲解:
https://github.com/1991wangliang/tx-lcn
如果你需要一个直接配置好的成品开箱即用,你可以下载笔者整理好的包,按readme.txt的描述启动即可。
https://pan.baidu.com/s/1gSXd3sFmMPPFNAWVlJ_jCw
另外所需本地环境需自行下载:
zookeeper
redis
2、配置解析
参考官网配置,这里做出解释:
在LcnConfg.java中,我们添加了如下注解:
@Configuration
@EnableTransactionManagement(proxyTargetClass=true)
@ComponentScan(basePackages={"com.codingapi.tx.*","com.iking.provider.*"})
@ImportResource(locations = {"classpath*:dubbo_provider.xml"})
public class LcnConfig implements TxManagerTxUrlService{
@Autowired
private Environment env;
/**
* 获取代理连接池
* @return
*/
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
/**
* 注入LCN的代理连接池
* @return
*/
@Bean("transactionManager")
public PlatformTransactionManager txManager(){
return new DataSourceTransactionManager(dataSource());
}
@Override
public String getTxUrl() {
return env.getProperty("tx.manager.url");
}
}
1)首先呢,我们将此类标注为全局配置类,使用@Configuration
2)我们使用@EnableTransactionManagement(proxyTargetClass=true)开启事务远程代理,并进行连接池和LCN代理的注入:
@Autowired
private Environment env;
/**
* 获取代理连接池
* @return
*/
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
/**
* 注入LCN的代理连接池
* @return
*/
@Bean("transactionManager")
public PlatformTransactionManager txManager(){
return new DataSourceTransactionManager(dataSource());
}
这个注解等同于官网上xml中的下列代码:
以及:
3)使用@ComponentScan(basePackages={“com.codingapi.tx.","com.iking.provider.”})扫描lcn以及本项目相关路径,等同于官网demo中的:
4)最后,我们实现了TxManagerTxUrlService接口,将tx-manager的路径进行自定义配置:
public class LcnConfig implements TxManagerTxUrlService{
@Override
public String getTxUrl() {
return env.getProperty("tx.manager.url");
}
application.properties中添加路径配置即可:
#tx-manager
tx.manager.url=http://127.0.0.1:8899/tx/manager/
5)最后,我们将dubbo_provider.xml引进来:
@ImportResource(locations = {"classpath*:dubbo_provider.xml"})
配置介绍到此为止,即可进行测试,如有疑问,烦请@笔者:Q:980420579 Q群:697819474