阿里开源Fescar分布式事务解决 demo运行初探

项目地址

Github :https://github.com/alibaba/fescar
中文文档:https://github.com/alibaba/fescar/wiki/Home_Chinese
demo:https://github.com/fescar-group/fescar-samples
dubbo官网使用fecar的案例

从Github上下载的fescar目测是没有example的,所以需要从demo地址里下载demo。关于官网的案例就不赘述了,直接开始运行步骤。

一、导入项目

1.导入案例demo

个人使用的是STS,解压从第三个地址下载的fescar-samples压缩包。然后用STS导入。
导入项目
没必要全部导入,我测试的是dubbo例子。springboot的例子还没测,有兴趣的自己动手。

2.导入server

从第一个地址下载的zip解压后,导入该目录下的所有工程。主要是server工程里有依赖的版本号需要从父工程获取,如果只导入server会提示Maven找不到依赖的。所以干脆全导入即可。
阿里开源Fescar分布式事务解决 demo运行初探_第1张图片

二、创建数据库

官网给的例子是在一个库里创建三张表,然后配置相同的数据源,追求简单。我选择创建三个库,分别将账户、订单、库存的表放到各自对应的数据库中,也是为了更贴近实际生产的情况模拟。
在这里插入图片描述

1.每个库先分别创建表undo_log

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_unionkey` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=159 DEFAULT CHARSET=utf8

UNDO_LOG 此表用于 Fescar 的AT模式。

2.创建库存表storage_tbl

在fescar_storage库创建表storage_tbl

DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3.创建订单表order_tbl

在fescar_order库创建表order_tbl

DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT 0,
  `money` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

4.创建账户表account_tbl

在fescar_account库创建表account_tbl

DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `money` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

至此,数据库的准备完成
阿里开源Fescar分布式事务解决 demo运行初探_第2张图片

三、修改配置文件

阿里开源Fescar分布式事务解决 demo运行初探_第3张图片
如图,修改数据库配置文件。三个数据源对应的数据库url以及账号密码。

四、启动服务

1.启动server

阿里开源Fescar分布式事务解决 demo运行初探_第4张图片

2.启动业务服务

阿里开源Fescar分布式事务解决 demo运行初探_第5张图片
前三个服务的启动顺序随意,启动后最终启动DubboBusinessTester接口运行。运行后程序会给账户表和库存表各自初始化一条数据。
在这里插入图片描述
阿里开源Fescar分布式事务解决 demo运行初探_第6张图片
此时运行DubboBusinessTester的main方法后控制台会报错
在这里插入图片描述
原因是demo里的purchase方法中官方抛出一个异常。

	@Override
	@GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")
	public void purchase(String userId, String commodityCode, int orderCount) {
		LOGGER.info("purchase begin ... xid: " + RootContext.getXID());
		storageService.deduct(commodityCode, orderCount);
		orderService.create(userId, commodityCode, orderCount);
        throw new RuntimeException("xxx");
	}

注释掉后再运行就可以看到事务全部提交,三个库的业务表都更新或插入了相关记录。至此,官方demo运行完毕。

五、debug看事务提交及回滚情况

阿里开源Fescar分布式事务解决 demo运行初探_第7张图片
当代码执行这一步之前,查看数据库。
库存表的count减少了2变为98
库存表的count减少了2变为98
账户表金额money减少了400变为599
在这里插入图片描述
并且订单表生成了一条记录
在这里插入图片描述
由此证明,本地事务已经提交了。但是全局事务还是可以回滚的,继续执行,会抛出事先写好的异常。全局事务回滚,再看数据库时,三张表的数据全部回滚为初始状态。

public class TransactionalTemplate {

    /**
     * Execute object.
     *
     * @param business the business
     * @return the object
     * @throws ExecutionException the execution exception
     */
    public Object execute(TransactionalExecutor business) throws TransactionalExecutor.ExecutionException {

        // 1. get or create a transaction
        GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();

        // 2. begin transaction开启事务
        try {
            tx.begin(business.timeout(), business.name());

        } catch (TransactionException txe) {
            throw new TransactionalExecutor.ExecutionException(tx, txe,
                TransactionalExecutor.Code.BeginFailure);

        }

        Object rs = null;
        try {

            // Do Your Business业务处理
            rs = business.execute();

        } catch (Throwable ex) {

            // 3. any business exception, rollback.
            try {
               //回滚
                tx.rollback();

                // 3.1 Successfully rolled back
                throw new TransactionalExecutor.ExecutionException(tx, TransactionalExecutor.Code.RollbackDone, ex);

            } catch (TransactionException txe) {
                // 3.2 Failed to rollback
                throw new TransactionalExecutor.ExecutionException(tx, txe,
                    TransactionalExecutor.Code.RollbackFailure, ex);

            } finally {
                GlobalTransactionContext.clean();
            }

        }

        // 4. everything is fine, commit.
        try {
            tx.commit();

        } catch (TransactionException txe) {
            // 4.1 Failed to commit
            throw new TransactionalExecutor.ExecutionException(tx, txe,
                TransactionalExecutor.Code.CommitFailure);

        } finally {
            GlobalTransactionContext.clean();
        }
        return rs;
    }

}

你可能感兴趣的:(微服务,山雨欲来,拥抱开源框架,探索分布式)