Skip to content
LCN dubbo demo
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.idea
hibernate-demo
jdbc-demo
mybatis-demo
README.md
test.sql

README.md

dubbo LCN分布式事务示例demo

Dubbo Demo使用讲解地址:http://www.txlcn.org/video.html  

使用说明

框架分为jdbc/hibernate/mybatis三个版本。各个版本之间除了DB框架差异以外,其他配置都相同。

demo分为两类,demo1/demo2 只是消费者与提供者两个的简单demo。以及demo1/2/3/4/5复杂类型调用关系。

demo1/demo2类型:

demo1作为消费者(分布式事务的发起者)调用demo2.

demo1/2/3/4/5类型:

demo1作为分布式事务的发起者,调用了demo2 demo3,demo3有调用了demo4 demo5.

使用步骤

  1. 见wikiTxManager启动说明

  2. 添加配置maven配置

    <dependency>
        <groupId>com.github.1991wangliang</groupId>
        <artifactId>dubbo-transaction</artifactId>
        <version>1.0.0</version>
    </dependency>
    
  1. 添加tx.properties

#txmanager地址  http://txmanager ip:txmanager port/txmanager name/tx/manager/getServer 写法固定
url=http://127.0.0.1:8761/tx/manager/getServer

#事务补偿记录配置


#db 数据库类型 目前支持 mysql oracle sqlserver
compensate.db.dbType = mysql



  1. 添加事务拦截器,确保拦截器的优先级高于spring事务优先级
@Aspect
@Component
public class TxTransactionInterceptor  implements Ordered{

    @Autowired
    private TxManagerInterceptor txManagerInterceptor;

    @Override
    public int getOrder() {
        return 1;
    }

    @Around("execution(* com.demo.service.impl.*Impl.*(..))")
    public Object around(ProceedingJoinPoint point)throws Throwable{
        return txManagerInterceptor.around(point);
    }
}

注意:
@Around 拦截地址不能包含com.lorne.tx.*
LCN是不控制事务。切面仅用于识别LCN分布式事务的作用。

  1. 添加META-INF\dubbo\com.alibaba.dubbo.rpc.Filter配置。

transactionFilter=com.lorne.tx.dubbo.filter.TransactionFilter

在dubbo配置文件下添加

 <!-- 请求拦截器-->
 <dubbo:consumer  filter="transactionFilter" />
 
 <!-- 拒绝重复调用-->
 <dubbo:provider delay="-1" timeout="6000"  port="20881"  retries="0"/>
 
  1. 创建数据库,项目都是依赖相同的数据库,创建一次其他的demo下将不再需要重复创建。mysql数据库,库名称test
USE test;

DROP TABLE IF EXISTS `t_test`;

CREATE TABLE `t_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

  1. spring配置说明

若spring下面配置了<aop:aspectj-autoproxy expose-proxy="true"/>增加proxy-target-class="true"

如下:

 <aop:aspectj-autoproxy expose-proxy="true" proxy-target-class="true" />

  1. 连接池配置,后面操作的连接池都必须是LCN代理连接池
    <!--mysql druid连接池配置-->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf8"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="5"/>
        <!-- 连接池最大并发使用连接数量 -->
        <property name="maxActive" value="50"/>
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="1"/>
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000"/>
        <!-- 打开pscache功能  在mysql5.5以上版本支持 -->
        <property name="poolPreparedStatements" value="true"/>
        <!-- 指定每个连接上的pscache的大小 -->
        <property name="maxPoolPreparedStatementPerConnectionSize" value="33"/>
        <property name="validationQuery" value="select 1"/>
        <property name="testOnBorrow" value="false"/>
        <!-- 归还连接时执行validationQuery  ,检测是否有效,设置为true这样会降低性能 -->
        <property name="testOnReturn" value="false"/>
        <!-- 申请链接的时间是否检测 -->
        <property name="testWhileIdle" value="true"/>
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000"/>
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="25200000"/>
        <!-- 打开超过时间限制是否回收功能 -->
        <property name="removeAbandoned" value="true"/>
        <!-- 超过多长时间 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="1800"/>
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true"/>
        <!-- 监控数据库 -->
        <property name="filters" value="stat"/>
        <!--<property name="filters" value="mergeStat"/>-->
        <!-- 慢sql监控 10毫秒 -->
        <!--<property name="connectionProperties" value="druid.stat.slowSqlMillis=10" />-->
    </bean>
    
    <!--mysql 补偿连接池 -->
   <bean name="compensateDruidDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
       <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=utf8"/>
       <property name="username" value="root"/>
       <property name="password" value="root"/>
       <!-- 初始化连接大小 -->
       <property name="initialSize" value="1"/>
       <!-- 连接池最大并发使用连接数量 -->
       <property name="maxActive" value="5"/>
       <!-- 连接池最小空闲 -->
       <property name="minIdle" value="1"/>
       <!-- 获取连接最大等待时间 -->
       <property name="maxWait" value="60000"/>
       <!-- 打开pscache功能  在mysql5.5以上版本支持 -->
       <property name="poolPreparedStatements" value="true"/>
       <!-- 指定每个连接上的pscache的大小 -->
       <property name="maxPoolPreparedStatementPerConnectionSize" value="33"/>
       <property name="validationQuery" value="select 1"/>
       <property name="testOnBorrow" value="false"/>
       <!-- 归还连接时执行validationQuery  ,检测是否有效,设置为true这样会降低性能 -->
       <property name="testOnReturn" value="false"/>
       <!-- 申请链接的时间是否检测 -->
       <property name="testWhileIdle" value="true"/>
       <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
       <property name="timeBetweenEvictionRunsMillis" value="60000"/>
       <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
       <property name="minEvictableIdleTimeMillis" value="25200000"/>
       <!-- 打开超过时间限制是否回收功能 -->
       <property name="removeAbandoned" value="true"/>
       <!-- 超过多长时间 1800秒,也就是30分钟 -->
       <property name="removeAbandonedTimeout" value="1800"/>
       <!-- 关闭abanded连接时输出错误日志 -->
       <property name="logAbandoned" value="true"/>
       <!-- 监控数据库 -->
       <property name="filters" value="stat"/>
       <!--<property name="filters" value="mergeStat"/>-->
       <!-- 慢sql监控 10毫秒 -->
       <!--<property name="connectionProperties" value="druid.stat.slowSqlMillis=10" />-->
   </bean>

   <!-- 补偿bean -->
   <bean name="compensateDataSource" class="com.lorne.tx.compensate.repository.CompensateDataSource">
       <property name="dataSource" ref="compensateDruidDataSource"></property>
   </bean>

        
    <!--lcn代理连接池配置-->
    <bean name="lcnDataSourceProxy" class="com.lorne.tx.db.LCNDataSourceProxy">
        <property name="dataSource" ref="dataSource"/>
          <!-- 分布式事务参与的最大连接数,确保不要超过普通连接池的最大值即可 -->
        <property name="maxCount" value="20"/>
    </bean>
    
    
    <!--jdbcTemplate -->
    <bean id="jdbcTemplate"
          class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource">
            <ref bean="lcnDataSourceProxy"/>
        </property>
    </bean>
        
    <!--jdbc事务配置 -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="lcnDataSourceProxy" />
    </bean>
    


    

注意事项

  1. 禁止重名的bean对象。

事务的补偿机制是基于java反射的方式重新执行一次需要补偿的业务。因此执行的时候需要获取到业务的service对象,LCN是基于spring的ApplicationContent的getBean方法获取bean的对象的。因此不允许出现重名对象。

在配置服务的时候注意,如下禁止:

    <dubbo:service interface="com.demo.service.Test2Service" ref="test2Service"  />

    <bean id="test2Service" class="com.demo.service.impl.Test2ServiceImpl"   />
    

应该使用如下方式:

    <dubbo:service interface="com.demo.service.Test2Service" ref="test2ServiceImpl"  />
    

测试说明

demo1/demo2类型:

运行demo2下的main包的XXXDemo的main函数,再在tomcat运行demo1,然后访问http://ip:port/xxx_demo/index地址。

效果:/by zero 异常所有事务都回滚。

说明: demo1都是消费者,默认在业务里添加了int v = 100/0;异常代码。因此在不注释的情况下事务回归。

demo1/2/3/4/5类型:

分别运行demo5、demo4、demo3、demo2下的main包的XXXDemo的main函数,再在tomcat运行demo1,然后访问http://ip:port/xxx_demo/index地址。

效果:/by zero 异常所有事务都回滚。

说明:demo1和demo3是消费者,默认在业务里添加了int v = 100/0;,demo3这行已注释,默认回滚,全部注释掉会提交事务。

技术交流群:554855843

You can’t perform that action at this time.