You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@dubbo.apache.org by il...@apache.org on 2019/04/24 06:06:05 UTC

[incubator-dubbo-samples] branch master updated: add transaction example

This is an automated email from the ASF dual-hosted git repository.

iluo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo-samples.git


The following commit(s) were added to refs/heads/master by this push:
     new 0c77487  add transaction example
0c77487 is described below

commit 0c7748787e32afcd28e3b33803a47f473e9c5c6e
Author: Ian Luo <ia...@gmail.com>
AuthorDate: Wed Apr 24 13:57:38 2019 +0800

    add transaction example
---
 dubbo-samples-transaction/README.md                |  48 +++++++++
 dubbo-samples-transaction/pom.xml                  | 111 +++++++++++++++++++++
 .../apache/dubbo/samples/ApplicationKeeper.java    |  77 ++++++++++++++
 .../main/java/org/apache/dubbo/samples/Order.java  |  57 +++++++++++
 .../dubbo/samples/service/AccountService.java      |  32 ++++++
 .../dubbo/samples/service/BusinessService.java     |  33 ++++++
 .../apache/dubbo/samples/service/OrderService.java |  35 +++++++
 .../dubbo/samples/service/StorageService.java      |  32 ++++++
 .../samples/service/impl/AccountServiceImpl.java   |  50 ++++++++++
 .../samples/service/impl/BusinessServiceImpl.java  |  65 ++++++++++++
 .../samples/service/impl/OrderServiceImpl.java     | 101 +++++++++++++++++++
 .../samples/service/impl/StorageServiceImpl.java   |  54 ++++++++++
 .../starter/DubboAccountServiceStarter.java        |  43 ++++++++
 .../dubbo/samples/starter/DubboBusinessTester.java |  41 ++++++++
 .../samples/starter/DubboOrderServiceStarter.java  |  41 ++++++++
 .../starter/DubboStorageServiceStarter.java        |  42 ++++++++
 .../src/main/resources/docker/docker-compose.yml   |  15 +++
 .../src/main/resources/docker/mysql/Dockerfile     |   6 ++
 .../main/resources/docker/mysql/sql/dubbo-biz.sql  |  34 +++++++
 .../main/resources/docker/mysql/sql/undo-log.sql   |  15 +++
 .../src/main/resources/docker/seata/Dockerfile     |  12 +++
 .../src/main/resources/docker/seata/conf/file.conf |  63 ++++++++++++
 .../main/resources/docker/seata/conf/registry.conf |  51 ++++++++++
 .../src/main/resources/jdbc.properties             |  29 ++++++
 .../src/main/resources/log4j.properties            |  23 +++++
 .../resources/spring/dubbo-account-service.xml     |  71 +++++++++++++
 .../src/main/resources/spring/dubbo-business.xml   |  41 ++++++++
 .../main/resources/spring/dubbo-order-service.xml  |  74 ++++++++++++++
 .../resources/spring/dubbo-storage-service.xml     |  71 +++++++++++++
 pom.xml                                            |   1 +
 30 files changed, 1368 insertions(+)

diff --git a/dubbo-samples-transaction/README.md b/dubbo-samples-transaction/README.md
new file mode 100644
index 0000000..8ecff32
--- /dev/null
+++ b/dubbo-samples-transaction/README.md
@@ -0,0 +1,48 @@
+# Dubbo Transaction Example
+
+This example shows how a global transaction manager works in Dubbo framework. Here we use [seata](https://github.com/seata/seata) as an example, but other transaction managers are possible to work with Dubbo too if they provide the corresponding Dubbo filter implementation.
+
+## How To Run
+
+#### Step 1. Start Registry Center, Transaction Manager and Database
+
+In this example, a docker compose file is provided to start registry center, transaction manager and database all together very easily. We use zookeeper as Dubbo's registry center, and [seata](https://github.com/seata/seata) as transaction manager and mysql as database server. But at the same time, it requires you to prepare docker environment as a prerequisite. You can refer to [docker quick start](https://www.docker.com/get-started) to install.
+
+```bash
+cd src/main/resources/docker
+docker-compose up
+```
+
+#### Step 2. Build Examples
+
+Execute the following maven command under *dubbo-samples-transaction* directory, or simply import the whole sample project into IDE.
+
+```bash
+mvn clean package
+```
+
+#### Step 3. Run Examples
+
+In this examples, there are three Dubbo services provided, which are *AccountService*, *OrderService*, *StorageService*:
+
+0. Execute *DubboAccountServiceStarter* to start *AccountService*
+0. Execute *DubboOrderServiceStarter* to start *OrderService*
+0. Execute *DubboStorageServiceStarter* to start *StorageService*
+
+*BusinessService* is not a Dubbo service but a normal Spring bean. It's used to verify the distributed transaction among *AccountService*, *OrderService*, *StorageService*. If transaction succeeds, then *storageService* will deduct commodity from the storage, *orderService* will place the order and eventually debit from user's account by *AccountService*. 
+
+```java
+@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");
+}
+```
+
+In this example, since *BusinessService*'s *purchase* method throw an Exception within the transaction, this transaction will not succeed. You can verify the balance from the database tables *storage_tbl*, *order_tbl*, *account_tbl*.
+
+To run *BusinessService*, simply launch *DubboBusinessTester*.
+
+This example shows how a distributed transaction is used in Dubbo application with classic spring. For more advanced usage, pls. refer to [santa samples project](https://github.com/seata/seata-samples)
diff --git a/dubbo-samples-transaction/pom.xml b/dubbo-samples-transaction/pom.xml
new file mode 100644
index 0000000..ff19186
--- /dev/null
+++ b/dubbo-samples-transaction/pom.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>dubbo-samples-all</artifactId>
+        <groupId>org.apache.dubbo</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dubbo-samples-transaction</artifactId>
+
+    <properties>
+        <source.level>1.8</source.level>
+        <target.level>1.8</target.level>
+        <dubbo.version>2.7.1</dubbo.version>
+        <seata.version>0.5.0</seata.version>
+        <spring.version>4.3.16.RELEASE</spring.version>
+        <mysql-connector.version>8.0.15</mysql-connector.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.dubbo</groupId>
+                <artifactId>dubbo-dependencies-bom</artifactId>
+                <version>${dubbo.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo</artifactId>
+            <version>${dubbo.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-dependencies-zookeeper</artifactId>
+            <version>${dubbo.version}</version>
+            <type>pom</type>
+        </dependency>
+
+        <dependency>
+            <groupId>io.seata</groupId>
+            <artifactId>seata-spring</artifactId>
+            <version>${seata.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.seata</groupId>
+            <artifactId>seata-dubbo</artifactId>
+            <version>${seata.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.apache.dubbo</groupId>
+                    <artifactId>dubbo</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jdbc</artifactId>
+            <version>${spring.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>${mysql-connector.version}</version>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${source.level}</source>
+                    <target>${target.level}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/ApplicationKeeper.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/ApplicationKeeper.java
new file mode 100644
index 0000000..cff342c
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/ApplicationKeeper.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.support.AbstractApplicationContext;
+
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * The type Application keeper.
+ */
+public class ApplicationKeeper {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationKeeper.class);
+
+    private final ReentrantLock LOCK = new ReentrantLock();
+    private final Condition STOP = LOCK.newCondition();
+
+    /**
+     * Instantiates a new Application keeper.
+     *
+     * @param applicationContext the application context
+     */
+    public ApplicationKeeper(AbstractApplicationContext applicationContext) {
+        addShutdownHook(applicationContext);
+    }
+
+    private void addShutdownHook(final AbstractApplicationContext applicationContext) {
+        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+            try {
+                applicationContext.close();
+                LOGGER.info("ApplicationContext " + applicationContext + " is closed.");
+            } catch (Exception e) {
+                LOGGER.error("Failed to close ApplicationContext", e);
+            }
+
+            try {
+                LOCK.lock();
+                STOP.signal();
+            } finally {
+                LOCK.unlock();
+            }
+        }));
+    }
+
+    /**
+     * Keep.
+     */
+    public void keep() {
+        synchronized (LOCK) {
+            try {
+                LOGGER.info("Application is keep running ... ");
+                LOCK.wait();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/Order.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/Order.java
new file mode 100644
index 0000000..d692cba
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/Order.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples;
+
+import java.io.Serializable;
+
+/**
+ * The type Order.
+ */
+public class Order implements Serializable {
+    /**
+     * The Id.
+     */
+    public long id;
+    /**
+     * The User id.
+     */
+    public String userId;
+    /**
+     * The Commodity code.
+     */
+    public String commodityCode;
+    /**
+     * The Count.
+     */
+    public int count;
+    /**
+     * The Money.
+     */
+    public int money;
+
+    @Override
+    public String toString() {
+        return "Order{" +
+                "id=" + id +
+                ", userId='" + userId + '\'' +
+                ", commodityCode='" + commodityCode + '\'' +
+                ", count=" + count +
+                ", money=" + money +
+                '}';
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/AccountService.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/AccountService.java
new file mode 100644
index 0000000..a3013cf
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/AccountService.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service;
+
+/**
+ * The interface Account service.
+ */
+public interface AccountService {
+
+    /**
+     * debit
+     *
+     * @param userId userId
+     * @param money  amount to debit
+     */
+    void debit(String userId, int money);
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/BusinessService.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/BusinessService.java
new file mode 100644
index 0000000..f6c6258
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/BusinessService.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service;
+
+/**
+ * The interface Business service.
+ */
+public interface BusinessService {
+
+    /**
+     * purchase
+     *
+     * @param userId        user id
+     * @param commodityCode commodity code
+     * @param orderCount    order amount
+     */
+    void purchase(String userId, String commodityCode, int orderCount);
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/OrderService.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/OrderService.java
new file mode 100644
index 0000000..56e8d63
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/OrderService.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service;
+
+import org.apache.dubbo.samples.Order;
+
+/**
+ * The interface Order service.
+ */
+public interface OrderService {
+    /**
+     * create order
+     *
+     * @param userId        user id
+     * @param commodityCode commodity code
+     * @param orderCount    order amount
+     * @return created order
+     */
+    Order create(String userId, String commodityCode, int orderCount);
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/StorageService.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/StorageService.java
new file mode 100644
index 0000000..9afeb5c
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/StorageService.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service;
+
+/**
+ * The interface Storage service.
+ */
+public interface StorageService {
+
+    /**
+     * deduct stock
+     *
+     * @param commodityCode commodity code
+     * @param count         amount to deduct
+     */
+    void deduct(String commodityCode, int count);
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/AccountServiceImpl.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/AccountServiceImpl.java
new file mode 100644
index 0000000..dbb6679
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/AccountServiceImpl.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service.impl;
+
+import org.apache.dubbo.samples.service.AccountService;
+
+import io.seata.core.context.RootContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public class AccountServiceImpl implements AccountService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(AccountService.class);
+
+    private JdbcTemplate jdbcTemplate;
+
+    /**
+     * Sets jdbc template.
+     *
+     * @param jdbcTemplate the jdbc template
+     */
+    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+        this.jdbcTemplate = jdbcTemplate;
+    }
+
+    @Override
+    public void debit(String userId, int money) {
+        LOGGER.info("Account Service ... xid: " + RootContext.getXID());
+        LOGGER.info("Deducting balance SQL: update account_tbl set money = money - {} where user_id = {}", money, userId);
+
+        jdbcTemplate.update("update account_tbl set money = money - ? where user_id = ?", new Object[]{money, userId});
+        LOGGER.info("Account Service End ... ");
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/BusinessServiceImpl.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/BusinessServiceImpl.java
new file mode 100644
index 0000000..2d6be81
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/BusinessServiceImpl.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service.impl;
+
+import io.seata.core.context.RootContext;
+import io.seata.spring.annotation.GlobalTransactional;
+
+import org.apache.dubbo.samples.service.BusinessService;
+import org.apache.dubbo.samples.service.OrderService;
+import org.apache.dubbo.samples.service.StorageService;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BusinessServiceImpl implements BusinessService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BusinessService.class);
+
+    private StorageService storageService;
+    private OrderService orderService;
+
+    @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");
+
+    }
+
+    /**
+     * Sets storage service.
+     *
+     * @param storageService the storage service
+     */
+    public void setStorageService(StorageService storageService) {
+        this.storageService = storageService;
+    }
+
+    /**
+     * Sets order service.
+     *
+     * @param orderService the order service
+     */
+    public void setOrderService(OrderService orderService) {
+        this.orderService = orderService;
+    }
+
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/OrderServiceImpl.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/OrderServiceImpl.java
new file mode 100644
index 0000000..3e93675
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/OrderServiceImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service.impl;
+
+import org.apache.dubbo.samples.Order;
+import org.apache.dubbo.samples.service.AccountService;
+import org.apache.dubbo.samples.service.OrderService;
+
+import io.seata.core.context.RootContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.support.GeneratedKeyHolder;
+import org.springframework.jdbc.support.KeyHolder;
+
+import java.sql.PreparedStatement;
+
+public class OrderServiceImpl implements OrderService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class);
+
+    private AccountService accountService;
+
+    private JdbcTemplate jdbcTemplate;
+
+    @Override
+    public Order create(String userId, String commodityCode, int orderCount) {
+        LOGGER.info("Order Service Begin ... xid: " + RootContext.getXID());
+
+        // calculate payment
+        int orderMoney = calculate(commodityCode, orderCount);
+
+        // debit from the account
+        accountService.debit(userId, orderMoney);
+
+        final Order order = new Order();
+        order.userId = userId;
+        order.commodityCode = commodityCode;
+        order.count = orderCount;
+        order.money = orderMoney;
+
+        KeyHolder keyHolder = new GeneratedKeyHolder();
+
+        LOGGER.info("Order Service SQL: insert into order_tbl (user_id, commodity_code, count, money) values ({}, {}, {}, {})", userId, commodityCode, orderCount, orderMoney);
+
+        jdbcTemplate.update(con -> {
+            PreparedStatement pst = con.prepareStatement(
+                    "insert into order_tbl (user_id, commodity_code, count, money) values (?, ?, ?, ?)",
+                    PreparedStatement.RETURN_GENERATED_KEYS);
+            pst.setObject(1, order.userId);
+            pst.setObject(2, order.commodityCode);
+            pst.setObject(3, order.count);
+            pst.setObject(4, order.money);
+            return pst;
+        }, keyHolder);
+
+        order.id = keyHolder.getKey().longValue();
+
+        LOGGER.info("Order Service End ... Created " + order);
+
+        return order;
+    }
+
+    /**
+     * Sets account service.
+     *
+     * @param accountService the account service
+     */
+    public void setAccountService(AccountService accountService) {
+        this.accountService = accountService;
+    }
+
+    /**
+     * Sets jdbc template.
+     *
+     * @param jdbcTemplate the jdbc template
+     */
+    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+        this.jdbcTemplate = jdbcTemplate;
+    }
+
+    private int calculate(String commodityId, int orderCount) {
+        return 200 * orderCount;
+    }
+
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/StorageServiceImpl.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/StorageServiceImpl.java
new file mode 100644
index 0000000..a6635c3
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/service/impl/StorageServiceImpl.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.service.impl;
+
+import org.apache.dubbo.samples.service.StorageService;
+
+import io.seata.core.context.RootContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public class StorageServiceImpl implements StorageService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(StorageService.class);
+
+    private JdbcTemplate jdbcTemplate;
+
+    /**
+     * Set jdbc template.
+     *
+     * @param jdbcTemplate the jdbc template
+     */
+    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+        this.jdbcTemplate = jdbcTemplate;
+    }
+
+    @Override
+    public void deduct(String commodityCode, int count) {
+        LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID());
+        LOGGER.info("Deducting inventory SQL: update storage_tbl set count = count - {} where commodity_code = {}",
+                count, commodityCode);
+
+        jdbcTemplate.update("update storage_tbl set count = count - ? where commodity_code = ?",
+                new Object[]{count, commodityCode});
+        LOGGER.info("Storage Service End ... ");
+
+    }
+
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboAccountServiceStarter.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboAccountServiceStarter.java
new file mode 100644
index 0000000..54f0b72
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboAccountServiceStarter.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.starter;
+
+import org.apache.dubbo.samples.ApplicationKeeper;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * The type Dubbo account service starter.
+ */
+public class DubboAccountServiceStarter {
+    /**
+     * 2. Account service is ready. A buyer register an account: U100001 on my e-commerce platform
+     *
+     * @param args the input arguments
+     */
+    public static void main(String[] args) {
+        ClassPathXmlApplicationContext accountContext = new ClassPathXmlApplicationContext("spring/dubbo-account-service.xml");
+        accountContext.getBean("service");
+        JdbcTemplate accountJdbcTemplate = (JdbcTemplate) accountContext.getBean("jdbcTemplate");
+        accountJdbcTemplate.update("delete from account_tbl where user_id = 'U100001'");
+        accountJdbcTemplate.update("insert into account_tbl(user_id, money) values ('U100001', 999)");
+
+        new ApplicationKeeper(accountContext).keep();
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboBusinessTester.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboBusinessTester.java
new file mode 100644
index 0000000..fa97703
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboBusinessTester.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.starter;
+
+import org.apache.dubbo.samples.service.BusinessService;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * The type Dubbo business tester.
+ */
+public class DubboBusinessTester {
+    /**
+     * The entry point of application.
+     *
+     * @param args the input arguments
+     */
+    public static void main(String[] args) {
+        /**
+         *  4. The whole e-commerce platform is ready , The buyer(U100001) create an order on the sku(C00321) , the count is 2
+         */
+        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/dubbo-business.xml");
+        final BusinessService business = (BusinessService) context.getBean("business");
+        business.purchase("U100001", "C00321", 2);
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboOrderServiceStarter.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboOrderServiceStarter.java
new file mode 100644
index 0000000..d5edfde
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboOrderServiceStarter.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.starter;
+
+import org.apache.dubbo.samples.ApplicationKeeper;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * The type Dubbo order service starter.
+ */
+public class DubboOrderServiceStarter {
+    /**
+     * The entry point of application.
+     *
+     * @param args the input arguments
+     */
+    public static void main(String[] args) {
+        /**
+         *  3. Order service is ready . Waiting for buyers to order
+         */
+        ClassPathXmlApplicationContext orderContext = new ClassPathXmlApplicationContext("spring/dubbo-order-service.xml");
+        orderContext.getBean("service");
+        new ApplicationKeeper(orderContext).keep();
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboStorageServiceStarter.java b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboStorageServiceStarter.java
new file mode 100644
index 0000000..40b3e1e
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/java/org/apache/dubbo/samples/starter/DubboStorageServiceStarter.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.samples.starter;
+
+import org.apache.dubbo.samples.ApplicationKeeper;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * The type Dubbo storage service starter.
+ */
+public class DubboStorageServiceStarter {
+    /**
+     * 1. Storage service is ready . A seller add 100 storage to a sku: C00321
+     *
+     * @param args the input arguments
+     */
+    public static void main(String[] args) {
+        ClassPathXmlApplicationContext storageContext = new ClassPathXmlApplicationContext("spring/dubbo-storage-service.xml");
+        storageContext.getBean("service");
+        JdbcTemplate storageJdbcTemplate = (JdbcTemplate) storageContext.getBean("jdbcTemplate");
+        storageJdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'");
+        storageJdbcTemplate.update("insert into storage_tbl(commodity_code, count) values ('C00321', 100)");
+        new ApplicationKeeper(storageContext).keep();
+    }
+}
diff --git a/dubbo-samples-transaction/src/main/resources/docker/docker-compose.yml b/dubbo-samples-transaction/src/main/resources/docker/docker-compose.yml
new file mode 100644
index 0000000..d9db4f5
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/docker-compose.yml
@@ -0,0 +1,15 @@
+version: '3.3'
+services:
+  seata-mysql:
+    build: mysql
+    ports:
+      - "3306:3306"
+  seata-server:
+    build: seata
+    ports:
+      - "8091:8091"
+  zookeeper:
+    image: "zookeeper:latest"
+    ports:
+      - "2181:2181"
+
diff --git a/dubbo-samples-transaction/src/main/resources/docker/mysql/Dockerfile b/dubbo-samples-transaction/src/main/resources/docker/mysql/Dockerfile
new file mode 100644
index 0000000..abdcb13
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/mysql/Dockerfile
@@ -0,0 +1,6 @@
+FROM mysql
+
+ENV MYSQL_DATABASE seata-demo
+ENV MYSQL_ROOT_PASSWORD helloworld
+
+COPY sql /docker-entrypoint-initdb.d/
diff --git a/dubbo-samples-transaction/src/main/resources/docker/mysql/sql/dubbo-biz.sql b/dubbo-samples-transaction/src/main/resources/docker/mysql/sql/dubbo-biz.sql
new file mode 100644
index 0000000..57014fa
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/mysql/sql/dubbo-biz.sql
@@ -0,0 +1,34 @@
+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;
+
+
+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;
+
+
+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;
diff --git a/dubbo-samples-transaction/src/main/resources/docker/mysql/sql/undo-log.sql b/dubbo-samples-transaction/src/main/resources/docker/mysql/sql/undo-log.sql
new file mode 100644
index 0000000..83bcb61
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/mysql/sql/undo-log.sql
@@ -0,0 +1,15 @@
+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`),
+    UNIQUE KEY `ux_undo_log` (`xid`, `branch_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
diff --git a/dubbo-samples-transaction/src/main/resources/docker/seata/Dockerfile b/dubbo-samples-transaction/src/main/resources/docker/seata/Dockerfile
new file mode 100644
index 0000000..dd4377b
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/seata/Dockerfile
@@ -0,0 +1,12 @@
+FROM openjdk:8-jre-alpine
+
+RUN mkdir -p /seata
+WORKDIR /seata
+
+RUN wget -U "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36" https://github.com/seata/seata/releases/download/0.5.0/seata-server-0.5.0.zip \
+&& unzip seata-server-0.5.0.zip
+
+COPY ./conf/ /seata/conf
+
+EXPOSE 8091
+CMD ["/bin/sh", "/seata/bin/seata-server.sh"]
diff --git a/dubbo-samples-transaction/src/main/resources/docker/seata/conf/file.conf b/dubbo-samples-transaction/src/main/resources/docker/seata/conf/file.conf
new file mode 100644
index 0000000..a38ab36
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/seata/conf/file.conf
@@ -0,0 +1,63 @@
+transport {
+  # tcp udt unix-domain-socket
+  type = "TCP"
+  #NIO NATIVE
+  server = "NIO"
+  #enable heartbeat
+  heartbeat = true
+  #thread factory for netty
+  thread-factory {
+    boss-thread-prefix = "NettyBoss"
+    worker-thread-prefix = "NettyServerNIOWorker"
+    server-executor-thread-prefix = "NettyServerBizHandler"
+    share-boss-worker = false
+    client-selector-thread-prefix = "NettyClientSelector"
+    client-selector-thread-size = 1
+    client-worker-thread-prefix = "NettyClientWorkerThread"
+    # netty boss thread size,will not be used for UDT
+    boss-thread-size = 1
+    #auto default pin or 8
+    worker-thread-size = 8
+  }
+}
+
+service {
+  #vgroup->rgroup
+  vgroup_mapping.my_test_tx_group = "default"
+  #only support single node
+  default.grouplist = "127.0.0.1:8091"
+  #degrade current not support
+  enableDegrade = false
+  #disable
+  disable = false
+}
+
+client {
+  async.commit.buffer.limit = 10000
+  lock {
+    retry.internal = 10
+    retry.times = 30
+  }
+}
+
+
+## transaction log store
+store {
+  ## store mode: file、db
+  mode = "file"
+
+  ## file store
+  file {
+    dir = "file_store/dubbo"
+
+    # branch session size , if exceeded first try compress lockkey, still exceeded throws exceptions
+    max-branch-session-size = 16384
+    # globe session size , if exceeded throws exceptions
+    max-global-session-size = 512
+    # file buffer size , if exceeded allocate new buffer
+    file-write-buffer-cache-size = 16384
+    # when recover batch read size
+    session.reload.read_size = 100
+  }
+}
+
diff --git a/dubbo-samples-transaction/src/main/resources/docker/seata/conf/registry.conf b/dubbo-samples-transaction/src/main/resources/docker/seata/conf/registry.conf
new file mode 100644
index 0000000..fa9a4da
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/docker/seata/conf/registry.conf
@@ -0,0 +1,51 @@
+registry {
+  # file 、nacos 、eureka、redis、zk
+  type = "file"
+
+  nacos {
+    serverAddr = "localhost"
+    namespace = "public"
+    cluster = "default"
+  }
+  eureka {
+    serviceUrl = "http://localhost:1001/eureka"
+    application = "default"
+    weight = "1"
+  }
+  redis {
+    serverAddr = "localhost:6379"
+    db = "0"
+  }
+  zk {
+    cluster = "default"
+    serverAddr = "127.0.0.1:2181"
+    session.timeout = 6000
+    connect.timeout = 2000
+  }
+  file {
+    name = "file.conf"
+  }
+}
+
+config {
+  # file、nacos 、apollo、zk
+  type = "file"
+
+  nacos {
+    serverAddr = "localhost"
+    namespace = "public"
+    cluster = "default"
+  }
+  apollo {
+    app.id = "fescar-server"
+    apollo.meta = "http://192.168.1.204:8801"
+  }
+  zk {
+    serverAddr = "127.0.0.1:2181"
+    session.timeout = 6000
+    connect.timeout = 2000
+  }
+  file {
+    name = "file.conf"
+  }
+}
diff --git a/dubbo-samples-transaction/src/main/resources/jdbc.properties b/dubbo-samples-transaction/src/main/resources/jdbc.properties
new file mode 100644
index 0000000..3b13f61
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/jdbc.properties
@@ -0,0 +1,29 @@
+#
+#  Copyright 1999-2018 Alibaba Group Holding Ltd.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+jdbc.account.url=jdbc:mysql://localhost:3306/seata-demo
+jdbc.account.username=root
+jdbc.account.password=helloworld
+jdbc.account.driver=com.mysql.jdbc.Driver
+# storage db config
+jdbc.storage.url=jdbc:mysql://localhost:3306/seata-demo
+jdbc.storage.username=root
+jdbc.storage.password=helloworld
+jdbc.storage.driver=com.mysql.jdbc.Driver
+# order db config
+jdbc.order.url=jdbc:mysql://localhost:3306/seata-demo
+jdbc.order.username=root
+jdbc.order.password=helloworld
+jdbc.order.driver=com.mysql.jdbc.Driver
diff --git a/dubbo-samples-transaction/src/main/resources/log4j.properties b/dubbo-samples-transaction/src/main/resources/log4j.properties
new file mode 100644
index 0000000..2e299bb
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/log4j.properties
@@ -0,0 +1,23 @@
+#
+#
+#   Licensed to the Apache Software Foundation (ASF) under one or more
+#   contributor license agreements.  See the NOTICE file distributed with
+#   this work for additional information regarding copyright ownership.
+#   The ASF licenses this file to You under the Apache License, Version 2.0
+#   (the "License"); you may not use this file except in compliance with
+#   the License.  You may obtain a copy of the License at
+#
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS,
+#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#   See the License for the specific language governing permissions and
+#   limitations under the License.
+#
+#
+log4j.rootLogger=info, stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n
diff --git a/dubbo-samples-transaction/src/main/resources/spring/dubbo-account-service.xml b/dubbo-samples-transaction/src/main/resources/spring/dubbo-account-service.xml
new file mode 100644
index 0000000..12de164
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/spring/dubbo-account-service.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations" value="classpath:jdbc.properties"/>
+    </bean>
+
+    <bean name="accountDataSource" class="com.alibaba.druid.pool.DruidDataSource"
+          init-method="init" destroy-method="close">
+        <property name="url" value="${jdbc.account.url}"/>
+        <property name="username" value="${jdbc.account.username}"/>
+        <property name="password" value="${jdbc.account.password}"/>
+        <property name="driverClassName" value="${jdbc.account.driver}"/>
+        <property name="initialSize" value="0"/>
+        <property name="maxActive" value="180"/>
+        <property name="minIdle" value="0"/>
+        <property name="maxWait" value="60000"/>
+        <property name="validationQuery" value="Select 'x' from DUAL"/>
+        <property name="testOnBorrow" value="false"/>
+        <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"/>
+        <property name="removeAbandonedTimeout" value="1800"/>
+        <property name="logAbandoned" value="true"/>
+        <property name="filters" value="mergeStat"/>
+    </bean>
+
+    <bean id="accountDataSourceProxy" class="io.seata.rm.datasource.DataSourceProxy">
+        <constructor-arg ref="accountDataSource"/>
+    </bean>
+
+    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
+        <property name="dataSource" ref="accountDataSourceProxy"/>
+    </bean>
+
+    <dubbo:application name="dubbo-demo-account-service"/>
+    <dubbo:registry address="zookeeper://localhost:2181" />
+    <dubbo:protocol name="dubbo" port="20881"/>
+    <dubbo:service interface="org.apache.dubbo.samples.service.AccountService" ref="service" timeout="10000"/>
+
+    <bean id="service" class="org.apache.dubbo.samples.service.impl.AccountServiceImpl">
+        <property name="jdbcTemplate" ref="jdbcTemplate"/>
+    </bean>
+
+    <bean class="io.seata.spring.annotation.GlobalTransactionScanner">
+        <constructor-arg value="dubbo-demo-account-service"/>
+        <constructor-arg value="my_test_tx_group"/>
+    </bean>
+</beans>
diff --git a/dubbo-samples-transaction/src/main/resources/spring/dubbo-business.xml b/dubbo-samples-transaction/src/main/resources/spring/dubbo-business.xml
new file mode 100644
index 0000000..665f9c1
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/spring/dubbo-business.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                        http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+    <dubbo:application name="dubbo-demo-app"/>
+    <dubbo:registry address="zookeeper://localhost:2181" />
+    <dubbo:reference id="orderService" check="false" interface="org.apache.dubbo.samples.service.OrderService"/>
+    <dubbo:reference id="storageService" check="false" interface="org.apache.dubbo.samples.service.StorageService"/>
+
+    <bean id="business" class="org.apache.dubbo.samples.service.impl.BusinessServiceImpl">
+        <property name="orderService" ref="orderService"/>
+        <property name="storageService" ref="storageService"/>
+    </bean>
+
+    <bean class="io.seata.spring.annotation.GlobalTransactionScanner">
+        <constructor-arg value="dubbo-demo-app"/>
+        <constructor-arg value="my_test_tx_group"/>
+    </bean>
+
+</beans>
diff --git a/dubbo-samples-transaction/src/main/resources/spring/dubbo-order-service.xml b/dubbo-samples-transaction/src/main/resources/spring/dubbo-order-service.xml
new file mode 100644
index 0000000..15eb3c4
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/spring/dubbo-order-service.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations" value="classpath:jdbc.properties"/>
+    </bean>
+
+    <bean name="orderDataSource" class="com.alibaba.druid.pool.DruidDataSource"
+          init-method="init" destroy-method="close">
+        <property name="url" value="${jdbc.order.url}"/>
+        <property name="username" value="${jdbc.order.username}"/>
+        <property name="password" value="${jdbc.order.password}"/>
+        <property name="driverClassName" value="${jdbc.order.driver}"/>
+        <property name="initialSize" value="0"/>
+        <property name="maxActive" value="180"/>
+        <property name="minIdle" value="0"/>
+        <property name="maxWait" value="60000"/>
+        <property name="validationQuery" value="Select 'x' from DUAL"/>
+        <property name="testOnBorrow" value="false"/>
+        <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"/>
+        <property name="removeAbandonedTimeout" value="1800"/>
+        <property name="logAbandoned" value="true"/>
+        <property name="filters" value="mergeStat"/>
+    </bean>
+
+    <bean id="orderDataSourceProxy" class="io.seata.rm.datasource.DataSourceProxy">
+        <constructor-arg ref="orderDataSource"/>
+    </bean>
+
+    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
+        <property name="dataSource" ref="orderDataSourceProxy"/>
+    </bean>
+
+    <dubbo:application name="dubbo-demo-order-service"/>
+    <dubbo:registry address="zookeeper://localhost:2181" />
+    <dubbo:protocol name="dubbo" port="20883"/>
+    <dubbo:service interface="org.apache.dubbo.samples.service.OrderService" ref="service" timeout="10000"/>
+
+    <dubbo:reference id="accountService" check="false" interface="org.apache.dubbo.samples.service.AccountService"/>
+
+    <bean id="service" class="org.apache.dubbo.samples.service.impl.OrderServiceImpl">
+        <property name="jdbcTemplate" ref="jdbcTemplate"/>
+        <property name="accountService" ref="accountService"/>
+    </bean>
+
+    <bean class="io.seata.spring.annotation.GlobalTransactionScanner">
+        <constructor-arg value="dubbo-demo-order-service"/>
+        <constructor-arg value="my_test_tx_group"/>
+    </bean>
+</beans>
diff --git a/dubbo-samples-transaction/src/main/resources/spring/dubbo-storage-service.xml b/dubbo-samples-transaction/src/main/resources/spring/dubbo-storage-service.xml
new file mode 100644
index 0000000..e450e4c
--- /dev/null
+++ b/dubbo-samples-transaction/src/main/resources/spring/dubbo-storage-service.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations" value="classpath:jdbc.properties"/>
+    </bean>
+
+    <bean name="storageDataSource" class="com.alibaba.druid.pool.DruidDataSource"
+          init-method="init" destroy-method="close">
+        <property name="url" value="${jdbc.storage.url}"/>
+        <property name="username" value="${jdbc.storage.username}"/>
+        <property name="password" value="${jdbc.storage.password}"/>
+        <property name="driverClassName" value="${jdbc.storage.driver}"/>
+        <property name="initialSize" value="0"/>
+        <property name="maxActive" value="180"/>
+        <property name="minIdle" value="0"/>
+        <property name="maxWait" value="60000"/>
+        <property name="validationQuery" value="Select 'x' from DUAL"/>
+        <property name="testOnBorrow" value="false"/>
+        <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"/>
+        <property name="removeAbandonedTimeout" value="1800"/>
+        <property name="logAbandoned" value="true"/>
+        <property name="filters" value="mergeStat"/>
+    </bean>
+
+    <bean id="storageDataSourceProxy" class="io.seata.rm.datasource.DataSourceProxy">
+        <constructor-arg ref="storageDataSource"/>
+    </bean>
+
+    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
+        <property name="dataSource" ref="storageDataSourceProxy"/>
+    </bean>
+
+    <dubbo:application name="dubbo-demo-storage-service"/>
+    <dubbo:registry address="zookeeper://localhost:2181"/>
+    <dubbo:protocol name="dubbo" port="20882"/>
+    <dubbo:service interface="org.apache.dubbo.samples.service.StorageService" ref="service" timeout="10000"/>
+
+    <bean id="service" class="org.apache.dubbo.samples.service.impl.StorageServiceImpl">
+        <property name="jdbcTemplate" ref="jdbcTemplate"/>
+    </bean>
+
+    <bean class="io.seata.spring.annotation.GlobalTransactionScanner">
+        <constructor-arg value="dubbo-demo-storage-service"/>
+        <constructor-arg value="my_test_tx_group"/>
+    </bean>
+</beans>
diff --git a/pom.xml b/pom.xml
index 905a29a..52e4c1b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,6 +66,7 @@
         <module>dubbo-samples-version</module>
         <module>dubbo-samples-zipkin</module>
         <module>dubbo-samples-zookeeper</module>
+        <module>dubbo-samples-transaction</module>
     </modules>
 
 </project>


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@dubbo.apache.org
For additional commands, e-mail: notifications-help@dubbo.apache.org