diff --git a/.gitignore b/.gitignore
index e34b7b267cd5f0f3f6bcec4a544be0f55896447b..44b06f93f74c2f13f603c08d372ee6f1a9916c5d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@ target/
 *.tar.gz
 *.class
 .flattened-pom.xml
+dependency-reduced-pom.xml
 
 # eclipse ignore
 .settings/
@@ -36,4 +37,4 @@ target/
 # system ignore
 .DS_Store
 Thumbs.db
-*.orig
\ No newline at end of file
+*.orig
diff --git a/README.md b/README.md
index a4676b789b661abd4042e378ad139435b2fcc6db..766f57396908bb6a08a090b9e0108954f2a5135c 100644
--- a/README.md
+++ b/README.md
@@ -81,7 +81,7 @@ For more details about principle and design, please go to [Seata wiki page](http
 
 ## Maven dependency
 ```xml
-<seata.version>0.5.1</seata.version>
+<seata.version>0.5.2</seata.version>
 
 <dependency>
     <groupId>io.seata</groupId>
diff --git a/all/pom.xml b/all/pom.xml
index 8f092f4971df482b34d259b9ce14998a4336f3db..e05b28dcc51fc273b1ece3c53da6649cfb4c7bf4 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -21,7 +21,7 @@
 
     <groupId>io.seata</groupId>
     <artifactId>seata-all</artifactId>
-    <version>0.5.2</version>
+    <version>0.6.0</version>
 
     <name>Seata All-in-one ${project.version}</name>
     <url>http://seata.io</url>
@@ -112,6 +112,11 @@
             <artifactId>seata-config-consul</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>io.seata</groupId>
+            <artifactId>seata-config-etcd3</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>io.seata</groupId>
             <artifactId>seata-core</artifactId>
@@ -423,7 +428,7 @@
                             <createSourcesJar>true</createSourcesJar>
                             <promoteTransitiveDependencies>false</promoteTransitiveDependencies>
                             <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
-                            <createDependencyReducedPom>false</createDependencyReducedPom>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
                             <artifactSet>
                                 <includes>
                                     <include>io.seata:seata-common</include>
@@ -433,6 +438,7 @@
                                     <include>io.seata:seata-config-nacos</include>
                                     <include>io.seata:seata-config-zk</include>
                                     <include>io.seata:seata-config-consul</include>
+                                    <include>io.seata:seata-config-etcd3</include>
                                     <include>io.seata:seata-discovery-core</include>
                                     <include>io.seata:seata-discovery-consul</include>
                                     <include>io.seata:seata-discovery-eureka</include>
@@ -473,6 +479,12 @@
                                         <exclude>registry.conf</exclude>
                                     </excludes>
                                 </filter>
+                                <filter>
+                                    <artifact>*:*</artifact>
+                                    <excludes>
+                                        <exclude>META-INF/maven/**</exclude>
+                                    </excludes>
+                                </filter>
                             </filters>
                         </configuration>
                     </execution>
@@ -497,20 +509,12 @@
                         <artifactId>maven-javadoc-plugin</artifactId>
                         <version>2.10.4</version>
                         <configuration>
-                            <encoding>${project.build.sourceEncoding}</encoding>
-                            <detectOfflineLinks>true</detectOfflineLinks>
-                            <breakiterator>true</breakiterator>
-                            <author>false</author>
-                            <keywords>true</keywords>
-                            <quiet>true</quiet>
-                            <includeDependencySources>true</includeDependencySources>
-                            <dependencySourceIncludes>
-                                <dependencySourceInclude>io.seata:seata-*</dependencySourceInclude>
-                            </dependencySourceIncludes>
+                            <charset>${project.build.sourceEncoding}</charset>
+                            <failOnError>false</failOnError>
                         </configuration>
                         <executions>
                             <execution>
-                                <id>attach-javadocs</id>
+                                <phase>package</phase>
                                 <goals>
                                     <goal>jar</goal>
                                 </goals>
diff --git a/bom/pom.xml b/bom/pom.xml
index dc5ca5ed57d17aeb4a6dc867a52838db9739f390..76b370961a07827c951514fb175132b7753b6c67 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -20,7 +20,7 @@
 
     <groupId>io.seata</groupId>
     <artifactId>seata-bom</artifactId>
-    <version>0.5.2</version>
+    <version>0.6.0</version>
 
     <modelVersion>4.0.0</modelVersion>
     <packaging>pom</packaging>
@@ -30,29 +30,28 @@
     <properties>
         <spring.version>4.3.23.RELEASE</spring.version>
         <netty4.version>4.1.24.Final</netty4.version>
-        <junit.version>4.12</junit.version>
         <dubbo.version>2.7.0</dubbo.version>
         <dubbo.alibaba.version>2.6.5</dubbo.alibaba.version>
         <sofa.rpc.version>5.5.3</sofa.rpc.version>
-        <fastjson.version>1.2.48</fastjson.version>
+        <fastjson.version>1.2.58</fastjson.version>
         <config.version>1.2.1</config.version>
         <slf4j-api.version>1.7.22</slf4j-api.version>
         <logback-classic.version>1.2.0</logback-classic.version>
         <commons-lang.version>2.6</commons-lang.version>
         <commons-pool2.version>2.4.2</commons-pool2.version>
         <commons-pool.version>1.6</commons-pool.version>
+        <commons-dbcp.version>1.3</commons-dbcp.version>
         <cglib.version>3.1</cglib.version>
         <aopalliance.version>1.0</aopalliance.version>
         <zkclient.version>0.10</zkclient.version>
         <curator-test.version>2.9.1</curator-test.version>
         <spring-context-support.version>1.0.2</spring-context-support.version>
-        <testng.version>6.4</testng.version>
         <jacoco-maven-plugin.version>0.8.3</jacoco-maven-plugin.version>
         <apollo-client.version>1.1.0</apollo-client.version>
         <redis-clients.version>2.9.0</redis-clients.version>
         <eureka-clients.version>1.9.5</eureka-clients.version>
         <consul-clients.version>1.4.2</consul-clients.version>
-        <nacos-client.version>0.9.1</nacos-client.version>
+        <nacos-client.version>1.0.0</nacos-client.version>
         <etcd-client-v3.version>0.3.0</etcd-client-v3.version>
         <testcontainers.version>1.11.2</testcontainers.version>
         <guava.version>27.0.1-jre</guava.version>
@@ -63,6 +62,9 @@
         <httpcore.version>4.4.11</httpcore.version>
         <druid.version>1.1.12</druid.version>
         <caffeine.version>2.7.0</caffeine.version>
+        <oracle.client.version>10.2.0.3.0</oracle.client.version>
+        <mysql.client.version>5.1.30</mysql.client.version>
+        <h2.version>1.4.181</h2.version>
     </properties>
 
     <dependencyManagement>
@@ -270,6 +272,21 @@
                 <artifactId>caffeine</artifactId>
                 <version>${caffeine.version}</version>
             </dependency>
+            <dependency>
+                <groupId>commons-dbcp</groupId>
+                <artifactId>commons-dbcp</artifactId>
+                <version>${commons-dbcp.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.h2database</groupId>
+                <artifactId>h2</artifactId>
+                <version>${h2.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>mysql</groupId>
+                <artifactId>mysql-connector-java</artifactId>
+                <version>${mysql.client.version}</version>
+            </dependency>
 
         </dependencies>
     </dependencyManagement>
diff --git a/common/src/main/java/io/seata/common/Constants.java b/common/src/main/java/io/seata/common/Constants.java
index a76bacb155dc6214c17b7940b45c608442f8b10c..e39d856f5b9584fa0bb18826a4248dde8fac7acd 100644
--- a/common/src/main/java/io/seata/common/Constants.java
+++ b/common/src/main/java/io/seata/common/Constants.java
@@ -15,6 +15,8 @@
  */
 package io.seata.common;
 
+import java.nio.charset.Charset;
+
 /**
  * The type Constants.
  *
@@ -97,4 +99,13 @@ public class Constants {
      */
     public final static String TCC_ACTION_CONTEXT = "actionContext";
 
+    /**
+     * default charset name
+     */
+    public static final String DEFAULT_CHARSET_NAME = "UTF-8";
+    
+    /**
+     * default charset is utf-8
+     */
+    public static final Charset DEFAULT_CHARSET = Charset.forName(DEFAULT_CHARSET_NAME);
 }
diff --git a/common/src/main/java/io/seata/common/loader/EnhancedServiceLoader.java b/common/src/main/java/io/seata/common/loader/EnhancedServiceLoader.java
index d10d95999bce5fb89b5c12b2aa19024c8c7fd767..4c80b9c59f32c13c106d2c59f72b00ff104bd050 100644
--- a/common/src/main/java/io/seata/common/loader/EnhancedServiceLoader.java
+++ b/common/src/main/java/io/seata/common/loader/EnhancedServiceLoader.java
@@ -18,6 +18,8 @@ package io.seata.common.loader;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -27,6 +29,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import io.seata.common.Constants;
 import io.seata.common.executor.Initialize;
 import io.seata.common.util.CollectionUtils;
 
@@ -102,12 +105,48 @@ public class EnhancedServiceLoader {
         return loadFile(service, activateName, loader);
     }
 
+    /**
+     * Load s.
+     *
+     * @param <S>          the type parameter
+     * @param service      the service
+     * @param activateName the activate name
+     * @param args         the args
+     * @return the s
+     * @throws EnhancedServiceNotFoundException the enhanced service not found exception
+     */
+    public static <S> S load(Class<S> service, String activateName, Object[] args) throws EnhancedServiceNotFoundException {
+        Class[] argsType = null;
+        if(args != null && args.length > 0){
+            argsType = new Class[args.length];
+            for(int i = 0; i < args.length; i ++){
+                argsType[i] = args[i].getClass();
+            }
+        }
+        return loadFile(service, activateName, findClassLoader(), argsType, args);
+    }
+
+    /**
+     * Load s.
+     *
+     * @param <S>          the type parameter
+     * @param service      the service
+     * @param activateName the activate name
+     * @param argsType     the args type
+     * @param args         the args
+     * @return the s
+     * @throws EnhancedServiceNotFoundException the enhanced service not found exception
+     */
+    public static <S> S load(Class<S> service, String activateName, Class[] argsType, Object[] args) throws EnhancedServiceNotFoundException {
+        return loadFile(service, activateName, findClassLoader(), argsType, args);
+    }
+
     /**
      * get all implements
      *
      * @param <S>     the type parameter
      * @param service the service
-     * @return list
+     * @return list list
      */
     public static <S> List<S> loadAll(Class<S> service) {
         List<S> allInstances = new ArrayList<>();
@@ -117,7 +156,7 @@ public class EnhancedServiceLoader {
         }
         try {
             for (Class clazz : allClazzs) {
-                allInstances.add(initInstance(service, clazz));
+                allInstances.add(initInstance(service, clazz, null, null));
             }
         } catch (Throwable t) {
             throw new EnhancedServiceNotFoundException(t);
@@ -150,8 +189,12 @@ public class EnhancedServiceLoader {
         return findAllExtensionClass(service, null, loader);
     }
 
-    @SuppressWarnings("rawtypes")
     private static <S> S loadFile(Class<S> service, String activateName, ClassLoader loader) {
+        return loadFile(service, activateName, loader, null, null);
+    }
+
+        @SuppressWarnings("rawtypes")
+    private static <S> S loadFile(Class<S> service, String activateName, ClassLoader loader, Class[] argTypes, Object[] args) {
         try {
             boolean foundFromCache = true;
             List<Class> extensions = providers.get(service);
@@ -173,7 +216,7 @@ public class EnhancedServiceLoader {
                     Class clz = extensions.get(i);
                     @SuppressWarnings("unchecked")
                     LoadLevel activate = (LoadLevel)clz.getAnnotation(LoadLevel.class);
-                    if (activate != null && activateName.equals(activate.name())) {
+                    if (activate != null && activateName.equalsIgnoreCase(activate.name())) {
                         activateExtensions.add(clz);
                     }
                 }
@@ -187,7 +230,7 @@ public class EnhancedServiceLoader {
                         + "] and classloader : " + ObjectUtils.toString(loader));
             }
             Class<?> extension = extensions.get(extensions.size() - 1);
-            S result = initInstance(service, extension);
+            S result = initInstance(service, extension, argTypes, args);
             if (!foundFromCache && LOGGER.isInfoEnabled()) {
                 LOGGER.info("load " + service.getSimpleName() + "[" + activateName + "] extension by class[" + extension
                     .getName() + "]");
@@ -259,7 +302,7 @@ public class EnhancedServiceLoader {
                 java.net.URL url = urls.nextElement();
                 BufferedReader reader = null;
                 try {
-                    reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
+                    reader = new BufferedReader(new InputStreamReader(url.openStream(), Constants.DEFAULT_CHARSET));
                     String line = null;
                     while ((line = reader.readLine()) != null) {
                         final int ci = line.indexOf('#');
@@ -292,13 +335,26 @@ public class EnhancedServiceLoader {
      * @param <S>       the type parameter
      * @param service   the service
      * @param implClazz the impl clazz
-     * @return s
-     * @throws IllegalAccessException the illegal access exception
-     * @throws InstantiationException the instantiation exception
+     * @param argTypes  the arg types
+     * @param args      the args
+     * @return s s
+     * @throws IllegalAccessException    the illegal access exception
+     * @throws InstantiationException    the instantiation exception
+     * @throws NoSuchMethodException     the no such method exception
+     * @throws InvocationTargetException the invocation target exception
      */
-    protected static <S> S initInstance(Class<S> service, Class implClazz)
-        throws IllegalAccessException, InstantiationException {
-        S s = service.cast(implClazz.newInstance());
+    protected static <S> S initInstance(Class<S> service, Class implClazz, Class[] argTypes, Object[] args)
+            throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
+        S s = null;
+        if(argTypes != null && args != null){
+            // Constructor with arguments
+            Constructor<S> constructor = implClazz.getDeclaredConstructor(argTypes);
+            constructor.setAccessible(true);
+            s = service.cast(constructor.newInstance(args));
+        }else {
+            // default Constructor
+            s = service.cast(implClazz.newInstance());
+        }
         if (s instanceof Initialize) {
             ((Initialize)s).init();
         }
diff --git a/common/src/main/java/io/seata/common/loader/LoadLevel.java b/common/src/main/java/io/seata/common/loader/LoadLevel.java
index b01ebf76c744fdd5c81cb0c9dce906b77171e92b..b887ed509b0736b68735babcc4fc74ed4c0e63ed 100644
--- a/common/src/main/java/io/seata/common/loader/LoadLevel.java
+++ b/common/src/main/java/io/seata/common/loader/LoadLevel.java
@@ -43,5 +43,5 @@ public @interface LoadLevel {
      *
      * @return the int
      */
-    int order();
+    int order() default 0;
 }
diff --git a/common/src/main/java/io/seata/common/util/BlobUtils.java b/common/src/main/java/io/seata/common/util/BlobUtils.java
index 3eb62aa0c282eb63f94ee9dce9a070817c63ca1d..60ddc7eaabc774d6be132cca358500edce9893e1 100644
--- a/common/src/main/java/io/seata/common/util/BlobUtils.java
+++ b/common/src/main/java/io/seata/common/util/BlobUtils.java
@@ -15,19 +15,18 @@
  */
 package io.seata.common.util;
 
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
 import java.sql.Blob;
 
 import javax.sql.rowset.serial.SerialBlob;
 
-import io.seata.common.exception.ShouldNeverHappenException;
+import io.seata.common.Constants;
 import io.seata.common.exception.ShouldNeverHappenException;
 
 /**
  * The type Blob utils.
  *
  * @author jimin.jm @alibaba-inc.com
+ * @author Geng Zhang
  */
 public class BlobUtils {
 
@@ -47,7 +46,7 @@ public class BlobUtils {
         }
 
         try {
-            return new SerialBlob(str.getBytes());
+            return new SerialBlob(str.getBytes(Constants.DEFAULT_CHARSET));
         } catch (Exception e) {
             throw new ShouldNeverHappenException(e);
         }
@@ -65,26 +64,43 @@ public class BlobUtils {
         }
 
         try {
-            return new String(blob.getBytes((long)1, (int)blob.length()));
+            return new String(blob.getBytes((long) 1, (int) blob.length()), Constants.DEFAULT_CHARSET);
         } catch (Exception e) {
             throw new ShouldNeverHappenException(e);
         }
     }
 
     /**
-     * Input stream 2 string string.
+     * Byte array to blob
      *
-     * @param is the is
-     * @return the string
+     * @param bytes the byte array
+     * @return the blob
+     */
+    public static Blob bytes2Blob(byte[] bytes) {
+        if (bytes == null) {
+            return null;
+        }
+
+        try {
+            return new SerialBlob(bytes);
+        } catch (Exception e) {
+            throw new ShouldNeverHappenException(e);
+        }
+    }
+
+    /**
+     * Blob to byte array.
+     *
+     * @param blob the blob
+     * @return the byte array
      */
-    public static String inputStream2String(InputStream is) {
+    public static byte[] blob2Bytes(Blob blob) {
+        if (blob == null) {
+            return null;
+        }
+
         try {
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            int i = -1;
-            while ((i = is.read()) != -1) {
-                baos.write(i);
-            }
-            return baos.toString();
+            return blob.getBytes((long) 1, (int) blob.length());
         } catch (Exception e) {
             throw new ShouldNeverHappenException(e);
         }
diff --git a/common/src/main/java/io/seata/common/util/CollectionUtils.java b/common/src/main/java/io/seata/common/util/CollectionUtils.java
index 76126fc4cf4d51da9d26ebdcad2914519a906a7c..d56b80eb1ec4eadd79428c829f38541aa83f36ad 100644
--- a/common/src/main/java/io/seata/common/util/CollectionUtils.java
+++ b/common/src/main/java/io/seata/common/util/CollectionUtils.java
@@ -16,6 +16,7 @@
 package io.seata.common.util;
 
 import java.util.Collection;
+import java.util.Iterator;
 
 /**
  * The type Collection utils.
@@ -45,6 +46,49 @@ public class CollectionUtils {
         return col != null && col.size() > 0;
     }
 
+    /**
+     * Is empty boolean.
+     *
+     * @param array the array
+     * @return the boolean
+     */
+    public static boolean isEmpty(Object[] array){
+        return !isNotEmpty(array);
+    }
+
+    /**
+     * Is not empty boolean.
+     *
+     * @param array the array
+     * @return the boolean
+     */
+    public static boolean isNotEmpty(Object[] array){
+        return array != null && array.length > 0;
+    }
+
+    /**
+     * To string string.
+     *
+     * @param col the col
+     * @return the string
+     */
+    public static String toString(Collection col){
+        if(isEmpty(col)){
+            return "";
+        }
+        StringBuffer sb = new StringBuffer();
+        sb.append("[");
+        Iterator it = col.iterator();
+        while (it.hasNext()){
+            Object obj = it.next();
+            sb.append(StringUtils.toString(obj));
+            sb.append(",");
+        }
+        sb.deleteCharAt(sb.length() - 1);
+        sb.append("]");
+        return sb.toString();
+    }
+  
     /**
      * Is size equals boolean.
      *
diff --git a/common/src/main/java/io/seata/common/util/DurationUtil.java b/common/src/main/java/io/seata/common/util/DurationUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..567fc85e3f5acbbfdc6a4568388821ce4c029b62
--- /dev/null
+++ b/common/src/main/java/io/seata/common/util/DurationUtil.java
@@ -0,0 +1,74 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.common.util;
+
+import java.time.Duration;
+
+/**
+ * @author XCXCXCXCX
+ */
+public class DurationUtil {
+
+    public static final Duration DEFAULT_DURATION = Duration.ofMillis(-1);
+
+    public static final String DAY_UNIT = "d";
+    public static final String HOUR_UNIT = "h";
+    public static final String MINIUTE_UNIT = "m";
+    public static final String SECOND_UNIT = "s";
+    public static final String MILLIS_SECOND_UNIT = "ms";
+
+    public static Duration parse(String str) {
+        if(StringUtils.isBlank(str)){
+            return DEFAULT_DURATION;
+        }
+
+        if (str.contains(MILLIS_SECOND_UNIT)) {
+            Long value = doParse(MILLIS_SECOND_UNIT, str);
+            return value == null ? null : Duration.ofMillis(value);
+        } else if (str.contains(DAY_UNIT)) {
+            Long value = doParse(DAY_UNIT, str);
+            return value == null ? null : Duration.ofDays(value);
+        } else if (str.contains(HOUR_UNIT)) {
+            Long value = doParse(HOUR_UNIT, str);
+            return value == null ? null : Duration.ofHours(value);
+        } else if (str.contains(MINIUTE_UNIT)) {
+            Long value = doParse(MINIUTE_UNIT, str);
+            return value == null ? null : Duration.ofMinutes(value);
+        } else if (str.contains(SECOND_UNIT)) {
+            Long value = doParse(SECOND_UNIT, str);
+            return value == null ? null : Duration.ofSeconds(value);
+        }
+        try {
+            int millis = Integer.parseInt(str);
+            return Duration.ofMillis(millis);
+        }catch (Exception e){
+            throw new UnsupportedOperationException(str + " can't parse to duration", e);
+        }
+    }
+
+    private static Long doParse(String unit, String str) {
+        str = str.replace(unit, "");
+        if ("".equals(str)) {
+            return null;
+        }
+        try {
+            return Long.parseLong(str);
+        } catch (NumberFormatException e) {
+            throw new UnsupportedOperationException("\"" + str + "\" can't parse to Duration", e);
+        }
+    }
+
+}
diff --git a/common/src/main/java/io/seata/common/util/StringUtils.java b/common/src/main/java/io/seata/common/util/StringUtils.java
index 217538aae17674ca53488f42b9a03268df82745f..e6a1714e78bedfc5a7e35b09dc8184f7df641bd9 100644
--- a/common/src/main/java/io/seata/common/util/StringUtils.java
+++ b/common/src/main/java/io/seata/common/util/StringUtils.java
@@ -15,19 +15,17 @@
  */
 package io.seata.common.util;
 
+import io.seata.common.Constants;
+import io.seata.common.exception.ShouldNeverHappenException;
+
 import java.io.ByteArrayOutputStream;
-import java.io.IOException;
 import java.io.InputStream;
 import java.lang.reflect.Field;
-import java.sql.Blob;
-import java.sql.SQLException;
 import java.text.SimpleDateFormat;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Map;
 
-import javax.sql.rowset.serial.SerialBlob;
-
 /**
  * The type String utils.
  *
@@ -37,7 +35,6 @@ import javax.sql.rowset.serial.SerialBlob;
 public class StringUtils {
 
     private StringUtils() {
-
     }
 
     /**
@@ -54,7 +51,7 @@ public class StringUtils {
      * Is blank string ?
      *
      * @param str the str
-     * @return boolean
+     * @return boolean boolean
      */
     public static boolean isBlank(String str) {
         int length;
@@ -74,7 +71,7 @@ public class StringUtils {
      * Is Not blank string ?
      *
      * @param str the str
-     * @return boolean
+     * @return boolean boolean
      */
     public static boolean isNotBlank(String str) {
         int length;
@@ -91,56 +88,83 @@ public class StringUtils {
         return false;
     }
 
+     /**
+     * Equals boolean.
+     *
+     * @param a the a
+     * @param b the b
+     * @return boolean
+     */
+    public static boolean equals(String a, String b) {
+        if (a == null) {
+            return b == null;
+        }
+        return a.equals(b);
+    }
+
     /**
-     * String 2 blob blob.
+     * Equals ignore case boolean.
      *
-     * @param str the str
-     * @return the blob
-     * @throws SQLException the sql exception
+     * @param a the a
+     * @param b the b
+     * @return the boolean
      */
-    public static Blob string2blob(String str) throws SQLException {
-        if (str == null) {
-            return null;
+    public static boolean equalsIgnoreCase(String a, String b) {
+        if (a == null) {
+            return b == null;
         }
-        return new SerialBlob(str.getBytes());
+        return a.equalsIgnoreCase(b);
     }
 
     /**
-     * Blob 2 string string.
+     * Input stream 2 string string.
      *
-     * @param blob the blob
+     * @param is the is
      * @return the string
-     * @throws SQLException the sql exception
      */
-    public static String blob2string(Blob blob) throws SQLException {
-        if (blob == null) {
+    public static String inputStream2String(InputStream is) {
+        if (is == null) {
             return null;
         }
-
-        return new String(blob.getBytes((long)1, (int)blob.length()));
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            int i = -1;
+            while ((i = is.read()) != -1) {
+                baos.write(i);
+            }
+            return baos.toString(Constants.DEFAULT_CHARSET_NAME);
+        } catch (Exception e) {
+            throw new ShouldNeverHappenException(e);
+        }
     }
 
     /**
-     * Input stream 2 string string.
+     * Input stream to byte array
      *
      * @param is the is
-     * @return the string
-     * @throws IOException the io exception
+     * @return the byte array
      */
-    public static String inputStream2String(InputStream is) throws IOException {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        int i = -1;
-        while ((i = is.read()) != -1) {
-            baos.write(i);
+    public static byte[] inputStream2Bytes(InputStream is) {
+        if (is == null) {
+            return null;
+        }
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            int i = -1;
+            while ((i = is.read()) != -1) {
+                baos.write(i);
+            }
+            return baos.toByteArray();
+        } catch (Exception e) {
+            throw new ShouldNeverHappenException(e);
         }
-        return baos.toString();
     }
 
     /**
      * Object.toString()
      *
      * @param obj the obj
-     * @return string
+     * @return string string
      */
     public static String toString(Object obj){
         if (obj == null){
@@ -197,32 +221,4 @@ public class StringUtils {
         }
         return sb.toString();
     }
-
-    /**
-     * Equals boolean.
-     *
-     * @param a the a
-     * @param b the b
-     * @return boolean
-     */
-    public static boolean equals(String a, String b) {
-        if (a == null) {
-            return b == null;
-        }
-        return a.equals(b);
-    }
-
-    /**
-     * Equals ignore case boolean.
-     *
-     * @param a the a
-     * @param b the b
-     * @return the boolean
-     */
-    public static boolean equalsIgnoreCase(String a, String b) {
-        if (a == null) {
-            return b == null;
-        }
-        return a.equalsIgnoreCase(b);
-    }
 }
diff --git a/common/src/test/java/io/seata/common/util/BlobUtilsTest.java b/common/src/test/java/io/seata/common/util/BlobUtilsTest.java
index 53a0a6217aeb29cc6e9bdc5713beb568817d6e04..f643ad49caa625d2aea7c8df6b61f397d18dec0b 100644
--- a/common/src/test/java/io/seata/common/util/BlobUtilsTest.java
+++ b/common/src/test/java/io/seata/common/util/BlobUtilsTest.java
@@ -15,21 +15,22 @@
  */
 package io.seata.common.util;
 
-import java.io.InputStream;
-import java.nio.charset.Charset;
+import java.io.UnsupportedEncodingException;
 import java.sql.SQLException;
 
 import javax.sql.rowset.serial.SerialBlob;
 
-import org.junit.jupiter.api.Disabled;
+import io.seata.common.Constants;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNull;
 
 /**
  * The type Blob utils test.
  *
  * @author Otis.z
+ * @author Geng Zhang
  * @date 2019 /2/26
  */
 public class BlobUtilsTest {
@@ -41,8 +42,9 @@ public class BlobUtilsTest {
      */
     @Test
     public void testString2blob() throws SQLException {
+        assertNull(BlobUtils.string2blob(null));
         assertThat(BlobUtils.string2blob("123abc")).isEqualTo(
-            new SerialBlob("123abc".getBytes(Charset.forName("UTF-8"))));
+            new SerialBlob("123abc".getBytes(Constants.DEFAULT_CHARSET)));
     }
 
     /**
@@ -52,19 +54,24 @@ public class BlobUtilsTest {
      */
     @Test
     public void testBlob2string() throws SQLException {
-        assertThat(BlobUtils.blob2string(new SerialBlob("123absent".getBytes(Charset.forName("UTF-8"))))).isEqualTo(
+        assertNull(BlobUtils.blob2string(null));
+        assertThat(BlobUtils.blob2string(new SerialBlob("123absent".getBytes(Constants.DEFAULT_CHARSET)))).isEqualTo(
             "123absent");
     }
 
-    /**
-     * Test input stream 2 string.
-     */
     @Test
-    @Disabled
-    public void testInputStream2String() {
-        InputStream inputStream = BlobUtilsTest.class.getClassLoader().getResourceAsStream("test.txt");
-        assertThat(BlobUtils.inputStream2String(inputStream)).isEqualTo("abc\n"
-            + ":\"klsdf\n"
-            + "2ks,x:\".,-3sd˚ø≤ø¬≥");
+    void bytes2Blob() throws UnsupportedEncodingException, SQLException {
+        assertNull(BlobUtils.bytes2Blob(null));
+        byte[] bs = "xxa哈哈dd".getBytes(Constants.DEFAULT_CHARSET_NAME);
+        assertThat(BlobUtils.bytes2Blob(bs)).isEqualTo(
+                new SerialBlob(bs));
+    }
+
+    @Test
+    void blob2Bytes() throws UnsupportedEncodingException, SQLException {
+        assertNull(BlobUtils.blob2Bytes(null));
+        byte[] bs = "xxa哈哈dd".getBytes(Constants.DEFAULT_CHARSET_NAME);
+        assertThat(BlobUtils.blob2Bytes(new SerialBlob(bs))).isEqualTo(
+                bs);
     }
 }
diff --git a/common/src/test/java/io/seata/common/util/StringUtilsTest.java b/common/src/test/java/io/seata/common/util/StringUtilsTest.java
index 1eae80462bf81c5027cf26d27b03472e1c1cb1d4..c816c0358cb28d6585e64155debf1431d57d9732 100644
--- a/common/src/test/java/io/seata/common/util/StringUtilsTest.java
+++ b/common/src/test/java/io/seata/common/util/StringUtilsTest.java
@@ -15,17 +15,15 @@
  */
 package io.seata.common.util;
 
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.io.InputStream;
-import java.sql.SQLException;
-
-import javax.sql.rowset.serial.SerialBlob;
 
+import io.seata.common.Constants;
 import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNull;
 
 /**
  * The type String utils test.
@@ -48,43 +46,25 @@ public class StringUtilsTest {
         assertThat(StringUtils.isNullOrEmpty(" ")).isFalse();
     }
 
-    /**
-     * Test string 2 blob.
-     *
-     * @throws SQLException the sql exception
-     */
     @Test
-    public void testString2blob() throws SQLException {
-        assertThat(StringUtils.string2blob(null)).isNull();
-        String[] strs = new String[] {"abc", "", " "};
-        for (String str : strs) {
-            assertThat(StringUtils.string2blob(str)).isEqualTo(new SerialBlob(str.getBytes()));
-        }
-    }
-
-    /**
-     * Test blob 2 string.
-     *
-     * @throws SQLException the sql exception
-     */
-    @Test
-    public void testBlob2string() throws SQLException {
-        String[] strs = new String[] {"abc", " "};
-        for (String str : strs) {
-            assertThat(StringUtils.blob2string(new SerialBlob(str.getBytes()))).isEqualTo(str);
-
-        }
+    public void testInputStream2String() throws IOException {
+        assertNull(StringUtils.inputStream2String(null));
+        String data = "abc\n"
+                + ":\"klsdf\n"
+                + "2ks,x:\".,-3sd˚ø≤ø¬≥";
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(data.getBytes(Constants.DEFAULT_CHARSET));
+        assertThat(StringUtils.inputStream2String(inputStream)).isEqualTo(data);
     }
 
-    /**
-     * Test input stream 2 string.
-     */
     @Test
-    @Disabled
-    public void testInputStream2String() throws IOException {
-        InputStream inputStream = StringUtilsTest.class.getClassLoader().getResourceAsStream("test.txt");
-        assertThat(StringUtils.inputStream2String(inputStream))
-            .isEqualTo("abc\n" + ":\"klsdf\n" + "2ks,x:\".,-3sd˚ø≤ø¬≥");
+    void inputStream2Bytes() {
+        assertNull(StringUtils.inputStream2Bytes(null));
+        String data = "abc\n"
+                + ":\"klsdf\n"
+                + "2ks,x:\".,-3sd˚ø≤ø¬≥";
+        byte[] bs = data.getBytes(Constants.DEFAULT_CHARSET);
+        ByteArrayInputStream inputStream = new ByteArrayInputStream(data.getBytes(Constants.DEFAULT_CHARSET));
+        assertThat(StringUtils.inputStream2Bytes(inputStream)).isEqualTo(bs);
     }
 
     @Test
diff --git a/config/pom.xml b/config/pom.xml
index cfdf735708d9a990e40b3d4c67684db6b14e5584..36b384ebda602dee7c1c79dd701a55b0556e94be 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -32,6 +32,7 @@
         <module>seata-config-nacos</module>
         <module>seata-config-zk</module>
         <module>seata-config-all</module>
+        <module>seata-config-etcd3</module>
         <module>seata-config-consul</module>
     </modules>
 </project>
diff --git a/config/seata-config-all/pom.xml b/config/seata-config-all/pom.xml
index 3cf62928e1bac49a9d6203b4258a5078b54ddf48..46da42a13db477fe6b62752993ebbb50c5c0808e 100644
--- a/config/seata-config-all/pom.xml
+++ b/config/seata-config-all/pom.xml
@@ -41,6 +41,11 @@
             <artifactId>seata-config-nacos</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>seata-config-etcd3</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>seata-config-consul</artifactId>
diff --git a/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java b/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java
index 7cd509eccdd5cdafdc960f322a2fda8f4c0a2311..0092f4f36ac5020307908c5969b4aa5fd918f300 100644
--- a/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/AbstractConfiguration.java
@@ -15,6 +15,11 @@
  */
 package io.seata.config;
 
+
+import io.seata.common.util.DurationUtil;
+
+import java.time.Duration;
+
 /**
  * The type Abstract configuration.
  *
@@ -61,6 +66,22 @@ public abstract class AbstractConfiguration<T> implements Configuration<T> {
         return getLong(dataId, 0L);
     }
 
+    @Override
+    public Duration getDuration(String dataId) {
+        return getDuration(dataId, Duration.ZERO);
+    }
+
+    @Override
+    public Duration getDuration(String dataId, Duration defaultValue) {
+        return getDuration(dataId, defaultValue, DEFAULT_CONFIG_TIMEOUT);
+    }
+
+    @Override
+    public Duration getDuration(String dataId, Duration defaultValue, long timeoutMills) {
+        String result = getConfig(dataId, String.valueOf(defaultValue.toMillis() + "ms"), timeoutMills);
+        return DurationUtil.parse(result);
+    }
+
     @Override
     public boolean getBoolean(String dataId, boolean defaultValue, long timeoutMills) {
         String result = getConfig(dataId, String.valueOf(defaultValue), timeoutMills);
diff --git a/config/seata-config-core/src/main/java/io/seata/config/ConfigType.java b/config/seata-config-core/src/main/java/io/seata/config/ConfigType.java
index 866fddb8d67eec8836d9e0799ff7bcaf29b99755..6f8cf55a4ede1c2a2e1e629c3396df06f3d05c56 100644
--- a/config/seata-config-core/src/main/java/io/seata/config/ConfigType.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/ConfigType.java
@@ -41,7 +41,11 @@ public enum ConfigType {
     /**
      * Consul config type
      */
-    Consul;
+    Consul,
+    /**
+     * Etcd3 config type
+     */
+    Etcd3;
 
     /**
      * Gets type.
diff --git a/config/seata-config-core/src/main/java/io/seata/config/Configuration.java b/config/seata-config-core/src/main/java/io/seata/config/Configuration.java
index bb3e1a7c18cdbcb96d47a8b498b35f46baf8292a..67ec8679191004e5ca74dd3439c93728106ec809 100644
--- a/config/seata-config-core/src/main/java/io/seata/config/Configuration.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/Configuration.java
@@ -15,6 +15,7 @@
  */
 package io.seata.config;
 
+import java.time.Duration;
 import java.util.List;
 
 /**
@@ -80,6 +81,33 @@ public interface Configuration<T> {
      */
     long getLong(String dataId);
 
+    /**
+     * Gets duration.
+     *
+     * @param dataId
+     * @return the duration
+     */
+    Duration getDuration(String dataId);
+
+    /**
+     * Gets duration.
+     *
+     * @param   dataId
+     * @param   defaultValue
+     * @return  the duration
+     */
+    Duration getDuration(String dataId, Duration defaultValue);
+
+    /**
+     * Gets duration.
+     *
+     * @param   dataId
+     * @param   defaultValue
+     * @param   timeoutMills
+     * @return  he duration
+     */
+    Duration getDuration(String dataId, Duration defaultValue, long timeoutMills);
+
     /**
      * Gets boolean.
      *
diff --git a/config/seata-config-core/src/main/java/io/seata/config/ConfigurationFactory.java b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationFactory.java
index 0b802b3d344e9c3010500f6bc34a3dd79ba8d7b7..cd5ea345d5cf050f3213a354a6120ea8810488b1 100644
--- a/config/seata-config-core/src/main/java/io/seata/config/ConfigurationFactory.java
+++ b/config/seata-config-core/src/main/java/io/seata/config/ConfigurationFactory.java
@@ -17,8 +17,6 @@ package io.seata.config;
 
 import io.seata.common.exception.NotSupportYetException;
 import io.seata.common.loader.EnhancedServiceLoader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Objects;
 
@@ -26,10 +24,9 @@ import java.util.Objects;
  * The type Configuration factory.
  *
  * @author jimin.jm @alibaba-inc.com
- * @date 2018 /12/24
+ * @author Geng Zhang
  */
 public final class ConfigurationFactory {
-    private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationFactory.class);
     private static final String REGISTRY_CONF = "registry.conf";
     /**
      * The constant FILE_INSTANCE.
@@ -38,20 +35,33 @@ public final class ConfigurationFactory {
     private static final String NAME_KEY = "name";
     private static final String FILE_TYPE = "file";
 
+    private static volatile Configuration CONFIG_INSTANCE = null;
+
     /**
      * Gets instance.
      *
      * @return the instance
      */
     public static Configuration getInstance() {
+        if (CONFIG_INSTANCE == null) {
+            synchronized (Configuration.class) {
+                if (CONFIG_INSTANCE == null) {
+                    CONFIG_INSTANCE = buildConfiguration();
+                }
+            }
+        }
+        return CONFIG_INSTANCE;
+    }
+
+    private static Configuration buildConfiguration() {
         ConfigType configType = null;
         String configTypeName = null;
         try {
             configTypeName = FILE_INSTANCE.getConfig(ConfigurationKeys.FILE_ROOT_CONFIG + ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR
                 + ConfigurationKeys.FILE_ROOT_TYPE);
             configType = ConfigType.getType(configTypeName);
-        } catch (Exception exx) {
-            throw new NotSupportYetException("not support register type: " + configTypeName);
+        } catch (Exception e) {
+            throw new NotSupportYetException("not support register type: " + configTypeName, e);
         }
         if (ConfigType.File == configType) {
             String pathDataId = ConfigurationKeys.FILE_ROOT_CONFIG + ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR
diff --git a/config/seata-config-core/src/main/resources/file.conf b/config/seata-config-core/src/main/resources/file.conf
index dc09514d367b205f6a0fdb8dfc45d462c7bddf20..a166f8d5c5cc9ca87bc056f68e49b0c5dfbe7577 100644
--- a/config/seata-config-core/src/main/resources/file.conf
+++ b/config/seata-config-core/src/main/resources/file.conf
@@ -69,4 +69,8 @@ client {
     retry.times = 30
   }
   report.retry.count = 5
-}
\ No newline at end of file
+}
+
+transaction {
+  undo.data.validation = true
+}
diff --git a/config/seata-config-core/src/main/resources/registry.conf b/config/seata-config-core/src/main/resources/registry.conf
index 1d6c35982564b2f8330a6a9bdb46f2aa12ae407c..5115876d916fa5e59a5511796e5cc92622f5a442 100644
--- a/config/seata-config-core/src/main/resources/registry.conf
+++ b/config/seata-config-core/src/main/resources/registry.conf
@@ -45,7 +45,7 @@ registry {
 }
 
 config {
-  # file、nacos 、apollo、zk、consul
+  # file、nacos 、apollo、zk、consul、etcd3
   type = "file"
 
   nacos {
@@ -65,6 +65,9 @@ config {
     session.timeout = 6000
     connect.timeout = 2000
   }
+  etcd3 {
+    serverAddr = "http://localhost:2379"
+  }
   file {
     name = "file.conf"
   }
diff --git a/config/seata-config-etcd3/pom.xml b/config/seata-config-etcd3/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..beb590dfffecbf490d7b14acefa3725f12fc4cf1
--- /dev/null
+++ b/config/seata-config-etcd3/pom.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~  Copyright 1999-2019 Seata.io Group.
+  ~
+  ~  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.
+  -->
+<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>
+        <groupId>io.seata</groupId>
+        <artifactId>seata-config</artifactId>
+        <version>${revision}</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>seata-config-etcd3</artifactId>
+    <name>seata-config-etcd3 ${project.version}</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.seata</groupId>
+            <artifactId>seata-config-core</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.etcd</groupId>
+            <artifactId>jetcd-core</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.guava</groupId>
+                    <artifactId>guava</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/config/seata-config-etcd3/src/main/java/io/seata/config/etcd/EtcdConfiguration.java b/config/seata-config-etcd3/src/main/java/io/seata/config/etcd/EtcdConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..6eed7d53035ab7a7ba1f540a7e9a769399758114
--- /dev/null
+++ b/config/seata-config-etcd3/src/main/java/io/seata/config/etcd/EtcdConfiguration.java
@@ -0,0 +1,318 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.config.etcd;
+
+import io.etcd.jetcd.ByteSequence;
+import io.etcd.jetcd.Client;
+import io.etcd.jetcd.KeyValue;
+import io.etcd.jetcd.Watch;
+import io.etcd.jetcd.kv.DeleteResponse;
+import io.etcd.jetcd.kv.GetResponse;
+import io.etcd.jetcd.kv.PutResponse;
+import io.etcd.jetcd.kv.TxnResponse;
+import io.etcd.jetcd.op.Cmp;
+import io.etcd.jetcd.op.CmpTarget;
+import io.etcd.jetcd.op.Op;
+import io.etcd.jetcd.options.PutOption;
+import io.etcd.jetcd.watch.WatchResponse;
+import io.seata.common.exception.ShouldNeverHappenException;
+import io.seata.common.thread.NamedThreadFactory;
+import io.seata.common.util.CollectionUtils;
+import io.seata.config.AbstractConfiguration;
+import io.seata.config.ConfigChangeListener;
+import io.seata.config.ConfigFuture;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import static io.netty.util.CharsetUtil.UTF_8;
+import static io.seata.config.ConfigurationKeys.FILE_CONFIG_SPLIT_CHAR;
+import static io.seata.config.ConfigurationKeys.FILE_ROOT_CONFIG;
+
+/**
+ * @author xingfudeshi@gmail.com
+ * @date 2019/05/10
+ */
+public class EtcdConfiguration extends AbstractConfiguration<ConfigChangeListener> {
+    private static final Logger LOGGER = LoggerFactory.getLogger(EtcdConfiguration.class);
+    private static volatile EtcdConfiguration instance;
+    private static volatile Client client;
+
+    private static final Configuration FILE_CONFIG = ConfigurationFactory.FILE_INSTANCE;
+    private static final String SERVER_ADDR_KEY = "serverAddr";
+    private static final String CONFIG_TYPE = "etcd3";
+    private static final String FILE_CONFIG_KEY_PREFIX = FILE_ROOT_CONFIG + FILE_CONFIG_SPLIT_CHAR + CONFIG_TYPE + FILE_CONFIG_SPLIT_CHAR;
+    private static final int THREAD_POOL_NUM = 1;
+    private static final int MAP_INITIAL_CAPACITY = 8;
+    private static ExecutorService etcdConfigExecutor = null;
+    private static ExecutorService etcdNotifierExecutor = null;
+    private static ConcurrentMap<String, List<ConfigChangeListener>> configListenersMap = null;
+    private static ConcurrentHashMap<String, List<ConfigChangeNotifier>> configChangeNotifiersMap = null;
+
+    private static final long VERSION_NOT_EXIST = 0;
+
+    private EtcdConfiguration() {
+    }
+
+    /**
+     * get instance
+     *
+     * @return
+     */
+    public static EtcdConfiguration getInstance() {
+        if (null == instance) {
+            synchronized (EtcdConfiguration.class) {
+                if (null == instance) {
+                    etcdConfigExecutor = new ThreadPoolExecutor(THREAD_POOL_NUM, THREAD_POOL_NUM,
+                        Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("etcd-config-executor", THREAD_POOL_NUM));
+                    etcdNotifierExecutor = new ThreadPoolExecutor(THREAD_POOL_NUM, THREAD_POOL_NUM,
+                        Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("etcd-config-notifier-executor", THREAD_POOL_NUM));
+                    configListenersMap = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY);
+                    configChangeNotifiersMap = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY);
+                    instance = new EtcdConfiguration();
+                }
+            }
+        }
+        return instance;
+    }
+
+
+    @Override
+    public String getTypeName() {
+        return CONFIG_TYPE;
+    }
+
+    @Override
+    public String getConfig(String dataId, String defaultValue, long timeoutMills) {
+        ConfigFuture configFuture = new ConfigFuture(dataId, defaultValue, ConfigFuture.ConfigOperation.GET, timeoutMills);
+        etcdConfigExecutor.execute(() -> {
+            complete(getClient().getKVClient().get(ByteSequence.from(dataId, UTF_8)), configFuture);
+        });
+        return (String) configFuture.get();
+    }
+
+    @Override
+    public boolean putConfig(String dataId, String content, long timeoutMills) {
+        ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigFuture.ConfigOperation.PUT, timeoutMills);
+        etcdConfigExecutor.execute(() -> {
+            complete(getClient().getKVClient().put(ByteSequence.from(dataId, UTF_8), ByteSequence.from(content, UTF_8)), configFuture);
+        });
+        return (Boolean) configFuture.get();
+    }
+
+    @Override
+    public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
+        ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigFuture.ConfigOperation.PUTIFABSENT, timeoutMills);
+        etcdConfigExecutor.execute(() -> {
+            //use etcd transaction to ensure the atomic operation
+            complete(client.getKVClient().txn()
+                //whether the key exists
+                .If(new Cmp(ByteSequence.from(dataId, UTF_8), Cmp.Op.EQUAL, CmpTarget.version(VERSION_NOT_EXIST)))
+                //not exist,then will create
+                .Then(Op.put(ByteSequence.from(dataId, UTF_8), ByteSequence.from(content, UTF_8), PutOption.DEFAULT))
+                .commit(), configFuture);
+        });
+        return (Boolean) configFuture.get();
+    }
+
+    @Override
+    public boolean removeConfig(String dataId, long timeoutMills) {
+        ConfigFuture configFuture = new ConfigFuture(dataId, null, ConfigFuture.ConfigOperation.REMOVE, timeoutMills);
+        etcdConfigExecutor.execute(() -> {
+            complete(getClient().getKVClient().delete(ByteSequence.from(dataId, UTF_8)), configFuture);
+        });
+        return (Boolean) configFuture.get();
+    }
+
+    @Override
+    public void addConfigListener(String dataId, ConfigChangeListener listener) {
+        configListenersMap.putIfAbsent(dataId, new ArrayList<>());
+        configChangeNotifiersMap.putIfAbsent(dataId, new ArrayList<>());
+        ConfigChangeNotifier configChangeNotifier = new ConfigChangeNotifier(dataId, listener);
+        configChangeNotifiersMap.get(dataId).add(configChangeNotifier);
+        if (null != listener.getExecutor()) {
+            listener.getExecutor().submit(configChangeNotifier);
+        } else {
+            etcdNotifierExecutor.submit(configChangeNotifier);
+        }
+    }
+
+    @Override
+    public void removeConfigListener(String dataId, ConfigChangeListener listener) {
+        List<ConfigChangeListener> configChangeListeners = getConfigListeners(dataId);
+        if (configChangeListeners == null) {
+            return;
+        }
+        List<ConfigChangeListener> newChangeListenerList = new ArrayList<>();
+        for (ConfigChangeListener changeListener : configChangeListeners) {
+            if (!changeListener.equals(listener)) {
+                newChangeListenerList.add(changeListener);
+            }
+        }
+        configListenersMap.put(dataId, newChangeListenerList);
+        if (null != listener.getExecutor()) {
+            listener.getExecutor().shutdownNow();
+        }
+        //remove and stop the configChangeNotifier
+        List<ConfigChangeNotifier> configChangeNotifiers = configChangeNotifiersMap.get(dataId);
+        List<ConfigChangeNotifier> newConfigChangeNotifiers = new ArrayList<>();
+        for (ConfigChangeNotifier configChangeNotifier : configChangeNotifiers) {
+            if (!listener.equals(configChangeNotifier.getListener())) {
+                newConfigChangeNotifiers.add(configChangeNotifier);
+            } else {
+                configChangeNotifier.stop();
+            }
+        }
+        configChangeNotifiersMap.put(dataId, newConfigChangeNotifiers);
+    }
+
+    @Override
+    public List getConfigListeners(String dataId) {
+        return configListenersMap.get(dataId);
+    }
+
+    /**
+     * get client
+     *
+     * @return client
+     */
+    private static Client getClient() {
+        if (null == client) {
+            synchronized (EtcdConfiguration.class) {
+                if (null == client) {
+                    client = Client.builder().endpoints(FILE_CONFIG.getConfig(FILE_CONFIG_KEY_PREFIX + SERVER_ADDR_KEY)).build();
+                }
+            }
+        }
+        return client;
+    }
+
+    /**
+     * complete the future
+     *
+     * @param completableFuture
+     * @param configFuture
+     * @param <T>
+     */
+    private <T> void complete(CompletableFuture<T> completableFuture, ConfigFuture configFuture) {
+        try {
+            T response = completableFuture.get();
+            if (response instanceof GetResponse) {
+                List<KeyValue> keyValues = ((GetResponse) response).getKvs();
+                if (CollectionUtils.isNotEmpty(keyValues)) {
+                    ByteSequence value = keyValues.get(0).getValue();
+                    if (null != value) {
+                        configFuture.setResult(value.toString(UTF_8));
+                    }
+                }
+            } else if (response instanceof PutResponse) {
+                configFuture.setResult(Boolean.TRUE);
+            } else if (response instanceof TxnResponse) {
+                boolean result = ((TxnResponse) response).isSucceeded();
+                //create key if file does not exist)
+                if (result) {
+                    configFuture.setResult(Boolean.TRUE);
+                }
+            } else if (response instanceof DeleteResponse) {
+                configFuture.setResult(Boolean.TRUE);
+            } else {
+                throw new ShouldNeverHappenException("unsupported response type");
+            }
+        } catch (Exception e) {
+            LOGGER.error("error occurred while completing the future{}", e.getMessage());
+        }
+    }
+
+    /**
+     * the type config change notifier
+     */
+    private static class ConfigChangeNotifier implements Runnable {
+        private final String dataId;
+        private final ConfigChangeListener listener;
+        private Watch.Watcher watcher;
+
+        ConfigChangeNotifier(String dataId, ConfigChangeListener listener) {
+            this.dataId = dataId;
+            this.listener = listener;
+        }
+
+        /**
+         * get the listener
+         *
+         * @return ConfigChangeListener
+         */
+        ConfigChangeListener getListener() {
+            return this.listener;
+        }
+
+        @Override
+        public void run() {
+            Watch watchClient = getClient().getWatchClient();
+            watcher = watchClient.watch(ByteSequence.from(dataId, UTF_8), new Watch.Listener() {
+                @Override
+                public void onNext(WatchResponse response) {
+                    notifyListeners();
+                }
+
+                @Override
+                public void onError(Throwable throwable) {
+
+                }
+
+                @Override
+                public void onCompleted() {
+
+                }
+            });
+        }
+
+        /**
+         * notify listeners
+         */
+        private void notifyListeners() {
+            try {
+                GetResponse getResponse = getClient().getKVClient().get(ByteSequence.from(dataId, UTF_8)).get();
+                List<KeyValue> keyValues = getResponse.getKvs();
+                if (CollectionUtils.isNotEmpty(keyValues)) {
+                    for (ConfigChangeListener listener : configListenersMap.get(this.dataId)) {
+                        listener.receiveConfigInfo(keyValues.get(0).getValue().toString(UTF_8));
+                    }
+                }
+            } catch (Exception e) {
+                LOGGER.error("error occurred while getting value{}", e.getMessage());
+            }
+        }
+
+
+        /**
+         * stop the notifier
+         */
+        public void stop() {
+            this.watcher.close();
+        }
+    }
+}
diff --git a/config/seata-config-etcd3/src/main/java/io/seata/config/etcd/EtcdConfigurationProvider.java b/config/seata-config-etcd3/src/main/java/io/seata/config/etcd/EtcdConfigurationProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..acb7e28db96a3a89bd13a14dccbab2043b1894b0
--- /dev/null
+++ b/config/seata-config-etcd3/src/main/java/io/seata/config/etcd/EtcdConfigurationProvider.java
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.config.etcd;
+
+import io.seata.common.loader.LoadLevel;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationProvider;
+
+/**
+ * @author xingfudeshi@gmail.com
+ * @date 2019/04/12
+ */
+@LoadLevel(name = "Etcd3", order = 1)
+public class EtcdConfigurationProvider implements ConfigurationProvider {
+    @Override
+    public Configuration provide() {
+        return EtcdConfiguration.getInstance();
+    }
+}
diff --git a/config/seata-config-etcd3/src/main/resources/META-INF/services/io.seata.config.ConfigurationProvider b/config/seata-config-etcd3/src/main/resources/META-INF/services/io.seata.config.ConfigurationProvider
new file mode 100644
index 0000000000000000000000000000000000000000..ce01ac197600438bb941beca28567a291b72de90
--- /dev/null
+++ b/config/seata-config-etcd3/src/main/resources/META-INF/services/io.seata.config.ConfigurationProvider
@@ -0,0 +1 @@
+io.seata.config.etcd.EtcdConfigurationProvider
\ No newline at end of file
diff --git a/core/pom.xml b/core/pom.xml
index a6a71f8e60dd4515aefbe2b27e6ac8e3830ed300..9670f9fd495d0d935e7c983159d6dbdc0149e737 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -55,6 +55,17 @@
             <groupId>commons-pool</groupId>
             <artifactId>commons-pool</artifactId>
         </dependency>
+        <dependency>
+            <groupId>commons-dbcp</groupId>
+            <artifactId>commons-dbcp</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 </project>
diff --git a/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java b/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java
index 4df7b3f11c6a64cc8a5d17133149c422fb686ce6..dc6f93fef8cb28a49d0ebc8a63ec92bfe78c5dcb 100644
--- a/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java
+++ b/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java
@@ -92,4 +92,111 @@ public class ConfigurationKeys {
      * The constant CLIENT_REPORT_RETRY_COUNT.
      */
     public static final String CLIENT_REPORT_RETRY_COUNT = CLIENT_PREFIX + "report.retry.count";
+
+    /**
+     * The constant STORE_DB_GLOBAL_TABLE.
+     */
+    public static final String STORE_DB_GLOBAL_TABLE  = "store.db.global.table";
+
+    /**
+     * The constant STORE_DB_BRANCH_TABLE.
+     */
+    public static final String STORE_DB_BRANCH_TABLE  = "store.db.branch.table";
+
+    /**
+     * The constant STORE_DB_GLOBAL_DEFAULT_TABLE.
+     */
+    public static final String STORE_DB_GLOBAL_DEFAULT_TABLE  = "global_table";
+
+    /**
+     * The constant STORE_DB_BRANCH_DEFAULT_TABLE.
+     */
+    public static final String STORE_DB_BRANCH_DEFAULT_TABLE  = "branch_table";
+
+    /**
+     * The constant STORE_DB_DATASOURCE_TYPE.
+     */
+    public static final String STORE_DB_DATASOURCE_TYPE  = "store.db.datasource";
+
+
+    /**
+     * The constant STORE_DB_TYPE.
+     */
+    public static final String STORE_DB_TYPE  = "store.db.db-type";
+
+    /**
+     * The constant STORE_DB_URL.
+     */
+    public static final String STORE_DB_URL  = "store.db.url";
+
+    /**
+     * The constant STORE_DB_USER.
+     */
+    public static final String STORE_DB_USER  = "store.db.user";
+
+    /**
+     * The constant STORE_DB_PASSWORD.
+     */
+    public static final String STORE_DB_PASSWORD  = "store.db.password";
+
+    /**
+     * The constant STORE_DB_MIN_CONN.
+     */
+    public static final String STORE_DB_MIN_CONN = "store.db.min-conn";
+
+    /**
+     * The constant STORE_DB_MAX_CONN.
+     */
+    public static final String STORE_DB_MAX_CONN  = "store.db.max-conn";
+
+    /**
+     * The constant STORE_DB_LOG_QUERY_LIMIT.
+     */
+    public static final String STORE_DB_LOG_QUERY_LIMIT  = "store.db.query-limit";
+
+    /**
+     * The constant LOCK_MODE.
+     */
+    public static final String LOCK_MODE =  "lock.mode";
+
+    /**
+     * The constant LOCK_DB_TABLE.
+     */
+    public static final String LOCK_DB_TABLE  = "lock.db.lock-table";
+
+    /**
+     * The constant LOCK_DB_DEFAULT_TABLE.
+     */
+    public static final String LOCK_DB_DEFAULT_TABLE  = "lock_table";
+
+    /**
+     * The constant COMMITING_RETRY_DELAY.
+     */
+    public static final String  COMMITING_RETRY_DELAY = "recovery.committing-retry-delay";
+
+    /**
+     * The constant ASYN_COMMITING_RETRY_DELAY.
+     */
+    public static final String  ASYN_COMMITING_RETRY_DELAY = "recovery.asyn-committing-retry-delay";
+
+    /**
+     * The constant ROLLBACKING_RETRY_DELAY.
+     */
+    public static final String  ROLLBACKING_RETRY_DELAY = "recovery.rollbacking-retry-delay";
+
+    /**
+     * The constant TIMEOUT_RETRY_DELAY.
+     */
+    public static final String  TIMEOUT_RETRY_DELAY = "recovery.timeout-retry-delay";
+
+
+    /**
+     * The constant TRANSACTION_PREFIX.
+     */
+    public static final String TRANSACTION_PREFIX = "transaction.";
+
+    /**
+     * The constant RM_DATASOURCE_UNOD_VALIDATION.
+     */
+    public static final String TRANSACTION_UNOD_DATA_VALIDATION = TRANSACTION_PREFIX + "undo.data.validation";
 }
diff --git a/core/src/main/java/io/seata/core/constants/DBType.java b/core/src/main/java/io/seata/core/constants/DBType.java
new file mode 100644
index 0000000000000000000000000000000000000000..cdb0174b98522575ce93f1178a10db4e58724bac
--- /dev/null
+++ b/core/src/main/java/io/seata/core/constants/DBType.java
@@ -0,0 +1,93 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.constants;
+
+import io.seata.common.util.StringUtils;
+
+/**
+ * database type
+ *
+ * @author zhangsen
+ * @data 2019 /4/2
+ */
+public enum DBType {
+
+    /**
+     * Mysql db type.
+     */
+    MYSQL,
+
+    /**
+     * Oracle db type.
+     */
+    ORACLE,
+
+    /**
+     * Db 2 db type.
+     */
+    DB2,
+
+    /**
+     * Sqlserver db type.
+     */
+    SQLSERVER,
+
+    /**
+     * Sybaee db type.
+     */
+    SYBAEE,
+
+    /**
+     * H2 db type.
+     */
+    H2,
+
+    /**
+     * Sqlite db type.
+     */
+    SQLITE,
+
+    /**
+     * Access db type.
+     */
+    ACCESS,
+
+    /**
+     * Postgresql db type.
+     */
+    POSTGRESQL,
+
+    /**
+     * Oceanbase db type.
+     */
+    OCEANBASE;
+
+    /**
+     * Valueof db type.
+     *
+     * @param dbType the db type
+     * @return the db type
+     */
+    public static DBType valueof (String dbType){
+        for(DBType dt : values()){
+            if(StringUtils.equalsIgnoreCase(dt.name(),dbType)){
+                return dt;
+            }
+        }
+        throw new IllegalArgumentException("unknown dbtype:" + dbType);
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/io/seata/core/exception/AbstractExceptionHandler.java b/core/src/main/java/io/seata/core/exception/AbstractExceptionHandler.java
index 9aa741dd28dcaf3754de65586e880f74b25a8284..a8501be705ae2c278b4b787cefd27de54e899694 100644
--- a/core/src/main/java/io/seata/core/exception/AbstractExceptionHandler.java
+++ b/core/src/main/java/io/seata/core/exception/AbstractExceptionHandler.java
@@ -15,6 +15,8 @@
  */
 package io.seata.core.exception;
 
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
 import io.seata.core.protocol.ResultCode;
 import io.seata.core.protocol.transaction.AbstractTransactionRequest;
 import io.seata.core.protocol.transaction.AbstractTransactionResponse;
@@ -26,6 +28,11 @@ import io.seata.core.protocol.transaction.AbstractTransactionResponse;
  */
 public abstract class AbstractExceptionHandler {
 
+    /**
+     * The constant CONFIG.
+     */
+    protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
+
     /**
      * The interface Callback.
      *
diff --git a/core/src/main/java/io/seata/core/lock/AbstractLocker.java b/core/src/main/java/io/seata/core/lock/AbstractLocker.java
new file mode 100644
index 0000000000000000000000000000000000000000..ddb0dd073ef8c6c0ffa7ac535fd2dd756be8d8df
--- /dev/null
+++ b/core/src/main/java/io/seata/core/lock/AbstractLocker.java
@@ -0,0 +1,85 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.lock;
+
+import io.seata.common.util.CollectionUtils;
+import io.seata.core.store.LockDO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The type Abstract locker.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+public abstract class AbstractLocker implements Locker {
+
+    /**
+     * The constant LOGGER.
+     */
+    protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractLocker.class);
+
+    /**
+     * The constant LOCK_SPLIT.
+     */
+    protected static final String LOCK_SPLIT = "^^^";
+
+    /**
+     * Convert to lock do list.
+     *
+     * @param locks the locks
+     * @return the list
+     */
+    protected List<LockDO> convertToLockDO(List<RowLock> locks){
+        List<LockDO> lockDOs = new ArrayList<>();
+        if(CollectionUtils.isEmpty(locks)){
+            return lockDOs;
+        }
+        for(RowLock rowLock : locks){
+            LockDO lockDO = new LockDO();
+            lockDO.setBranchId(rowLock.getBranchId());
+            lockDO.setPk(rowLock.getPk());
+            lockDO.setResourceId(rowLock.getResourceId());
+            lockDO.setRowKey(getRowKey(rowLock.getResourceId(), rowLock.getTableName(), rowLock.getPk()));
+            lockDO.setXid(rowLock.getXid());
+            lockDO.setTransactionId(rowLock.getTransactionId());
+            lockDO.setTableName(rowLock.getTableName());
+            lockDOs.add(lockDO);
+        }
+        return lockDOs;
+    }
+
+    /**
+     * Get row key string.
+     *
+     * @param resourceId the resource id
+     * @param tableName  the table name
+     * @param pk         the pk
+     * @return the string
+     */
+    protected String getRowKey(String resourceId, String tableName, String pk){
+        return new StringBuilder().append(resourceId).append(LOCK_SPLIT).append(tableName).append(LOCK_SPLIT).append(pk).toString();
+    }
+
+    @Override
+    public void cleanAllLocks() {
+
+    }
+}
diff --git a/core/src/main/java/io/seata/core/lock/LocalDBLocker.java b/core/src/main/java/io/seata/core/lock/LocalDBLocker.java
new file mode 100644
index 0000000000000000000000000000000000000000..c342e8f6ecfeaf6adb951b79b63e8551e6071ab8
--- /dev/null
+++ b/core/src/main/java/io/seata/core/lock/LocalDBLocker.java
@@ -0,0 +1,42 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.lock;
+
+import java.util.List;
+
+/**
+ * The type Local db locker.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+public class LocalDBLocker extends AbstractLocker {
+
+    @Override
+    public boolean acquireLock(List<RowLock> rowLock) {
+        return false;
+    }
+
+    @Override
+    public boolean releaseLock(List<RowLock> rowLock) {
+        return false;
+    }
+
+    @Override
+    public boolean isLockable(List<RowLock> rowLock) {
+        return false;
+    }
+}
diff --git a/core/src/main/java/io/seata/core/lock/LockMode.java b/core/src/main/java/io/seata/core/lock/LockMode.java
new file mode 100644
index 0000000000000000000000000000000000000000..f1a11d0b9ea30818009ebd3324c7ebf155f7334e
--- /dev/null
+++ b/core/src/main/java/io/seata/core/lock/LockMode.java
@@ -0,0 +1,37 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.lock;
+
+/**
+ * lock mode
+ *
+ * @author zhangsen
+ * @data 2019 /4/25
+ */
+public enum LockMode {
+
+    /**
+     * store the lock in memory of server
+     */
+    MEMORY,
+
+    /**
+     * store the lock in db of server
+     */
+    DB;
+
+
+}
diff --git a/core/src/main/java/io/seata/core/lock/Locker.java b/core/src/main/java/io/seata/core/lock/Locker.java
new file mode 100644
index 0000000000000000000000000000000000000000..8990699d3179e672b709dc270ca4e2bfd3df6d44
--- /dev/null
+++ b/core/src/main/java/io/seata/core/lock/Locker.java
@@ -0,0 +1,59 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.lock;
+
+import java.util.List;
+
+/**
+ * The interface Locker.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+public interface Locker {
+
+    /**
+     * Acquire lock boolean.
+     *
+     * @param rowLock the row lock
+     * @return the boolean
+     */
+    boolean acquireLock(List<RowLock> rowLock) ;
+
+    /**
+     * Un lock boolean.
+     *
+     * @param rowLock the row lock
+     * @return the boolean
+     */
+    boolean releaseLock(List<RowLock> rowLock);
+
+    /**
+     * Is lockable boolean.
+     *
+     * @param rowLock the row lock
+     * @return the boolean
+     */
+    boolean isLockable(List<RowLock> rowLock);
+
+    /**
+     * Clean all locks boolean.
+     *
+     * @return the boolean
+     */
+    void cleanAllLocks();
+}
+
diff --git a/core/src/main/java/io/seata/core/lock/RowLock.java b/core/src/main/java/io/seata/core/lock/RowLock.java
new file mode 100644
index 0000000000000000000000000000000000000000..9675cb9011dfbfb43cdf93cad7e72b5fcc8041ec
--- /dev/null
+++ b/core/src/main/java/io/seata/core/lock/RowLock.java
@@ -0,0 +1,193 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.lock;
+
+import io.seata.common.util.StringUtils;
+
+/**
+ * The type Row lock.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+public class RowLock {
+
+    private String xid;
+
+    private Long transactionId;
+
+    private Long branchId;
+
+    private String resourceId;
+
+    private String tableName;
+
+    private String pk;
+
+    private String rowKey;
+
+    private String feature;
+
+    /**
+     * Gets xid.
+     *
+     * @return the xid
+     */
+    public String getXid() {
+        return xid;
+    }
+
+    /**
+     * Sets xid.
+     *
+     * @param xid the xid
+     */
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Gets transaction id.
+     *
+     * @return the transaction id
+     */
+    public Long getTransactionId() {
+        return transactionId;
+    }
+
+    /**
+     * Sets transaction id.
+     *
+     * @param transactionId the transaction id
+     */
+    public void setTransactionId(Long transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    /**
+     * Gets branch id.
+     *
+     * @return the branch id
+     */
+    public Long getBranchId() {
+        return branchId;
+    }
+
+    /**
+     * Sets branch id.
+     *
+     * @param branchId the branch id
+     */
+    public void setBranchId(Long branchId) {
+        this.branchId = branchId;
+    }
+
+    /**
+     * Gets resource id.
+     *
+     * @return the resource id
+     */
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    /**
+     * Sets resource id.
+     *
+     * @param resourceId the resource id
+     */
+    public void setResourceId(String resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    /**
+     * Gets table name.
+     *
+     * @return the table name
+     */
+    public String getTableName() {
+        return tableName;
+    }
+
+    /**
+     * Sets table name.
+     *
+     * @param tableName the table name
+     */
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+    /**
+     * Gets pk.
+     *
+     * @return the pk
+     */
+    public String getPk() {
+        return pk;
+    }
+
+    /**
+     * Sets pk.
+     *
+     * @param pk the pk
+     */
+    public void setPk(String pk) {
+        this.pk = pk;
+    }
+
+    /**
+     * Gets row key.
+     *
+     * @return the row key
+     */
+    public String getRowKey() {
+        return rowKey;
+    }
+
+    /**
+     * Sets row key.
+     *
+     * @param rowKey the row key
+     */
+    public void setRowKey(String rowKey) {
+        this.rowKey = rowKey;
+    }
+
+    /**
+     * Gets feature.
+     *
+     * @return the feature
+     */
+    public String getFeature() {
+        return feature;
+    }
+
+    /**
+     * Sets feature.
+     *
+     * @param feature the feature
+     */
+    public void setFeature(String feature) {
+        this.feature = feature;
+    }
+
+    @Override
+    public String toString(){
+        return StringUtils.toString(this);
+    }
+}
+
diff --git a/core/src/main/java/io/seata/core/protocol/AbstractMessage.java b/core/src/main/java/io/seata/core/protocol/AbstractMessage.java
index e6f3dd07e09806d84d15d33ebeb789bb5a27e2b6..60ec91b978dc47578dcaff7feab954784b14759f 100644
--- a/core/src/main/java/io/seata/core/protocol/AbstractMessage.java
+++ b/core/src/main/java/io/seata/core/protocol/AbstractMessage.java
@@ -18,6 +18,7 @@ package io.seata.core.protocol;
 import java.io.Serializable;
 import java.nio.charset.Charset;
 
+import io.seata.common.Constants;
 import io.seata.core.protocol.transaction.BranchCommitRequest;
 import io.seata.core.protocol.transaction.BranchCommitResponse;
 import io.seata.core.protocol.transaction.BranchRegisterRequest;
@@ -152,7 +153,7 @@ public abstract class AbstractMessage implements MessageCodec, Serializable {
     /**
      * The constant UTF8.
      */
-    protected static final Charset UTF8 = Charset.forName("utf-8");
+    protected static final Charset UTF8 = Constants.DEFAULT_CHARSET;
     /**
      * The Ctx.
      */
diff --git a/core/src/main/java/io/seata/core/protocol/Version.java b/core/src/main/java/io/seata/core/protocol/Version.java
index 3f5a40470e71efcebe125749b3f86fcb6a191363..de8dcf726bdfaa06499bd858c897b0e72a5a12e9 100644
--- a/core/src/main/java/io/seata/core/protocol/Version.java
+++ b/core/src/main/java/io/seata/core/protocol/Version.java
@@ -31,7 +31,7 @@ public class Version {
     /**
      * The constant CURRENT.
      */
-    public static final String CURRENT = "0.5.2";
+    public static final String CURRENT = "0.6.0";
 
     /**
      * The constant VERSION_MAP.
diff --git a/core/src/main/java/io/seata/core/rpc/ChannelManager.java b/core/src/main/java/io/seata/core/rpc/ChannelManager.java
index d63086ea2510701a7d83819fc67228eed69e8287..9de2904e93e0adb312fd7d2161fc69a82da4a036 100644
--- a/core/src/main/java/io/seata/core/rpc/ChannelManager.java
+++ b/core/src/main/java/io/seata/core/rpc/ChannelManager.java
@@ -29,7 +29,6 @@ import io.seata.core.protocol.IncompatibleVersionException;
 import io.seata.core.protocol.RegisterRMRequest;
 import io.seata.core.protocol.RegisterTMRequest;
 import io.seata.core.protocol.Version;
-import io.seata.core.rpc.netty.NettyPoolKey.TransactionRole;
 
 import io.netty.channel.Channel;
 import io.seata.core.rpc.netty.NettyPoolKey;
diff --git a/core/src/main/java/io/seata/core/rpc/RpcContext.java b/core/src/main/java/io/seata/core/rpc/RpcContext.java
index b605b72d067841bc0481c08f7cc24fc621d34697..6ba531eb16a7f183ad4acb68aef5b01ac331a2d8 100644
--- a/core/src/main/java/io/seata/core/rpc/RpcContext.java
+++ b/core/src/main/java/io/seata/core/rpc/RpcContext.java
@@ -23,7 +23,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 import io.seata.common.Constants;
-import io.seata.core.rpc.netty.NettyPoolKey.TransactionRole;
 
 import io.netty.channel.Channel;
 import io.seata.core.rpc.netty.NettyPoolKey;
diff --git a/core/src/main/java/io/seata/core/rpc/netty/AbstractRpcRemoting.java b/core/src/main/java/io/seata/core/rpc/netty/AbstractRpcRemoting.java
index 44c33d31fdf1f6c6e4c9ffbe6c5b655971f6fd3e..d5bf8625ca79b07c032939ee0b2cb043cecba62d 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/AbstractRpcRemoting.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/AbstractRpcRemoting.java
@@ -35,12 +35,7 @@ import java.util.concurrent.TimeoutException;
 import io.seata.common.exception.FrameworkErrorCode;
 import io.seata.common.exception.FrameworkException;
 import io.seata.common.thread.NamedThreadFactory;
-import io.seata.core.protocol.HeartbeatMessage;
-import io.seata.core.protocol.MergeMessage;
-import io.seata.core.protocol.MessageFuture;
-import io.seata.core.protocol.RpcMessage;
 
-import io.seata.core.rpc.Disposable;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelDuplexHandler;
 import io.netty.channel.ChannelFuture;
diff --git a/core/src/main/java/io/seata/core/rpc/netty/NettyClientConfig.java b/core/src/main/java/io/seata/core/rpc/netty/NettyClientConfig.java
index 2ae97ced878cd0769a94a07cb83ba51ccd7b7578..24c7a0f7c513c833f89ef5cdf1e436f4861e9c54 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/NettyClientConfig.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/NettyClientConfig.java
@@ -15,8 +15,6 @@
  */
 package io.seata.core.rpc.netty;
 
-import io.seata.core.rpc.netty.NettyPoolKey.TransactionRole;
-
 import io.netty.channel.Channel;
 
 /**
diff --git a/core/src/main/java/io/seata/core/rpc/netty/NettyPoolableFactory.java b/core/src/main/java/io/seata/core/rpc/netty/NettyPoolableFactory.java
index db29b7804655a27606d1fff89d7b681cb430a639..9d69006f9fb758d045d82ed4cbfe42ac0b68959a 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/NettyPoolableFactory.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/NettyPoolableFactory.java
@@ -21,7 +21,6 @@ import io.seata.common.exception.FrameworkException;
 import io.seata.common.util.NetUtil;
 import io.seata.core.protocol.RegisterRMResponse;
 import io.seata.core.protocol.RegisterTMResponse;
-import io.seata.core.rpc.netty.NettyPoolKey.TransactionRole;
 
 import io.netty.channel.Channel;
 import org.apache.commons.pool.KeyedPoolableObjectFactory;
diff --git a/core/src/main/java/io/seata/core/rpc/netty/RegisterCheckAuthHandler.java b/core/src/main/java/io/seata/core/rpc/netty/RegisterCheckAuthHandler.java
index d078a4df0dadcae0de5fd50f01012ecb84ff1878..ef0afc75f63805f4c2aac2ad037fa4ea6e18241a 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/RegisterCheckAuthHandler.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/RegisterCheckAuthHandler.java
@@ -15,8 +15,6 @@
  */
 package io.seata.core.rpc.netty;
 
-import io.seata.core.protocol.RegisterRMRequest;
-import io.seata.core.protocol.RegisterTMRequest;
 import io.seata.core.protocol.RegisterRMRequest;
 import io.seata.core.protocol.RegisterTMRequest;
 
diff --git a/core/src/main/java/io/seata/core/rpc/netty/RegisterMsgListener.java b/core/src/main/java/io/seata/core/rpc/netty/RegisterMsgListener.java
index 42a9eedbac5694f4334dc45a000bb58de1777401..98ba76fad0374ae459e138973143a08443817aa4 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/RegisterMsgListener.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/RegisterMsgListener.java
@@ -15,8 +15,6 @@
  */
 package io.seata.core.rpc.netty;
 
-import io.seata.core.protocol.AbstractMessage;
-
 import io.netty.channel.Channel;
 import io.seata.core.protocol.AbstractMessage;
 
diff --git a/core/src/main/java/io/seata/core/store/BranchTransactionDO.java b/core/src/main/java/io/seata/core/store/BranchTransactionDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..63c784daf6c6676238e22e55dc7f589720bbab63
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/BranchTransactionDO.java
@@ -0,0 +1,277 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store;
+
+
+import io.seata.common.util.StringUtils;
+import io.seata.core.model.BranchStatus;
+
+import java.util.Date;
+
+/**
+ * branch transaction data object
+ *
+ * @author zhangsen
+ * @data 2019 /3/26
+ */
+public class BranchTransactionDO {
+
+    private String xid;
+
+    private long transactionId;
+
+    private long branchId;
+
+    private String resourceGroupId;
+
+    private String resourceId;
+
+    private String lockKey;
+
+    private String branchType;
+
+    private int status = BranchStatus.Unknown.getCode();
+
+    private String clientId;
+
+    private String applicationData;
+
+    private Date gmtCreate;
+
+    private Date gmtModified;
+
+    /**
+     * Gets xid.
+     *
+     * @return the xid
+     */
+    public String getXid() {
+        return xid;
+    }
+
+    /**
+     * Sets xid.
+     *
+     * @param xid the xid
+     */
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Gets transaction id.
+     *
+     * @return the transaction id
+     */
+    public long getTransactionId() {
+        return transactionId;
+    }
+
+    /**
+     * Sets transaction id.
+     *
+     * @param transactionId the transaction id
+     */
+    public void setTransactionId(long transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    /**
+     * Gets branch id.
+     *
+     * @return the branch id
+     */
+    public long getBranchId() {
+        return branchId;
+    }
+
+    /**
+     * Sets branch id.
+     *
+     * @param branchId the branch id
+     */
+    public void setBranchId(long branchId) {
+        this.branchId = branchId;
+    }
+
+    /**
+     * Gets resource group id.
+     *
+     * @return the resource group id
+     */
+    public String getResourceGroupId() {
+        return resourceGroupId;
+    }
+
+    /**
+     * Sets resource group id.
+     *
+     * @param resourceGroupId the resource group id
+     */
+    public void setResourceGroupId(String resourceGroupId) {
+        this.resourceGroupId = resourceGroupId;
+    }
+
+    /**
+     * Gets resource id.
+     *
+     * @return the resource id
+     */
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    /**
+     * Sets resource id.
+     *
+     * @param resourceId the resource id
+     */
+    public void setResourceId(String resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    /**
+     * Gets lock key.
+     *
+     * @return the lock key
+     */
+    public String getLockKey() {
+        return lockKey;
+    }
+
+    /**
+     * Sets lock key.
+     *
+     * @param lockKey the lock key
+     */
+    public void setLockKey(String lockKey) {
+        this.lockKey = lockKey;
+    }
+
+    /**
+     * Gets branch type.
+     *
+     * @return the branch type
+     */
+    public String getBranchType() {
+        return branchType;
+    }
+
+    /**
+     * Sets branch type.
+     *
+     * @param branchType the branch type
+     */
+    public void setBranchType(String branchType) {
+        this.branchType = branchType;
+    }
+
+    /**
+     * Gets status.
+     *
+     * @return the status
+     */
+    public int getStatus() {
+        return status;
+    }
+
+    /**
+     * Sets status.
+     *
+     * @param status the status
+     */
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+    /**
+     * Gets client id.
+     *
+     * @return the client id
+     */
+    public String getClientId() {
+        return clientId;
+    }
+
+    /**
+     * Sets client id.
+     *
+     * @param clientId the client id
+     */
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    /**
+     * Gets application data.
+     *
+     * @return the application data
+     */
+    public String getApplicationData() {
+        return applicationData;
+    }
+
+    /**
+     * Sets application data.
+     *
+     * @param applicationData the application data
+     */
+    public void setApplicationData(String applicationData) {
+        this.applicationData = applicationData;
+    }
+
+    /**
+     * Gets gmt create.
+     *
+     * @return the gmt create
+     */
+    public Date getGmtCreate() {
+        return gmtCreate;
+    }
+
+    /**
+     * Sets gmt create.
+     *
+     * @param gmtCreate the gmt create
+     */
+    public void setGmtCreate(Date gmtCreate) {
+        this.gmtCreate = gmtCreate;
+    }
+
+    /**
+     * Gets gmt modified.
+     *
+     * @return the gmt modified
+     */
+    public Date getGmtModified() {
+        return gmtModified;
+    }
+
+    /**
+     * Sets gmt modified.
+     *
+     * @param gmtModified the gmt modified
+     */
+    public void setGmtModified(Date gmtModified) {
+        this.gmtModified = gmtModified;
+    }
+
+    @Override
+    public String toString(){
+        return StringUtils.toString(this);
+    }
+
+}
diff --git a/core/src/main/java/io/seata/core/store/GlobalTransactionDO.java b/core/src/main/java/io/seata/core/store/GlobalTransactionDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..74c5e9ae13f7e5e978fb88d4c6fb40f816c78502
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/GlobalTransactionDO.java
@@ -0,0 +1,256 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store;
+
+
+import io.seata.common.util.StringUtils;
+
+import java.util.Date;
+
+/**
+ * Global Transaction data object
+ *
+ * @author zhangsen
+ * @data 2019 /3/26
+ */
+public class GlobalTransactionDO {
+
+    private String xid;
+
+    private long transactionId;
+
+    private int status;
+
+    private String applicationId;
+
+    private String transactionServiceGroup;
+
+    private String transactionName;
+
+    private int timeout;
+
+    private long beginTime;
+
+    private String applicationData;
+
+    private Date gmtCreate;
+
+    private Date gmtModified;
+
+    /**
+     * Gets xid.
+     *
+     * @return the xid
+     */
+    public String getXid() {
+        return xid;
+    }
+
+    /**
+     * Sets xid.
+     *
+     * @param xid the xid
+     */
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Gets status.
+     *
+     * @return the status
+     */
+    public int getStatus() {
+        return status;
+    }
+
+    /**
+     * Sets status.
+     *
+     * @param status the status
+     */
+    public void setStatus(int status) {
+        this.status = status;
+    }
+
+    /**
+     * Gets application id.
+     *
+     * @return the application id
+     */
+    public String getApplicationId() {
+        return applicationId;
+    }
+
+    /**
+     * Sets application id.
+     *
+     * @param applicationId the application id
+     */
+    public void setApplicationId(String applicationId) {
+        this.applicationId = applicationId;
+    }
+
+    /**
+     * Gets transaction service group.
+     *
+     * @return the transaction service group
+     */
+    public String getTransactionServiceGroup() {
+        return transactionServiceGroup;
+    }
+
+    /**
+     * Sets transaction service group.
+     *
+     * @param transactionServiceGroup the transaction service group
+     */
+    public void setTransactionServiceGroup(String transactionServiceGroup) {
+        this.transactionServiceGroup = transactionServiceGroup;
+    }
+
+    /**
+     * Gets transaction name.
+     *
+     * @return the transaction name
+     */
+    public String getTransactionName() {
+        return transactionName;
+    }
+
+    /**
+     * Sets transaction name.
+     *
+     * @param transactionName the transaction name
+     */
+    public void setTransactionName(String transactionName) {
+        this.transactionName = transactionName;
+    }
+
+    /**
+     * Gets timeout.
+     *
+     * @return the timeout
+     */
+    public int getTimeout() {
+        return timeout;
+    }
+
+    /**
+     * Sets timeout.
+     *
+     * @param timeout the timeout
+     */
+    public void setTimeout(int timeout) {
+        this.timeout = timeout;
+    }
+
+    /**
+     * Gets begin time.
+     *
+     * @return the begin time
+     */
+    public long getBeginTime() {
+        return beginTime;
+    }
+
+    /**
+     * Sets begin time.
+     *
+     * @param beginTime the begin time
+     */
+    public void setBeginTime(long beginTime) {
+        this.beginTime = beginTime;
+    }
+
+    /**
+     * Gets transaction id.
+     *
+     * @return the transaction id
+     */
+    public long getTransactionId() {
+        return transactionId;
+    }
+
+    /**
+     * Sets transaction id.
+     *
+     * @param transactionId the transaction id
+     */
+    public void setTransactionId(long transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    /**
+     * Gets application data.
+     *
+     * @return the application data
+     */
+    public String getApplicationData() {
+        return applicationData;
+    }
+
+    /**
+     * Sets application data.
+     *
+     * @param applicationData the application data
+     */
+    public void setApplicationData(String applicationData) {
+        this.applicationData = applicationData;
+    }
+
+    /**
+     * Gets gmt create.
+     *
+     * @return the gmt create
+     */
+    public Date getGmtCreate() {
+        return gmtCreate;
+    }
+
+    /**
+     * Sets gmt create.
+     *
+     * @param gmtCreate the gmt create
+     */
+    public void setGmtCreate(Date gmtCreate) {
+        this.gmtCreate = gmtCreate;
+    }
+
+    /**
+     * Gets gmt modified.
+     *
+     * @return the gmt modified
+     */
+    public Date getGmtModified() {
+        return gmtModified;
+    }
+
+    /**
+     * Sets gmt modified.
+     *
+     * @param gmtModified the gmt modified
+     */
+    public void setGmtModified(Date gmtModified) {
+        this.gmtModified = gmtModified;
+    }
+
+    @Override
+    public String toString(){
+        return StringUtils.toString(this);
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/io/seata/core/store/LockDO.java b/core/src/main/java/io/seata/core/store/LockDO.java
new file mode 100644
index 0000000000000000000000000000000000000000..51b242de627e4f581c1d99ebe048f93770b31f1a
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/LockDO.java
@@ -0,0 +1,178 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store;
+
+import io.seata.common.util.StringUtils;
+
+/**
+ * The type Lock do.
+ *
+ * @author zhangsen
+ * @data 2019 /4/25
+ */
+public class LockDO {
+
+    private String xid;
+
+    private Long transactionId;
+
+    private Long branchId;
+
+    private String resourceId;
+
+    private String tableName;
+
+    private String pk;
+
+    private String rowKey;
+
+    /**
+     * Instantiates a new Lock do.
+     */
+    public LockDO() {
+    }
+
+    /**
+     * Gets xid.
+     *
+     * @return the xid
+     */
+    public String getXid() {
+        return xid;
+    }
+
+    /**
+     * Sets xid.
+     *
+     * @param xid the xid
+     */
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Gets transaction id.
+     *
+     * @return the transaction id
+     */
+    public Long getTransactionId() {
+        return transactionId;
+    }
+
+    /**
+     * Sets transaction id.
+     *
+     * @param transactionId the transaction id
+     */
+    public void setTransactionId(Long transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    /**
+     * Gets resource id.
+     *
+     * @return the resource id
+     */
+    public String getResourceId() {
+        return resourceId;
+    }
+
+    /**
+     * Sets resource id.
+     *
+     * @param resourceId the resource id
+     */
+    public void setResourceId(String resourceId) {
+        this.resourceId = resourceId;
+    }
+
+    /**
+     * Gets row key.
+     *
+     * @return the row key
+     */
+    public String getRowKey() {
+        return rowKey;
+    }
+
+    /**
+     * Sets row key.
+     *
+     * @param rowKey the row key
+     */
+    public void setRowKey(String rowKey) {
+        this.rowKey = rowKey;
+    }
+
+    /**
+     * Gets table name.
+     *
+     * @return the table name
+     */
+    public String getTableName() {
+        return tableName;
+    }
+
+    /**
+     * Sets table name.
+     *
+     * @param tableName the table name
+     */
+    public void setTableName(String tableName) {
+        this.tableName = tableName;
+    }
+
+    /**
+     * Gets pk.
+     *
+     * @return the pk
+     */
+    public String getPk() {
+        return pk;
+    }
+
+    /**
+     * Sets pk.
+     *
+     * @param pk the pk
+     */
+    public void setPk(String pk) {
+        this.pk = pk;
+    }
+
+    /**
+     * Gets branch id.
+     *
+     * @return the branch id
+     */
+    public Long getBranchId() {
+        return branchId;
+    }
+
+    /**
+     * Sets branch id.
+     *
+     * @param branchId the branch id
+     */
+    public void setBranchId(Long branchId) {
+        this.branchId = branchId;
+    }
+
+    @Override
+    public String toString() {
+        return StringUtils.toString(this);
+    }
+}
diff --git a/core/src/main/java/io/seata/core/store/LockStore.java b/core/src/main/java/io/seata/core/store/LockStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..49e92e6ab104a88af069a3a8087906964cb1dd5d
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/LockStore.java
@@ -0,0 +1,68 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store;
+
+import java.util.List;
+
+/**
+ * The interface Lock store.
+ *
+ * @author zhangsen
+ * @data 2019 /4/25
+ */
+public interface LockStore {
+
+    /**
+     * Acquire lock boolean.
+     *
+     * @param lockDO the lock do
+     * @return the boolean
+     */
+    boolean acquireLock(LockDO lockDO);
+
+
+    /**
+     * Acquire lock boolean.
+     *
+     * @param lockDOs the lock d os
+     * @return the boolean
+     */
+    boolean acquireLock(List<LockDO> lockDOs);
+
+    /**
+     * Un lock boolean.
+     *
+     * @param lockDO the lock do
+     * @return the boolean
+     */
+    boolean unLock(LockDO lockDO);
+
+    /**
+     * Un lock boolean.
+     *
+     * @param lockDOs the lock d os
+     * @return the boolean
+     */
+    boolean unLock(List<LockDO> lockDOs);
+
+    /**
+     * Is lockable boolean.
+     *
+     * @param lockDOs the lock do
+     * @return the boolean
+     */
+    boolean isLockable(List<LockDO> lockDOs);
+}
diff --git a/core/src/main/java/io/seata/core/store/LogStore.java b/core/src/main/java/io/seata/core/store/LogStore.java
new file mode 100644
index 0000000000000000000000000000000000000000..f02b0ddc6d2d2fe1ed7b4fcf6c2b67206b33d6b0
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/LogStore.java
@@ -0,0 +1,110 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store;
+
+
+import java.util.List;
+
+/**
+ * the transaction log store
+ *
+ * @author zhangsen
+ * @data 2019 /3/26
+ */
+public interface LogStore {
+
+    /**
+     * Query global transaction do global transaction do.
+     *
+     * @param xid the xid
+     * @return the global transaction do
+     */
+    GlobalTransactionDO queryGlobalTransactionDO(String xid);
+
+    /**
+     * Query global transaction do global transaction do.
+     *
+     * @param transactionId the transaction id
+     * @return the global transaction do
+     */
+    GlobalTransactionDO queryGlobalTransactionDO(long transactionId);
+
+    /**
+     * Query global transaction do list.
+     *
+     * @param status the status
+     * @param limit  the limit
+     * @return the list
+     */
+    List<GlobalTransactionDO> queryGlobalTransactionDO(int[] status, int limit);
+
+    /**
+     * Insert global transaction do boolean.
+     *
+     * @param globalTransactionDO the global transaction do
+     * @return the boolean
+     */
+    boolean insertGlobalTransactionDO(GlobalTransactionDO globalTransactionDO);
+
+    /**
+     * Update global transaction do boolean.
+     *
+     * @param globalTransactionDO the global transaction do
+     * @return the boolean
+     */
+    boolean updateGlobalTransactionDO(GlobalTransactionDO globalTransactionDO);
+
+    /**
+     * Delete global transaction do boolean.
+     *
+     * @param globalTransactionDO the global transaction do
+     * @return the boolean
+     */
+    boolean deleteGlobalTransactionDO(GlobalTransactionDO globalTransactionDO);
+
+    /**
+     * Query branch transaction do boolean.
+     *
+     * @param xid the xid
+     * @return the boolean
+     */
+    List<BranchTransactionDO> queryBranchTransactionDO(String xid);
+
+    /**
+     * Insert branch transaction do boolean.
+     *
+     * @param branchTransactionDO the branch transaction do
+     * @return the boolean
+     */
+    boolean insertBranchTransactionDO(BranchTransactionDO branchTransactionDO);
+
+    /**
+     * Update branch transaction do boolean.
+     *
+     * @param branchTransactionDO the branch transaction do
+     * @return the boolean
+     */
+    boolean updateBranchTransactionDO(BranchTransactionDO branchTransactionDO);
+
+    /**
+     * Delete branch transaction do boolean.
+     *
+     * @param branchTransactionDO the branch transaction do
+     * @return the boolean
+     */
+    boolean deleteBranchTransactionDO(BranchTransactionDO branchTransactionDO);
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/io/seata/core/store/db/AbstractDataSourceGenerator.java b/core/src/main/java/io/seata/core/store/db/AbstractDataSourceGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..2cdbcb00ce6237948bc7d6bc0df50c16be6236cc
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/db/AbstractDataSourceGenerator.java
@@ -0,0 +1,148 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import io.seata.common.exception.StoreException;
+import io.seata.common.util.StringUtils;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
+import io.seata.core.constants.ConfigurationKeys;
+import io.seata.core.constants.DBType;
+
+/**
+ * The type Abstract data source generator.
+ *
+ * @author zhangsen
+ * @data 2019 /4/24
+ */
+public abstract class AbstractDataSourceGenerator implements DataSourceGenerator {
+
+    /**
+     * The constant CONFIG.
+     */
+    protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
+
+    /**
+     * Get db type db type.
+     *
+     * @return the db type
+     */
+    protected DBType getDBType(){
+        return DBType.valueof(CONFIG.getConfig(ConfigurationKeys.STORE_DB_TYPE));
+    }
+
+    /**
+     * Get url string.
+     *
+     * @return the string
+     */
+    protected String getUrl(){
+        String url = CONFIG.getConfig(ConfigurationKeys.STORE_DB_URL);
+        if(StringUtils.isBlank(url)){
+            throw new StoreException("the {store.db.url} can't empty.");
+        }
+        return url;
+    }
+
+    /**
+     * Get user string.
+     *
+     * @return the string
+     */
+    protected String getUser(){
+        String user = CONFIG.getConfig(ConfigurationKeys.STORE_DB_USER);
+        if(StringUtils.isBlank(user)){
+            throw new StoreException("the {store.db.user} can't empty.");
+        }
+        return user;
+    }
+
+    /**
+     * Get password string.
+     *
+     * @return the string
+     */
+    protected String getPassword(){
+        String password = CONFIG.getConfig(ConfigurationKeys.STORE_DB_PASSWORD);
+        return password;
+    }
+
+    /**
+     * Get min conn int.
+     *
+     * @return the int
+     */
+    protected int getMinConn(){
+        int minConn = CONFIG.getInt(ConfigurationKeys.STORE_DB_MIN_CONN);
+        return minConn<0?0:minConn;
+    }
+
+    /**
+     * Get max conn int.
+     *
+     * @return the int
+     */
+    protected int getMaxConn(){
+        int maxConn = CONFIG.getInt(ConfigurationKeys.STORE_DB_MAX_CONN);
+        return maxConn<0?1:maxConn;
+    }
+
+
+    /**
+     * Get driver name string.
+     *
+     * @param dbType the db type
+     * @return the string
+     */
+    protected static String getDriverName(DBType dbType){
+        if(DBType.H2.equals(dbType)){
+            return "org.h2.Driver";
+        }else if(DBType.MYSQL.equals(dbType)){
+            return "com.mysql.jdbc.Driver";
+        }else if(DBType.ORACLE.equals(dbType)){
+            return "oracle.jdbc.OracleDriver";
+        }else if(DBType.SYBAEE.equals(dbType)){
+            return "com.sybase.jdbc2.jdbc.SybDriver";
+        }else if(DBType.SQLSERVER.equals(dbType)){
+            return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
+        }else if(DBType.SQLITE.equals(dbType)){
+            return "org.sqlite.JDBC";
+        }else if(DBType.POSTGRESQL.equals(dbType)){
+            return "org.postgresql.Driver";
+        }else if(DBType.ACCESS.equals(dbType)){
+            return "com.hxtt.sql.access.AccessDriver";
+        }else if(DBType.DB2.equals(dbType)){
+            return "com.ibm.db2.jcc.DB2Driver";
+        }else {
+            throw new StoreException("Unsupported database type, dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get validation query string.
+     *
+     * @param dbType the db type
+     * @return the string
+     */
+    protected String getValidationQuery(DBType dbType){
+        if(DBType.ORACLE.equals(dbType)){
+            return "select sysdate from dual";
+        }else {
+            return "select 1";
+        }
+    }
+
+}
diff --git a/core/src/main/java/io/seata/core/store/db/DataSourceGenerator.java b/core/src/main/java/io/seata/core/store/db/DataSourceGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..5687513969b78841e5753f4494c775da014682bc
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/db/DataSourceGenerator.java
@@ -0,0 +1,35 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import javax.sql.DataSource;
+
+/**
+ * The interface Data source generator.
+ *
+ * @author zhangsen
+ * @data 2019 /4/24
+ */
+public interface DataSourceGenerator {
+
+    /**
+     * create DataSource from config
+     *
+     * @return data source
+     */
+    DataSource generateDataSource();
+
+}
diff --git a/core/src/main/java/io/seata/core/store/db/LockStoreDataBaseDAO.java b/core/src/main/java/io/seata/core/store/db/LockStoreDataBaseDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1aac28881446cb93480abae031c65a7d214c774
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/db/LockStoreDataBaseDAO.java
@@ -0,0 +1,356 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import io.seata.common.exception.StoreException;
+import io.seata.common.executor.Initialize;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.util.StringUtils;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
+import io.seata.core.constants.ConfigurationKeys;
+import io.seata.core.store.LockDO;
+import io.seata.core.store.LockStore;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The type Data base lock store.
+ *
+ * @author zhangsen
+ * @data 2019 /4/25
+ */
+@LoadLevel(name = "db")
+public class LockStoreDataBaseDAO implements LockStore, Initialize {
+
+    /**
+     * The constant CONFIG.
+     */
+    protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
+
+    /**
+     * The Log store data source.
+     */
+    protected DataSource logStoreDataSource = null;
+
+    /**
+     * The Lock table.
+     */
+    protected String lockTable;
+
+    /**
+     * The Db type.
+     */
+    protected String dbType;
+
+    /**
+     * Instantiates a new Data base lock store dao.
+     *
+     * @param logStoreDataSource the log store data source
+     */
+    public LockStoreDataBaseDAO(DataSource logStoreDataSource) {
+        this.logStoreDataSource = logStoreDataSource;
+    }
+
+    @Override
+    public void init() {
+        lockTable = CONFIG.getConfig(ConfigurationKeys.LOCK_DB_TABLE, ConfigurationKeys.LOCK_DB_DEFAULT_TABLE);
+        dbType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_TYPE);
+        if (StringUtils.isBlank(dbType)) {
+            throw new StoreException("there must be db type.");
+        }
+        if (logStoreDataSource == null) {
+            throw new StoreException("there must be logStoreDataSource.");
+        }
+    }
+
+    @Override
+    public boolean acquireLock(LockDO lockDO) {
+        List<LockDO> locks = new ArrayList<>();
+        locks.add(lockDO);
+        return acquireLock(locks);
+    }
+
+    @Override
+    public boolean acquireLock(List<LockDO> lockDOs) {
+        Connection conn = null;
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(false);
+
+            //check lock
+            StringBuilder sb = new StringBuilder();
+            for(int i = 0; i < lockDOs.size(); i++){
+                sb.append("?");
+                if( i != (lockDOs.size() - 1)){
+                    sb.append(", ");
+                }
+            }
+            boolean canLock = true, isReLock = false;
+            //query
+            String checkLockSQL = LockStoreSqls.getCheckLockableSql(lockTable, sb.toString(), dbType);
+            ps = conn.prepareStatement(checkLockSQL);
+            for (int i = 0; i < lockDOs.size(); i++){
+                ps.setString(i+1, lockDOs.get(i).getRowKey());
+            }
+            rs = ps.executeQuery();
+            while (rs.next()) {
+                if(StringUtils.equals(rs.getString("xid"), lockDOs.get(0).getXid())){
+                    isReLock = true;
+                }else {
+                    canLock &= false;
+                }
+            }
+
+            if(!canLock){
+                conn.rollback();
+                return false;
+            }
+
+            if(isReLock){
+                conn.rollback();
+                return true;
+            }
+
+            //lock
+            for(LockDO lockDO : lockDOs){
+                if(!doAcquireLock(conn, lockDO)) {
+                    conn.rollback();
+                    return false;
+                }
+            }
+            conn.commit();
+            return true;
+        } catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if (rs != null) {
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean unLock(LockDO lockDO) {
+        List<LockDO> locks = new ArrayList<>();
+        locks.add(lockDO);
+        return unLock(locks);
+    }
+
+    @Override
+    public boolean unLock(List<LockDO> lockDOs) {
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+
+            StringBuilder sb = new StringBuilder();
+            for(int i = 0; i< lockDOs.size(); i++){
+                sb.append("?");
+                if(i != (lockDOs.size() - 1)){
+                    sb.append(", ");
+                }
+            }
+            //batch release lock
+            String batchDeleteSQL = LockStoreSqls.getBatchDeleteLockSql(lockTable, sb.toString(), dbType);
+            ps = conn.prepareStatement(batchDeleteSQL);
+            ps.setString(1, lockDOs.get(0).getXid());
+            for(int i = 0; i< lockDOs.size(); i++){
+                ps.setString(i+2, lockDOs.get(i).getRowKey());
+            }
+            return ps.executeUpdate() > 0;
+        } catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean isLockable(List<LockDO> lockDOs) {
+        Connection conn = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            if(!checkLockable(conn, lockDOs)){
+                return false;
+            }
+            return true;
+        } catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Do acquire lock boolean.
+     *
+     * @param conn   the conn
+     * @param lockDO the lock do
+     * @return the boolean
+     */
+    protected boolean doAcquireLock(Connection conn, LockDO lockDO) {
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            //insert
+            String insertLockSQL = LockStoreSqls.getInsertLockSQL(lockTable, dbType);
+            ps = conn.prepareStatement(insertLockSQL);
+            ps.setString(1, lockDO.getXid());
+            ps.setLong(2, lockDO.getTransactionId());
+            ps.setLong(3, lockDO.getBranchId());
+            ps.setString(4, lockDO.getResourceId());
+            ps.setString(5, lockDO.getTableName());
+            ps.setString(6, lockDO.getPk());
+            ps.setString(7, lockDO.getRowKey());
+            return ps.executeUpdate() > 0;
+        } catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if (rs != null) {
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Check lock boolean.
+     *
+     * @param conn    the conn
+     * @param lockDOs the lock do
+     * @return the boolean
+     */
+    protected boolean checkLockable(Connection conn, List<LockDO> lockDOs){
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            StringBuilder sb = new StringBuilder();
+            for(int i = 0; i < lockDOs.size(); i++){
+                sb.append("?");
+                if( i != (lockDOs.size() - 1)){
+                    sb.append(", ");
+                }
+            }
+
+            //query
+            String checkLockSQL = LockStoreSqls.getCheckLockableSql(lockTable, sb.toString(), dbType);
+            ps = conn.prepareStatement(checkLockSQL);
+            for (int i = 0; i < lockDOs.size(); i++){
+                ps.setString(i+1, lockDOs.get(i).getRowKey());
+            }
+            rs = ps.executeQuery();
+            while (rs.next()) {
+                String xid = rs.getString("xid");
+                if(!StringUtils.equals(xid, lockDOs.get(0).getXid())){
+                    return false;
+                }
+            }
+            return true;
+        }catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if (rs != null) {
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets lock table.
+     *
+     * @param lockTable the lock table
+     */
+    public void setLockTable(String lockTable) {
+        this.lockTable = lockTable;
+    }
+
+    /**
+     * Sets db type.
+     *
+     * @param dbType the db type
+     */
+    public void setDbType(String dbType) {
+        this.dbType = dbType;
+    }
+
+    /**
+     * Sets log store data source.
+     *
+     * @param logStoreDataSource the log store data source
+     */
+    public void setLogStoreDataSource(DataSource logStoreDataSource) {
+        this.logStoreDataSource = logStoreDataSource;
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/io/seata/core/store/db/LockStoreSqls.java b/core/src/main/java/io/seata/core/store/db/LockStoreSqls.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c95473e2693b3b7fe2e35c850aae4f34186649a
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/db/LockStoreSqls.java
@@ -0,0 +1,143 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import io.seata.common.exception.NotSupportYetException;
+import io.seata.core.constants.DBType;
+
+/**
+ * The type Lock store sqls.
+ *
+ * @author zhangsen
+ * @data 2019 /4/26
+ */
+public class LockStoreSqls {
+
+    /**
+     * The constant LOCK_TABLE_PLACEHOLD.
+     */
+    public static final String LOCK_TABLE_PLACEHOLD = " #lock_table# ";
+
+    /**
+     * The constant IN_PARAMS_PLACEHOLD.
+     */
+    public static final String IN_PARAMS_PLACEHOLD = " #in_params# ";
+
+    /**
+     * The constant ALL_COLUMNS.
+     */
+    public static final String ALL_COLUMNS = "xid, transaction_id, branch_id, resource_id, table_name, pk, row_key, gmt_create, gmt_modified";
+
+    /**
+     * The constant INSERT_LOCK_SQL_MYSQL.
+     */
+    public static final String INSERT_LOCK_SQL_MYSQL = "insert into " + LOCK_TABLE_PLACEHOLD + "("+ ALL_COLUMNS +")" +
+            "values (?, ?, ?, ?, ?, ?, ?, now(), now())";
+
+    /**
+     * The constant INSERT_LOCK_SQL_ORACLE.
+     */
+    public static final String INSERT_LOCK_SQL_ORACLE = "insert into " + LOCK_TABLE_PLACEHOLD + "("+ ALL_COLUMNS +")" +
+            "values (?, ?, ?, ?, ?, ?, ?, sysdate, sysdate)";
+
+    /**
+     * The constant DELETE_LOCK_SQL.
+     */
+    public static final String DELETE_LOCK_SQL = "delete from " + LOCK_TABLE_PLACEHOLD  + " where row_key = ? and xid = ?";
+
+    /**
+     * The constant BATCH_DELETE_LOCK_SQL.
+     */
+    public static final String BATCH_DELETE_LOCK_SQL = "delete from " + LOCK_TABLE_PLACEHOLD  + " where xid = ? and row_key in ("+ IN_PARAMS_PLACEHOLD +") ";
+
+    /**
+     * The constant QUERY_LOCK_SQL.
+     */
+    public static final String QUERY_LOCK_SQL = "select " + ALL_COLUMNS + " from " + LOCK_TABLE_PLACEHOLD
+            + " where row_key = ? ";
+
+    /**
+     * The constant CHECK_LOCK_SQL.
+     */
+    public static final String CHECK_LOCK_SQL =  "select " + ALL_COLUMNS + " from " + LOCK_TABLE_PLACEHOLD
+            + " where row_key in ("+ IN_PARAMS_PLACEHOLD +")"  ;
+
+    /**
+     * Get insert lock sql string.
+     *
+     * @param lockTable the lock table
+     * @param dbType    the db type
+     * @return the string
+     */
+    public static String getInsertLockSQL(String lockTable, String dbType){
+        if(DBType.MYSQL.name().equalsIgnoreCase(dbType)
+                || DBType.OCEANBASE.name().equalsIgnoreCase(dbType)
+                || DBType.H2.name().equalsIgnoreCase(dbType)){
+            return INSERT_LOCK_SQL_MYSQL.replace(LOCK_TABLE_PLACEHOLD, lockTable);
+        }else if(DBType.ORACLE.name().equalsIgnoreCase(dbType)){
+            return INSERT_LOCK_SQL_ORACLE.replace(LOCK_TABLE_PLACEHOLD, lockTable);
+        }else{
+            throw new NotSupportYetException("unknown dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get delete lock sql string.
+     *
+     * @param lockTable the lock table
+     * @param dbType    the db type
+     * @return the string
+     */
+    public static String getDeleteLockSql(String lockTable, String dbType){
+        return DELETE_LOCK_SQL.replace(LOCK_TABLE_PLACEHOLD, lockTable);
+    }
+
+    /**
+     * Get batch delete lock sql string.
+     *
+     * @param lockTable      the lock table
+     * @param paramPlaceHold the param place hold
+     * @param dbType         the db type
+     * @return the string
+     */
+    public static String getBatchDeleteLockSql(String lockTable, String paramPlaceHold, String dbType){
+        return BATCH_DELETE_LOCK_SQL.replace(LOCK_TABLE_PLACEHOLD, lockTable).replace(IN_PARAMS_PLACEHOLD, paramPlaceHold);
+    }
+
+    /**
+     * Get query lock sql string.
+     *
+     * @param lockTable the lock table
+     * @param dbType    the db type
+     * @return the string
+     */
+    public static String getQueryLockSql(String lockTable, String dbType){
+        return QUERY_LOCK_SQL.replace(LOCK_TABLE_PLACEHOLD, lockTable);
+    }
+
+    /**
+     * Get check lock sql string.
+     *
+     * @param lockTable      the lock table
+     * @param paramPlaceHold the param place hold
+     * @param dbType         the db type
+     * @return the string
+     */
+    public static String getCheckLockableSql(String lockTable, String paramPlaceHold, String dbType){
+        return CHECK_LOCK_SQL.replace(LOCK_TABLE_PLACEHOLD, lockTable).replace(IN_PARAMS_PLACEHOLD, paramPlaceHold);
+    }
+
+}
diff --git a/core/src/main/java/io/seata/core/store/db/LogStoreDataBaseDAO.java b/core/src/main/java/io/seata/core/store/db/LogStoreDataBaseDAO.java
new file mode 100644
index 0000000000000000000000000000000000000000..4248ce45929b891bf5f3656f147b1e428555c5df
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/db/LogStoreDataBaseDAO.java
@@ -0,0 +1,533 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import io.seata.common.exception.StoreException;
+import io.seata.common.executor.Initialize;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.util.StringUtils;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
+import io.seata.core.constants.ConfigurationKeys;
+import io.seata.core.store.BranchTransactionDO;
+import io.seata.core.store.GlobalTransactionDO;
+import io.seata.core.store.LogStore;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The type Log store data base dao.
+ *
+ * @author zhangsen
+ * @data 2019 /4/2
+ */
+@LoadLevel(name = "db")
+public class LogStoreDataBaseDAO implements LogStore, Initialize {
+
+    /**
+     * The constant CONFIG.
+     */
+    protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
+
+    /**
+     * The Log store data source.
+     */
+    protected DataSource logStoreDataSource = null;
+
+    /**
+     * The Global table.
+     */
+    protected String globalTable;
+
+    /**
+     * The Brach table.
+     */
+    protected String brachTable;
+
+    private String dbType;
+
+    /**
+     * Instantiates a new Log store data base dao.
+     */
+    public LogStoreDataBaseDAO(){
+    }
+
+    /**
+     * Instantiates a new Log store data base dao.
+     *
+     * @param logStoreDataSource the log store data source
+     */
+    public LogStoreDataBaseDAO(DataSource logStoreDataSource) {
+        this.logStoreDataSource = logStoreDataSource;
+    }
+
+    @Override
+    public void init() {
+        globalTable = CONFIG.getConfig(ConfigurationKeys.STORE_DB_GLOBAL_TABLE, ConfigurationKeys.STORE_DB_GLOBAL_DEFAULT_TABLE);
+        brachTable = CONFIG.getConfig(ConfigurationKeys.STORE_DB_BRANCH_TABLE, ConfigurationKeys.STORE_DB_BRANCH_DEFAULT_TABLE);
+        dbType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_TYPE);
+        if(StringUtils.isBlank(dbType)){
+            throw new StoreException("there must be db type.");
+        }
+        if(logStoreDataSource == null){
+            throw new StoreException("there must be logStoreDataSource.");
+        }
+    }
+
+    @Override
+    public GlobalTransactionDO queryGlobalTransactionDO(String xid) {
+        String sql = LogStoreSqls.getQueryGlobalTransactionSQL(globalTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, xid);
+            rs = ps.executeQuery();
+            if(rs.next()){
+                return convertGlobalTransactionDO(rs);
+            }else {
+                return null;
+            }
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(rs != null){
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+
+    @Override
+    public GlobalTransactionDO queryGlobalTransactionDO(long transactionId){
+        String sql = LogStoreSqls.getQueryGlobalTransactionSQLByTransactionId(globalTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setLong(1, transactionId);
+            rs = ps.executeQuery();
+            if(rs.next()){
+                return convertGlobalTransactionDO(rs);
+            }else {
+                return null;
+            }
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(rs != null){
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public List<GlobalTransactionDO> queryGlobalTransactionDO(int[] statuses, int limit) {
+        List<GlobalTransactionDO> ret = new ArrayList<GlobalTransactionDO>();
+        Connection conn = null;
+        PreparedStatement ps = null;
+        ResultSet rs = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+
+            StringBuilder sb = new StringBuilder();
+            for(int i = 0; i < statuses.length; i ++){
+                sb.append("?");
+                if(i != (statuses.length -1)){
+                    sb.append(", ");
+                }
+            }
+
+            String sql = LogStoreSqls.getQueryGlobalTransactionSQLByStatus(globalTable, dbType, sb.toString());
+            ps = conn.prepareStatement(sql);
+            for(int i = 0; i < statuses.length; i ++){
+                int status = statuses[i];
+                ps.setInt(i+1, status);
+            }
+            ps.setInt(statuses.length +1, limit);
+            rs = ps.executeQuery();
+            while(rs.next()){
+                ret.add(convertGlobalTransactionDO(rs));
+            }
+            return ret;
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(rs != null){
+                try {
+                    rs.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean insertGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) {
+        String sql = LogStoreSqls.getInsertGlobalTransactionSQL(globalTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try{
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, globalTransactionDO.getXid());
+            ps.setLong(2, globalTransactionDO.getTransactionId());
+            ps.setInt(3, globalTransactionDO.getStatus());
+            ps.setString(4, globalTransactionDO.getApplicationId());
+            ps.setString(5, globalTransactionDO.getTransactionServiceGroup());
+            ps.setString(6, globalTransactionDO.getTransactionName());
+            ps.setInt(7, globalTransactionDO.getTimeout());
+            ps.setLong(8, globalTransactionDO.getBeginTime());
+            ps.setString(9, globalTransactionDO.getApplicationData());
+            return ps.executeUpdate() > 0;
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean updateGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) {
+        String sql = LogStoreSqls.getUpdateGlobalTransactionStatusSQL(globalTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try{
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setInt(1, globalTransactionDO.getStatus());
+            ps.setString(2, globalTransactionDO.getXid());
+            return ps.executeUpdate() > 0;
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean deleteGlobalTransactionDO(GlobalTransactionDO globalTransactionDO) {
+        String sql = LogStoreSqls.getDeleteGlobalTransactionSQL(globalTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try{
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, globalTransactionDO.getXid());
+            return ps.executeUpdate() > 0;
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public List<BranchTransactionDO> queryBranchTransactionDO(String xid) {
+        List<BranchTransactionDO> rets = new ArrayList<>();
+        String sql = LogStoreSqls.getQureyBranchTransaction(brachTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, xid);
+
+            ResultSet rs = ps.executeQuery();
+            while(rs.next()){
+                rets.add(convertBranchTransactionDO(rs));
+            }
+            return rets;
+        } catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean insertBranchTransactionDO(BranchTransactionDO branchTransactionDO) {
+        String sql = LogStoreSqls.getInsertBranchTransactionSQL(brachTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try {
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, branchTransactionDO.getXid());
+            ps.setLong(2, branchTransactionDO.getTransactionId());
+            ps.setLong(3, branchTransactionDO.getBranchId());
+            ps.setString(4, branchTransactionDO.getResourceGroupId());
+            ps.setString(5, branchTransactionDO.getResourceId());
+            ps.setString(6, branchTransactionDO.getLockKey());
+            ps.setString(7, branchTransactionDO.getBranchType());
+            ps.setInt(8, branchTransactionDO.getStatus());
+            ps.setString(9, branchTransactionDO.getClientId());
+            ps.setString(10, branchTransactionDO.getApplicationData());
+            return ps.executeUpdate() > 0;
+        } catch (SQLException e) {
+            throw new StoreException(e);
+        } finally {
+            if (ps != null) {
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean updateBranchTransactionDO(BranchTransactionDO branchTransactionDO) {
+        String sql = LogStoreSqls.getUpdateBranchTransactionStatusSQL(brachTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try{
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setInt(1, branchTransactionDO.getStatus());
+            ps.setString(2, branchTransactionDO.getXid());
+            ps.setLong(3, branchTransactionDO.getBranchId());
+            return ps.executeUpdate() > 0;
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean deleteBranchTransactionDO(BranchTransactionDO branchTransactionDO) {
+        String sql = LogStoreSqls.getDeleteBranchTransactionByBranchIdSQL(brachTable, dbType);
+        Connection conn = null;
+        PreparedStatement ps = null;
+        try{
+            conn = logStoreDataSource.getConnection();
+            conn.setAutoCommit(true);
+            ps = conn.prepareStatement(sql);
+            ps.setString(1, branchTransactionDO.getXid());
+            ps.setLong(2, branchTransactionDO.getBranchId());
+            return ps.executeUpdate() > 0;
+        }catch (SQLException e){
+            throw new StoreException(e);
+        }finally {
+            if(ps != null){
+                try {
+                    ps.close();
+                } catch (SQLException e) {
+                }
+            }
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+
+    private GlobalTransactionDO convertGlobalTransactionDO(ResultSet rs) throws SQLException {
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid(rs.getString("xid"));
+        globalTransactionDO.setStatus(rs.getInt("status"));
+        globalTransactionDO.setApplicationId(rs.getString("application_id"));
+        globalTransactionDO.setBeginTime(rs.getLong("begin_time"));
+        globalTransactionDO.setTimeout(rs.getInt("timeout"));
+        globalTransactionDO.setTransactionId(rs.getLong("transaction_id"));
+        globalTransactionDO.setTransactionName(rs.getString("transaction_name"));
+        globalTransactionDO.setTransactionServiceGroup(rs.getString("transaction_service_group"));
+        globalTransactionDO.setApplicationData(rs.getString("application_data"));
+        globalTransactionDO.setGmtCreate(rs.getTimestamp("gmt_create"));
+        globalTransactionDO.setGmtModified(rs.getTimestamp("gmt_modified"));
+        return globalTransactionDO;
+    }
+
+    private BranchTransactionDO convertBranchTransactionDO(ResultSet rs) throws SQLException {
+        BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+        branchTransactionDO.setResourceGroupId(rs.getString("resource_group_id"));
+        branchTransactionDO.setStatus(rs.getInt("status"));
+        branchTransactionDO.setApplicationData(rs.getString("application_data"));
+        branchTransactionDO.setClientId(rs.getString("client_id"));
+        branchTransactionDO.setLockKey(rs.getString("lock_key"));
+        branchTransactionDO.setXid(rs.getString("xid"));
+        branchTransactionDO.setResourceId(rs.getString("resource_id"));
+        branchTransactionDO.setBranchId(rs.getLong("branch_id"));
+        branchTransactionDO.setBranchType(rs.getString("branch_type"));
+        branchTransactionDO.setTransactionId(rs.getLong("transaction_id"));
+        branchTransactionDO.setGmtCreate(rs.getTimestamp("gmt_create"));
+        branchTransactionDO.setGmtModified(rs.getTimestamp("gmt_modified"));
+        return branchTransactionDO;
+    }
+
+    /**
+     * Sets log store data source.
+     *
+     * @param logStoreDataSource the log store data source
+     */
+    public void setLogStoreDataSource(DataSource logStoreDataSource) {
+        this.logStoreDataSource = logStoreDataSource;
+    }
+
+    /**
+     * Sets global table.
+     *
+     * @param globalTable the global table
+     */
+    public void setGlobalTable(String globalTable) {
+        this.globalTable = globalTable;
+    }
+
+    /**
+     * Sets brach table.
+     *
+     * @param brachTable the brach table
+     */
+    public void setBrachTable(String brachTable) {
+        this.brachTable = brachTable;
+    }
+
+    /**
+     * Sets db type.
+     *
+     * @param dbType the db type
+     */
+    public void setDbType(String dbType) {
+        this.dbType = dbType;
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/java/io/seata/core/store/db/LogStoreSqls.java b/core/src/main/java/io/seata/core/store/db/LogStoreSqls.java
new file mode 100644
index 0000000000000000000000000000000000000000..69308324d633a11b49c875384d0128744ac6ff10
--- /dev/null
+++ b/core/src/main/java/io/seata/core/store/db/LogStoreSqls.java
@@ -0,0 +1,323 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+
+import io.seata.common.exception.NotSupportYetException;
+import io.seata.core.constants.DBType;
+
+/**
+ * database log store SQLs
+ *
+ * @author zhangsen
+ * @data 2019 /4/2
+ */
+public class LogStoreSqls {
+
+    /**
+     * The constant GLOBAL_TABLE_PLACEHOLD.
+     */
+    public static final String GLOBAL_TABLE_PLACEHOLD = " #global_table# ";
+
+    /**
+     * The constant BRANCH_TABLE_PLACEHOLD.
+     */
+    public static final String BRANCH_TABLE_PLACEHOLD = " #branch_table# ";
+
+
+    /**
+     * The constant PRAMETER_PLACEHOLD.
+     */
+    public static final String PRAMETER_PLACEHOLD = " #PRAMETER_PLACEHOLD# ";
+
+    /**
+     * The constant ALL_GLOBAL_COLUMNS.
+     */
+    public static final String ALL_GLOBAL_COLUMNS = "xid, transaction_id, status, application_id, transaction_service_group, transaction_name, timeout, begin_time, application_data, gmt_create, gmt_modified ";
+
+    /**
+     * The constant ALL_BRANCH_COLUMNS.
+     */
+    protected static final String ALL_BRANCH_COLUMNS = "xid, transaction_id, branch_id, resource_group_id, resource_id, lock_key, branch_type, status, client_id, application_data, gmt_create, gmt_modified ";
+
+    /**
+     * The constant INSERT_GLOBAL_TRANSACTION_MYSQL.
+     */
+    public static final String INSERT_GLOBAL_TRANSACTION_MYSQL = "insert into " + GLOBAL_TABLE_PLACEHOLD + "("+ ALL_GLOBAL_COLUMNS +")" +
+            "values(?, ?, ?, ?, ?, ?, ?, ?, ?, now(), now()) ";
+
+    /**
+     * The constant INSERT_GLOBAL_TRANSACTION_ORACLE.
+     */
+    public static final String INSERT_GLOBAL_TRANSACTION_ORACLE = "insert into " + GLOBAL_TABLE_PLACEHOLD + "("+ ALL_GLOBAL_COLUMNS +")" +
+            "values(?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate, sysdate) ";
+
+    /**
+     * The constant UPDATE_GLOBAL_TRANSACTION_STATUS_MYSQL.
+     */
+    public static final String UPDATE_GLOBAL_TRANSACTION_STATUS_MYSQL = "update "+ GLOBAL_TABLE_PLACEHOLD + " set status = ?, gmt_modified = now() where xid = ?";
+
+    /**
+     * The constant UPDATE_GLOBAL_TRANSACTION_STATUS_ORACLE.
+     */
+    public static final String UPDATE_GLOBAL_TRANSACTION_STATUS_ORACLE = "update "+ GLOBAL_TABLE_PLACEHOLD + " set status = ?, gmt_modified = sysdate where xid = ?";
+
+    /**
+     * The constant DELETE_GLOBAL_TRANSACTION.
+     */
+    public static final String DELETE_GLOBAL_TRANSACTION = "delete from " + GLOBAL_TABLE_PLACEHOLD + " where xid = ?";
+
+    /**
+     * The constant QUERY_GLOBAL_TRANSACTION.
+     */
+    public static final String QUERY_GLOBAL_TRANSACTION = "select "+ALL_GLOBAL_COLUMNS+" from " + GLOBAL_TABLE_PLACEHOLD + " where xid = ?";
+
+
+    /**
+     * The constant QUERY_GLOBAL_TRANSACTION_ID.
+     */
+    public static final String QUERY_GLOBAL_TRANSACTION_BY_ID = "select "+ALL_GLOBAL_COLUMNS+" from " + GLOBAL_TABLE_PLACEHOLD + " where transaction_id = ?";
+
+
+    /**
+     * The constant QUERY_GLOBAL_TRANSACTION_BY_STATUS.
+     */
+    public static final String QUERY_GLOBAL_TRANSACTION_BY_STATUS = "select "+ALL_GLOBAL_COLUMNS+" from " + GLOBAL_TABLE_PLACEHOLD +
+            " where status in (" + PRAMETER_PLACEHOLD + ") order by gmt_modified limit ?";
+    /**
+     * The constant QUERY_GLOBAL_TRANSACTION_FOR_RECOVERY_MYSQL.
+     */
+    public static final String QUERY_GLOBAL_TRANSACTION_FOR_RECOVERY_MYSQL = "select "+ALL_GLOBAL_COLUMNS+" from " + GLOBAL_TABLE_PLACEHOLD + " where status in (" +
+            "0, 2, 3, 4, 5, 6, 7, 8, 10 ,12, 14) order by gmt_modified limit ?";
+
+    /**
+     * The constant QUERY_GLOBAL_TRANSACTION_FOR_RECOVERY_ORACLE.
+     */
+    public static final String QUERY_GLOBAL_TRANSACTION_FOR_RECOVERY_ORACLE = "select A.* from ( select "+ALL_GLOBAL_COLUMNS+" from " + GLOBAL_TABLE_PLACEHOLD + " where status in (" +
+            "0, 2, 3, 4, 5, 6, 7, 8, 10 ,12, 14) order by gmt_modified ) A where ROWNUM <= ?" ;
+
+
+    /**
+     * The constant INSERT_BRANCH_TRANSACTION_MYSQL.
+     */
+    public static final String INSERT_BRANCH_TRANSACTION_MYSQL = "insert into " + BRANCH_TABLE_PLACEHOLD + "("+ ALL_BRANCH_COLUMNS +")" +
+            "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, now(), now())";
+
+    /**
+     * The constant INSERT_BRANCH_TRANSACTION_ORACLE.
+     */
+    public static final String INSERT_BRANCH_TRANSACTION_ORACLE = "insert into " + BRANCH_TABLE_PLACEHOLD + "("+ ALL_BRANCH_COLUMNS +")" +
+            "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate, sysdate)";
+
+    /**
+     * The constant UPDATE_BRANCH_TRANSACTION_STATUS_MYSQL.
+     */
+    public static final String UPDATE_BRANCH_TRANSACTION_STATUS_MYSQL = "update "+ BRANCH_TABLE_PLACEHOLD + " set status = ?, gmt_modified = now() where xid = ? and branch_id = ?";
+
+    /**
+     * The constant UPDATE_BRANCH_TRANSACTION_STATUS_ORACLE.
+     */
+    public static final String UPDATE_BRANCH_TRANSACTION_STATUS_ORACLE = "update "+ BRANCH_TABLE_PLACEHOLD + " set status = ?, gmt_modified = sysdate where xid = ? and branch_id = ?" ;
+
+    /**
+     * The constant DELETE_BRANCH_TRANSACTION_BY_BRANCH_ID.
+     */
+    public static final String DELETE_BRANCH_TRANSACTION_BY_BRANCH_ID = "delete from " + BRANCH_TABLE_PLACEHOLD + " where xid = ? and branch_id = ?";
+
+    /**
+     * The constant DELETE_BRANCH_TRANSACTION_BY_XID.
+     */
+    public static final String DELETE_BRANCH_TRANSACTION_BY_XID = "delete from " + BRANCH_TABLE_PLACEHOLD + " where xid = ?";
+
+    /**
+     * The constant QUREY_BRANCH_TRANSACTION.
+     */
+    public static final String QUREY_BRANCH_TRANSACTION =  "select "+ALL_BRANCH_COLUMNS+" from " + BRANCH_TABLE_PLACEHOLD + " where xid = ?";
+
+    /**
+     * Get insert global transaction sql string.
+     *
+     * @param globalTable the global table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getInsertGlobalTransactionSQL(String globalTable, String dbType){
+        if(DBType.MYSQL.name().equalsIgnoreCase(dbType)
+                || DBType.OCEANBASE.name().equalsIgnoreCase(dbType)
+                || DBType.H2.name().equalsIgnoreCase(dbType)){
+            return INSERT_GLOBAL_TRANSACTION_MYSQL.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+        }else if(DBType.ORACLE.name().equalsIgnoreCase(dbType)){
+            return INSERT_GLOBAL_TRANSACTION_ORACLE.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+        }else{
+            throw new NotSupportYetException("unknown dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get update global transaction status sql string.
+     *
+     * @param globalTable the global table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getUpdateGlobalTransactionStatusSQL(String globalTable, String dbType){
+        if(DBType.MYSQL.name().equalsIgnoreCase(dbType)
+                || DBType.OCEANBASE.name().equalsIgnoreCase(dbType)
+                || DBType.H2.name().equalsIgnoreCase(dbType)){
+            return UPDATE_GLOBAL_TRANSACTION_STATUS_MYSQL.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+        }else if(DBType.ORACLE.name().equalsIgnoreCase(dbType)){
+            return UPDATE_GLOBAL_TRANSACTION_STATUS_ORACLE.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+        }else{
+            throw new NotSupportYetException("unknown dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get delete global transaction sql string.
+     *
+     * @param globalTable the global table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getDeleteGlobalTransactionSQL(String globalTable, String dbType){
+        return DELETE_GLOBAL_TRANSACTION.replace(GLOBAL_TABLE_PLACEHOLD, globalTable );
+    }
+
+    /**
+     * Get query global transaction sql string.
+     *
+     * @param globalTable the global table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getQueryGlobalTransactionSQL(String globalTable, String dbType){
+        return QUERY_GLOBAL_TRANSACTION.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+    }
+
+    /**
+     * Get query global transaction sql by transaction id string.
+     *
+     * @param globalTable the global table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getQueryGlobalTransactionSQLByTransactionId(String globalTable, String dbType){
+        return QUERY_GLOBAL_TRANSACTION_BY_ID.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+    }
+
+
+    /**
+     * Get query global transaction sql by status string.
+     *
+     * @param globalTable       the global table
+     * @param dbType            the db type
+     * @param paramsPlaceHolder the params place holder
+     * @return the string
+     */
+    public static String getQueryGlobalTransactionSQLByStatus(String globalTable, String dbType, String paramsPlaceHolder){
+        return QUERY_GLOBAL_TRANSACTION_BY_STATUS.replace(GLOBAL_TABLE_PLACEHOLD, globalTable).replace(PRAMETER_PLACEHOLD, paramsPlaceHolder);
+    }
+
+    /**
+     * Get query global transaction for recovery sql string.
+     *
+     * @param globalTable the global table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getQueryGlobalTransactionForRecoverySQL(String globalTable, String dbType){
+        if(DBType.MYSQL.name().equalsIgnoreCase(dbType)
+                || DBType.OCEANBASE.name().equalsIgnoreCase(dbType)
+                || DBType.H2.name().equalsIgnoreCase(dbType)){
+            return QUERY_GLOBAL_TRANSACTION_FOR_RECOVERY_MYSQL.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+        }else if(DBType.ORACLE.name().equalsIgnoreCase(dbType)){
+            return QUERY_GLOBAL_TRANSACTION_FOR_RECOVERY_ORACLE.replace(GLOBAL_TABLE_PLACEHOLD, globalTable);
+        }else{
+            throw new NotSupportYetException("unknown dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get insert branch transaction sql string.
+     *
+     * @param branchTable the branch table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getInsertBranchTransactionSQL(String branchTable, String dbType){
+        if(DBType.MYSQL.name().equalsIgnoreCase(dbType)
+                || DBType.OCEANBASE.name().equalsIgnoreCase(dbType)
+                || DBType.H2.name().equalsIgnoreCase(dbType)){
+            return INSERT_BRANCH_TRANSACTION_MYSQL.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+        }else if(DBType.ORACLE.name().equalsIgnoreCase(dbType)){
+            return INSERT_BRANCH_TRANSACTION_ORACLE.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+        }else{
+            throw new NotSupportYetException("unknown dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get update branch transaction status sql string.
+     *
+     * @param branchTable the branch table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getUpdateBranchTransactionStatusSQL(String branchTable, String dbType){
+        if(DBType.MYSQL.name().equalsIgnoreCase(dbType)
+                || DBType.OCEANBASE.name().equalsIgnoreCase(dbType)
+                || DBType.H2.name().equalsIgnoreCase(dbType)){
+            return UPDATE_BRANCH_TRANSACTION_STATUS_MYSQL.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+        }else if(DBType.ORACLE.name().equalsIgnoreCase(dbType)){
+            return UPDATE_BRANCH_TRANSACTION_STATUS_ORACLE.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+        }else{
+            throw new NotSupportYetException("unknown dbType:" + dbType);
+        }
+    }
+
+    /**
+     * Get delete branch transaction by branch id sql string.
+     *
+     * @param branchTable the branch table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getDeleteBranchTransactionByBranchIdSQL(String branchTable, String dbType){
+        return DELETE_BRANCH_TRANSACTION_BY_BRANCH_ID.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+    }
+
+    /**
+     * Get delete branch transaction by x id string.
+     *
+     * @param branchTable the branch table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getDeleteBranchTransactionByXId(String branchTable, String dbType){
+        return DELETE_BRANCH_TRANSACTION_BY_XID.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+    }
+
+    /**
+     * Get qurey branch transaction string.
+     *
+     * @param branchTable the branch table
+     * @param dbType      the db type
+     * @return the string
+     */
+    public static String getQureyBranchTransaction(String branchTable, String dbType){
+        return QUREY_BRANCH_TRANSACTION.replace(BRANCH_TABLE_PLACEHOLD, branchTable);
+    }
+}
\ No newline at end of file
diff --git a/core/src/main/resources/META-INF/services/io.seata.core.store.LockStore b/core/src/main/resources/META-INF/services/io.seata.core.store.LockStore
new file mode 100644
index 0000000000000000000000000000000000000000..bd6ff3d994a20720bb3bdad8c301924d8e99cd38
--- /dev/null
+++ b/core/src/main/resources/META-INF/services/io.seata.core.store.LockStore
@@ -0,0 +1 @@
+io.seata.core.store.db.LockStoreDataBaseDAO
\ No newline at end of file
diff --git a/core/src/main/resources/META-INF/services/io.seata.core.store.LogStore b/core/src/main/resources/META-INF/services/io.seata.core.store.LogStore
new file mode 100644
index 0000000000000000000000000000000000000000..f95309566f9bbb2a56d0de1e67ac9e265dd3524e
--- /dev/null
+++ b/core/src/main/resources/META-INF/services/io.seata.core.store.LogStore
@@ -0,0 +1 @@
+io.seata.core.store.db.LogStoreDataBaseDAO
\ No newline at end of file
diff --git a/core/src/test/java/io/seata/core/protocol/RegisterTMRequestTest.java b/core/src/test/java/io/seata/core/protocol/RegisterTMRequestTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d76a6c79dc47e8822849b119e70de30be98f51fa
--- /dev/null
+++ b/core/src/test/java/io/seata/core/protocol/RegisterTMRequestTest.java
@@ -0,0 +1,192 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.protocol;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import io.netty.buffer.ByteBuf;
+import static io.netty.buffer.Unpooled.buffer;
+
+/**
+ * RegisterTMRequest Test
+ * 
+ * @author kaitithoma
+ * @author Danaykap
+ * 
+ * @date 2019/05/13
+ *
+ */
+
+public class RegisterTMRequestTest {
+
+	private static RegisterTMRequest registerTMRequest;
+	private static AbstractIdentifyRequest air;
+	private static final String APP_ID = "applicationId";
+	private static final String TSG = "transactionServiceGroup";
+	private static final String ED = "extraData";
+	private static final short TYPE_CODE = 101;
+	private static final ByteBuf BB = buffer(128);
+	
+	/** Constructor without arguments **/
+	@BeforeAll
+	public static void setupNull() {
+		registerTMRequest = new RegisterTMRequest();
+		air = Mockito.mock(
+				AbstractIdentifyRequest.class, 
+			    Mockito.CALLS_REAL_METHODS);
+	}
+
+	/** Constructor with arguments **/
+	@BeforeAll
+	public static void setupWithValues() {
+		registerTMRequest = new RegisterTMRequest(APP_ID, TSG, ED);
+		air = Mockito.mock(
+				AbstractIdentifyRequest.class, 
+			    Mockito.CALLS_REAL_METHODS);
+	}
+
+	/** Test get type code **/
+	@Test
+	public void testGetTypeCode() {
+		Assertions.assertEquals(TYPE_CODE, registerTMRequest.getTypeCode());
+	}
+
+	/**
+	 * Test toString having all the parameters initialized to null
+	 */
+	@Test
+	public void testToStringNullValues() {
+		Assertions.assertEquals("RegisterTMRequest{" + "applicationId='" + null + '\'' + ", transactionServiceGroup='"
+				+ null + '\'' + '}', registerTMRequest.toString());
+	}
+
+	/**
+	 * Test decode method with empty parameter
+	 */
+	@Test
+	public void testDecodeEmpty() {
+		BB.clear();
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeLessThanTwo() {
+		BB.clear();
+		for (int i = 0; i < 2; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeMoreThanThree() {
+		BB.clear();
+		for (int i = 0; i < 3; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeLessThanFour() {
+		BB.clear();
+		for (int i = 0; i < 4; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeMoreLessThanOne() {
+		BB.clear();
+		for (int i = 0; i < 1; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeMoreLessThanFourWithZero() {
+		BB.clear();
+		for (int i = 0; i < 4; i++) {
+			BB.writeZero(i);
+		}
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeFalseLessThanTwoWithDifferentReadable() {
+		BB.clear();
+		for (int i = 0; i < 1; i++) {
+			BB.writeZero(i);
+		}
+		for (int i = 1; i < 2; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertFalse(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeTrueLessThanFive() {
+		BB.clear();
+		for (int i = 0; i < 4; i++) {
+			BB.writeZero(i);
+		}
+		for (int i = 4; i < 5; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertTrue(air.decode(BB));
+	}
+	
+	/**
+	 * Test decode method with initialized parameter
+	 */
+	@Test
+	public void testDecodeTrueLessThanSixteen() {
+		BB.clear();
+		for (int i = 0; i < 15; i++) {
+			BB.writeZero(i);
+		}
+		for (int i = 15; i < 16; i++) {
+			BB.writeShort(i);
+		}
+		Assertions.assertTrue(air.decode(BB));
+	}
+	
+}
diff --git a/core/src/test/java/io/seata/core/store/db/DataBaseLockStoreDAOTest.java b/core/src/test/java/io/seata/core/store/db/DataBaseLockStoreDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..eee248eb8cdf8244dc1567a496caeda1481c26c0
--- /dev/null
+++ b/core/src/test/java/io/seata/core/store/db/DataBaseLockStoreDAOTest.java
@@ -0,0 +1,300 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import io.seata.core.store.LockDO;
+import org.apache.commons.dbcp.BasicDataSource;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author zhangsen
+ * @data 2019/4/26
+ */
+public class DataBaseLockStoreDAOTest {
+
+    static LockStoreDataBaseDAO dataBaseLockStoreDAO  = null;
+
+    static BasicDataSource dataSource = null;
+
+    @BeforeAll
+    public static void start(){
+        dataSource =  new BasicDataSource();
+        dataSource.setDriverClassName("org.h2.Driver");
+        dataSource.setUrl("jdbc:h2:./db_store/lock");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+
+        dataBaseLockStoreDAO = new LockStoreDataBaseDAO(dataSource);
+        dataBaseLockStoreDAO.setDbType("h2");
+        dataBaseLockStoreDAO.setLockTable("lock_table");
+
+        prepareTable(dataSource);
+    }
+
+    private static void prepareTable(BasicDataSource dataSource) {
+        Connection conn = null;
+        try {
+            conn = dataSource.getConnection();
+            Statement s = conn.createStatement();
+            try {
+                s.execute("drop table lock_table");
+            } catch (Exception e) {
+            }
+            s.execute("CREATE TABLE lock_table ( xid varchar(96) ,  transaction_id long , branch_id long, resource_id varchar(32) ,table_name varchar(32) ,pk varchar(32) ,  row_key  varchar(128) primary key not null, gmt_create TIMESTAMP(6) ,gmt_modified TIMESTAMP(6) ) ");
+            System.out.println("create table lock_table success.");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void test_acquireLocks() throws SQLException {
+        List<LockDO> lockDOs = new ArrayList<>();
+        for(int i = 0; i < 3; i++){
+            LockDO lock = new LockDO();
+            lock.setResourceId("abc");
+            lock.setXid("abc-123:123");
+            lock.setTransactionId(123L);
+            lock.setBranchId((long) i);
+            lock.setRowKey("abc-"+i);
+            lock.setPk(String.valueOf(i));
+            lock.setTableName("t");
+            lockDOs.add(lock);
+        }
+
+        boolean ret = dataBaseLockStoreDAO.acquireLock(lockDOs);
+        Assertions.assertTrue(ret);
+
+        String sql = "select * from lock_table where xid = 'abc-123:123' and table_name  = 't' and row_key in ('abc-0','abc-1','abc-2')"  ;
+        Connection conn =  null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+
+        Assertions.assertTrue(dataBaseLockStoreDAO.unLock(lockDOs));
+
+    }
+
+
+    @Test
+    public void test_re_acquireLocks() throws SQLException {
+        List<LockDO> lockDOs = new ArrayList<>();
+        for(int i = 0; i < 3; i++){
+            LockDO lock = new LockDO();
+            lock.setResourceId("abc");
+            lock.setXid("abc-123:123");
+            lock.setTransactionId(123L);
+            lock.setBranchId((long) i);
+            lock.setRowKey("abc-"+i);
+            lock.setPk(String.valueOf(i));
+            lock.setTableName("t");
+            lockDOs.add(lock);
+        }
+
+        boolean ret = dataBaseLockStoreDAO.acquireLock(lockDOs);
+        Assertions.assertTrue(ret);
+
+        String sql = "select * from lock_table where xid = 'abc-123:123' and table_name  = 't' and row_key in ('abc-0','abc-1','abc-2')"  ;
+        Connection conn =  null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+
+        //lock again
+        Assertions.assertTrue(dataBaseLockStoreDAO.acquireLock(lockDOs));
+
+        Assertions.assertTrue(dataBaseLockStoreDAO.unLock(lockDOs));
+
+    }
+
+    @Test
+    public void tes_unLocks() throws SQLException {
+        List<LockDO> lockDOs = new ArrayList<>();
+        for(int i = 0; i < 3; i++){
+            LockDO lock = new LockDO();
+            lock.setResourceId("abc");
+            lock.setXid("abc-456:123");
+            lock.setTransactionId(123L);
+            lock.setBranchId((long) i);
+            lock.setRowKey("abc-"+i);
+            lock.setPk(String.valueOf(i));
+            lock.setTableName("t");
+            lockDOs.add(lock);
+        }
+
+        boolean ret = dataBaseLockStoreDAO.acquireLock(lockDOs);
+        Assertions.assertTrue(ret);
+
+        String sql = "select * from lock_table where xid = 'abc-456:123' and table_name  = 't' and row_key in ('abc-0','abc-1','abc-2')"  ;
+        Connection conn =  null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            //unlock
+            Assertions.assertTrue(dataBaseLockStoreDAO.unLock(lockDOs));
+
+            rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(false);
+            }else {
+                Assertions.assertTrue(true);
+            }
+
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+
+
+    }
+
+
+    @Test
+    public void test_isLockable_can(){
+        List<LockDO> lockDOs = new ArrayList<>();
+        for(int i = 0; i < 3; i++){
+            LockDO lock = new LockDO();
+            lock.setResourceId("abc");
+            lock.setXid("abc-678:123");
+            lock.setTransactionId(123L);
+            lock.setBranchId((long) i);
+            lock.setRowKey("abc-"+i);
+            lock.setPk(String.valueOf(i));
+            lock.setTableName("t");
+            lockDOs.add(lock);
+        }
+
+        boolean ret = dataBaseLockStoreDAO.acquireLock(lockDOs);
+        Assertions.assertTrue(ret);
+
+        //unlock
+        Assertions.assertTrue(dataBaseLockStoreDAO.unLock(lockDOs));
+    }
+
+    @Test
+    public void test_isLockable_cannot() throws SQLException {
+        List<LockDO> lockDOs = new ArrayList<>();
+        for(int i = 0; i < 3; i++){
+            LockDO lock = new LockDO();
+            lock.setResourceId("abc");
+            lock.setXid("abc-123:222");
+            lock.setTransactionId(222L);
+            lock.setBranchId((long) i);
+            lock.setRowKey("abc-"+i);
+            lock.setPk(String.valueOf(i));
+            lock.setTableName("t");
+            lockDOs.add(lock);
+        }
+
+        boolean ret = dataBaseLockStoreDAO.acquireLock(lockDOs);
+        Assertions.assertTrue(ret);
+
+        String sql = "select * from lock_table where xid = 'abc-123:222' and table_name  = 't' and row_key in ('abc-0','abc-1','abc-2')"  ;
+        Connection conn =  null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+
+        List<LockDO> lockDOs_2 = new ArrayList<>();
+        for(int i = 0; i < 3; i++){
+            LockDO lock = new LockDO();
+            lock.setResourceId("abc");
+            lock.setXid("abc-123:333");
+            lock.setTransactionId(333L);
+            lock.setBranchId((long) i);
+            lock.setRowKey("abc-"+i);
+            lock.setPk(String.valueOf(i));
+            lock.setTableName("t");
+            lockDOs_2.add(lock);
+        }
+
+        boolean ret2 = dataBaseLockStoreDAO.acquireLock(lockDOs_2);
+        Assertions.assertTrue(!ret2);
+
+    }
+
+
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/io/seata/core/store/db/LogStoreDataBaseDAOTest.java b/core/src/test/java/io/seata/core/store/db/LogStoreDataBaseDAOTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..12aaf5259ea700c61b503a93aca3ac9435c93758
--- /dev/null
+++ b/core/src/test/java/io/seata/core/store/db/LogStoreDataBaseDAOTest.java
@@ -0,0 +1,659 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.core.store.db;
+
+import io.seata.common.util.CollectionUtils;
+import io.seata.core.store.BranchTransactionDO;
+import io.seata.core.store.GlobalTransactionDO;
+import org.apache.commons.dbcp.BasicDataSource;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+
+/**
+ * @author zhangsen
+ * @data 2019/4/26
+ */
+public class LogStoreDataBaseDAOTest {
+
+    static LogStoreDataBaseDAO logStoreDataBaseDAO  = null;
+
+    static BasicDataSource dataSource = null;
+
+    @BeforeAll
+    public static void start(){
+        dataSource =  new BasicDataSource();
+        dataSource.setDriverClassName("org.h2.Driver");
+        dataSource.setUrl("jdbc:h2:./db_store/log");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+
+        logStoreDataBaseDAO = new LogStoreDataBaseDAO(dataSource);
+        logStoreDataBaseDAO.setDbType("h2");
+        logStoreDataBaseDAO.setGlobalTable("global_table");
+        logStoreDataBaseDAO.setBrachTable("branch_table");
+
+        prepareTable(dataSource);
+    }
+
+    private static void prepareTable(BasicDataSource dataSource) {
+        Connection conn = null;
+        try {
+            conn = dataSource.getConnection();
+            Statement s = conn.createStatement();
+            try {
+                s.execute("drop table global_table");
+            } catch (Exception e) {
+            }
+//            xid, transaction_id, status, application_id, transaction_service_group, transaction_name, timeout, begin_time, application_data, gmt_create, gmt_modified
+            s.execute("CREATE TABLE global_table ( xid varchar(96) primary key,  transaction_id long , STATUS int,  application_id varchar(32), transaction_service_group varchar(32) ,transaction_name varchar(32) ,timeout int,  begin_time long, application_data varchar(500), gmt_create TIMESTAMP(6) ,gmt_modified TIMESTAMP(6) ) ");
+            System.out.println("create table global_table success.");
+
+            try {
+                s.execute("drop table branch_table");
+            } catch (Exception e) {
+            }
+//            xid, transaction_id, branch_id, resource_group_id, resource_id, lock_key, branch_type, status, client_id, application_data, gmt_create, gmt_modified
+            s.execute("CREATE TABLE branch_table ( xid varchar(96),  transaction_id long , branch_id long primary key, resource_group_id varchar(32), resource_id varchar(32) ,lock_key varchar(64) ,branch_type varchar(32) ,  status int , client_id varchar(128),  application_data varchar(500),  gmt_create TIMESTAMP(6) ,gmt_modified TIMESTAMP(6) ) ");
+            System.out.println("create table branch_table success.");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void queryGlobalTransactionDO_by_xid() throws SQLException {
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid("abc-123:978786");
+        globalTransactionDO.setApplicationData("abc=87867978");
+        globalTransactionDO.setTransactionServiceGroup("abc");
+        globalTransactionDO.setTransactionName("test");
+        globalTransactionDO.setTransactionId(143546567);
+        globalTransactionDO.setTimeout(20);
+        globalTransactionDO.setBeginTime(System.currentTimeMillis());
+        globalTransactionDO.setApplicationId("test");
+        globalTransactionDO.setStatus(1);
+
+        boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+        Assertions.assertTrue(ret);
+
+
+        GlobalTransactionDO globalTransactionDO_db = logStoreDataBaseDAO.queryGlobalTransactionDO("abc-123:978786");
+        Assertions.assertNotNull(globalTransactionDO_db);
+
+        Assertions.assertEquals(globalTransactionDO_db.getBeginTime(), globalTransactionDO_db.getBeginTime());
+        Assertions.assertEquals(globalTransactionDO_db.getTransactionName(), globalTransactionDO_db.getTransactionName());
+        Assertions.assertEquals(globalTransactionDO_db.getTransactionId(), globalTransactionDO_db.getTransactionId());
+        Assertions.assertEquals(globalTransactionDO_db.getStatus(), globalTransactionDO_db.getStatus());
+        Assertions.assertEquals(globalTransactionDO_db.getTimeout(), globalTransactionDO_db.getTimeout());
+        Assertions.assertEquals(globalTransactionDO_db.getTransactionServiceGroup(), globalTransactionDO_db.getTransactionServiceGroup());
+        Assertions.assertEquals(globalTransactionDO_db.getApplicationId(), globalTransactionDO_db.getApplicationId());
+        Assertions.assertNotNull(globalTransactionDO_db.getGmtCreate());
+        Assertions.assertNotNull(globalTransactionDO_db.getGmtModified());
+
+
+        String delSql = "delete from global_table where xid= 'abc-123:978786'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            //delete
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+
+    }
+
+    @Test
+    public void queryGlobalTransactionDO_by_transaction_id() throws SQLException {
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid("abc-123:676787978");
+        globalTransactionDO.setApplicationData("abc=234356");
+        globalTransactionDO.setTransactionServiceGroup("abc");
+        globalTransactionDO.setTransactionName("test");
+        globalTransactionDO.setTransactionId(867978970);
+        globalTransactionDO.setTimeout(20);
+        globalTransactionDO.setBeginTime(System.currentTimeMillis());
+        globalTransactionDO.setApplicationId("test");
+        globalTransactionDO.setStatus(1);
+
+        boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+        Assertions.assertTrue(ret);
+
+        GlobalTransactionDO globalTransactionDO_db = logStoreDataBaseDAO.queryGlobalTransactionDO(867978970L);
+        Assertions.assertNotNull(globalTransactionDO_db);
+
+        Assertions.assertEquals(globalTransactionDO_db.getXid(), globalTransactionDO_db.getXid());
+        Assertions.assertEquals(globalTransactionDO_db.getBeginTime(), globalTransactionDO_db.getBeginTime());
+        Assertions.assertEquals(globalTransactionDO_db.getTransactionName(), globalTransactionDO_db.getTransactionName());
+        Assertions.assertEquals(globalTransactionDO_db.getTransactionId(), globalTransactionDO_db.getTransactionId());
+        Assertions.assertEquals(globalTransactionDO_db.getStatus(), globalTransactionDO_db.getStatus());
+        Assertions.assertEquals(globalTransactionDO_db.getTimeout(), globalTransactionDO_db.getTimeout());
+        Assertions.assertEquals(globalTransactionDO_db.getTransactionServiceGroup(), globalTransactionDO_db.getTransactionServiceGroup());
+        Assertions.assertEquals(globalTransactionDO_db.getApplicationId(), globalTransactionDO_db.getApplicationId());
+        Assertions.assertNotNull(globalTransactionDO_db.getGmtCreate());
+        Assertions.assertNotNull(globalTransactionDO_db.getGmtModified());
+
+        String delSql = "delete from global_table where xid= 'abc-123:978786'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            //delete
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+
+    }
+
+    @Test
+    public void queryGlobalTransactionDO_by_statuses() throws SQLException {
+        {
+            GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+            globalTransactionDO.setXid("abc-123:1267");
+            globalTransactionDO.setApplicationData("abc=234356");
+            globalTransactionDO.setTransactionServiceGroup("abc");
+            globalTransactionDO.setTransactionName("test");
+            globalTransactionDO.setTransactionId(867978970);
+            globalTransactionDO.setTimeout(20);
+            globalTransactionDO.setBeginTime(System.currentTimeMillis());
+            globalTransactionDO.setApplicationId("test");
+            globalTransactionDO.setStatus(1);
+
+            Assertions.assertTrue(logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO));
+        }
+        {
+            GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+            globalTransactionDO.setXid("abc-123:6978");
+            globalTransactionDO.setApplicationData("abc=87867978");
+            globalTransactionDO.setTransactionServiceGroup("abc");
+            globalTransactionDO.setTransactionName("test");
+            globalTransactionDO.setTransactionId(143546567);
+            globalTransactionDO.setTimeout(20);
+            globalTransactionDO.setBeginTime(System.currentTimeMillis());
+            globalTransactionDO.setApplicationId("test");
+            globalTransactionDO.setStatus(2);
+
+            boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+            Assertions.assertTrue(ret);
+        }
+        {
+            GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+            globalTransactionDO.setXid("abc-123:5657");
+            globalTransactionDO.setApplicationData("abc=5454");
+            globalTransactionDO.setTransactionServiceGroup("abc");
+            globalTransactionDO.setTransactionName("test");
+            globalTransactionDO.setTransactionId(12345);
+            globalTransactionDO.setTimeout(20);
+            globalTransactionDO.setBeginTime(System.currentTimeMillis());
+            globalTransactionDO.setApplicationId("test");
+            globalTransactionDO.setStatus(1);
+
+            boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+            Assertions.assertTrue(ret);
+        }
+
+        List<GlobalTransactionDO> globalTransactionDOs = logStoreDataBaseDAO.queryGlobalTransactionDO(new int[]{1}, 10);
+        Assertions.assertNotNull(globalTransactionDOs);
+        Assertions.assertEquals(2, globalTransactionDOs.size());
+
+        if("abc-123:5657".equals(globalTransactionDOs.get(0).getXid()) && "abc-123:1267".equals(globalTransactionDOs.get(1).getXid())){
+            Assertions.assertTrue(true);
+        }else if("abc-123:5657".equals(globalTransactionDOs.get(1).getXid()) && "abc-123:1267".equals(globalTransactionDOs.get(0).getXid())){
+            Assertions.assertTrue(true);
+        }else {
+            Assertions.assertTrue(false);
+        }
+
+        String delSql = "delete from global_table where xid in ('abc-123:1267', 'abc-123:6978', 'abc-123:5657')";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void queryGlobalTransactionDO_by_statuses_limit() throws SQLException {
+        {
+            GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+            globalTransactionDO.setXid("abc-123:1267");
+            globalTransactionDO.setApplicationData("abc=234356");
+            globalTransactionDO.setTransactionServiceGroup("abc");
+            globalTransactionDO.setTransactionName("test");
+            globalTransactionDO.setTransactionId(867978970);
+            globalTransactionDO.setTimeout(20);
+            globalTransactionDO.setBeginTime(System.currentTimeMillis());
+            globalTransactionDO.setApplicationId("test");
+            globalTransactionDO.setStatus(1);
+
+            Assertions.assertTrue(logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO));
+        }
+        {
+            GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+            globalTransactionDO.setXid("abc-123:6978");
+            globalTransactionDO.setApplicationData("abc=87867978");
+            globalTransactionDO.setTransactionServiceGroup("abc");
+            globalTransactionDO.setTransactionName("test");
+            globalTransactionDO.setTransactionId(143546567);
+            globalTransactionDO.setTimeout(20);
+            globalTransactionDO.setBeginTime(System.currentTimeMillis());
+            globalTransactionDO.setApplicationId("test");
+            globalTransactionDO.setStatus(2);
+
+            boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+            Assertions.assertTrue(ret);
+        }
+        {
+            GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+            globalTransactionDO.setXid("abc-123:5657");
+            globalTransactionDO.setApplicationData("abc=5454");
+            globalTransactionDO.setTransactionServiceGroup("abc");
+            globalTransactionDO.setTransactionName("test");
+            globalTransactionDO.setTransactionId(12345);
+            globalTransactionDO.setTimeout(20);
+            globalTransactionDO.setBeginTime(System.currentTimeMillis());
+            globalTransactionDO.setApplicationId("test");
+            globalTransactionDO.setStatus(1);
+
+            boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+            Assertions.assertTrue(ret);
+        }
+
+        List<GlobalTransactionDO> globalTransactionDOs = logStoreDataBaseDAO.queryGlobalTransactionDO(new int[]{1}, 1);
+        Assertions.assertNotNull(globalTransactionDOs);
+        Assertions.assertEquals(1, globalTransactionDOs.size());
+
+        if("abc-123:1267".equals(globalTransactionDOs.get(0).getXid())){
+            Assertions.assertTrue(true);
+        }else {
+            Assertions.assertTrue(false);
+        }
+
+        String delSql = "delete from global_table where xid in ('abc-123:1267', 'abc-123:6978', 'abc-123:5657')";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+
+    }
+
+    @Test
+    public void insertGlobalTransactionDO() throws SQLException {
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid("abc-123:333");
+        globalTransactionDO.setApplicationData("abc=5454");
+        globalTransactionDO.setTransactionServiceGroup("abc");
+        globalTransactionDO.setTransactionName("test");
+        globalTransactionDO.setTransactionId(12345);
+        globalTransactionDO.setTimeout(20);
+        globalTransactionDO.setBeginTime(System.currentTimeMillis());
+        globalTransactionDO.setApplicationId("test");
+        globalTransactionDO.setStatus(1);
+
+        boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+        Assertions.assertTrue(ret);
+
+        String sql = "select * from global_table where xid= 'abc-123:333'";
+        String delSql = "delete from global_table where xid= 'abc-123:333'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else{
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void updateGlobalTransactionDO() throws SQLException {
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid("abc-123:222");
+        globalTransactionDO.setApplicationData("abc=5454");
+        globalTransactionDO.setTransactionServiceGroup("abc");
+        globalTransactionDO.setTransactionName("test");
+        globalTransactionDO.setTransactionId(12345);
+        globalTransactionDO.setTimeout(20);
+        globalTransactionDO.setBeginTime(System.currentTimeMillis());
+        globalTransactionDO.setApplicationId("test");
+        globalTransactionDO.setStatus(1);
+
+        boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+        Assertions.assertTrue(ret);
+
+        String sql = "select * from global_table where xid= 'abc-123:222'";
+        String delSql = "delete from global_table where xid= 'abc-123:222'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(1, rs.getInt("status"));
+            }else{
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            //update
+            globalTransactionDO.setStatus(2);
+            Assertions.assertTrue(logStoreDataBaseDAO.updateGlobalTransactionDO(globalTransactionDO));
+
+            rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(2, rs.getInt("status"));
+            }else{
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            //delete
+            conn.createStatement().execute(delSql);
+
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+
+    }
+
+    @Test
+    public void deleteGlobalTransactionDO() throws SQLException {
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid("abc-123:555");
+        globalTransactionDO.setApplicationData("abc=5454");
+        globalTransactionDO.setTransactionServiceGroup("abc");
+        globalTransactionDO.setTransactionName("test");
+        globalTransactionDO.setTransactionId(12345);
+        globalTransactionDO.setTimeout(20);
+        globalTransactionDO.setBeginTime(System.currentTimeMillis());
+        globalTransactionDO.setApplicationId("test");
+        globalTransactionDO.setStatus(1);
+
+        boolean ret = logStoreDataBaseDAO.insertGlobalTransactionDO(globalTransactionDO);
+        Assertions.assertTrue(ret);
+
+        //delete
+        Assertions.assertTrue(logStoreDataBaseDAO.deleteGlobalTransactionDO(globalTransactionDO));
+
+        //check
+
+        String sql = "select * from global_table where xid= 'abc-123:555'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(false);
+            }else{
+                Assertions.assertTrue(true);
+            }
+            rs.close();
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void queryBranchTransactionDO() throws SQLException {
+        {
+            //creata data for test
+            BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+            branchTransactionDO.setResourceId("qqqq");
+            branchTransactionDO.setXid("abc-123:6789");
+            branchTransactionDO.setTransactionId(24234235);
+            branchTransactionDO.setBranchId(345465676);
+            branchTransactionDO.setBranchType("TCC");
+            branchTransactionDO.setResourceGroupId("abc");
+            branchTransactionDO.setLockKey("t:1,2,3;t2,4,5,6");
+            branchTransactionDO.setResourceGroupId("a");
+            branchTransactionDO.setClientId("1.1.1.1");
+            branchTransactionDO.setStatus(1);
+            branchTransactionDO.setApplicationData("abc=123");
+            branchTransactionDO.setResourceGroupId("test");
+
+            boolean ret = logStoreDataBaseDAO.insertBranchTransactionDO(branchTransactionDO);
+            Assertions.assertTrue(ret);
+        }
+        {
+            //creata data for test
+            BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+            branchTransactionDO.setResourceId("qqqq");
+            branchTransactionDO.setXid("abc-123:6789");
+            branchTransactionDO.setTransactionId(24234235);
+            branchTransactionDO.setBranchId(78563453);
+            branchTransactionDO.setBranchType("TCC");
+            branchTransactionDO.setResourceGroupId("abc");
+            branchTransactionDO.setLockKey("t:6;t2:7");
+            branchTransactionDO.setResourceGroupId("a");
+            branchTransactionDO.setClientId("1.1.1.1");
+            branchTransactionDO.setStatus(1);
+            branchTransactionDO.setApplicationData("abc=123");
+            branchTransactionDO.setResourceGroupId("test");
+
+            boolean ret = logStoreDataBaseDAO.insertBranchTransactionDO(branchTransactionDO);
+            Assertions.assertTrue(ret);
+        }
+
+        List<BranchTransactionDO> rets = logStoreDataBaseDAO.queryBranchTransactionDO("abc-123:6789");
+        Assertions.assertTrue(CollectionUtils.isNotEmpty(rets));
+        Assertions.assertEquals(2, rets.size());
+
+        if(78563453 == rets.get(0).getBranchId() && 345465676 == rets.get(1).getBranchId()){
+            Assertions.assertTrue(true);
+        }else if(78563453 == rets.get(1).getBranchId() && 345465676 == rets.get(0).getBranchId()){
+            Assertions.assertTrue(true);
+        }else {
+            Assertions.assertTrue(false);
+        }
+
+        String delSql = "delete from branch_table where xid= 'abc-123:6789' ";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+
+            conn.createStatement().execute(delSql);
+
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void insertBranchTransactionDO() throws SQLException {
+        BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+        branchTransactionDO.setResourceId("qqqq");
+        branchTransactionDO.setXid("abc-123:7777");
+        branchTransactionDO.setTransactionId(1285343);
+        branchTransactionDO.setBranchId(1234508);
+        branchTransactionDO.setBranchType("TCC");
+        branchTransactionDO.setResourceGroupId("abc");
+        branchTransactionDO.setLockKey("t:1,2,3;t2,4,5,6");
+        branchTransactionDO.setResourceGroupId("a");
+        branchTransactionDO.setClientId("1.1.1.1");
+        branchTransactionDO.setStatus(1);
+        branchTransactionDO.setApplicationData("abc=123");
+        branchTransactionDO.setResourceGroupId("test");
+
+        boolean ret = logStoreDataBaseDAO.insertBranchTransactionDO(branchTransactionDO);
+        Assertions.assertTrue(ret);
+
+
+        String sql = "select * from branch_table where xid= 'abc-123:7777' and branch_id = 1234508";
+        String delSql = "delete from branch_table where xid= 'abc-123:7777' and branch_id = 1234508";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+
+    }
+
+    @Test
+    public void updateBranchTransactionDO() throws SQLException {
+        BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+        branchTransactionDO.setResourceId("qqqq");
+        branchTransactionDO.setXid("abc-123:8888");
+        branchTransactionDO.setTransactionId(1285343);
+        branchTransactionDO.setBranchId(343434318);
+        branchTransactionDO.setBranchType("TCC");
+        branchTransactionDO.setResourceGroupId("abc");
+        branchTransactionDO.setLockKey("t:1,2,3;t2,4,5,6");
+        branchTransactionDO.setResourceGroupId("a");
+        branchTransactionDO.setClientId("1.1.1.1");
+        branchTransactionDO.setStatus(1);
+        branchTransactionDO.setApplicationData("abc=123");
+        branchTransactionDO.setResourceGroupId("test");
+
+        boolean ret = logStoreDataBaseDAO.insertBranchTransactionDO(branchTransactionDO);
+        Assertions.assertTrue(ret);
+
+        branchTransactionDO.setStatus(3);
+        Assertions.assertTrue(logStoreDataBaseDAO.updateBranchTransactionDO(branchTransactionDO));
+
+        String sql = "select * from branch_table where xid= 'abc-123:8888' and branch_id = 343434318";
+        String delSql = "delete from branch_table where xid= 'abc-123:8888' and branch_id = 343434318";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(3, rs.getInt("status"));
+            }else {
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void deleteBranchTransactionDO() throws SQLException {
+        BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+        branchTransactionDO.setResourceId("qqqq");
+        branchTransactionDO.setXid("abc-123:9999");
+        branchTransactionDO.setTransactionId(1285343);
+        branchTransactionDO.setBranchId(34567798);
+        branchTransactionDO.setBranchType("TCC");
+        branchTransactionDO.setResourceGroupId("abc");
+        branchTransactionDO.setLockKey("t:1,2,3;t2,4,5,6");
+        branchTransactionDO.setResourceGroupId("a");
+        branchTransactionDO.setClientId("1.1.1.1");
+        branchTransactionDO.setStatus(1);
+        branchTransactionDO.setApplicationData("abc=123");
+        branchTransactionDO.setResourceGroupId("test");
+
+        boolean ret = logStoreDataBaseDAO.insertBranchTransactionDO(branchTransactionDO);
+        Assertions.assertTrue(ret);
+
+
+        String sql = "select * from branch_table where xid= 'abc-123:9999' and branch_id = 34567798";
+        String delSql = "delete from branch_table where xid= 'abc-123:9999' and branch_id = 34567798";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            //delete
+            logStoreDataBaseDAO.deleteBranchTransactionDO(branchTransactionDO);
+
+            rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(false);
+            }else {
+                Assertions.assertTrue(true);
+            }
+            rs.close();
+
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/discovery/seata-discovery-core/src/test/java/io/seata/config/ConfigurationFactoryTest.java b/discovery/seata-discovery-core/src/test/java/io/seata/config/ConfigurationFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..663234beea118b4070074e7e240639fb45b8fbdb
--- /dev/null
+++ b/discovery/seata-discovery-core/src/test/java/io/seata/config/ConfigurationFactoryTest.java
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.config;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * @author Geng Zhang
+ */
+class ConfigurationFactoryTest {
+
+    @Test
+    void getInstance() {
+        Configuration configuration = ConfigurationFactory.getInstance();
+        // check singleton
+        Assertions.assertEquals(configuration, ConfigurationFactory.getInstance());
+    }
+}
\ No newline at end of file
diff --git a/discovery/seata-discovery-eureka/src/main/java/io/seata/discovery/registry/eureka/EurekaRegistryProvider.java b/discovery/seata-discovery-eureka/src/main/java/io/seata/discovery/registry/eureka/EurekaRegistryProvider.java
index 8687246b90f4326691946d9c9711d77a28b102d4..ceedb26bd643e360f0eb05336f850d46cbf27af0 100644
--- a/discovery/seata-discovery-eureka/src/main/java/io/seata/discovery/registry/eureka/EurekaRegistryProvider.java
+++ b/discovery/seata-discovery-eureka/src/main/java/io/seata/discovery/registry/eureka/EurekaRegistryProvider.java
@@ -16,7 +16,6 @@
 package io.seata.discovery.registry.eureka;
 
 import io.seata.common.loader.LoadLevel;
-import io.seata.discovery.registry.RegistryProvider;
 import io.seata.discovery.registry.RegistryService;
 import io.seata.discovery.registry.RegistryProvider;
 
diff --git a/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryProvider.java b/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryProvider.java
index 1acd0db7f7e5884331f8fc45d2bf4ef833cf06ee..d201ce29c22ecfa048187227808a61c485127834 100644
--- a/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryProvider.java
+++ b/discovery/seata-discovery-nacos/src/main/java/io/seata/discovery/registry/nacos/NacosRegistryProvider.java
@@ -16,7 +16,6 @@
 package io.seata.discovery.registry.nacos;
 
 import io.seata.common.loader.LoadLevel;
-import io.seata.discovery.registry.RegistryProvider;
 import io.seata.discovery.registry.RegistryService;
 import io.seata.discovery.registry.RegistryProvider;
 
diff --git a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryProvider.java b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryProvider.java
index 4585a45b09288cdb25a6450e4b0505f42e380a29..10bd29dcae9b36779f98a56456484048b1c491b3 100644
--- a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryProvider.java
+++ b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryProvider.java
@@ -18,8 +18,6 @@ package io.seata.discovery.registry.redis;
 import io.seata.common.loader.LoadLevel;
 import io.seata.discovery.registry.RegistryProvider;
 import io.seata.discovery.registry.RegistryService;
-import io.seata.discovery.registry.RegistryProvider;
-import io.seata.discovery.registry.RegistryService;
 
 /**
  * @author xingfudeshi@gmail.com
diff --git a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java
index 9c1d87a8810d048ffd9bc9bd6990f221ebe27120..1ea76541b20a846be149f11de61613d00eb1685e 100644
--- a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java
+++ b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java
@@ -34,7 +34,6 @@ import io.seata.common.util.StringUtils;
 import io.seata.config.Configuration;
 import io.seata.config.ConfigurationFactory;
 
-import io.seata.discovery.registry.RegistryService;
 import io.seata.discovery.registry.RegistryService;
 import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
 import org.slf4j.Logger;
diff --git a/pom.xml b/pom.xml
index e3628dda5353c2e1ae04bd8d33249e61d80f6352..d657ed812a4a9f7d79fa3b6be4bf121b1e61dc65 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,7 +82,7 @@
 
     <properties>
         <!-- seata version -->
-        <revision>0.5.2</revision>
+        <revision>0.6.0</revision>
 
         <!-- Compiler settings properties -->
         <maven.compiler.source>1.8</maven.compiler.source>
@@ -107,6 +107,7 @@
         <mockito-core.version>2.23.4</mockito-core.version>
         <assertj-core.version>3.12.2</assertj-core.version>
         <junit-platform-launcher.version>1.4.2</junit-platform-launcher.version>
+
     </properties>
 
     <!--test-->
@@ -142,7 +143,6 @@
             <scope>test</scope>
         </dependency>
     </dependencies>
-
     <dependencyManagement>
         <dependencies>
             <dependency>
diff --git a/rm-datasource/pom.xml b/rm-datasource/pom.xml
index 8ab21440bb40ac1e7b263efc4cf52e62eadbf24c..3b1a0435f453e409a57e89783e30dbe59943b88d 100644
--- a/rm-datasource/pom.xml
+++ b/rm-datasource/pom.xml
@@ -48,6 +48,17 @@
             <artifactId>caffeine</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>commons-dbcp</groupId>
+            <artifactId>commons-dbcp</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
 
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/AbstractPreparedStatementProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/AbstractPreparedStatementProxy.java
index b835dc354abd3e0ef3178aa93cd0562f69d0ce89..40adc924fa65e190a72eec5b9e1acc8b9a2a8fab 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/AbstractPreparedStatementProxy.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/AbstractPreparedStatementProxy.java
@@ -37,7 +37,6 @@ import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.List;
 
-import io.seata.rm.datasource.sql.struct.Null;
 import io.seata.rm.datasource.sql.struct.Null;
 
 /**
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/AsyncWorker.java b/rm-datasource/src/main/java/io/seata/rm/datasource/AsyncWorker.java
index f6076f882042d4e9c68a8e314bd3295da489e18a..dd5f1baa2c301e1d4af3b7f9f94fccdc1f05d4fb 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/AsyncWorker.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/AsyncWorker.java
@@ -178,7 +178,7 @@ public class AsyncWorker implements ResourceManagerInbound {
                     int maxSize = xids.size() > branchIds.size() ? xids.size() : branchIds.size();
                     if(maxSize == UNDOLOG_DELETE_LIMIT_SIZE){
                         try {
-                            UndoLogManager.batchDeleteUndoLog(xids, branchIds, UNDOLOG_DELETE_LIMIT_SIZE, conn);
+                            UndoLogManager.batchDeleteUndoLog(xids, branchIds, conn);
                         } catch (Exception ex) {
                             LOGGER.warn("Failed to batch delete undo log [" + branchIds + "/" + xids + "]", ex);
                         }
@@ -192,7 +192,7 @@ public class AsyncWorker implements ResourceManagerInbound {
                 }
 
                 try {
-                    UndoLogManager.batchDeleteUndoLog(xids, branchIds, UNDOLOG_DELETE_LIMIT_SIZE, conn);
+                    UndoLogManager.batchDeleteUndoLog(xids, branchIds, conn);
                 }catch (Exception ex) {
                     LOGGER.warn("Failed to batch delete undo log [" + branchIds + "/" + xids + "]", ex);
                 }
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/PreparedStatementProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/PreparedStatementProxy.java
index 5279ad772d763909db796a70bc0c4914cf60c2b3..492d59be5f2e29035eb4a32614df94c9cb383de8 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/PreparedStatementProxy.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/PreparedStatementProxy.java
@@ -20,8 +20,6 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.util.ArrayList;
 
-import io.seata.rm.datasource.exec.ExecuteTemplate;
-import io.seata.rm.datasource.exec.StatementCallback;
 import io.seata.rm.datasource.exec.ExecuteTemplate;
 import io.seata.rm.datasource.exec.StatementCallback;
 
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/StatementProxy.java b/rm-datasource/src/main/java/io/seata/rm/datasource/StatementProxy.java
index e0b1eb7ab681ed8b75d2c46ef2fcbbce50708337..955fc81c05899967d9356587bc0e42dac97b0878 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/StatementProxy.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/StatementProxy.java
@@ -19,8 +19,6 @@ import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
 
-import io.seata.rm.datasource.exec.ExecuteTemplate;
-import io.seata.rm.datasource.exec.StatementCallback;
 import io.seata.rm.datasource.exec.ExecuteTemplate;
 import io.seata.rm.datasource.exec.StatementCallback;
 
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java
index 6a3f3f848b557a7acbf926180e24c2731bb11519..26507eb74f349c13f00972747bbb97ada16a0014 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java
@@ -29,8 +29,6 @@ import io.seata.rm.datasource.sql.SQLDeleteRecognizer;
 import io.seata.rm.datasource.sql.SQLRecognizer;
 import io.seata.rm.datasource.sql.struct.TableMeta;
 import io.seata.rm.datasource.sql.struct.TableRecords;
-import io.seata.rm.datasource.undo.KeywordChecker;
-import io.seata.rm.datasource.undo.KeywordCheckerFactory;
 
 import io.seata.rm.datasource.undo.KeywordChecker;
 import io.seata.rm.datasource.undo.KeywordCheckerFactory;
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/WhereRecognizer.java b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/WhereRecognizer.java
index be6537bfe12793ab43e21fc383814b391c755967..26d87cd1d389bdcee4181b2ef07fdb92cce1dd64 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/sql/WhereRecognizer.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/sql/WhereRecognizer.java
@@ -17,7 +17,6 @@ package io.seata.rm.datasource.sql;
 
 import java.util.ArrayList;
 
-import io.seata.rm.datasource.ParametersHolder;
 import io.seata.rm.datasource.ParametersHolder;
 
 /**
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/AbstractUndoExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/AbstractUndoExecutor.java
index 779da87c8d18ce3ef524c158af330c1167cfe475..36f14f9720393487f4daa9a83da0fc2fbd84d167 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/AbstractUndoExecutor.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/AbstractUndoExecutor.java
@@ -15,16 +15,25 @@
  */
 package io.seata.rm.datasource.undo;
 
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.SQLException;
-import java.util.ArrayList;
-
+import com.alibaba.fastjson.JSON;
+import io.seata.common.util.StringUtils;
+import io.seata.config.ConfigurationFactory;
+import io.seata.core.constants.ConfigurationKeys;
 import io.seata.rm.datasource.DataCompareUtils;
 import io.seata.rm.datasource.sql.struct.Field;
 import io.seata.rm.datasource.sql.struct.KeyType;
 import io.seata.rm.datasource.sql.struct.Row;
+import io.seata.rm.datasource.sql.struct.TableMeta;
 import io.seata.rm.datasource.sql.struct.TableRecords;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The type Abstract undo executor.
@@ -34,6 +43,24 @@ import io.seata.rm.datasource.sql.struct.TableRecords;
  */
 public abstract class AbstractUndoExecutor {
 
+    /**
+     * Logger for AbstractUndoExecutor
+     **/
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractUndoExecutor.class);
+
+    /**
+     * template of check sql
+     * 
+     * TODO support multiple primary key
+     */
+    private static final String CHECK_SQL_TEMPLATE = "SELECT * FROM %s WHERE %s in (%s)";
+
+    /**
+     * Switch of undo data validation
+     */
+    public static final boolean IS_UNDO_DATA_VALIDATION_ENABLE = ConfigurationFactory.getInstance()
+            .getBoolean(ConfigurationKeys.TRANSACTION_UNOD_DATA_VALIDATION, true);
+
     /**
      * The Sql undo log.
      */
@@ -72,11 +99,10 @@ public abstract class AbstractUndoExecutor {
      */
     public void executeOn(Connection conn) throws SQLException {
 
-        // no need undo if the before data snapshot is equivalent to the after data snapshot.
-        if (DataCompareUtils.isRecordsEquals(sqlUndoLog.getBeforeImage(), sqlUndoLog.getAfterImage())) {
+        if (IS_UNDO_DATA_VALIDATION_ENABLE && !dataValidationAndGoOn(conn)) {
             return;
         }
-        dataValidation(conn);
+        
         try {
             String undoSQL = buildUndoSQL();
 
@@ -145,9 +171,125 @@ public abstract class AbstractUndoExecutor {
      * Data validation.
      *
      * @param conn the conn
-     * @throws SQLException the sql exception
+     * @return return true if data validation is ok and need continue undo, and return false if no need continue undo.
+     * @throws SQLException the sql exception such as has dirty data
      */
-    protected void dataValidation(Connection conn) throws SQLException {
+    protected boolean dataValidationAndGoOn(Connection conn) throws SQLException {
+        
+        TableRecords beforeRecords = sqlUndoLog.getBeforeImage();
+        TableRecords afterRecords = sqlUndoLog.getAfterImage();
+
+        // Compare current data with before data
+        // No need undo if the before data snapshot is equivalent to the after data snapshot.
+        if (DataCompareUtils.isRecordsEquals(beforeRecords, afterRecords)) {
+            if (LOGGER.isInfoEnabled()) {
+                LOGGER.info("Stop rollback because there is no data change " +
+                        "between the before data snapshot and the after data snapshot.");
+            }
+            // no need continue undo.
+            return false;
+        }
+
         // Validate if data is dirty.
+        TableRecords currentRecords = queryCurrentRecords(conn);
+        // compare with current data and after image.
+        if (!DataCompareUtils.isRecordsEquals(afterRecords, currentRecords)) {
+            
+            // If current data is not equivalent to the after data, then compare the current data with the before 
+            // data, too. No need continue to undo if current data is equivalent to the before data snapshot
+            if (DataCompareUtils.isRecordsEquals(beforeRecords, currentRecords)) {
+                if (LOGGER.isInfoEnabled()) {
+                    LOGGER.info("Stop rollback because there is no data change " +
+                            "between the before data snapshot and the current data snapshot.");
+                }
+                // no need continue undo.
+                return false;
+            } else {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug("check dirty datas failed, old and new data are not equal," +
+                            "tableName:[" + sqlUndoLog.getTableName() + "]," +
+                            "oldRows:[" + JSON.toJSONString(afterRecords.getRows()) + "]," +
+                            "newRows:[" + JSON.toJSONString(currentRecords.getRows()) + "].");
+                }
+                throw new SQLException("Has dirty records when undo.");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Query current records.
+     *
+     * @param conn the conn
+     * @return the table records
+     * @throws SQLException the sql exception
+     */
+    protected TableRecords queryCurrentRecords(Connection conn) throws SQLException {
+        TableRecords undoRecords = getUndoRows();
+        TableMeta tableMeta = undoRecords.getTableMeta();
+        String pkName = tableMeta.getPkName();
+        int pkType = tableMeta.getColumnMeta(pkName).getDataType();
+
+        // pares pk values
+        Object[] pkValues = parsePkValues(getUndoRows());
+        if (pkValues.length == 0) {
+            return TableRecords.empty(tableMeta);
+        }
+        StringBuffer replace = new StringBuffer();
+        for (int i = 0; i < pkValues.length; i++) {
+            replace.append("?,");
+        }
+        // build check sql
+        String checkSQL = String.format(CHECK_SQL_TEMPLATE, sqlUndoLog.getTableName(), pkName,
+                replace.substring(0, replace.length() - 1));
+        
+        PreparedStatement statement = null;
+        ResultSet checkSet = null;
+        TableRecords currentRecords;
+        try {
+            statement = conn.prepareStatement(checkSQL);
+            for (int i = 1; i <= pkValues.length; i++) {
+                statement.setObject(i, pkValues[i - 1], pkType);
+            }
+            checkSet = statement.executeQuery();
+            currentRecords = TableRecords.buildRecords(tableMeta, checkSet);
+        } finally {
+            if (checkSet != null) {
+                try {
+                    checkSet.close();
+                } catch (Exception e) {
+                }
+            }
+            if (statement != null) {
+                try {
+                    statement.close();
+                } catch (Exception e) {
+                }
+            }
+        }
+        return currentRecords;
+    }
+
+    /**
+     * Parse pk values object [ ].
+     *
+     * @param records the records
+     * @return the object [ ]
+     */
+    protected Object[] parsePkValues(TableRecords records) {
+        String pkName = records.getTableMeta().getPkName();
+        List<Row> undoRows = records.getRows();
+        Object[] pkValues = new Object[undoRows.size()];
+        for (int i = 0; i < undoRows.size(); i++) {
+            List<Field> fields = undoRows.get(i).getFields();
+            if (fields != null) {
+                for (Field field : fields) {
+                    if (StringUtils.equalsIgnoreCase(pkName, field.getName())) {
+                        pkValues[i] = field.getValue();
+                    }
+                }
+            }
+        }
+        return pkValues;
     }
 }
diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/UndoLogManager.java b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/UndoLogManager.java
index ab278f2e71f7450447bd440c55e9d02642f76b3f..deadf563778274db3f17e47c74e118aa964a7122 100644
--- a/rm-datasource/src/main/java/io/seata/rm/datasource/undo/UndoLogManager.java
+++ b/rm-datasource/src/main/java/io/seata/rm/datasource/undo/UndoLogManager.java
@@ -18,7 +18,6 @@ package io.seata.rm.datasource.undo;
 import com.alibaba.druid.util.JdbcConstants;
 import io.seata.common.exception.NotSupportYetException;
 import io.seata.common.util.BlobUtils;
-import io.seata.common.util.StringUtils;
 import io.seata.core.exception.TransactionException;
 import io.seata.rm.datasource.ConnectionContext;
 import io.seata.rm.datasource.ConnectionProxy;
@@ -161,7 +160,7 @@ public final class UndoLogManager {
                     }
 
                     Blob b = rs.getBlob("rollback_info");
-                    String rollbackInfo = StringUtils.blob2string(b);
+                    String rollbackInfo = BlobUtils.blob2string(b);
                     BranchUndoLog branchUndoLog = UndoLogParserFactory.getInstance().decode(rollbackInfo);
 
                     for (SQLUndoLog sqlUndoLog : branchUndoLog.getSqlUndoLogs()) {
@@ -234,13 +233,12 @@ public final class UndoLogManager {
      *
      * @param xids
      * @param branchIds
-     * @param limitSize
      * @param conn
      */
-    public static void batchDeleteUndoLog(Set<String> xids, Set<Long> branchIds, int limitSize, Connection conn) throws SQLException {
+    public static void batchDeleteUndoLog(Set<String> xids, Set<Long> branchIds, Connection conn) throws SQLException {
         int xidSize = xids.size();
         int branchIdSize = branchIds.size();
-        String batchDeleteSql = toBatchDeleteUndoLogSql(xidSize, branchIdSize,limitSize);
+        String batchDeleteSql = toBatchDeleteUndoLogSql(xidSize, branchIdSize);
         PreparedStatement deletePST = null;
         try {
             deletePST = conn.prepareStatement(batchDeleteSql);
@@ -268,15 +266,14 @@ public final class UndoLogManager {
 
     }
 
-    protected static String toBatchDeleteUndoLogSql(int xidSize, int branchIdSize,int limitSize) {
+    protected static String toBatchDeleteUndoLogSql(int xidSize, int branchIdSize) {
         StringBuilder sqlBuilder = new StringBuilder();
         sqlBuilder.append("DELETE FROM ")
                 .append(UNDO_LOG_TABLE_NAME)
                 .append(" WHERE  branch_id IN ");
-        appendInParam(xidSize, sqlBuilder);
-        sqlBuilder.append(" AND xid IN ");
         appendInParam(branchIdSize, sqlBuilder);
-        sqlBuilder.append(" LIMIT ").append(limitSize);
+        sqlBuilder.append(" AND xid IN ");
+        appendInParam(xidSize, sqlBuilder);
         return sqlBuilder.toString();
     }
 
diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..0d79fa178d00835eb2d884d33ebec799944fab62
--- /dev/null
+++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/AbstractUndoExecutorTest.java
@@ -0,0 +1,316 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.rm.datasource.undo;
+
+import io.seata.rm.datasource.sql.SQLType;
+import io.seata.rm.datasource.sql.struct.ColumnMeta;
+import io.seata.rm.datasource.sql.struct.Field;
+import io.seata.rm.datasource.sql.struct.Row;
+import io.seata.rm.datasource.sql.struct.TableMeta;
+import io.seata.rm.datasource.sql.struct.TableRecords;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Geng Zhang
+ */
+public class AbstractUndoExecutorTest extends BaseExecutorTest {
+
+    static BasicDataSource dataSource = null;
+
+    static Connection connection = null;
+
+    static TableMeta tableMeta = null;
+
+    @BeforeAll
+    public static void start() throws SQLException {
+        dataSource = new BasicDataSource();
+        dataSource.setDriverClassName("org.h2.Driver");
+        dataSource.setUrl("jdbc:h2:./db_store/test_undo");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+
+        connection = dataSource.getConnection();
+
+        tableMeta = mockTableMeta();
+    }
+
+    @AfterAll
+    public static void stop() {
+        if (connection != null) {
+            try {
+                connection.close();
+            } catch (SQLException e) {
+            }
+        }
+        if (dataSource != null) {
+            try {
+                dataSource.close();
+            } catch (SQLException e) {
+            }
+        }
+    }
+
+    @BeforeEach
+    private void prepareTable() {
+        execSQL("DROP TABLE table_name");
+        execSQL("CREATE TABLE table_name ( `id` int(8), `name` varchar(64), PRIMARY KEY (`id`))");
+    }
+
+    @Test
+    public void dataValidationUpdate() throws SQLException {
+        execSQL("INSERT INTO table_name(id, name) VALUES (12345,'aaa');");
+        execSQL("INSERT INTO table_name(id, name) VALUES (12346,'aaa');");
+
+        TableRecords beforeImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+
+        execSQL("update table_name set name = 'xxx' where id in (12345, 12346);");
+
+        TableRecords afterImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+
+        SQLUndoLog sqlUndoLog = new SQLUndoLog();
+        sqlUndoLog.setSqlType(SQLType.UPDATE);
+        sqlUndoLog.setTableMeta(tableMeta);
+        sqlUndoLog.setTableName("table_name");
+        sqlUndoLog.setBeforeImage(beforeImage);
+        sqlUndoLog.setAfterImage(afterImage);
+
+        TestUndoExecutor spy = new TestUndoExecutor(sqlUndoLog, false);
+
+        // case1: normal case  before:aaa -> after:xxx -> current:xxx
+        Assertions.assertTrue(spy.dataValidationAndGoOn(connection));
+
+        // case2: dirty data   before:aaa -> after:xxx -> current:yyy
+        execSQL("update table_name set name = 'yyy' where id in (12345, 12346);");
+        try {
+            spy.dataValidationAndGoOn(connection);
+            Assertions.fail();
+        } catch (Exception e) {
+            Assertions.assertTrue(e instanceof SQLException);
+        }
+
+        // case 3: before == current before:aaa -> after:xxx -> current:aaa
+        execSQL("update table_name set name = 'aaa' where id in (12345, 12346);");
+        Assertions.assertFalse(spy.dataValidationAndGoOn(connection));
+
+        // case 4: before == after   before:aaa -> after:aaa
+        afterImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+        sqlUndoLog.setAfterImage(afterImage);
+        Assertions.assertFalse(spy.dataValidationAndGoOn(connection));
+    }
+
+    @Test
+    public void dataValidationInsert() throws SQLException {
+        TableRecords beforeImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+
+        execSQL("INSERT INTO table_name(id, name) VALUES (12345,'aaa');");
+        execSQL("INSERT INTO table_name(id, name) VALUES (12346,'aaa');");
+
+        TableRecords afterImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+
+        SQLUndoLog sqlUndoLog = new SQLUndoLog();
+        sqlUndoLog.setSqlType(SQLType.INSERT);
+        sqlUndoLog.setTableMeta(tableMeta);
+        sqlUndoLog.setTableName("table_name");
+        sqlUndoLog.setBeforeImage(beforeImage);
+        sqlUndoLog.setAfterImage(afterImage);
+
+        TestUndoExecutor spy = new TestUndoExecutor(sqlUndoLog, false);
+
+        // case1: normal case  before:0 -> after:2 -> current:2 
+        Assertions.assertTrue(spy.dataValidationAndGoOn(connection));
+
+        // case2: dirty data   before:0 -> after:2 -> current:2' 
+        execSQL("update table_name set name = 'yyy' where id in (12345, 12346);");
+        try {
+            Assertions.assertTrue(spy.dataValidationAndGoOn(connection));
+            Assertions.fail();
+        } catch (Exception e) {
+            Assertions.assertTrue(e instanceof SQLException);
+        }
+
+        // case3: before == current   before:0 -> after:2 -> current:0
+        execSQL("delete from table_name where id in (12345, 12346);");
+        Assertions.assertFalse(spy.dataValidationAndGoOn(connection));
+
+        // case 4: before == after   before:0 -> after:0
+        afterImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+        sqlUndoLog.setAfterImage(afterImage);
+        Assertions.assertFalse(spy.dataValidationAndGoOn(connection));
+    }
+
+    @Test
+    public void dataValidationDelete() throws SQLException {
+        execSQL("INSERT INTO table_name(id, name) VALUES (12345,'aaa');");
+        execSQL("INSERT INTO table_name(id, name) VALUES (12346,'aaa');");
+
+        TableRecords beforeImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+
+        execSQL("delete from table_name where id in (12345, 12346);");
+
+        TableRecords afterImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+
+        SQLUndoLog sqlUndoLog = new SQLUndoLog();
+        sqlUndoLog.setSqlType(SQLType.INSERT);
+        sqlUndoLog.setTableMeta(tableMeta);
+        sqlUndoLog.setTableName("table_name");
+        sqlUndoLog.setBeforeImage(beforeImage);
+        sqlUndoLog.setAfterImage(afterImage);
+
+        TestUndoExecutor spy = new TestUndoExecutor(sqlUndoLog, true);
+
+        // case1: normal case  before:2 -> after:0 -> current:0
+        Assertions.assertTrue(spy.dataValidationAndGoOn(connection));
+
+        // case2: dirty data   before:2 -> after:0 -> current:1
+        execSQL("INSERT INTO table_name(id, name) VALUES (12345,'aaa');");
+        try {
+            Assertions.assertTrue(spy.dataValidationAndGoOn(connection));
+            Assertions.fail();
+        } catch (Exception e) {
+            Assertions.assertTrue(e instanceof SQLException);
+        }
+
+        // case3: before == current   before:2 -> after:0 -> current:2
+        execSQL("INSERT INTO table_name(id, name) VALUES (12346,'aaa');");
+        Assertions.assertFalse(spy.dataValidationAndGoOn(connection));
+
+        // case 4: before == after  before:2 -> after:2
+        afterImage = execQuery(tableMeta, "SELECT * FROM table_name WHERE id IN (12345, 12346);");
+        sqlUndoLog.setAfterImage(afterImage);
+        Assertions.assertFalse(spy.dataValidationAndGoOn(connection));
+    }
+
+    @Test
+    public void testParsePK() {
+        TableMeta tableMeta = Mockito.mock(TableMeta.class);
+        Mockito.when(tableMeta.getPkName()).thenReturn("id");
+        Mockito.when(tableMeta.getTableName()).thenReturn("table_name");
+
+        TableRecords beforeImage = new TableRecords();
+        beforeImage.setTableName("table_name");
+        beforeImage.setTableMeta(tableMeta);
+
+        List<Row> beforeRows = new ArrayList<>();
+        Row row0 = new Row();
+        Field field01 = addField(row0, "id", 1, "12345");
+        Field field02 = addField(row0, "age", 1, "2");
+        beforeRows.add(row0);
+        Row row1 = new Row();
+        Field field11 = addField(row1, "id", 1, "12346");
+        Field field12 = addField(row1, "age", 1, "2");
+        beforeRows.add(row1);
+        beforeImage.setRows(beforeRows);
+
+        SQLUndoLog sqlUndoLog = new SQLUndoLog();
+        sqlUndoLog.setSqlType(SQLType.UPDATE);
+        sqlUndoLog.setTableMeta(tableMeta);
+        sqlUndoLog.setTableName("table_name");
+        sqlUndoLog.setBeforeImage(beforeImage);
+        sqlUndoLog.setAfterImage(null);
+
+        TestUndoExecutor executor = new TestUndoExecutor(sqlUndoLog, true);
+        Object[] pkValues = executor.parsePkValues(beforeImage);
+        Assertions.assertEquals(2, pkValues.length);
+    }
+
+
+    private static TableMeta mockTableMeta() {
+        TableMeta tableMeta = Mockito.mock(TableMeta.class);
+        Mockito.when(tableMeta.getPkName()).thenReturn("ID");
+        Mockito.when(tableMeta.getTableName()).thenReturn("table_name");
+        ColumnMeta meta0 = Mockito.mock(ColumnMeta.class);
+        Mockito.when(meta0.getDataType()).thenReturn(Types.INTEGER);
+        Mockito.when(meta0.getColumnName()).thenReturn("ID");
+        Mockito.when(tableMeta.getColumnMeta("ID")).thenReturn(meta0);
+        ColumnMeta meta1 = Mockito.mock(ColumnMeta.class);
+        Mockito.when(meta1.getDataType()).thenReturn(Types.VARCHAR);
+        Mockito.when(meta1.getColumnName()).thenReturn("NAME");
+        Mockito.when(tableMeta.getColumnMeta("NAME")).thenReturn(meta1);
+        return tableMeta;
+    }
+
+    private void execSQL(String sql) {
+        Statement s = null;
+        try {
+            s = connection.createStatement();
+            s.execute(sql);
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    private TableRecords execQuery(TableMeta tableMeta, String sql) throws SQLException {
+        Statement s = null;
+        ResultSet set = null;
+        try {
+            s = connection.createStatement();
+            set = s.executeQuery(sql);
+            return TableRecords.buildRecords(tableMeta, set);
+        } finally {
+            if (set != null) {
+                try {
+                    set.close();
+                } catch (Exception e) {
+                }
+            }
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+}
+
+class TestUndoExecutor extends AbstractUndoExecutor {
+    private boolean isDelete;
+    public TestUndoExecutor(SQLUndoLog sqlUndoLog, boolean isDelete) {
+        super(sqlUndoLog);
+        this.isDelete = isDelete;
+    }
+
+    @Override
+    protected String buildUndoSQL() {
+        return null;
+    }
+
+    @Override
+    protected TableRecords getUndoRows() {
+        return isDelete ? sqlUndoLog.getBeforeImage() : sqlUndoLog.getAfterImage();
+    }
+}
diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoExecutorTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoExecutorTest.java
index eb7a0324bb26c6ddf99164c6fd544ea82d4ca17a..ae1174c8c5c77255cdeed702ce64ef86939fb7b9 100644
--- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoExecutorTest.java
+++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoExecutorTest.java
@@ -59,6 +59,7 @@ import io.seata.rm.datasource.sql.struct.TableMeta;
 import io.seata.rm.datasource.sql.struct.TableRecords;
 
 import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
 
 /**
  * The type Undo executor test.
@@ -88,7 +89,7 @@ public class UndoExecutorTest {
      * Test update.
      */
     @Test
-    public void testUpdate() {
+    public void testUpdate() throws SQLException {
         SQLUndoLog SQLUndoLog = new SQLUndoLog();
         SQLUndoLog.setTableName("my_test_table");
         SQLUndoLog.setSqlType(SQLType.UPDATE);
@@ -147,19 +148,18 @@ public class UndoExecutorTest {
         SQLUndoLog.setAfterImage(afterImage);
 
         AbstractUndoExecutor executor = UndoExecutorFactory.getUndoExecutor(JdbcConstants.MYSQL, SQLUndoLog);
-
-        try {
-            executor.executeOn(new MockConnection());
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
+        MockConnection connection = new MockConnection();
+        AbstractUndoExecutor spy = Mockito.spy(executor);
+        // skip data validation
+        Mockito.doReturn(true).when(spy).dataValidationAndGoOn(connection);
+        spy.executeOn(connection);
     }
 
     /**
      * Test insert.
      */
     @Test
-    public void testInsert() {
+    public void testInsert() throws SQLException {
         SQLUndoLog SQLUndoLog = new SQLUndoLog();
         SQLUndoLog.setTableName("my_test_table");
         SQLUndoLog.setSqlType(SQLType.INSERT);
@@ -217,19 +217,18 @@ public class UndoExecutorTest {
         SQLUndoLog.setAfterImage(afterImage);
 
         AbstractUndoExecutor executor = UndoExecutorFactory.getUndoExecutor(JdbcConstants.MYSQL, SQLUndoLog);
-
-        try {
-            executor.executeOn(new MockConnection());
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
+        MockConnection connection = new MockConnection();
+        AbstractUndoExecutor spy = Mockito.spy(executor);
+        // skip data validation
+        Mockito.doReturn(true).when(spy).dataValidationAndGoOn(connection);
+        spy.executeOn(connection);
     }
 
     /**
      * Test delete.
      */
     @Test
-    public void testDelete() {
+    public void testDelete() throws SQLException {
         SQLUndoLog SQLUndoLog = new SQLUndoLog();
         SQLUndoLog.setTableName("my_test_table");
         SQLUndoLog.setSqlType(SQLType.DELETE);
@@ -287,12 +286,11 @@ public class UndoExecutorTest {
         SQLUndoLog.setBeforeImage(beforeImage);
 
         AbstractUndoExecutor executor = UndoExecutorFactory.getUndoExecutor(JdbcConstants.MYSQL, SQLUndoLog);
-
-        try {
-            executor.executeOn(new MockConnection());
-        } catch (SQLException e) {
-            e.printStackTrace();
-        }
+        MockConnection connection = new MockConnection();
+        AbstractUndoExecutor spy = Mockito.spy(executor);
+        // skip data validation
+        Mockito.doReturn(true).when(spy).dataValidationAndGoOn(connection);
+        spy.executeOn(connection);
     }
 
     /**
diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoLogManagerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoLogManagerTest.java
index dcc8f5d4ddc3606f75d988fc9626f2aab8305ab9..e8fe5504dc9c67f710af88712bd032ca45d75dad 100644
--- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoLogManagerTest.java
+++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/UndoLogManagerTest.java
@@ -40,9 +40,10 @@ public class UndoLogManagerTest {
 
     private static final int APPEND_IN_SIZE = 10;
 
-    private static final int LIMIT_SIZE = 10;
 
-    private static final String THE_APPEND_IN_SIZE_PARAM_String = " (?,?,?,?,?,?,?,?,?,?) ";
+    private static final String THE_APPEND_IN_SIZE_PARAM_STRING = " (?,?,?,?,?,?,?,?,?,?) ";
+
+    private static final String THE_DOUBLE_APPEND_IN_SIZE_PARAM_STRING = " (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ";
 
     @Test
     public void testBatchDeleteUndoLog() throws Exception {
@@ -57,7 +58,7 @@ public class UndoLogManagerTest {
         Connection connection = mock(Connection.class);
         PreparedStatement preparedStatement = mock(PreparedStatement.class);
         when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);
-        UndoLogManager.batchDeleteUndoLog(xids, branchIds, LIMIT_SIZE, connection);
+        UndoLogManager.batchDeleteUndoLog(xids, branchIds, connection);
 
         //verify
         for (int i = 1;i <= APPEND_IN_SIZE;i++){
@@ -72,11 +73,10 @@ public class UndoLogManagerTest {
     @Test
     public void testToBatchDeleteUndoLogSql() {
         String expectedSqlString="DELETE FROM undo_log WHERE  branch_id IN " +
-                THE_APPEND_IN_SIZE_PARAM_String +
+                THE_APPEND_IN_SIZE_PARAM_STRING +
                 " AND xid IN " +
-                THE_APPEND_IN_SIZE_PARAM_String +
-                " LIMIT " + LIMIT_SIZE;
-        String batchDeleteUndoLogSql = UndoLogManager.toBatchDeleteUndoLogSql(APPEND_IN_SIZE, APPEND_IN_SIZE, LIMIT_SIZE);
+                THE_DOUBLE_APPEND_IN_SIZE_PARAM_STRING;
+        String batchDeleteUndoLogSql = UndoLogManager.toBatchDeleteUndoLogSql(APPEND_IN_SIZE * 2, APPEND_IN_SIZE);
         System.out.println(batchDeleteUndoLogSql);
         assertThat(batchDeleteUndoLogSql).isEqualTo(expectedSqlString);
     }
@@ -85,7 +85,7 @@ public class UndoLogManagerTest {
     public void testAppendInParam() {
         StringBuilder sqlBuilder = new StringBuilder();
         UndoLogManager.appendInParam(APPEND_IN_SIZE, sqlBuilder);
-        assertThat(sqlBuilder.toString()).isEqualTo(THE_APPEND_IN_SIZE_PARAM_String);
+        assertThat(sqlBuilder.toString()).isEqualTo(THE_APPEND_IN_SIZE_PARAM_STRING);
     }
 
 }
diff --git a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/keyword/MySQLKeywordCheckerTest.java b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/keyword/MySQLKeywordCheckerTest.java
index 879b77a88cdded38da225d3bf4418cd6c4042b5f..a3fd52afb1a3b2401660ba542b4b9c505e06a690 100644
--- a/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/keyword/MySQLKeywordCheckerTest.java
+++ b/rm-datasource/src/test/java/io/seata/rm/datasource/undo/mysql/keyword/MySQLKeywordCheckerTest.java
@@ -26,7 +26,6 @@ import io.seata.rm.datasource.sql.struct.TableRecords;
 import io.seata.rm.datasource.undo.KeywordChecker;
 import io.seata.rm.datasource.undo.KeywordCheckerFactory;
 import io.seata.rm.datasource.undo.SQLUndoLog;
-import io.seata.rm.datasource.undo.UndoExecutorTest;
 import io.seata.rm.datasource.undo.mysql.MySQLUndoDeleteExecutor;
 import io.seata.rm.datasource.undo.mysql.MySQLUndoInsertExecutor;
 import io.seata.rm.datasource.undo.mysql.MySQLUndoUpdateExecutor;
diff --git a/server/pom.xml b/server/pom.xml
index 55290bec0ee9cdfd89784ff3d71097cf4bbac865..870f8187e7a02253f64d37acbc851a3df2f067a7 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -45,6 +45,24 @@
             <version>${project.version}</version>
         </dependency>
 
+        <!-- for database -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-dbcp</groupId>
+            <artifactId>commons-dbcp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
     </dependencies>
 
     <build>
diff --git a/server/src/main/java/io/seata/server/AbstractTCInboundHandler.java b/server/src/main/java/io/seata/server/AbstractTCInboundHandler.java
index d6655196eeee371631db759df2e063a174c861c1..89fcbe94740f56d7a42802f87df788a6105c68c3 100644
--- a/server/src/main/java/io/seata/server/AbstractTCInboundHandler.java
+++ b/server/src/main/java/io/seata/server/AbstractTCInboundHandler.java
@@ -15,7 +15,6 @@
  */
 package io.seata.server;
 
-import io.seata.common.XID;
 import io.seata.core.exception.AbstractExceptionHandler;
 import io.seata.core.exception.TransactionException;
 import io.seata.core.model.GlobalStatus;
@@ -106,8 +105,7 @@ public abstract class AbstractTCInboundHandler extends AbstractExceptionHandler
             public void onTransactionException(GlobalRollbackRequest request, GlobalRollbackResponse response,
                 TransactionException tex) {
                 super.onTransactionException(request, response, tex);
-                GlobalSession globalSession = SessionHolder.findGlobalSession(
-                    XID.getTransactionId(request.getXid()));
+                GlobalSession globalSession = SessionHolder.findGlobalSession(request.getXid());
                 if (globalSession != null) {
                     response.setGlobalStatus(globalSession.getStatus());
                 } else {
@@ -118,8 +116,7 @@ public abstract class AbstractTCInboundHandler extends AbstractExceptionHandler
             @Override
             public void onException(GlobalRollbackRequest request, GlobalRollbackResponse response, Exception rex) {
                 super.onException(request, response, rex);
-                GlobalSession globalSession = SessionHolder.findGlobalSession(
-                    XID.getTransactionId(request.getXid()));
+                GlobalSession globalSession = SessionHolder.findGlobalSession(request.getXid());
                 if (globalSession != null) {
                     response.setGlobalStatus(globalSession.getStatus());
                 } else {
diff --git a/server/src/main/java/io/seata/server/Server.java b/server/src/main/java/io/seata/server/Server.java
index 92273a3e68fed718f276b95df19220e88994da68..0cec9d18b8713a6c006597b82ec0cd5db1c653b5 100644
--- a/server/src/main/java/io/seata/server/Server.java
+++ b/server/src/main/java/io/seata/server/Server.java
@@ -42,7 +42,7 @@ public class Server {
     private static final int SERVER_DEFAULT_PORT = 8091;
     private static final ThreadPoolExecutor WORKING_THREADS = new ThreadPoolExecutor(MIN_SERVER_POOL_SIZE,
         MAX_SERVER_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS,
-        new LinkedBlockingQueue(MAX_TASK_QUEUE_SIZE),
+        new LinkedBlockingQueue<>(MAX_TASK_QUEUE_SIZE),
         new NamedThreadFactory("ServerHandlerThread", MAX_SERVER_POOL_SIZE), new ThreadPoolExecutor.CallerRunsPolicy());
 
     /**
diff --git a/server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java b/server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java
index 15063da2cb22238481f6596ce9a22523fe84d368..18c1e80395fa9604463f5e10c9056cc2fadb1252 100644
--- a/server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java
+++ b/server/src/main/java/io/seata/server/coordinator/DefaultCoordinator.java
@@ -16,13 +16,17 @@
 package io.seata.server.coordinator;
 
 import java.io.IOException;
+import java.time.Duration;
 import java.util.Collection;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import io.seata.common.XID;
 import io.seata.common.thread.NamedThreadFactory;
+import io.seata.common.util.CollectionUtils;
+import io.seata.core.constants.ConfigurationKeys;
+import io.seata.common.util.DurationUtil;
+import io.seata.config.ConfigurationFactory;
 import io.seata.core.exception.TransactionException;
 import io.seata.core.model.BranchStatus;
 import io.seata.core.model.BranchType;
@@ -78,6 +82,44 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
 
     private static final int TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS = 5000;
 
+    /**
+     * The Committing retry delay.
+     */
+    protected int committingRetryDelay = CONFIG.getInt(ConfigurationKeys.COMMITING_RETRY_DELAY, 5);
+
+    /**
+     * The Asyn committing retry delay.
+     */
+    protected int asynCommittingRetryDelay = CONFIG.getInt(ConfigurationKeys.ASYN_COMMITING_RETRY_DELAY, 5);
+
+    /**
+     * The Rollbacking retry delay.
+     */
+    protected int rollbackingRetryDelay = CONFIG.getInt(ConfigurationKeys.ROLLBACKING_RETRY_DELAY, 5);
+
+    /**
+     * The Timeout retry delay.
+     */
+    protected int timeoutRetryDelay = CONFIG.getInt(ConfigurationKeys.TIMEOUT_RETRY_DELAY, 5);
+
+    private static final int ALWAYS_RETRY_BOUNDARY = 0;
+
+    private static final Duration MAX_COMMIT_RETRY_TIMEOUT = ConfigurationFactory.getInstance().getDuration(ConfigurationKeys.SERVICE_PREFIX + "max.commit.retry.timeout", DurationUtil.DEFAULT_DURATION, 100);
+
+    private static final Duration MAX_ROLLBACK_RETRY_TIMEOUT = ConfigurationFactory.getInstance().getDuration(ConfigurationKeys.SERVICE_PREFIX + "max.rollback.retry.timeout", DurationUtil.DEFAULT_DURATION, 100);
+
+    private ScheduledThreadPoolExecutor retryRollbacking = new ScheduledThreadPoolExecutor(1,
+            new NamedThreadFactory("RetryRollbacking", 1));
+
+    private ScheduledThreadPoolExecutor retryCommitting = new ScheduledThreadPoolExecutor(1,
+            new NamedThreadFactory("RetryCommitting", 1));
+
+    private ScheduledThreadPoolExecutor asyncCommitting = new ScheduledThreadPoolExecutor(1,
+            new NamedThreadFactory("AsyncCommitting", 1));
+
+    private ScheduledThreadPoolExecutor timeoutCheck = new ScheduledThreadPoolExecutor(1,
+            new NamedThreadFactory("TxTimeoutCheck", 1));
+
     private ServerMessageSender messageSender;
 
     private Core core = CoreFactory.get();
@@ -156,7 +198,7 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             request.setApplicationData(applicationData);
             request.setBranchType(branchType);
 
-            GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+            GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
             if(globalSession == null){
                 return BranchStatus.PhaseTwo_Committed;
             }
@@ -165,9 +207,7 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             BranchCommitResponse response = (BranchCommitResponse)messageSender.sendSyncRequest(resourceId,
                 branchSession.getClientId(), request);
             return response.getBranchStatus();
-        } catch (IOException e) {
-            throw new TransactionException(FailedToSendBranchCommitRequest, branchId + "/" + xid, e);
-        } catch (TimeoutException e) {
+        } catch (IOException | TimeoutException e) {
             throw new TransactionException(FailedToSendBranchCommitRequest, branchId + "/" + xid, e);
         }
     }
@@ -185,7 +225,7 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             request.setApplicationData(applicationData);
             request.setBranchType(branchType);
 
-            GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+            GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
             if(globalSession == null){
                 return BranchStatus.PhaseTwo_Rollbacked;
             }
@@ -194,27 +234,34 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             BranchRollbackResponse response = (BranchRollbackResponse)messageSender.sendSyncRequest(resourceId,
                 branchSession.getClientId(), request);
             return response.getBranchStatus();
-        } catch (IOException e) {
-            throw new TransactionException(FailedToSendBranchRollbackRequest, branchId + "/" + xid, e);
-        } catch (TimeoutException e) {
+        } catch (IOException | TimeoutException e) {
             throw new TransactionException(FailedToSendBranchRollbackRequest, branchId + "/" + xid, e);
         }
     }
 
-    private void timeoutCheck() throws TransactionException {
+    /**
+     * Timeout check.
+     *
+     * @throws TransactionException the transaction exception
+     */
+    protected void timeoutCheck() throws TransactionException {
         Collection<GlobalSession> allSessions = SessionHolder.getRootSessionManager().allSessions();
+        if(CollectionUtils.isEmpty(allSessions)){
+            return;
+        }
         if (allSessions.size() > 0 && LOGGER.isDebugEnabled()) {
             LOGGER.debug("Transaction Timeout Check Begin: " + allSessions.size());
         }
         for (GlobalSession globalSession : allSessions) {
             if (LOGGER.isDebugEnabled()) {
-                LOGGER.debug(globalSession.getTransactionId() + " " + globalSession.getStatus() + " " +
+                LOGGER.debug(globalSession.getXid() + " " + globalSession.getStatus() + " " +
                     globalSession.getBeginTime() + " " + globalSession.getTimeout());
             }
             boolean shouldTimeout = globalSession.lockAndExcute(() -> {
                 if (globalSession.getStatus() != GlobalStatus.Begin || !globalSession.isTimeout()) {
                     return false;
                 }
+                globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
                 globalSession.close();
                 globalSession.changeStatus(GlobalStatus.TimeoutRollbacking);
                 return true;
@@ -223,7 +270,7 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
                 continue;
             }
             LOGGER.info(
-                "Global transaction[" + globalSession.getTransactionId() + "] is timeout and will be rolled back.");
+                "Global transaction[" + globalSession.getXid() + "] is timeout and will be rolled back.");
 
             globalSession.addSessionLifecycleListener(SessionHolder.getRetryRollbackingSessionManager());
             SessionHolder.getRetryRollbackingSessionManager().addGlobalSession(globalSession);
@@ -235,107 +282,129 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
 
     }
 
-    private void handleRetryRollbacking() {
+    /**
+     * Handle retry rollbacking.
+     */
+    protected void handleRetryRollbacking() {
         Collection<GlobalSession> rollbackingSessions = SessionHolder.getRetryRollbackingSessionManager().allSessions();
+        if(CollectionUtils.isEmpty(rollbackingSessions)){
+            return;
+        }
+        long now = System.currentTimeMillis();
         for (GlobalSession rollbackingSession : rollbackingSessions) {
             try {
+                if(isRetryTimeout(now, MAX_ROLLBACK_RETRY_TIMEOUT.toMillis(), rollbackingSession.getBeginTime())){
+                    /**
+                     * Prevent thread safety issues
+                     */
+                    SessionHolder.getRetryCommittingSessionManager().removeGlobalSession(rollbackingSession);
+                    LOGGER.error("GlobalSession rollback retry timeout [{}]", rollbackingSession.getTransactionId());
+                    continue;
+                }
+                rollbackingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
                 core.doGlobalRollback(rollbackingSession, true);
             } catch (TransactionException ex) {
                 LOGGER.info("Failed to retry rollbacking [{}] {} {}",
-                    rollbackingSession.getTransactionId(), ex.getCode(), ex.getMessage());
+                    rollbackingSession.getXid(), ex.getCode(), ex.getMessage());
             }
         }
     }
 
-    private void handleRetryCommitting() {
+    /**
+     * Handle retry committing.
+     */
+    protected void handleRetryCommitting() {
         Collection<GlobalSession> committingSessions = SessionHolder.getRetryCommittingSessionManager().allSessions();
+        if(CollectionUtils.isEmpty(committingSessions)){
+           return;
+        }
+        long now = System.currentTimeMillis();
         for (GlobalSession committingSession : committingSessions) {
             try {
+                if(isRetryTimeout(now, MAX_COMMIT_RETRY_TIMEOUT.toMillis(), committingSession.getBeginTime())){
+                    /**
+                     * Prevent thread safety issues
+                     */
+                    SessionHolder.getRetryCommittingSessionManager().removeGlobalSession(committingSession);
+                    LOGGER.error("GlobalSession commit retry timeout [{}]", committingSession.getTransactionId());
+                    continue;
+                }
+                committingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
                 core.doGlobalCommit(committingSession, true);
             } catch (TransactionException ex) {
                 LOGGER.info("Failed to retry committing [{}] {} {}",
-                    committingSession.getTransactionId(), ex.getCode(), ex.getMessage());
+                    committingSession.getXid(), ex.getCode(), ex.getMessage());
             }
         }
     }
 
-    private void handleAsyncCommitting() {
+    private boolean isRetryTimeout(long now, long timeout, long beginTime){
+        /**
+         * Start timing when the session begin
+         */
+        if(timeout >= ALWAYS_RETRY_BOUNDARY &&
+                now - beginTime > timeout){
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Handle async committing.
+     */
+    protected void handleAsyncCommitting() {
         Collection<GlobalSession> asyncCommittingSessions = SessionHolder.getAsyncCommittingSessionManager()
             .allSessions();
+        if(CollectionUtils.isEmpty(asyncCommittingSessions)){
+            return;
+        }
         for (GlobalSession asyncCommittingSession : asyncCommittingSessions) {
             try {
+                asyncCommittingSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
                 core.doGlobalCommit(asyncCommittingSession, true);
             } catch (TransactionException ex) {
                 LOGGER.info("Failed to async committing [{}] {} {}",
-                    asyncCommittingSession.getTransactionId(), ex.getCode(), ex.getMessage());
+                    asyncCommittingSession.getXid(), ex.getCode(), ex.getMessage());
             }
         }
     }
 
-    private ScheduledThreadPoolExecutor retryRollbacking = new ScheduledThreadPoolExecutor(1,
-        new NamedThreadFactory("RetryRollbacking", 1));
-
-    private ScheduledThreadPoolExecutor retryCommitting = new ScheduledThreadPoolExecutor(1,
-        new NamedThreadFactory("RetryCommitting", 1));
-
-    private ScheduledThreadPoolExecutor asyncCommitting = new ScheduledThreadPoolExecutor(1,
-        new NamedThreadFactory("AsyncCommitting", 1));
-
-    private ScheduledThreadPoolExecutor timeoutCheck = new ScheduledThreadPoolExecutor(1,
-        new NamedThreadFactory("TxTimeoutCheck", 1));
 
     /**
      * Init.
      */
     public void init() {
-        retryRollbacking.scheduleAtFixedRate(new Runnable() {
-
-            @Override
-            public void run() {
-                try {
-                    handleRetryRollbacking();
-                } catch (Exception e) {
-                    LOGGER.info("Exception retry rollbacking ... ", e);
-                }
-
+        retryRollbacking.scheduleAtFixedRate(() -> {
+            try {
+                handleRetryRollbacking();
+            } catch (Exception e) {
+                LOGGER.info("Exception retry rollbacking ... ", e);
             }
-        }, 0, 5, TimeUnit.MILLISECONDS);
-
-        retryCommitting.scheduleAtFixedRate(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    handleRetryCommitting();
-                } catch (Exception e) {
-                    LOGGER.info("Exception retry committing ... ", e);
-                }
+        }, 0, rollbackingRetryDelay, TimeUnit.SECONDS);
 
+        retryCommitting.scheduleAtFixedRate(() -> {
+            try {
+                handleRetryCommitting();
+            } catch (Exception e) {
+                LOGGER.info("Exception retry committing ... ", e);
             }
-        }, 0, 5, TimeUnit.MILLISECONDS);
-
-        asyncCommitting.scheduleAtFixedRate(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    handleAsyncCommitting();
-                } catch (Exception e) {
-                    LOGGER.info("Exception async committing ... ", e);
-                }
+        }, 0, committingRetryDelay, TimeUnit.SECONDS);
 
+        asyncCommitting.scheduleAtFixedRate(() -> {
+            try {
+                handleAsyncCommitting();
+            } catch (Exception e) {
+                LOGGER.info("Exception async committing ... ", e);
             }
-        }, 0, 10, TimeUnit.MILLISECONDS);
-
-        timeoutCheck.scheduleAtFixedRate(new Runnable() {
-            @Override
-            public void run() {
-                try {
-                    timeoutCheck();
-                } catch (Exception e) {
-                    LOGGER.info("Exception timeout checking ... ", e);
-                }
+        }, 0, asynCommittingRetryDelay, TimeUnit.SECONDS);
 
+        timeoutCheck.scheduleAtFixedRate(() -> {
+            try {
+                timeoutCheck();
+            } catch (Exception e) {
+                LOGGER.info("Exception timeout checking ... ", e);
             }
-        }, 0, 2, TimeUnit.MILLISECONDS);
+        }, 0, timeoutRetryDelay, TimeUnit.SECONDS);
     }
 
     @Override
@@ -369,14 +438,14 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             retryCommitting.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS);
             asyncCommitting.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS);
             timeoutCheck.awaitTermination(TIMED_TASK_SHUTDOWN_MAX_WAIT_MILLS, TimeUnit.MILLISECONDS);
-        } catch (InterruptedException ingore) {
+        } catch (InterruptedException ignore) {
 
         }
-        // 2. sencond close netty flow
+        // 2. second close netty flow
         if (messageSender instanceof RpcServer){
             ((RpcServer) messageSender).destroy();
         }
-        // 3. last destory SessionHolder
+        // 3. last destroy SessionHolder
         SessionHolder.destory();
     }
 }
diff --git a/server/src/main/java/io/seata/server/coordinator/DefaultCore.java b/server/src/main/java/io/seata/server/coordinator/DefaultCore.java
index 1ba36763f1f056f21eacd7bb8a65b7ba471f96ad..cd10d4281badee62d4a4df6fdd45d443554ca383 100644
--- a/server/src/main/java/io/seata/server/coordinator/DefaultCore.java
+++ b/server/src/main/java/io/seata/server/coordinator/DefaultCore.java
@@ -23,7 +23,7 @@ import io.seata.core.model.BranchType;
 import io.seata.core.model.GlobalStatus;
 import io.seata.core.model.ResourceManagerInbound;
 import io.seata.server.lock.LockManager;
-import io.seata.server.lock.LockManagerFactory;
+import io.seata.server.lock.LockerFactory;
 import io.seata.server.session.BranchSession;
 import io.seata.server.session.GlobalSession;
 import io.seata.server.session.SessionHelper;
@@ -46,7 +46,7 @@ public class DefaultCore implements Core {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCore.class);
 
-    private LockManager lockManager = LockManagerFactory.get();
+    private LockManager lockManager = LockerFactory.getLockManager();
 
     private ResourceManagerInbound resourceManagerInbound;
 
@@ -58,7 +58,7 @@ public class DefaultCore implements Core {
     @Override
     public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid,
                                String applicationData, String lockKeys) throws TransactionException {
-        GlobalSession globalSession = assertGlobalSessionNotNull(XID.getTransactionId(xid));
+        GlobalSession globalSession = assertGlobalSessionNotNull(xid);
         return globalSession.lockAndExcute(() -> {
             if (!globalSession.isActive()) {
                 throw new TransactionException(GlobalTransactionNotActive, "Current Status: " + globalSession.getStatus());
@@ -67,6 +67,7 @@ public class DefaultCore implements Core {
                 throw new TransactionException(GlobalTransactionStatusInvalid,
                         globalSession.getStatus() + " while expecting " + GlobalStatus.Begin);
             }
+            globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
             BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, branchType, resourceId,
                     applicationData, lockKeys, clientId);
             if (!branchSession.lock()) {
@@ -81,10 +82,10 @@ public class DefaultCore implements Core {
         });
     }
 
-    private GlobalSession assertGlobalSessionNotNull(long transactionId) throws TransactionException {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+    private GlobalSession assertGlobalSessionNotNull(String xid) throws TransactionException {
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         if (globalSession == null) {
-            throw new TransactionException(TransactionExceptionCode.GlobalTransactionNotExist, "" + transactionId + "");
+            throw new TransactionException(TransactionExceptionCode.GlobalTransactionNotExist, "" + xid + "");
         }
         return globalSession;
     }
@@ -93,11 +94,12 @@ public class DefaultCore implements Core {
     @Override
     public void branchReport(BranchType branchType, String xid, long branchId, BranchStatus status,
                              String applicationData) throws TransactionException {
-        GlobalSession globalSession = assertGlobalSessionNotNull(XID.getTransactionId(xid));
+        GlobalSession globalSession = assertGlobalSessionNotNull(xid);
         BranchSession branchSession = globalSession.getBranch(branchId);
         if (branchSession == null) {
             throw new TransactionException(BranchTransactionNotExist);
         }
+        globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         globalSession.changeBranchStatus(branchSession, status);
     }
 
@@ -105,7 +107,7 @@ public class DefaultCore implements Core {
     public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys)
         throws TransactionException {
         if (branchType == BranchType.AT) {
-            return lockManager.isLockable(XID.getTransactionId(xid), resourceId, lockKeys);
+            return lockManager.isLockable(xid, resourceId, lockKeys);
         } else {
             return true;
         }
@@ -121,17 +123,19 @@ public class DefaultCore implements Core {
 
         session.begin();
 
-        return XID.generateXID(session.getTransactionId());
+        return session.getXid();
     }
 
     @Override
     public GlobalStatus commit(String xid) throws TransactionException {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         if (globalSession == null) {
             return GlobalStatus.Finished;
         }
+        globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         // just lock changeStatus
         boolean shouldCommit = globalSession.lockAndExcute(() -> {
+            //the lock should release after branch commit
             globalSession.closeAndClean(); // Highlight: Firstly, close the session, then no more branch can be registered.
             if (globalSession.getStatus() == GlobalStatus.Begin) {
                 globalSession.changeStatus(GlobalStatus.Committing);
@@ -175,7 +179,7 @@ public class DefaultCore implements Core {
                         } else {
                             SessionHelper.endCommitFailed(globalSession);
                             LOGGER.error("Finally, failed to commit global[{}] since branch[{}] commit failed",
-                                globalSession.getTransactionId(), branchSession.getBranchId());
+                                globalSession.getXid(), branchSession.getBranchId());
                             return;
                         }
                     default:
@@ -189,7 +193,7 @@ public class DefaultCore implements Core {
                         } else {
                             LOGGER.error(
                                 "Failed to commit global[{}] since branch[{}] commit failed, will retry later.",
-                                globalSession.getTransactionId(), branchSession.getBranchId());
+                                globalSession.getXid(), branchSession.getBranchId());
                             return;
                         }
 
@@ -206,11 +210,11 @@ public class DefaultCore implements Core {
 
         }
         if (globalSession.hasBranch()) {
-            LOGGER.info("Global[{}] committing is NOT done.", globalSession.getTransactionId());
+            LOGGER.info("Global[{}] committing is NOT done.", globalSession.getXid());
             return;
         }
         SessionHelper.endCommitted(globalSession);
-        LOGGER.info("Global[{}] committing is successfully done.", globalSession.getTransactionId());
+        LOGGER.info("Global[{}] committing is successfully done.", globalSession.getXid());
     }
 
     private void asyncCommit(GlobalSession globalSession) throws TransactionException {
@@ -238,10 +242,11 @@ public class DefaultCore implements Core {
 
     @Override
     public GlobalStatus rollback(String xid) throws TransactionException {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         if (globalSession == null) {
             return GlobalStatus.Finished;
         }
+        globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         // just lock changeStatus
         boolean shouldRollBack = globalSession.lockAndExcute(() -> {
             globalSession.close(); // Highlight: Firstly, close the session, then no more branch can be registered.
@@ -279,7 +284,7 @@ public class DefaultCore implements Core {
                         continue;
                     case PhaseTwo_RollbackFailed_Unretryable:
                         SessionHelper.endRollbackFailed(globalSession);
-                        LOGGER.error("Failed to rollback global[" + globalSession.getTransactionId() + "] since branch["
+                        LOGGER.error("Failed to rollback global[" + globalSession.getXid() + "] since branch["
                             + branchSession.getBranchId() + "] rollback failed");
                         return;
                     default:
@@ -304,7 +309,7 @@ public class DefaultCore implements Core {
 
     @Override
     public GlobalStatus getStatus(String xid) throws TransactionException {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         return globalSession.getStatus();
     }
 }
diff --git a/server/src/main/java/io/seata/server/lock/AbstractLockManager.java b/server/src/main/java/io/seata/server/lock/AbstractLockManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..a8db3a54d9214c10a7e4eb5638532003f25fa717
--- /dev/null
+++ b/server/src/main/java/io/seata/server/lock/AbstractLockManager.java
@@ -0,0 +1,117 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock;
+
+import io.seata.common.XID;
+import io.seata.common.util.StringUtils;
+import io.seata.core.lock.RowLock;
+import io.seata.server.session.BranchSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The type Abstract lock manager.
+ *
+ * @author zhangsen
+ * @data 2019 /4/25
+ */
+public abstract class AbstractLockManager implements LockManager {
+
+    /**
+     * The constant LOGGER.
+     */
+    protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractLockManager.class);
+
+    /**
+     * Collect row locks list.`
+     *
+     * @param branchSession the branch session
+     * @return the list
+     */
+    protected List<RowLock> collectRowLocks(BranchSession branchSession){
+        List<RowLock> locks = new ArrayList<>();
+        if(branchSession == null || StringUtils.isBlank(branchSession.getLockKey())){
+            return locks;
+        }
+        String xid = branchSession.getXid();
+        String resourceId = branchSession.getResourceId();
+        long transactionId = branchSession.getTransactionId();
+
+        String lockKey = branchSession.getLockKey();
+
+        return collectRowLocks(lockKey, resourceId, xid, transactionId, branchSession.getBranchId());
+    }
+
+    /**
+     * Collect row locks list.
+     *
+     * @param lockKey    the lock key
+     * @param resourceId the resource id
+     * @param xid        the xid
+     * @return the list
+     */
+    protected List<RowLock> collectRowLocks(String lockKey, String resourceId, String xid) {
+        return collectRowLocks(lockKey, resourceId, xid, XID.getTransactionId(xid), null);
+    }
+
+    /**
+     * Collect row locks list.
+     *
+     * @param lockKey       the lock key
+     * @param resourceId    the resource id
+     * @param xid           the xid
+     * @param transactionId the transaction id
+     * @param branchID      the branch id
+     * @return the list
+     */
+    protected List<RowLock> collectRowLocks(String lockKey, String resourceId, String xid, Long transactionId, Long branchID){
+        List<RowLock> locks = new ArrayList<RowLock>();
+
+        String[] tableGroupedLockKeys = lockKey.split(";");
+        for (String tableGroupedLockKey : tableGroupedLockKeys) {
+            int idx = tableGroupedLockKey.indexOf(":");
+            if (idx < 0) {
+                return locks;
+            }
+            String tableName = tableGroupedLockKey.substring(0, idx);
+            String mergedPKs = tableGroupedLockKey.substring(idx + 1);
+            if(StringUtils.isBlank(mergedPKs)){
+                return locks;
+            }
+            String[] pks = mergedPKs.split(",");
+            if(pks == null || pks.length == 0){
+                return locks;
+            }
+            for(String pk : pks){
+                if(StringUtils.isNotBlank(pk)){
+                    RowLock rowLock = new RowLock();
+                    rowLock.setXid(xid);
+                    rowLock.setTransactionId(transactionId);
+                    rowLock.setBranchId(branchID);
+                    rowLock.setTableName(tableName);
+                    rowLock.setPk(pk);
+                    rowLock.setResourceId(resourceId);
+                    locks.add(rowLock);
+                }
+            }
+        }
+        return locks;
+    }
+
+}
diff --git a/server/src/main/java/io/seata/server/lock/DefaultLockManager.java b/server/src/main/java/io/seata/server/lock/DefaultLockManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd66e979987d4c4ee7d5bf900b5c94862b966230
--- /dev/null
+++ b/server/src/main/java/io/seata/server/lock/DefaultLockManager.java
@@ -0,0 +1,103 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock;
+
+import io.seata.common.util.CollectionUtils;
+import io.seata.common.util.StringUtils;
+import io.seata.core.exception.TransactionException;
+import io.seata.core.lock.Locker;
+import io.seata.core.lock.RowLock;
+import io.seata.server.session.BranchSession;
+
+import java.util.List;
+
+/**
+ * The type Default lock manager.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+public class DefaultLockManager extends AbstractLockManager {
+
+    private static Locker locker = null;
+
+    @Override
+    public boolean acquireLock(BranchSession branchSession) throws TransactionException {
+        String lockKey = branchSession.getLockKey();
+        if (StringUtils.isNullOrEmpty(lockKey)) {
+            //no lock
+            return true;
+        }
+        //get locks of branch
+        List<RowLock> locks = collectRowLocks(branchSession);
+        if(CollectionUtils.isEmpty(locks)){
+            //no lock
+            return true;
+        }
+        return getLocker(branchSession).acquireLock(locks);
+    }
+
+    @Override
+    public boolean releaseLock(BranchSession branchSession) throws TransactionException {
+        List<RowLock> locks = collectRowLocks(branchSession);
+        if(CollectionUtils.isEmpty(locks)){
+            //no lock
+            return true;
+        }
+        try{
+            return getLocker(branchSession).releaseLock(locks);
+        }catch(Exception t){
+            LOGGER.error("unLock error, branchSession:" + branchSession, t);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isLockable(String xid, String resourceId, String lockKey) throws TransactionException {
+        List<RowLock> locks = collectRowLocks(lockKey, resourceId, xid);
+        try{
+            return getLocker().isLockable(locks);
+        }catch(Exception t){
+            LOGGER.error("isLockable error, xid:" + xid + ", resourceId:"+resourceId + ", lockKey:"+lockKey, t);
+            return false;
+        }
+    }
+
+    @Override
+    public void cleanAllLocks() throws TransactionException {
+        getLocker().cleanAllLocks();
+    }
+
+    /**
+     * Gets locker.
+     *
+     * @return the locker
+     */
+    protected Locker getLocker() {
+        return getLocker(null);
+    }
+
+    /**
+     * Gets locker.
+     *
+     * @param branchSession the branch session
+     * @return the locker
+     */
+    protected Locker getLocker(BranchSession branchSession) {
+        return LockerFactory.get(branchSession);
+    }
+
+}
diff --git a/server/src/main/java/io/seata/server/lock/DefaultLockManagerImpl.java b/server/src/main/java/io/seata/server/lock/DefaultLockManagerImpl.java
deleted file mode 100644
index 14a68549987fbf913437cdef1265b84d1239113c..0000000000000000000000000000000000000000
--- a/server/src/main/java/io/seata/server/lock/DefaultLockManagerImpl.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *  Copyright 1999-2019 Seata.io Group.
- *
- *  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.
- */
-package io.seata.server.lock;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import io.netty.util.internal.ConcurrentSet;
-import io.seata.common.exception.ShouldNeverHappenException;
-import io.seata.common.util.StringUtils;
-import io.seata.core.exception.TransactionException;
-import io.seata.server.session.BranchSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * The type Default lock manager.
- *
- * @author sharajava
- */
-public class DefaultLockManagerImpl implements LockManager {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultLockManagerImpl.class);
-
-    private static final int BUCKET_PER_TABLE = 128;
-
-    private static final
-    ConcurrentHashMap<String/* resourceId */,
-        ConcurrentHashMap<String/* tableName */,
-            ConcurrentHashMap<Integer/* bucketId */,
-                Map<String/* pk */, Long/* transactionId */>>>>
-        LOCK_MAP = new ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>>>();
-
-    @Override
-    public boolean acquireLock(BranchSession branchSession) throws TransactionException {
-        String resourceId = branchSession.getResourceId();
-        long transactionId = branchSession.getTransactionId();
-        ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>> dbLockMap = LOCK_MAP.get(resourceId);
-        if (dbLockMap == null) {
-            LOCK_MAP.putIfAbsent(resourceId,
-                new ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>>());
-            dbLockMap = LOCK_MAP.get(resourceId);
-        }
-        ConcurrentHashMap<Map<String, Long>, Set<String>> bucketHolder = branchSession.getLockHolder();
-
-        String lockKey = branchSession.getLockKey();
-        if (StringUtils.isNullOrEmpty(lockKey)) {
-            return true;
-        }
-
-        String[] tableGroupedLockKeys = lockKey.split(";");
-        for (String tableGroupedLockKey : tableGroupedLockKeys) {
-            int idx = tableGroupedLockKey.indexOf(":");
-            if (idx < 0) {
-                branchSession.unlock();
-                throw new ShouldNeverHappenException("Wrong format of LOCK KEYS: " + branchSession.getLockKey());
-            }
-            String tableName = tableGroupedLockKey.substring(0, idx);
-            String mergedPKs = tableGroupedLockKey.substring(idx + 1);
-            ConcurrentHashMap<Integer, Map<String, Long>> tableLockMap = dbLockMap.get(tableName);
-            if (tableLockMap == null) {
-                dbLockMap.putIfAbsent(tableName, new ConcurrentHashMap<Integer, Map<String, Long>>());
-                tableLockMap = dbLockMap.get(tableName);
-            }
-            String[] pks = mergedPKs.split(",");
-            for (String pk : pks) {
-                int bucketId = pk.hashCode() % BUCKET_PER_TABLE;
-                Map<String, Long> bucketLockMap = tableLockMap.get(bucketId);
-                if (bucketLockMap == null) {
-                    tableLockMap.putIfAbsent(bucketId, new HashMap<String, Long>());
-                    bucketLockMap = tableLockMap.get(bucketId);
-                }
-                synchronized (bucketLockMap) {
-                    Long lockingTransactionId = bucketLockMap.get(pk);
-                    if (lockingTransactionId == null) {
-                        // No existing lock
-                        bucketLockMap.put(pk, transactionId);
-                        Set<String> keysInHolder = bucketHolder.get(bucketLockMap);
-                        if (keysInHolder == null) {
-                            bucketHolder.putIfAbsent(bucketLockMap, new ConcurrentSet<String>());
-                            keysInHolder = bucketHolder.get(bucketLockMap);
-                        }
-                        keysInHolder.add(pk);
-
-                    } else if (lockingTransactionId.longValue() == transactionId) {
-                        // Locked by me
-                        continue;
-                    } else {
-                        LOGGER.info(
-                            "Global lock on [" + tableName + ":" + pk + "] is holding by " + lockingTransactionId);
-                        branchSession.unlock(); // Release all acquired locks.
-                        return false;
-                    }
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isLockable(long transactionId, String resourceId, String lockKey) throws TransactionException {
-        ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>> dbLockMap = LOCK_MAP.get(resourceId);
-        if (dbLockMap == null) {
-            return true;
-        }
-        String[] tableGroupedLockKeys = lockKey.split(";");
-        for (String tableGroupedLockKey : tableGroupedLockKeys) {
-            int idx = tableGroupedLockKey.indexOf(":");
-            if (idx < 0) {
-                throw new ShouldNeverHappenException("Wrong format of LOCK KEYS: " + lockKey);
-            }
-            String tableName = tableGroupedLockKey.substring(0, idx);
-            String mergedPKs = tableGroupedLockKey.substring(idx + 1);
-            ConcurrentHashMap<Integer, Map<String, Long>> tableLockMap = dbLockMap.get(tableName);
-            if (tableLockMap == null) {
-                continue;
-            }
-            String[] pks = mergedPKs.split(",");
-            for (String pk : pks) {
-                int bucketId = pk.hashCode() % BUCKET_PER_TABLE;
-                Map<String, Long> bucketLockMap = tableLockMap.get(bucketId);
-                if (bucketLockMap == null) {
-                    continue;
-                }
-                Long lockingTransactionId = bucketLockMap.get(pk);
-                if (lockingTransactionId == null || lockingTransactionId.longValue() == transactionId) {
-                    // Locked by me
-                    continue;
-                } else {
-                    LOGGER.info("Global lock on [" + tableName + ":" + pk + "] is holding by " + lockingTransactionId);
-                    return false;
-                }
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void cleanAllLocks() throws TransactionException {
-        LOCK_MAP.clear();
-    }
-
-    @Override
-    public boolean releaseLock(BranchSession branchSession) throws TransactionException {
-        ConcurrentHashMap<Map<String, Long>, Set<String>> lockHolder = branchSession.getLockHolder();
-        if (lockHolder.size() == 0) {
-            return true;
-        }
-        Iterator<Entry<Map<String, Long>, Set<String>>> it = lockHolder.entrySet().iterator();
-        while (it.hasNext()) {
-            Map.Entry<Map<String, Long>, Set<String>> entry = it.next();
-            Map<String, Long> bucket = entry.getKey();
-            Set<String> keys = entry.getValue();
-            synchronized (bucket) {
-                for (String key : keys) {
-                    Long v = bucket.get(key);
-                    if (v == null) {
-                        continue;
-                    }
-                    if (v.longValue() == branchSession.getTransactionId()) {
-                        bucket.remove(key);
-                    }
-                }
-            }
-        }
-        lockHolder.clear();
-        return true;
-    }
-}
diff --git a/server/src/main/java/io/seata/server/lock/LockManager.java b/server/src/main/java/io/seata/server/lock/LockManager.java
index 54bcef3c0b4e6c0edb376e128dabc64dec3192b5..64e7bd7317e9069f39b5f7c706370dff43e58fa1 100644
--- a/server/src/main/java/io/seata/server/lock/LockManager.java
+++ b/server/src/main/java/io/seata/server/lock/LockManager.java
@@ -35,29 +35,30 @@ public interface LockManager {
     boolean acquireLock(BranchSession branchSession) throws TransactionException;
 
     /**
-     * Is lockable boolean.
+     * Un lock boolean.
      *
-     * @param transactionId the transaction id
-     * @param resourceId    the resource id
-     * @param lockKey       the lock key
+     * @param branchSession the branch session
      * @return the boolean
      * @throws TransactionException the transaction exception
      */
-    boolean isLockable(long transactionId, String resourceId, String lockKey) throws TransactionException;
+    boolean releaseLock(BranchSession branchSession) throws TransactionException;
 
     /**
-     * Clean all locks.
+     * Is lockable boolean.
      *
+     * @param xid        the xid
+     * @param resourceId the resource id
+     * @param lockKey    the lock key
+     * @return the boolean
      * @throws TransactionException the transaction exception
      */
-    void cleanAllLocks() throws TransactionException;
+    boolean isLockable(String xid, String resourceId, String lockKey) throws TransactionException;
 
     /**
-     * Release lock boolean.
+     * Clean all locks.
      *
-     * @param branchSession the branch session
-     * @return the boolean
      * @throws TransactionException the transaction exception
      */
-    boolean releaseLock(BranchSession branchSession) throws TransactionException;
+    void cleanAllLocks() throws TransactionException;
+
 }
diff --git a/server/src/main/java/io/seata/server/lock/LockerFactory.java b/server/src/main/java/io/seata/server/lock/LockerFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..6a402f0a447ffa4a311b5584d33b3b5dc0523291
--- /dev/null
+++ b/server/src/main/java/io/seata/server/lock/LockerFactory.java
@@ -0,0 +1,99 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock;
+
+import io.seata.common.loader.EnhancedServiceLoader;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
+import io.seata.core.constants.ConfigurationKeys;
+import io.seata.core.lock.LockMode;
+import io.seata.core.lock.Locker;
+import io.seata.core.store.db.DataSourceGenerator;
+import io.seata.server.session.BranchSession;
+
+import javax.sql.DataSource;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The type Lock manager factory.
+ *
+ * @author sharajava
+ */
+public class LockerFactory {
+
+    /**
+     * The constant CONFIG.
+     */
+    protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
+
+    /**
+     * The constant locker.
+     */
+    protected static Locker locker = null;
+
+    /**
+     * The constant lockerMap.
+     */
+    protected static Map<String, Locker> lockerMap = new ConcurrentHashMap<>();
+
+    /**
+     * The constant lockManager.
+     */
+    protected static LockManager lockManager = new DefaultLockManager();
+
+    /**
+     * Get lock manager.
+     *
+     * @return the lock manager
+     */
+    public static synchronized final LockManager getLockManager() {
+        return lockManager;
+    }
+
+    /**
+     * Get lock manager.
+     *
+     * @param branchSession the branch session
+     * @return the lock manager
+     */
+    public static synchronized final Locker get(BranchSession branchSession) {
+        String lockMode = CONFIG.getConfig(ConfigurationKeys.LOCK_MODE);
+        if(LockMode.DB.name().equalsIgnoreCase(lockMode)){
+            if(lockerMap.get(lockMode) != null){
+                return lockerMap.get(lockMode);
+            }
+            //init dataSource
+            String datasourceType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE);
+            DataSourceGenerator dataSourceGenerator = EnhancedServiceLoader.load(DataSourceGenerator.class, datasourceType);
+            DataSource logStoreDataSource = dataSourceGenerator.generateDataSource();
+            locker = EnhancedServiceLoader.load(Locker.class, lockMode, new Class[]{DataSource.class}, new Object[]{logStoreDataSource});
+            lockerMap.put(lockMode, locker);
+        }else if(LockMode.MEMORY.name().equalsIgnoreCase(lockMode)){
+            if(branchSession == null){
+                throw new IllegalArgumentException("branchSession can be null for memory lockMode.");
+            }
+            locker = EnhancedServiceLoader.load(Locker.class, lockMode,
+                    new Class[]{BranchSession.class}, new Object[]{branchSession} );
+        }else {
+            //other locker
+            locker = EnhancedServiceLoader.load(Locker.class, lockMode);
+        }
+        return locker;
+    }
+
+
+}
diff --git a/server/src/main/java/io/seata/server/lock/db/DataBaseLocker.java b/server/src/main/java/io/seata/server/lock/db/DataBaseLocker.java
new file mode 100644
index 0000000000000000000000000000000000000000..5721727fdc8478ce3f0067ea7946cedf3240971e
--- /dev/null
+++ b/server/src/main/java/io/seata/server/lock/db/DataBaseLocker.java
@@ -0,0 +1,101 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock.db;
+
+import io.seata.common.loader.EnhancedServiceLoader;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.util.CollectionUtils;
+import io.seata.core.lock.AbstractLocker;
+import io.seata.core.lock.LockMode;
+import io.seata.core.lock.RowLock;
+import io.seata.core.store.LockStore;
+
+import javax.sql.DataSource;
+import java.util.List;
+
+/**
+ * The type Data base locker.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+@LoadLevel(name = "db")
+public class DataBaseLocker extends AbstractLocker {
+
+    private LockStore lockStore;
+
+    /**
+     * Instantiates a new Data base locker.
+     */
+    public DataBaseLocker(){
+    }
+
+    /**
+     * Instantiates a new Data base locker.
+     *
+     * @param logStoreDataSource the log store data source
+     */
+    public DataBaseLocker(DataSource logStoreDataSource){
+        lockStore = EnhancedServiceLoader.load(LockStore.class, LockMode.DB.name(), new Class[]{DataSource.class}, new Object[]{logStoreDataSource});
+    }
+
+    @Override
+    public boolean acquireLock(List<RowLock> locks) {
+        if(CollectionUtils.isEmpty(locks)){
+            //no lock
+            return true;
+        }
+        try{
+            return lockStore.acquireLock(convertToLockDO(locks));
+        }catch(Exception t){
+            LOGGER.error("AcquireLock error, locks:" + CollectionUtils.toString(locks), t);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean releaseLock(List<RowLock> locks) {
+        if(CollectionUtils.isEmpty(locks)){
+            //no lock
+            return true;
+        }
+        try{
+            return lockStore.unLock(convertToLockDO(locks));
+        }catch(Exception t){
+            LOGGER.error("unLock error, locks:" + CollectionUtils.toString(locks), t);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean isLockable(List<RowLock> locks) {
+        try{
+            return lockStore.isLockable(convertToLockDO(locks));
+        }catch(Exception t){
+            LOGGER.error("isLockable error, locks:" + CollectionUtils.toString(locks), t);
+            return false;
+        }
+    }
+
+    /**
+     * Sets lock store.
+     *
+     * @param lockStore the lock store
+     */
+    public void setLockStore(LockStore lockStore) {
+        this.lockStore = lockStore;
+    }
+}
diff --git a/server/src/main/java/io/seata/server/lock/memory/MemoryLocker.java b/server/src/main/java/io/seata/server/lock/memory/MemoryLocker.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4dbb9423e63a02dfb9dd86c0e3386ce34116012
--- /dev/null
+++ b/server/src/main/java/io/seata/server/lock/memory/MemoryLocker.java
@@ -0,0 +1,193 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock.memory;
+
+import io.netty.util.internal.ConcurrentSet;
+import io.seata.common.exception.FrameworkException;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.util.CollectionUtils;
+import io.seata.core.exception.TransactionException;
+import io.seata.core.lock.AbstractLocker;
+import io.seata.core.lock.RowLock;
+import io.seata.server.session.BranchSession;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The type Memory locker.
+ *
+ * @author zhangsen
+ * @data 2019 -05-15
+ */
+@LoadLevel(name="memory")
+public class MemoryLocker extends AbstractLocker {
+
+    private static final int BUCKET_PER_TABLE = 128;
+
+    private static final ConcurrentHashMap<String/* resourceId */,
+            ConcurrentHashMap<String/* tableName */,
+                    ConcurrentHashMap<Integer/* bucketId */,
+                            Map<String/* pk */, Long/* transactionId */>>>>
+            LOCK_MAP = new ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>>>();
+
+    /**
+     * The Branch session.
+     */
+    protected BranchSession branchSession = null;
+
+    /**
+     * Instantiates a new Memory locker.
+     *
+     * @param branchSession the branch session
+     */
+    public MemoryLocker(BranchSession branchSession){
+        this.branchSession = branchSession;
+    }
+
+    @Override
+    public boolean acquireLock(List<RowLock> rowLocks)  {
+        if(CollectionUtils.isEmpty(rowLocks)){
+            //no lock
+            return true;
+        }
+        String resourceId = branchSession.getResourceId();
+        long transactionId = branchSession.getTransactionId();
+
+        ConcurrentHashMap<Map<String, Long>, Set<String>> bucketHolder = branchSession.getLockHolder();
+        ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>> dbLockMap = LOCK_MAP.get(resourceId);
+        if (dbLockMap == null) {
+            LOCK_MAP.putIfAbsent(resourceId, new ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>>());
+            dbLockMap = LOCK_MAP.get(resourceId);
+        }
+
+        for(RowLock lock : rowLocks){
+            String tableName = lock.getTableName();
+            String pk = lock.getPk();
+            ConcurrentHashMap<Integer, Map<String, Long>> tableLockMap = dbLockMap.get(tableName);
+            if (tableLockMap == null) {
+                dbLockMap.putIfAbsent(tableName, new ConcurrentHashMap<Integer, Map<String, Long>>());
+                tableLockMap = dbLockMap.get(tableName);
+            }
+            int bucketId = pk.hashCode() % BUCKET_PER_TABLE;
+            Map<String, Long> bucketLockMap = tableLockMap.get(bucketId);
+            if (bucketLockMap == null) {
+                tableLockMap.putIfAbsent(bucketId, new ConcurrentHashMap<String, Long>());
+                bucketLockMap = tableLockMap.get(bucketId);
+            }
+            synchronized (bucketLockMap) {
+                Long lockingTransactionId = bucketLockMap.get(pk);
+                if (lockingTransactionId == null) {
+                    //No existing lock
+                    bucketLockMap.put(pk, transactionId);
+                    Set<String> keysInHolder = bucketHolder.get(bucketLockMap);
+                    if (keysInHolder == null) {
+                        bucketHolder.putIfAbsent(bucketLockMap, new ConcurrentSet<String>());
+                        keysInHolder = bucketHolder.get(bucketLockMap);
+                    }
+                    keysInHolder.add(pk);
+
+                } else if (lockingTransactionId.longValue() == transactionId) {
+                    // Locked by me
+                    continue;
+                } else {
+                    LOGGER.info("Global lock on [" + tableName + ":" + pk + "] is holding by " + lockingTransactionId);
+                    try {
+                        // Release all acquired locks.
+                        branchSession.unlock();
+                    } catch (TransactionException e) {
+                        throw new FrameworkException(e);
+                    }
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean releaseLock(List<RowLock> rowLock) {
+        ConcurrentHashMap<Map<String, Long>, Set<String>> lockHolder = branchSession.getLockHolder();
+        if (lockHolder == null || lockHolder.size() == 0) {
+            return true;
+        }
+        Iterator<Map.Entry<Map<String, Long>, Set<String>>> it = lockHolder.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Map<String, Long>, Set<String>> entry = it.next();
+            Map<String, Long> bucket = entry.getKey();
+            Set<String> keys = entry.getValue();
+            synchronized (bucket) {
+                for (String key : keys) {
+                    Long v = bucket.get(key);
+                    if (v == null) {
+                        continue;
+                    }
+                    if (v.longValue() == branchSession.getTransactionId()) {
+                        bucket.remove(key);
+                    }
+                }
+            }
+        }
+        lockHolder.clear();
+        return true;
+    }
+
+    @Override
+    public boolean isLockable(List<RowLock> rowLocks) {
+        if(CollectionUtils.isEmpty(rowLocks)){
+            //no lock
+            return true;
+        }
+        Long transactionId = rowLocks.get(0).getTransactionId();
+        String resourceId = rowLocks.get(0).getResourceId();
+        ConcurrentHashMap<String, ConcurrentHashMap<Integer, Map<String, Long>>> dbLockMap = LOCK_MAP.get(resourceId);
+        if (dbLockMap == null) {
+            return true;
+        }
+        for(RowLock rowLock : rowLocks){
+            String xid = rowLock.getXid();
+            String tableName = rowLock.getTableName();
+            String pk = rowLock.getPk();
+
+            ConcurrentHashMap<Integer, Map<String, Long>> tableLockMap = dbLockMap.get(tableName);
+            if (tableLockMap == null) {
+                continue;
+            }
+            int bucketId = pk.hashCode() % BUCKET_PER_TABLE;
+            Map<String, Long> bucketLockMap = tableLockMap.get(bucketId);
+            if (bucketLockMap == null) {
+                continue;
+            }
+            Long lockingTransactionId = bucketLockMap.get(pk);
+            if (lockingTransactionId == null || lockingTransactionId.longValue() == transactionId) {
+                // Locked by me
+                continue;
+            } else {
+                LOGGER.info("Global lock on [" + tableName + ":" + pk + "] is holding by " + lockingTransactionId);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void cleanAllLocks() {
+        LOCK_MAP.clear();
+    }
+}
diff --git a/server/src/main/java/io/seata/server/session/AbstractSessionManager.java b/server/src/main/java/io/seata/server/session/AbstractSessionManager.java
index d58f8b71d5a55f17f5031bac96fd2f03f0727643..8cce5790b8fabe0272fe21bcefb89485be30ea18 100644
--- a/server/src/main/java/io/seata/server/session/AbstractSessionManager.java
+++ b/server/src/main/java/io/seata/server/session/AbstractSessionManager.java
@@ -25,16 +25,8 @@ import io.seata.server.store.TransactionStoreManager.LogOperation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
 /**
  * The type Abstract session manager.
- *
- * @author sharajava
  */
 public abstract class AbstractSessionManager implements SessionManager, SessionLifecycleListener {
 
@@ -43,11 +35,6 @@ public abstract class AbstractSessionManager implements SessionManager, SessionL
      */
     protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractSessionManager.class);
 
-    /**
-     * The Session map.
-     */
-    protected Map<Long, GlobalSession> sessionMap = new ConcurrentHashMap<>();
-
     /**
      * The Transaction store manager.
      */
@@ -58,6 +45,12 @@ public abstract class AbstractSessionManager implements SessionManager, SessionL
      */
     protected String name;
 
+    /**
+     * Instantiates a new Abstract session manager.
+     */
+    public AbstractSessionManager() {
+    }
+
     /**
      * Instantiates a new Abstract session manager.
      *
@@ -73,15 +66,6 @@ public abstract class AbstractSessionManager implements SessionManager, SessionL
             LOGGER.debug("MANAGER[" + name + "] SESSION[" + session + "] " + LogOperation.GLOBAL_ADD);
         }
         writeSession(LogOperation.GLOBAL_ADD, session);
-        sessionMap.put(session.getTransactionId(), session);
-
-    }
-
-
-
-    @Override
-    public GlobalSession findGlobalSession(Long transactionId) {
-        return sessionMap.get(transactionId);
     }
 
     @Override
@@ -98,8 +82,6 @@ public abstract class AbstractSessionManager implements SessionManager, SessionL
             LOGGER.debug("MANAGER[" + name + "] SESSION[" + session + "] " + LogOperation.GLOBAL_REMOVE);
         }
         writeSession(LogOperation.GLOBAL_REMOVE, session);
-        sessionMap.remove(session.getTransactionId());
-
     }
 
     @Override
@@ -126,23 +108,6 @@ public abstract class AbstractSessionManager implements SessionManager, SessionL
             LOGGER.debug("MANAGER[" + name + "] SESSION[" + branchSession + "] " + LogOperation.GLOBAL_ADD);
         }
         writeSession(LogOperation.BRANCH_REMOVE, branchSession);
-
-    }
-
-    @Override
-    public Collection<GlobalSession> allSessions() {
-        return sessionMap.values();
-    }
-
-    @Override
-    public List<GlobalSession> findGlobalSessions(SessionCondition condition) {
-        List<GlobalSession> found = new ArrayList<>();
-        for (GlobalSession globalSession : sessionMap.values()) {
-                if (System.currentTimeMillis() - globalSession.getBeginTime() > condition.getOverTimeAliveMills()) {
-                    found.add(globalSession);
-                }
-        }
-        return found;
     }
 
     @Override
@@ -174,18 +139,29 @@ public abstract class AbstractSessionManager implements SessionManager, SessionL
     @Override
     public void onClose(GlobalSession globalSession) throws TransactionException {
         globalSession.setActive(false);
-
     }
 
     @Override
     public void onEnd(GlobalSession globalSession) throws TransactionException {
         removeGlobalSession(globalSession);
-
     }
 
-    private void writeSession(LogOperation logOperation, SessionStorable sessionStorable) throws TransactionException{
+    private void writeSession(LogOperation logOperation, SessionStorable sessionStorable) throws TransactionException {
         if (!transactionStoreManager.writeSession(logOperation, sessionStorable)) {
             throw new TransactionException(TransactionExceptionCode.FailedWriteSession);
         }
     }
+
+    @Override
+    public void destroy() {
+    }
+
+    /**
+     * Sets transaction store manager.
+     *
+     * @param transactionStoreManager the transaction store manager
+     */
+    public void setTransactionStoreManager(TransactionStoreManager transactionStoreManager) {
+        this.transactionStoreManager = transactionStoreManager;
+    }
 }
diff --git a/server/src/main/java/io/seata/server/session/BranchSession.java b/server/src/main/java/io/seata/server/session/BranchSession.java
index 31e51961235b42913019c6fe07317d14baac1d57..7354a88ab07deab31cdf3f9be992c64b8136ff62 100644
--- a/server/src/main/java/io/seata/server/session/BranchSession.java
+++ b/server/src/main/java/io/seata/server/session/BranchSession.java
@@ -15,22 +15,22 @@
  */
 package io.seata.server.session;
 
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
 import io.seata.common.util.CompressUtil;
 import io.seata.core.exception.TransactionException;
 import io.seata.core.model.BranchStatus;
 import io.seata.core.model.BranchType;
-import io.seata.server.lock.LockManagerFactory;
+import io.seata.server.lock.LockerFactory;
 import io.seata.server.store.SessionStorable;
 import io.seata.server.store.StoreConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * The type Branch session.
  *
@@ -45,6 +45,8 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
     private static ThreadLocal<ByteBuffer> byteBufferThreadLocal = ThreadLocal.withInitial(() -> ByteBuffer.allocate(
         MAX_BRANCH_SESSION_SIZE));
 
+    private String xid;
+
     private long transactionId;
 
     private long branchId;
@@ -64,7 +66,7 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
     private String applicationData;
 
     private ConcurrentHashMap<Map<String, Long>, Set<String>> lockHolder
-        = new ConcurrentHashMap<Map<String, Long>, Set<String>>();
+        = new ConcurrentHashMap<>();
 
     /**
      * Gets application data.
@@ -188,7 +190,7 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
      *
      * @param status the status
      */
-    void setStatus(BranchStatus status) {
+    public void setStatus(BranchStatus status) {
         this.status = status;
     }
 
@@ -228,6 +230,24 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
         this.branchId = branchId;
     }
 
+    /**
+     * Gets xid.
+     *
+     * @return the xid
+     */
+    public String getXid() {
+        return xid;
+    }
+
+    /**
+     * Sets xid.
+     *
+     * @param xid the xid
+     */
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
     @Override
     public String toString() {
         return "BR:" + branchId + "/" + transactionId;
@@ -249,12 +269,12 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
 
     @Override
     public boolean lock() throws TransactionException {
-        return LockManagerFactory.get().acquireLock(this);
+        return LockerFactory.getLockManager().acquireLock(this);
     }
 
     @Override
     public boolean unlock() throws TransactionException {
-        return LockManagerFactory.get().releaseLock(this);
+        return LockerFactory.getLockManager().releaseLock(this);
     }
 
     @Override
@@ -268,7 +288,9 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
 
         byte[] applicationDataBytes = applicationData != null ? applicationData.getBytes() : null;
 
-        int size = calBranchSessionSize(resourceIdBytes, lockKeyBytes, clientIdBytes, applicationDataBytes);
+        byte[] xidBytes = xid != null ? xid.getBytes() : null;
+
+        int size = calBranchSessionSize(resourceIdBytes, lockKeyBytes, clientIdBytes, applicationDataBytes, xidBytes);
 
         if (size > MAX_BRANCH_SESSION_SIZE) {
             if (lockKeyBytes == null) {
@@ -327,6 +349,13 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
             byteBuffer.putInt(0);
         }
 
+        if(xidBytes != null){
+            byteBuffer.putInt(xidBytes.length);
+            byteBuffer.put(xidBytes);
+        }else {
+            byteBuffer.putInt(0);
+        }
+
         byteBuffer.put((byte)status.getCode());
         byteBuffer.flip();
         byte[] result = new byte[byteBuffer.limit()];
@@ -335,18 +364,19 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
     }
 
     private int calBranchSessionSize(byte[] resourceIdBytes, byte[] lockKeyBytes, byte[] clientIdBytes,
-                                     byte[] applicationDataBytes) {
+                                     byte[] applicationDataBytes, byte[] xidBytes) {
         final int size = 8 // trascationId
-            + 8 // branchId
-            + 4 // resourceIdBytes.length
-            + 4 // lockKeyBytes.length
-            + 2 // clientIdBytes.length
-            + 4 // applicationDataBytes.length
-            + 1 // statusCode
-            + (resourceIdBytes == null ? 0 : resourceIdBytes.length)
-            + (lockKeyBytes == null ? 0 : lockKeyBytes.length)
-            + (clientIdBytes == null ? 0 : clientIdBytes.length)
-            + (applicationDataBytes == null ? 0 : applicationDataBytes.length);
+                + 8 // branchId
+                + 4 // resourceIdBytes.length
+                + 4 // lockKeyBytes.length
+                + 2 // clientIdBytes.length
+                + 4 // applicationDataBytes.length
+                + 1 // statusCode
+                + (resourceIdBytes == null ? 0 : resourceIdBytes.length)
+                + (lockKeyBytes == null ? 0 : lockKeyBytes.length)
+                + (clientIdBytes == null ? 0 : clientIdBytes.length)
+                + (applicationDataBytes == null ? 0 : applicationDataBytes.length)
+                + (xidBytes == null ? 0 : xidBytes.length);
         return size;
     }
 
@@ -369,7 +399,7 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
                 try {
                     this.lockKey = new String(CompressUtil.uncompress(byLockKey));
                 } catch (IOException e) {
-                    throw new RuntimeException("uncompress lockKey error", e);
+                    throw new RuntimeException("decompress lockKey error", e);
                 }
             } else {
                 this.lockKey = new String(byLockKey);
@@ -388,6 +418,12 @@ public class BranchSession implements Lockable, Comparable<BranchSession>, Sessi
             byteBuffer.get(byApplicationData);
             this.applicationData = new String(byApplicationData);
         }
+        int xidLen = byteBuffer.getInt();
+        if (xidLen > 0) {
+            byte[] xidBytes = new byte[xidLen];
+            byteBuffer.get(xidBytes);
+            this.xid = new String(xidBytes);
+        }
         this.status = BranchStatus.get(byteBuffer.get());
 
     }
diff --git a/server/src/main/java/io/seata/server/session/DefaultSessionManager.java b/server/src/main/java/io/seata/server/session/DefaultSessionManager.java
index ff24f7f6bbacc3ebdffb8bb9c2ecd8f02ae3bea5..a9fcf0cae66e943119e47166d17cf655527aee2c 100644
--- a/server/src/main/java/io/seata/server/session/DefaultSessionManager.java
+++ b/server/src/main/java/io/seata/server/session/DefaultSessionManager.java
@@ -15,19 +15,30 @@
  */
 package io.seata.server.session;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
+import io.seata.common.loader.LoadLevel;
+import io.seata.core.exception.TransactionException;
+import io.seata.server.store.AbstractTransactionStoreManager;
 import io.seata.server.store.SessionStorable;
-import io.seata.server.store.TransactionStoreManager;
-import io.seata.server.store.TransactionWriteStore;
 
 /**
- * The type Default session manager.
+ * The type Default session manager, store session data in memory.
  *
  * @author sharajava
  */
+@LoadLevel(name = "default")
 public class DefaultSessionManager extends AbstractSessionManager {
 
+    /**
+     * The Session map.
+     */
+    protected Map<String, GlobalSession> sessionMap = new ConcurrentHashMap<String, GlobalSession>();
+
     /**
      * Instantiates a new Default session manager.
      *
@@ -35,27 +46,45 @@ public class DefaultSessionManager extends AbstractSessionManager {
      */
     public DefaultSessionManager(String name) {
         super(name);
-        transactionStoreManager = new TransactionStoreManager() {
+        transactionStoreManager = new AbstractTransactionStoreManager() {
             @Override
             public boolean writeSession(LogOperation logOperation, SessionStorable session) {
                 return true;
             }
+        };
+    }
 
-            @Override
-            public void shutdown() {
+    @Override
+    public void addGlobalSession(GlobalSession session) throws TransactionException {
+        super.addGlobalSession(session);
+        sessionMap.put(session.getXid(), session);
+    }
 
-            }
+    @Override
+    public GlobalSession findGlobalSession(String xid)  {
+        return sessionMap.get(xid);
+    }
 
-            @Override
-            public List<TransactionWriteStore> readWriteStoreFromFile(int readSize, boolean isHistory) {
-                return null;
-            }
+    @Override
+    public void removeGlobalSession(GlobalSession session) throws TransactionException {
+        super.removeGlobalSession(session);
+        sessionMap.remove(session.getXid());
+    }
 
-            @Override
-            public boolean hasRemaining(boolean isHistory) {
-                return false;
+    @Override
+    public Collection<GlobalSession> allSessions() {
+        return sessionMap.values();
+    }
+
+    @Override
+    public List<GlobalSession> findGlobalSessions(SessionCondition condition) {
+        List<GlobalSession> found = new ArrayList<>();
+        for (GlobalSession globalSession : sessionMap.values()) {
+            if (System.currentTimeMillis() - globalSession.getBeginTime() > condition.getOverTimeAliveMills()) {
+                found.add(globalSession);
             }
-        };
+        }
+        return found;
     }
 
     @Override
diff --git a/server/src/main/java/io/seata/server/session/GlobalSession.java b/server/src/main/java/io/seata/server/session/GlobalSession.java
index 1c9f31d5bda543df6cf57fc452d9fda330d275e8..c76481782231c5d03362e7ccc2945615f711686d 100644
--- a/server/src/main/java/io/seata/server/session/GlobalSession.java
+++ b/server/src/main/java/io/seata/server/session/GlobalSession.java
@@ -15,6 +15,7 @@
  */
 package io.seata.server.session;
 
+import io.seata.common.XID;
 import io.seata.core.exception.TransactionException;
 import io.seata.core.exception.TransactionExceptionCode;
 import io.seata.core.model.BranchStatus;
@@ -47,6 +48,8 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
     private static ThreadLocal<ByteBuffer> byteBufferThreadLocal = ThreadLocal.withInitial(() -> ByteBuffer.allocate(
             MAX_GLOBAL_SESSION_SIZE));
 
+    private String xid;
+
     private long transactionId;
 
     private volatile GlobalStatus status;
@@ -61,7 +64,9 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
 
     private long beginTime;
 
-    private boolean active;
+    private String applicationData;
+
+    private boolean active = true;
 
     private ArrayList<BranchSession> branchSessions = new ArrayList<>();
 
@@ -165,7 +170,7 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
 
     }
 
-    private void clean() throws TransactionException {
+    public void clean() throws TransactionException {
         for (BranchSession branchSession : branchSessions) {
             branchSession.unlock();
         }
@@ -282,6 +287,7 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
         this.transactionServiceGroup = transactionServiceGroup;
         this.transactionName = transactionName;
         this.timeout = timeout;
+        this.xid = XID.generateXID(transactionId);
     }
 
     /**
@@ -293,6 +299,15 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
         return transactionId;
     }
 
+    /**
+     * Sets transaction id.
+     *
+     * @param transactionId the transaction id
+     */
+    public void setTransactionId(long transactionId) {
+        this.transactionId = transactionId;
+    }
+
     /**
      * Gets status.
      *
@@ -307,10 +322,28 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
      *
      * @param status the status
      */
-    void setStatus(GlobalStatus status) {
+    public void setStatus(GlobalStatus status) {
         this.status = status;
     }
 
+    /**
+     * Gets xid.
+     *
+     * @return the xid
+     */
+    public String getXid() {
+        return xid;
+    }
+
+    /**
+     * Sets xid.
+     *
+     * @param xid the xid
+     */
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
     /**
      * Gets application id.
      *
@@ -356,6 +389,32 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
         return beginTime;
     }
 
+    /**
+     * Sets begin time.
+     *
+     * @param beginTime the begin time
+     */
+    public void setBeginTime(long beginTime) {
+        this.beginTime = beginTime;
+    }
+
+    /**
+     * Gets application data.
+     *
+     * @return the application data
+     */
+    public String getApplicationData() {
+        return applicationData;
+    }
+
+    /**
+     * Sets application data.
+     *
+     * @param applicationData the application data
+     */
+    public void setApplicationData(String applicationData) {
+        this.applicationData = applicationData;
+    }
 
     /**
      * Create global session global session.
@@ -390,7 +449,11 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
 
         byte[] byTxNameBytes = transactionName != null ? transactionName.getBytes() : null;
 
-        int size = calGlobalSessionSize(byApplicationIdBytes, byServiceGroupBytes, byTxNameBytes);
+        byte[] xidBytes = xid != null ? xid.getBytes():null;
+
+        byte[] applicationDataBytes = applicationData != null ? applicationData.getBytes():null;
+
+        int size = calGlobalSessionSize(byApplicationIdBytes, byServiceGroupBytes, byTxNameBytes, xidBytes, applicationDataBytes);
 
         if (size > MAX_GLOBAL_SESSION_SIZE) {
             throw new RuntimeException("global session size exceeded, size : " + size + " maxBranchSessionSize : " +
@@ -420,6 +483,19 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
         } else {
             byteBuffer.putShort((short)0);
         }
+        if(xidBytes != null){
+            byteBuffer.putInt(xidBytes.length);
+            byteBuffer.put(xidBytes);
+        }else {
+            byteBuffer.putInt(0);
+        }
+        if(applicationDataBytes != null){
+            byteBuffer.putInt(applicationDataBytes.length);
+            byteBuffer.put(applicationDataBytes);
+        }else {
+            byteBuffer.putInt(0);
+        }
+
         byteBuffer.putLong(beginTime);
         byteBuffer.put((byte)status.getCode());
         byteBuffer.flip();
@@ -428,17 +504,20 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
         return result;
     }
 
-    private int calGlobalSessionSize(byte[] byApplicationIdBytes, byte[] byServiceGroupBytes, byte[] byTxNameBytes) {
+    private int calGlobalSessionSize(byte[] byApplicationIdBytes, byte[] byServiceGroupBytes, byte[] byTxNameBytes,
+                                     byte[] xidBytes,  byte[]  applicationDataBytes) {
         final int size = 8 // trascationId
-                + 4 // timeout
-                + 2 // byApplicationIdBytes.length
-                + 2 // byServiceGroupBytes.length
-                + 2 // byTxNameBytes.length
-                + 8 // beginTime
-                + 1 // statusCode
-                + (byApplicationIdBytes == null ? 0 : byApplicationIdBytes.length)
-                + (byServiceGroupBytes == null ? 0 : byServiceGroupBytes.length)
-                + (byTxNameBytes == null ? 0 : byTxNameBytes.length);
+            + 4 // timeout
+            + 2 // byApplicationIdBytes.length
+            + 2 // byServiceGroupBytes.length
+            + 2 // byTxNameBytes.length
+            + 8 // beginTime
+            + 1 // statusCode
+            + (byApplicationIdBytes == null ? 0 : byApplicationIdBytes.length)
+            + (byServiceGroupBytes == null ? 0 : byServiceGroupBytes.length)
+            + (byTxNameBytes == null ? 0 : byTxNameBytes.length)
+                + (xidBytes ==null ? 0 : xidBytes.length)
+                + (applicationDataBytes == null ?  0 : applicationDataBytes.length);
         return size;
     }
 
@@ -465,6 +544,19 @@ public class GlobalSession implements SessionLifecycle, SessionStorable {
             byteBuffer.get(byTxName);
             this.transactionName = new String(byTxName);
         }
+        int xidLen = byteBuffer.getInt();
+        if(xidLen > 0 ){
+            byte[] xidBytes = new byte[xidLen];
+            byteBuffer.get(xidBytes);
+            this.xid = new String(xidBytes);
+        }
+        int applicationDataLen = byteBuffer.getInt();
+        if(applicationDataLen > 0){
+            byte[] applicationDataLenBytes = new byte[applicationDataLen];
+            byteBuffer.get(applicationDataLenBytes);
+            this.applicationData = new String(applicationDataLenBytes);
+        }
+
         this.beginTime = byteBuffer.getLong();
         this.status = GlobalStatus.get(byteBuffer.get());
     }
diff --git a/server/src/main/java/io/seata/server/session/SessionCondition.java b/server/src/main/java/io/seata/server/session/SessionCondition.java
index 4063d7aa3780e9070e0d758140cbd20578e0de2e..1b192bb0c859918c544bb5bee8b591d94abea7c0 100644
--- a/server/src/main/java/io/seata/server/session/SessionCondition.java
+++ b/server/src/main/java/io/seata/server/session/SessionCondition.java
@@ -15,6 +15,8 @@
  */
 package io.seata.server.session;
 
+import io.seata.core.model.GlobalStatus;
+
 /**
  * The type Session condition.
  *
@@ -22,9 +24,46 @@ package io.seata.server.session;
  * @date 2018 /12/13
  */
 public class SessionCondition {
-
+    private Long transactionId;
+    private String xid;
+    private GlobalStatus status;
+    private GlobalStatus[] statuses;
     private long overTimeAliveMills;
 
+    /**
+     * Instantiates a new Session condition.
+     */
+    public SessionCondition() {
+    }
+
+    /**
+     * Instantiates a new Session condition.
+     *
+     * @param xid the xid
+     */
+    public SessionCondition(String xid) {
+        this.xid = xid;
+    }
+
+    /**
+     * Instantiates a new Session condition.
+     *
+     * @param status the status
+     */
+    public SessionCondition(GlobalStatus status) {
+        this.status = status;
+        statuses = new GlobalStatus[]{status};
+    }
+
+    /**
+     * Instantiates a new Session condition.
+     *
+     * @param statuses the statuses
+     */
+    public SessionCondition(GlobalStatus[] statuses) {
+        this.statuses = statuses;
+    }
+
     /**
      * Instantiates a new Session condition.
      *
@@ -34,6 +73,23 @@ public class SessionCondition {
         this.overTimeAliveMills = overTimeAliveMills;
     }
 
+    /**
+     * Gets status.
+     *
+     * @return the status
+     */
+    public GlobalStatus getStatus() {
+        return status;
+    }
+
+    /**
+     * Sets status.
+     *
+     * @param status the status
+     */
+    public void setStatus(GlobalStatus status) {
+        this.status = status;
+    }
 
     /**
      * Gets over time alive mills.
@@ -52,4 +108,28 @@ public class SessionCondition {
     public void setOverTimeAliveMills(long overTimeAliveMills) {
         this.overTimeAliveMills = overTimeAliveMills;
     }
+
+    public Long getTransactionId() {
+        return transactionId;
+    }
+
+    public void setTransactionId(Long transactionId) {
+        this.transactionId = transactionId;
+    }
+
+    public String getXid() {
+        return xid;
+    }
+
+    public void setXid(String xid) {
+        this.xid = xid;
+    }
+
+    public GlobalStatus[] getStatuses() {
+        return statuses;
+    }
+
+    public void setStatuses(GlobalStatus[] statuses) {
+        this.statuses = statuses;
+    }
 }
diff --git a/server/src/main/java/io/seata/server/session/SessionHelper.java b/server/src/main/java/io/seata/server/session/SessionHelper.java
index b3295d24e8f6596a641744b975eb616c851e9c0c..fec302b1535bcd8c6d28536e92eefa58efaf0183 100644
--- a/server/src/main/java/io/seata/server/session/SessionHelper.java
+++ b/server/src/main/java/io/seata/server/session/SessionHelper.java
@@ -47,6 +47,7 @@ public class SessionHelper {
             String applicationData, String lockKeys, String clientId) {
         BranchSession branchSession = new BranchSession();
 
+        branchSession.setXid(globalSession.getXid());
         branchSession.setTransactionId(globalSession.getTransactionId());
         branchSession.setBranchId(UUIDGenerator.generateUUID());
         branchSession.setBranchType(branchType);
diff --git a/server/src/main/java/io/seata/server/session/SessionHolder.java b/server/src/main/java/io/seata/server/session/SessionHolder.java
index 30f4b4d00b3ba3fc5cd47f98dd545b3fe705f95a..316b6e11d998fd35d4b52e5be4195737cafd08d2 100644
--- a/server/src/main/java/io/seata/server/session/SessionHolder.java
+++ b/server/src/main/java/io/seata/server/session/SessionHolder.java
@@ -21,6 +21,7 @@ import java.util.Collection;
 
 import io.seata.common.exception.ShouldNeverHappenException;
 import io.seata.common.exception.StoreException;
+import io.seata.common.loader.EnhancedServiceLoader;
 import io.seata.common.util.StringUtils;
 import io.seata.config.Configuration;
 import io.seata.config.ConfigurationFactory;
@@ -46,6 +47,11 @@ public class SessionHolder {
      */
     protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
 
+    /**
+     * The constant DEFAULT.
+     */
+    public static final String DEFAULT = "default";
+
     /**
      * The constant ROOT_SESSION_MANAGER_NAME.
      */
@@ -82,23 +88,33 @@ public class SessionHolder {
         //the store mode
         StoreMode storeMode = StoreMode.valueof(mode);
         if (StoreMode.DB.equals(storeMode)) {
-            //TODO database store
-
+            //database store
+            ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.name());
+            ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.name(), new Object[]{ASYNC_COMMITTING_SESSION_MANAGER_NAME});;
+            RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.name(), new Object[]{RETRY_COMMITTING_SESSION_MANAGER_NAME});;
+            RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.DB.name(), new Object[]{RETRY_ROLLBACKING_SESSION_MANAGER_NAME});;
         } else if (StoreMode.FILE.equals(storeMode)) {
             //file store
             String sessionStorePath = CONFIG.getConfig(ConfigurationKeys.STORE_FILE_DIR);
             if (sessionStorePath == null) {
                 throw new StoreException("the {store.file.dir} is empty.");
             }
-            ROOT_SESSION_MANAGER = new FileBasedSessionManager(ROOT_SESSION_MANAGER_NAME, sessionStorePath);
-            ASYNC_COMMITTING_SESSION_MANAGER = new DefaultSessionManager(ASYNC_COMMITTING_SESSION_MANAGER_NAME);
-            RETRY_COMMITTING_SESSION_MANAGER = new DefaultSessionManager(RETRY_COMMITTING_SESSION_MANAGER_NAME);
-            RETRY_ROLLBACKING_SESSION_MANAGER = new DefaultSessionManager(RETRY_ROLLBACKING_SESSION_MANAGER_NAME);
+            ROOT_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, StoreMode.FILE.name(), new Object[]{ROOT_SESSION_MANAGER_NAME, sessionStorePath});
+            ASYNC_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, DEFAULT, new Object[]{ASYNC_COMMITTING_SESSION_MANAGER_NAME});;
+            RETRY_COMMITTING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, DEFAULT, new Object[]{RETRY_COMMITTING_SESSION_MANAGER_NAME});;
+            RETRY_ROLLBACKING_SESSION_MANAGER = EnhancedServiceLoader.load(SessionManager.class, DEFAULT, new Object[]{RETRY_ROLLBACKING_SESSION_MANAGER_NAME});;
         } else {
             //unknown store
             throw new IllegalArgumentException("unknown store mode:" + mode);
         }
+        //relaod
+        reload();
+    }
 
+    /**
+     * Reload.
+     */
+    protected static void reload(){
         if (ROOT_SESSION_MANAGER instanceof Reloadable) {
             ((Reloadable) ROOT_SESSION_MANAGER).reload();
 
@@ -173,7 +189,6 @@ public class SessionHolder {
                 });
             }
         }
-
     }
 
     /**
@@ -227,11 +242,11 @@ public class SessionHolder {
     /**
      * Find global session.
      *
-     * @param transactionId the transaction id
+     * @param xid the xid
      * @return the global session
      */
-    public static GlobalSession findGlobalSession(Long transactionId) {
-        return getRootSessionManager().findGlobalSession(transactionId);
+    public static GlobalSession findGlobalSession(String xid)  {
+        return getRootSessionManager().findGlobalSession(xid);
     }
 
     public static void destory() {
diff --git a/server/src/main/java/io/seata/server/session/SessionManager.java b/server/src/main/java/io/seata/server/session/SessionManager.java
index 2883d440482d97d1f295b6c0acc8e7f72059203d..e7e94017191c71019e6b8ceb5f6264f853302070 100644
--- a/server/src/main/java/io/seata/server/session/SessionManager.java
+++ b/server/src/main/java/io/seata/server/session/SessionManager.java
@@ -41,11 +41,10 @@ public interface SessionManager extends SessionLifecycleListener, Disposable {
     /**
      * Find global session global session.
      *
-     * @param transactionId the transaction id
+     * @param xid the xid
      * @return the global session
-     * @throws TransactionException the transaction exception
      */
-    GlobalSession findGlobalSession(Long transactionId);
+    GlobalSession findGlobalSession(String xid) ;
 
     /**
      * Update global session status.
diff --git a/server/src/main/java/io/seata/server/session/db/DataBaseSessionManager.java b/server/src/main/java/io/seata/server/session/db/DataBaseSessionManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..333b78e3ba1312385497447c0b91e3354eb33444
--- /dev/null
+++ b/server/src/main/java/io/seata/server/session/db/DataBaseSessionManager.java
@@ -0,0 +1,186 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.session.db;
+
+import io.seata.common.exception.StoreException;
+import io.seata.common.executor.Initialize;
+import io.seata.common.loader.EnhancedServiceLoader;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.util.StringUtils;
+import io.seata.core.exception.TransactionException;
+import io.seata.core.model.BranchStatus;
+import io.seata.core.model.GlobalStatus;
+import io.seata.core.store.StoreMode;
+import io.seata.server.session.AbstractSessionManager;
+import io.seata.server.session.BranchSession;
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionCondition;
+import io.seata.server.session.SessionHolder;
+import io.seata.server.session.SessionLifecycleListener;
+import io.seata.server.session.SessionManager;
+import io.seata.server.store.TransactionStoreManager;
+import io.seata.server.store.TransactionStoreManager.LogOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * The Data base session manager.
+ *
+ * @author zhangsen
+ * @data 2019 /4/4
+ */
+@LoadLevel(name = "db")
+public class DataBaseSessionManager extends AbstractSessionManager implements SessionManager, SessionLifecycleListener, Initialize {
+
+    /**
+     * The constant LOGGER.
+     */
+    protected static final Logger LOGGER = LoggerFactory.getLogger(DataBaseSessionManager.class);
+
+    /**
+     * The Task name.
+     */
+    protected String taskName;
+
+    /**
+     * Instantiates a new Data base session manager.
+     */
+    public DataBaseSessionManager() {
+        super();
+    }
+
+    /**
+     * Instantiates a new Data base session manager.
+     *
+     * @param name the name
+     */
+    public DataBaseSessionManager(String name) {
+        super();
+        this.taskName = name;
+    }
+
+    @Override
+    public void init() {
+        transactionStoreManager = EnhancedServiceLoader.load(TransactionStoreManager.class, StoreMode.DB.name());
+    }
+
+    @Override
+    public void addGlobalSession(GlobalSession session) throws TransactionException {
+        if (StringUtils.isBlank(taskName)) {
+            boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_ADD, session);
+            if (!ret) {
+                throw new StoreException("addGlobalSession failed.");
+            }
+        }else {
+            boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session);
+            if (!ret) {
+                throw new StoreException("addGlobalSession failed.");
+            }
+        }
+    }
+
+    @Override
+    public void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status) throws TransactionException {
+        if (StringUtils.isNotBlank(taskName)) {
+            return;
+        }
+        session.setStatus(status);
+        boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_UPDATE, session);
+        if (!ret) {
+            throw new StoreException("updateGlobalSessionStatus failed.");
+        }
+    }
+
+    @Override
+    public void removeGlobalSession(GlobalSession session) throws TransactionException {
+        if (StringUtils.isNotBlank(taskName)) {
+            return;
+        }
+        boolean ret = transactionStoreManager.writeSession(LogOperation.GLOBAL_REMOVE, session);
+        if (!ret) {
+            throw new StoreException("removeGlobalSession failed.");
+        }
+    }
+
+    @Override
+    public void addBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException {
+        if (StringUtils.isNotBlank(taskName)) {
+            return;
+        }
+        boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_ADD, session);
+        if (!ret) {
+            throw new StoreException("addBranchSession failed.");
+        }
+    }
+
+    @Override
+    public void updateBranchSessionStatus(BranchSession session, BranchStatus status) throws TransactionException {
+        if (StringUtils.isNotBlank(taskName)) {
+            return;
+        }
+        boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_UPDATE, session);
+        if (!ret) {
+            throw new StoreException("updateBranchSessionStatus failed.");
+        }
+    }
+
+    @Override
+    public void removeBranchSession(GlobalSession globalSession, BranchSession session) throws TransactionException {
+        if (StringUtils.isNotBlank(taskName)) {
+            return;
+        }
+        boolean ret = transactionStoreManager.writeSession(LogOperation.BRANCH_REMOVE, session);
+        if (!ret) {
+            throw new StoreException("removeBranchSession failed.");
+        }
+    }
+
+    @Override
+    public GlobalSession findGlobalSession(String xid)  {
+        return transactionStoreManager.readSession(xid);
+    }
+
+    @Override
+    public Collection<GlobalSession> allSessions() {
+        //get by taskName
+        if (SessionHolder.ASYNC_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) {
+            return findGlobalSessions(new SessionCondition(GlobalStatus.AsyncCommitting));
+        } else if (SessionHolder.RETRY_COMMITTING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) {
+            return findGlobalSessions(new SessionCondition(new GlobalStatus[]{GlobalStatus.CommitRetrying}));
+        } else if (SessionHolder.RETRY_ROLLBACKING_SESSION_MANAGER_NAME.equalsIgnoreCase(taskName)) {
+            return findGlobalSessions(new SessionCondition(new GlobalStatus[]{GlobalStatus.RollbackRetrying,
+                    GlobalStatus.TimeoutRollbacking, GlobalStatus.TimeoutRollbackRetrying}));
+        } else {
+            //all data
+            return findGlobalSessions(new SessionCondition(new GlobalStatus[]{
+                    GlobalStatus.UnKnown, GlobalStatus.Begin,
+                    GlobalStatus.Committing, GlobalStatus.CommitRetrying, GlobalStatus.Rollbacking, GlobalStatus.RollbackRetrying,
+                    GlobalStatus.TimeoutRollbacking, GlobalStatus.TimeoutRollbackRetrying, GlobalStatus.AsyncCommitting}));
+        }
+    }
+
+    @Override
+    public List<GlobalSession> findGlobalSessions(SessionCondition condition) {
+        //nothing need to do
+        return transactionStoreManager.readSession(condition);
+    }
+
+
+
+}
\ No newline at end of file
diff --git a/server/src/main/java/io/seata/server/session/FileBasedSessionManager.java b/server/src/main/java/io/seata/server/session/file/FileBasedSessionManager.java
similarity index 71%
rename from server/src/main/java/io/seata/server/session/FileBasedSessionManager.java
rename to server/src/main/java/io/seata/server/session/file/FileBasedSessionManager.java
index 1684cccdface1af2f8aa7077c562b6837cba69c4..02ade24cefb126187f0f11b4a649ed0ad1ec4308 100644
--- a/server/src/main/java/io/seata/server/session/FileBasedSessionManager.java
+++ b/server/src/main/java/io/seata/server/session/file/FileBasedSessionManager.java
@@ -13,7 +13,7 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package io.seata.server.session;
+package io.seata.server.session.file;
 
 import java.io.File;
 import java.io.IOException;
@@ -23,21 +23,31 @@ import java.util.List;
 import java.util.Map;
 
 import io.seata.common.exception.ShouldNeverHappenException;
+import io.seata.common.loader.EnhancedServiceLoader;
+import io.seata.common.loader.LoadLevel;
 import io.seata.config.ConfigurationFactory;
 import io.seata.core.constants.ConfigurationKeys;
 import io.seata.core.model.GlobalStatus;
+import io.seata.core.store.StoreMode;
+import io.seata.server.session.BranchSession;
+import io.seata.server.session.DefaultSessionManager;
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.Reloadable;
+import io.seata.server.session.SessionManager;
+import io.seata.server.store.ReloadableStore;
 import io.seata.server.UUIDGenerator;
-import io.seata.server.store.FileTransactionStoreManager;
 import io.seata.server.store.SessionStorable;
 import io.seata.server.store.TransactionStoreManager;
 import io.seata.server.store.TransactionWriteStore;
 
+
 /**
  * The type File based session manager.
  *
  * @author jimin.jm @alibaba-inc.com
  */
-public class FileBasedSessionManager extends AbstractSessionManager implements Reloadable {
+@LoadLevel(name = "file")
+public class FileBasedSessionManager extends DefaultSessionManager implements Reloadable {
 
     private static final int READ_SIZE = ConfigurationFactory.getInstance().getInt(
         ConfigurationKeys.SERVICE_SESSION_RELOAD_READ_SIZE, 100);
@@ -51,7 +61,9 @@ public class FileBasedSessionManager extends AbstractSessionManager implements R
      */
     public FileBasedSessionManager(String name, String sessionStoreFilePath) throws IOException {
         super(name);
-        transactionStoreManager = new FileTransactionStoreManager(sessionStoreFilePath + File.separator + name, this);
+        transactionStoreManager = EnhancedServiceLoader.load(TransactionStoreManager.class, StoreMode.FILE.name(),
+                new Class[]{String.class, SessionManager.class},
+                new Object[]{sessionStoreFilePath + File.separator + name, this});
     }
 
     @Override
@@ -68,13 +80,13 @@ public class FileBasedSessionManager extends AbstractSessionManager implements R
 
         if (!unhandledBranchBuffer.isEmpty()) {
             unhandledBranchBuffer.values().forEach(branchSession -> {
-                long tid = branchSession.getTransactionId();
+                String xid = branchSession.getXid();
                 long bid = branchSession.getBranchId();
-                GlobalSession found = sessionMap.get(tid);
+                GlobalSession found = sessionMap.get(xid);
                 if (found == null) {
                     // Ignore
                     if (LOGGER.isInfoEnabled()) {
-                        LOGGER.info("GlobalSession Does Not Exists For BranchSession [" + bid + "/" + tid + "]");
+                        LOGGER.info("GlobalSession Does Not Exists For BranchSession [" + bid + "/" + xid + "]");
                     }
                 } else {
                     BranchSession existingBranch = found.getBranch(branchSession.getBranchId());
@@ -91,7 +103,7 @@ public class FileBasedSessionManager extends AbstractSessionManager implements R
 
     private void washSessions() {
         if (sessionMap.size() > 0) {
-            Iterator<Map.Entry<Long, GlobalSession>> iterator = sessionMap.entrySet().iterator();
+            Iterator<Map.Entry<String, GlobalSession>> iterator = sessionMap.entrySet().iterator();
             while (iterator.hasNext()) {
                 GlobalSession globalSession = iterator.next().getValue();
 
@@ -116,8 +128,11 @@ public class FileBasedSessionManager extends AbstractSessionManager implements R
     }
 
     private void restoreSessions(boolean isHistory, Map<Long, BranchSession> unhandledBranchBuffer) {
-        while (transactionStoreManager.hasRemaining(isHistory)) {
-            List<TransactionWriteStore> stores = transactionStoreManager.readWriteStoreFromFile(READ_SIZE, isHistory);
+        if(!(transactionStoreManager instanceof ReloadableStore)){
+            return;
+        }
+        while (((ReloadableStore)transactionStoreManager).hasRemaining(isHistory)) {
+            List<TransactionWriteStore> stores = ((ReloadableStore)transactionStoreManager).readWriteStore(READ_SIZE, isHistory);
             restore(stores, unhandledBranchBuffer);
         }
     }
@@ -131,31 +146,40 @@ public class FileBasedSessionManager extends AbstractSessionManager implements R
             switch (logOperation) {
                 case GLOBAL_ADD:
                 case GLOBAL_UPDATE: {
-                    GlobalSession globalSession = (GlobalSession)sessionStorable;
-                    long tid = globalSession.getTransactionId();
-                    GlobalSession foundGlobalSession = sessionMap.get(tid);
+                    GlobalSession globalSession = (GlobalSession) sessionStorable;
+                    if(globalSession.getTransactionId() == 0){
+                        LOGGER.error("Restore globalSession from file failed, the transactionId is zero , xid:" + globalSession.getXid());
+                        break;
+                    }
+                    GlobalSession foundGlobalSession = sessionMap.get(globalSession.getXid());
                     if (foundGlobalSession == null) {
-                        sessionMap.put(globalSession.getTransactionId(), globalSession);
+                        sessionMap.put(globalSession.getXid(), globalSession);
                     } else {
                         foundGlobalSession.setStatus(globalSession.getStatus());
                     }
                     break;
                 }
                 case GLOBAL_REMOVE: {
-                    GlobalSession globalSession = (GlobalSession)sessionStorable;
-                    long tid = globalSession.getTransactionId();
-                    if (sessionMap.remove(tid) == null) {
+                    GlobalSession globalSession = (GlobalSession) sessionStorable;
+                    if(globalSession.getTransactionId() == 0){
+                        LOGGER.error("Restore globalSession from file failed, the transactionId is zero , xid:" + globalSession.getXid());
+                        break;
+                    }
+                    if (sessionMap.remove(globalSession.getXid()) == null) {
                         if (LOGGER.isInfoEnabled()) {
-                            LOGGER.info("GlobalSession To Be Removed Does Not Exists [" + tid + "]");
+                            LOGGER.info("GlobalSession To Be Removed Does Not Exists [" + globalSession.getXid() + "]");
                         }
                     }
                     break;
                 }
                 case BRANCH_ADD:
                 case BRANCH_UPDATE: {
-                    BranchSession branchSession = (BranchSession)sessionStorable;
-                    long tid = branchSession.getTransactionId();
-                    GlobalSession foundGlobalSession = sessionMap.get(tid);
+                    BranchSession branchSession = (BranchSession) sessionStorable;
+                    if( branchSession.getTransactionId() == 0){
+                        LOGGER.error("Restore branchSession from file failed, the transactionId is zero , xid:" + branchSession.getXid());
+                        break;
+                    }
+                    GlobalSession foundGlobalSession = sessionMap.get(branchSession.getXid());
                     if (foundGlobalSession == null) {
                         unhandledBranchSessions.put(branchSession.getBranchId(), branchSession);
                     } else {
@@ -169,21 +193,25 @@ public class FileBasedSessionManager extends AbstractSessionManager implements R
                     break;
                 }
                 case BRANCH_REMOVE: {
-                    BranchSession branchSession = (BranchSession)sessionStorable;
-                    long tid = branchSession.getTransactionId();
+                    BranchSession branchSession = (BranchSession) sessionStorable;
+                    String xid = branchSession.getXid();
                     long bid = branchSession.getBranchId();
-                    GlobalSession found = sessionMap.get(tid);
+                    if(branchSession.getTransactionId() == 0){
+                        LOGGER.error("Restore branchSession from file failed, the transactionId is zero , xid:" + branchSession.getXid());
+                        break;
+                    }
+                    GlobalSession found = sessionMap.get(xid);
                     if (found == null) {
                         if (LOGGER.isInfoEnabled()) {
                             LOGGER.info(
-                                "GlobalSession To Be Updated (Remove Branch) Does Not Exists [" + bid + "/" + tid
-                                    + "]");
+                                    "GlobalSession To Be Updated (Remove Branch) Does Not Exists [" + bid + "/" + xid
+                                            + "]");
                         }
                     } else {
                         BranchSession theBranch = found.getBranch(bid);
                         if (theBranch == null) {
                             if (LOGGER.isInfoEnabled()) {
-                                LOGGER.info("BranchSession To Be Updated Does Not Exists [" + bid + "/" + tid + "]");
+                                LOGGER.info("BranchSession To Be Updated Does Not Exists [" + bid + "/" + xid + "]");
                             }
                         } else {
                             found.remove(theBranch);
diff --git a/server/src/main/java/io/seata/server/store/AbstractTransactionStoreManager.java b/server/src/main/java/io/seata/server/store/AbstractTransactionStoreManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..f024bd772bf063eef62b46623ff533b41eff6c3e
--- /dev/null
+++ b/server/src/main/java/io/seata/server/store/AbstractTransactionStoreManager.java
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.store;
+
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionCondition;
+
+import java.util.List;
+
+/**
+ * The type Abstract transaction store manager.
+ *
+ * @author zhangsen
+ * @data 2019 /4/25
+ */
+public abstract class AbstractTransactionStoreManager implements TransactionStoreManager {
+
+    @Override
+    public GlobalSession readSession(String xid) {
+        return null;
+    }
+
+    @Override
+    public List<GlobalSession> readSession(SessionCondition sessionCondition) {
+        return null;
+    }
+
+    @Override
+    public void shutdown() {
+    }
+}
diff --git a/server/src/main/java/io/seata/server/lock/LockManagerFactory.java b/server/src/main/java/io/seata/server/store/ReloadableStore.java
similarity index 54%
rename from server/src/main/java/io/seata/server/lock/LockManagerFactory.java
rename to server/src/main/java/io/seata/server/store/ReloadableStore.java
index 3468cc89449b3781808cf6771f4dae2962c5f5ee..d7b705c65a81f786ff5011dfab09ca8a749dbfcf 100644
--- a/server/src/main/java/io/seata/server/lock/LockManagerFactory.java
+++ b/server/src/main/java/io/seata/server/store/ReloadableStore.java
@@ -13,34 +13,34 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package io.seata.server.lock;
+package io.seata.server.store;
+
+import java.util.List;
 
 /**
- * The type Lock manager factory.
+ * The interface Reloadable store.
  *
- * @author sharajava
+ * @author zhangsen
+ * @data 2019 /4/24
  */
-public class LockManagerFactory {
-
-    private static class SingletonHolder {
-        private static LockManager INSTANCE = new DefaultLockManagerImpl();
-    }
+public interface ReloadableStore {
 
     /**
-     * Get lock manager.
+     * Read write store.
      *
-     * @return the lock manager
+     * @param readSize  the read size
+     * @param isHistory the is history
+     * @return the list
      */
-    public static final LockManager get() {
-        return SingletonHolder.INSTANCE;
-    }
+    List<TransactionWriteStore> readWriteStore(int readSize, boolean isHistory);
 
     /**
-     * Just for test mocking
+     * Has remaining boolean.
      *
-     * @param lockManager the lock manager
+     * @param isHistory the is history
+     * @return the boolean
      */
-    public static void set(LockManager lockManager) {
-        SingletonHolder.INSTANCE = lockManager;
-    }
+    boolean hasRemaining(boolean isHistory);
+
+
 }
diff --git a/server/src/main/java/io/seata/server/store/TransactionStoreManager.java b/server/src/main/java/io/seata/server/store/TransactionStoreManager.java
index da7d44a4ad942c6802dc4140170f5acd27922752..26dc122009c24b0fbc17c37d42227a4b864626c9 100644
--- a/server/src/main/java/io/seata/server/store/TransactionStoreManager.java
+++ b/server/src/main/java/io/seata/server/store/TransactionStoreManager.java
@@ -15,6 +15,9 @@
  */
 package io.seata.server.store;
 
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionCondition;
+
 import java.util.List;
 
 /**
@@ -33,27 +36,28 @@ public interface TransactionStoreManager {
      */
     boolean writeSession(LogOperation logOperation, SessionStorable session);
 
+
     /**
-     * Shutdown.
+     * Read global session global session.
+     *
+     * @param xid the xid
+     * @return the global session
      */
-    void shutdown();
+    GlobalSession readSession(String xid);
 
     /**
-     * Read write store from file list.
+     * Read session by status list.
      *
-     * @param readSize  the read size
-     * @param isHistory the is history
+     * @param sessionCondition the session condition
      * @return the list
      */
-    List<TransactionWriteStore> readWriteStoreFromFile(int readSize, boolean isHistory);
+    List<GlobalSession> readSession(SessionCondition sessionCondition);
 
     /**
-     * Has remaining boolean.
-     *
-     * @param isHistory the is history
-     * @return the boolean
+     * Shutdown.
      */
-    boolean hasRemaining(boolean isHistory);
+    void shutdown();
+
 
     /**
      * The enum Log operation.
diff --git a/server/src/main/java/io/seata/server/store/db/DatabaseTransactionStoreManager.java b/server/src/main/java/io/seata/server/store/db/DatabaseTransactionStoreManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cce734f8eaa4b9024b1d1b0886c488160a288ce
--- /dev/null
+++ b/server/src/main/java/io/seata/server/store/db/DatabaseTransactionStoreManager.java
@@ -0,0 +1,299 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.store.db;
+
+
+import io.seata.common.exception.StoreException;
+import io.seata.common.executor.Initialize;
+import io.seata.common.loader.EnhancedServiceLoader;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.util.CollectionUtils;
+import io.seata.common.util.StringUtils;
+import io.seata.config.Configuration;
+import io.seata.config.ConfigurationFactory;
+import io.seata.core.constants.ConfigurationKeys;
+import io.seata.core.model.BranchStatus;
+import io.seata.core.model.BranchType;
+import io.seata.core.model.GlobalStatus;
+import io.seata.core.store.BranchTransactionDO;
+import io.seata.core.store.GlobalTransactionDO;
+import io.seata.core.store.LogStore;
+import io.seata.core.store.StoreMode;
+import io.seata.core.store.db.DataSourceGenerator;
+import io.seata.server.session.BranchSession;
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionCondition;
+import io.seata.server.store.AbstractTransactionStoreManager;
+import io.seata.server.store.SessionStorable;
+import io.seata.server.store.TransactionStoreManager;
+
+import javax.sql.DataSource;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * The type Database transaction store manager.
+ *
+ * @author zhangsen
+ * @data 2019 /4/2
+ */
+@LoadLevel(name = "db")
+public class DatabaseTransactionStoreManager extends AbstractTransactionStoreManager implements TransactionStoreManager, Initialize {
+
+    /**
+     * The constant CONFIG.
+     */
+    protected static final Configuration CONFIG = ConfigurationFactory.getInstance();
+
+    /**
+     * The constant DEFAULT_LOG_QUERY_LIMIT.
+     */
+    protected static final int DEFAULT_LOG_QUERY_LIMIT = 100;
+
+    /**
+     * is inited
+     */
+    protected AtomicBoolean inited = new AtomicBoolean(false);
+
+    /**
+     * The Log store.
+     */
+    protected LogStore logStore ;
+
+
+    /**
+     * The Log query limit.
+     */
+    protected int logQueryLimit ;
+
+    /**
+     * Instantiates a new Database transaction store manager.
+     */
+    public DatabaseTransactionStoreManager(){
+    }
+
+    @Override
+    public synchronized void init(){
+        if(inited.get()){
+            return ;
+        }
+        logQueryLimit = CONFIG.getInt(ConfigurationKeys.STORE_DB_LOG_QUERY_LIMIT, DEFAULT_LOG_QUERY_LIMIT);
+        String datasourceType = CONFIG.getConfig(ConfigurationKeys.STORE_DB_DATASOURCE_TYPE);
+        //init dataSource
+        DataSourceGenerator dataSourceGenerator = EnhancedServiceLoader.load(DataSourceGenerator.class, datasourceType);
+        DataSource logStoreDataSource = dataSourceGenerator.generateDataSource();
+        logStore = EnhancedServiceLoader.load(LogStore.class, StoreMode.DB.name(), new Class[]{DataSource.class}, new Object[]{logStoreDataSource});
+        inited.set(true);
+    }
+
+    @Override
+    public boolean writeSession(LogOperation logOperation, SessionStorable session) {
+        if (LogOperation.GLOBAL_ADD.equals(logOperation)){
+            logStore.insertGlobalTransactionDO(convertGlobalTransactionDO(session));
+        }else if(LogOperation.GLOBAL_UPDATE.equals(logOperation)){
+            logStore.updateGlobalTransactionDO(convertGlobalTransactionDO(session));
+        }else if(LogOperation.GLOBAL_REMOVE.equals(logOperation)){
+            logStore.deleteGlobalTransactionDO(convertGlobalTransactionDO(session));
+        }else if(LogOperation.BRANCH_ADD.equals(logOperation)){
+            logStore.insertBranchTransactionDO(convertBranchTransactionDO(session));
+        }else if(LogOperation.BRANCH_UPDATE.equals(logOperation)){
+            logStore.updateBranchTransactionDO(convertBranchTransactionDO(session));
+        }else if(LogOperation.BRANCH_REMOVE.equals(logOperation)){
+            logStore.deleteBranchTransactionDO(convertBranchTransactionDO(session));
+        }else {
+            throw new StoreException("Unknown LogOperation:" + logOperation.name());
+        }
+        return true;
+    }
+
+    /**
+     * Read session global session.
+     *
+     * @param transactionId the transaction id
+     * @return the global session
+     */
+    public GlobalSession readSession(Long transactionId) {
+        //global transaction
+        GlobalTransactionDO globalTransactionDO = logStore.queryGlobalTransactionDO(transactionId);
+        if(globalTransactionDO == null){
+            return null;
+        }
+        //branch transactions
+        List<BranchTransactionDO> branchTransactionDOs = logStore.queryBranchTransactionDO(globalTransactionDO.getXid());
+        return getGlobalSession(globalTransactionDO, branchTransactionDOs);
+    }
+
+    /**
+     * Read session global session.
+     *
+     * @param xid the xid
+     * @return the global session
+     */
+    @Override
+    public GlobalSession readSession(String xid) {
+        //global transaction
+        GlobalTransactionDO globalTransactionDO = logStore.queryGlobalTransactionDO(xid);
+        if(globalTransactionDO == null){
+            return null;
+        }
+        //branch transactions
+        List<BranchTransactionDO> branchTransactionDOs = logStore.queryBranchTransactionDO(globalTransactionDO.getXid());
+        return getGlobalSession(globalTransactionDO, branchTransactionDOs);
+    }
+
+    /**
+     * Read session list.
+     *
+     * @param statuses the statuses
+     * @return the list
+     */
+    public List<GlobalSession> readSession(GlobalStatus[] statuses) {
+        int[] states = new int[statuses.length];
+        for(int i = 0; i < statuses.length; i++){
+            states[i] = statuses[i].getCode();
+        }
+        List<GlobalSession> globalSessions = new ArrayList<GlobalSession>();
+        //global transaction
+        List<GlobalTransactionDO> globalTransactionDOs = logStore.queryGlobalTransactionDO(states, logQueryLimit);
+        if(CollectionUtils.isEmpty(globalTransactionDOs)){
+            return null;
+        }
+        for(GlobalTransactionDO globalTransactionDO : globalTransactionDOs){
+            List<BranchTransactionDO> branchTransactionDOs = logStore.queryBranchTransactionDO(globalTransactionDO.getXid());
+            globalSessions.add(getGlobalSession(globalTransactionDO, branchTransactionDOs));
+        }
+        return globalSessions;
+    }
+
+    @Override
+    public List<GlobalSession> readSession(SessionCondition sessionCondition) {
+        if(StringUtils.isNotBlank(sessionCondition.getXid())){
+            GlobalSession globalSession = readSession(sessionCondition.getXid());
+            if(globalSession != null){
+                List<GlobalSession> globalSessions = new ArrayList();
+                globalSessions.add(globalSession);
+                return globalSessions;
+            }
+        }else if(sessionCondition.getTransactionId() != null){
+            GlobalSession globalSession = readSession(sessionCondition.getTransactionId());
+            if(globalSession != null){
+                List<GlobalSession> globalSessions = new ArrayList();
+                globalSessions.add(globalSession);
+                return globalSessions;
+            }
+        }else if(CollectionUtils.isNotEmpty(sessionCondition.getStatuses())){
+            return readSession(sessionCondition.getStatuses());
+        }
+        return null;
+    }
+
+    private GlobalSession getGlobalSession(GlobalTransactionDO globalTransactionDO, List<BranchTransactionDO> branchTransactionDOs){
+        GlobalSession globalSession = convertGlobalSession(globalTransactionDO);
+        //branch transactions
+        if(branchTransactionDOs != null && branchTransactionDOs.size() > 0){
+            for(BranchTransactionDO branchTransactionDO : branchTransactionDOs){
+                globalSession.add(convertBranchSession(branchTransactionDO));
+            }
+        }
+        return globalSession;
+    }
+
+    private GlobalSession convertGlobalSession(GlobalTransactionDO globalTransactionDO){
+        GlobalSession session = new GlobalSession(globalTransactionDO.getApplicationId(),
+                globalTransactionDO.getTransactionServiceGroup(),
+                globalTransactionDO.getTransactionName(),
+                globalTransactionDO.getTimeout());
+        session.setTransactionId(globalTransactionDO.getTransactionId());
+        session.setXid(globalTransactionDO.getXid());
+        session.setStatus(GlobalStatus.get(globalTransactionDO.getStatus()));
+        session.setApplicationData(globalTransactionDO.getApplicationData());
+        session.setBeginTime(globalTransactionDO.getBeginTime());
+        return session;
+    }
+
+    private BranchSession convertBranchSession(BranchTransactionDO branchTransactionDO){
+        BranchSession branchSession = new BranchSession();
+        branchSession.setXid(branchTransactionDO.getXid());
+        branchSession.setTransactionId(branchTransactionDO.getTransactionId());
+        branchSession.setApplicationData(branchTransactionDO.getApplicationData());
+        branchSession.setBranchId(branchTransactionDO.getBranchId());
+        branchSession.setBranchType(BranchType.valueOf(branchTransactionDO.getBranchType()));
+        branchSession.setResourceId(branchTransactionDO.getResourceId());
+        branchSession.setClientId(branchTransactionDO.getClientId());
+        branchSession.setLockKey(branchTransactionDO.getLockKey());
+        branchSession.setResourceGroupId(branchTransactionDO.getResourceGroupId());
+        branchSession.setStatus(BranchStatus.get(branchTransactionDO.getStatus()));
+        return branchSession;
+    }
+
+    private GlobalTransactionDO convertGlobalTransactionDO(SessionStorable session){
+        if(session == null || !(session instanceof GlobalSession)){
+            throw new IllegalArgumentException("the parameter of SessionStorable is not available, SessionStorable:" + StringUtils.toString(session));
+        }
+        GlobalSession globalSession = (GlobalSession) session;
+
+        GlobalTransactionDO globalTransactionDO = new GlobalTransactionDO();
+        globalTransactionDO.setXid(globalSession.getXid());
+        globalTransactionDO.setStatus(globalSession.getStatus().getCode());
+        globalTransactionDO.setApplicationId(globalSession.getApplicationId());
+        globalTransactionDO.setBeginTime(globalSession.getBeginTime());
+        globalTransactionDO.setTimeout(globalSession.getTimeout());
+        globalTransactionDO.setTransactionId(globalSession.getTransactionId());
+        globalTransactionDO.setTransactionName(globalSession.getTransactionName());
+        globalTransactionDO.setTransactionServiceGroup(globalSession.getTransactionServiceGroup());
+        globalTransactionDO.setApplicationData(globalSession.getApplicationData());
+        return globalTransactionDO;
+    }
+
+    private BranchTransactionDO convertBranchTransactionDO(SessionStorable session){
+        if(session == null || !(session instanceof BranchSession)){
+            throw new IllegalArgumentException("the parameter of SessionStorable is not available, SessionStorable:" + StringUtils.toString(session));
+        }
+        BranchSession branchSession = (BranchSession) session;
+
+        BranchTransactionDO branchTransactionDO = new BranchTransactionDO();
+        branchTransactionDO.setXid(branchSession.getXid());
+        branchTransactionDO.setBranchId(branchSession.getBranchId());
+        branchTransactionDO.setBranchType(branchSession.getBranchType().name());
+        branchTransactionDO.setClientId(branchSession.getClientId());
+        branchTransactionDO.setLockKey(branchSession.getLockKey());
+        branchTransactionDO.setResourceGroupId(branchSession.getResourceGroupId());
+        branchTransactionDO.setTransactionId(branchSession.getTransactionId());
+        branchTransactionDO.setApplicationData(branchSession.getApplicationData());
+        branchTransactionDO.setResourceId(branchSession.getResourceId());
+        branchTransactionDO.setStatus(branchSession.getStatus().getCode());
+        return branchTransactionDO;
+    }
+
+    /**
+     * Sets log store.
+     *
+     * @param logStore the log store
+     */
+    public void setLogStore(LogStore logStore) {
+        this.logStore = logStore;
+    }
+
+    /**
+     * Sets log query limit.
+     *
+     * @param logQueryLimit the log query limit
+     */
+    public void setLogQueryLimit(int logQueryLimit) {
+        this.logQueryLimit = logQueryLimit;
+    }
+}
\ No newline at end of file
diff --git a/server/src/main/java/io/seata/server/store/db/DbcpDataSourceGenerator.java b/server/src/main/java/io/seata/server/store/db/DbcpDataSourceGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..2cc8e14929e99b95f72331cf549bdec0438b99a7
--- /dev/null
+++ b/server/src/main/java/io/seata/server/store/db/DbcpDataSourceGenerator.java
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.store.db;
+
+import io.seata.common.loader.LoadLevel;
+import io.seata.core.store.db.AbstractDataSourceGenerator;
+import org.apache.commons.dbcp.BasicDataSource;
+
+import javax.sql.DataSource;
+
+/**
+ * The type Dbcp data source generator.
+ *
+ * @author zhangsen
+ * @data 2019 /4/24
+ */
+@LoadLevel(name = "dbcp")
+public class DbcpDataSourceGenerator extends AbstractDataSourceGenerator {
+
+    @Override
+    public DataSource generateDataSource() {
+        BasicDataSource ds = new BasicDataSource();
+        ds.setDriverClassName(getDriverName(getDBType()));
+        ds.setUrl(getUrl());
+        ds.setUsername(getUser());
+        ds.setPassword(getPassword());
+        ds.setInitialSize(getMinConn());
+        ds.setMaxActive(getMaxConn());
+        ds.setMinIdle(getMinConn());
+        ds.setMaxIdle(getMinConn());
+        ds.setMaxWait(5000);
+        ds.setTimeBetweenEvictionRunsMillis(120000);
+        ds.setNumTestsPerEvictionRun(1);
+        ds.setTestWhileIdle(true);
+        ds.setValidationQuery(getValidationQuery(getDBType()));
+        ds.setConnectionProperties("useUnicode=yes;characterEncoding=utf8;socketTimeout=5000;connectTimeout=500");
+        return ds;
+    }
+
+
+}
diff --git a/server/src/main/java/io/seata/server/store/db/DruidDataSourceGenerator.java b/server/src/main/java/io/seata/server/store/db/DruidDataSourceGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..04ddfe77b6320928108d0a97b0da4b52037f1026
--- /dev/null
+++ b/server/src/main/java/io/seata/server/store/db/DruidDataSourceGenerator.java
@@ -0,0 +1,54 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.store.db;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import io.seata.common.loader.LoadLevel;
+import io.seata.core.store.db.AbstractDataSourceGenerator;
+
+import javax.sql.DataSource;
+
+/**
+ * The type Druid data source generator.
+ *
+ * @author zhangsen
+ * @data 2019 /4/28
+ */
+@LoadLevel(name = "druid")
+public class DruidDataSourceGenerator extends AbstractDataSourceGenerator {
+
+    @Override
+    public DataSource generateDataSource() {
+        DruidDataSource ds = new DruidDataSource();
+        ds.setDriverClassName(getDriverName(getDBType()));
+        ds.setUrl(getUrl());
+        ds.setUsername(getUser());
+        ds.setPassword(getPassword());
+        ds.setInitialSize(getMinConn());
+        ds.setMaxActive(getMaxConn());
+        ds.setMinIdle(getMinConn());
+        ds.setMaxWait(5000);
+        ds.setTimeBetweenEvictionRunsMillis(120000);
+        ds.setMinEvictableIdleTimeMillis(300000);
+        ds.setTestWhileIdle(true);
+        ds.setTestOnBorrow(true);
+        ds.setPoolPreparedStatements(true);
+        ds.setMaxPoolPreparedStatementPerConnectionSize(20);
+        ds.setValidationQuery(getValidationQuery(getDBType()));
+        ds.setDefaultAutoCommit(true);
+        return ds;
+    }
+}
diff --git a/server/src/main/java/io/seata/server/store/FileTransactionStoreManager.java b/server/src/main/java/io/seata/server/store/file/FileTransactionStoreManager.java
similarity index 92%
rename from server/src/main/java/io/seata/server/store/FileTransactionStoreManager.java
rename to server/src/main/java/io/seata/server/store/file/FileTransactionStoreManager.java
index 9b3a32229c57e031c6c7c7edb1b00954a70a2a89..5f8e42d8a31bae8e1173f486c471a1e48fd298e3 100644
--- a/server/src/main/java/io/seata/server/store/FileTransactionStoreManager.java
+++ b/server/src/main/java/io/seata/server/store/file/FileTransactionStoreManager.java
@@ -13,16 +13,7 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package io.seata.server.store;
-
-import io.seata.common.thread.NamedThreadFactory;
-import io.seata.common.util.CollectionUtils;
-import io.seata.server.session.BranchSession;
-import io.seata.server.session.GlobalSession;
-import io.seata.server.session.SessionCondition;
-import io.seata.server.session.SessionManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+package io.seata.server.store.file;
 
 import java.io.File;
 import java.io.IOException;
@@ -33,17 +24,39 @@ import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.*;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.ReentrantLock;
 
+import io.seata.common.exception.StoreException;
+import io.seata.common.loader.LoadLevel;
+import io.seata.common.thread.NamedThreadFactory;
+import io.seata.common.util.CollectionUtils;
+import io.seata.server.session.BranchSession;
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionCondition;
+import io.seata.server.session.SessionManager;
+import io.seata.server.store.AbstractTransactionStoreManager;
+import io.seata.server.store.FlushDiskMode;
+import io.seata.server.store.ReloadableStore;
+import io.seata.server.store.SessionStorable;
+import io.seata.server.store.StoreConfig;
+import io.seata.server.store.TransactionStoreManager;
+import io.seata.server.store.TransactionWriteStore;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * The type File transaction store manager.
  *
  * @author jimin.jm @alibaba-inc.com
  */
-public class FileTransactionStoreManager implements TransactionStoreManager {
-
+@LoadLevel(name = "file")
+public class FileTransactionStoreManager extends AbstractTransactionStoreManager implements TransactionStoreManager, ReloadableStore {
     private static final Logger LOGGER = LoggerFactory.getLogger(FileTransactionStoreManager.class);
 
     private static final int MAX_THREAD_WRITE = 1;
@@ -119,8 +132,7 @@ public class FileTransactionStoreManager implements TransactionStoreManager {
      */
     public FileTransactionStoreManager(String fullFileName, SessionManager sessionManager) throws IOException {
         initFile(fullFileName);
-        fileWriteExecutor =
-                new ThreadPoolExecutor(MAX_THREAD_WRITE, MAX_THREAD_WRITE, Integer.MAX_VALUE, TimeUnit.MILLISECONDS,
+        fileWriteExecutor = new ThreadPoolExecutor(MAX_THREAD_WRITE, MAX_THREAD_WRITE, Integer.MAX_VALUE, TimeUnit.MILLISECONDS,
                         new LinkedBlockingQueue<Runnable>(),
                         new NamedThreadFactory("fileTransactionStore", MAX_THREAD_WRITE, true));
         writeDataFileRunnable = new WriteDataFileRunnable();
@@ -247,6 +259,16 @@ public class FileTransactionStoreManager implements TransactionStoreManager {
         return false;
     }
 
+    @Override
+    public GlobalSession readSession(String xid) {
+        throw new StoreException("unsupport for read from file, xid:" + xid);
+    }
+
+    @Override
+    public List<GlobalSession> readSession(SessionCondition sessionCondition) {
+        throw new StoreException("unsupport for read from file");
+    }
+
     @Override
     public void shutdown() {
         if (null != fileWriteExecutor) {
@@ -257,7 +279,7 @@ public class FileTransactionStoreManager implements TransactionStoreManager {
                 ++retry;
                 try {
                     Thread.sleep(SHUTDOWN_CHECK_INTERNAL);
-                } catch (InterruptedException exx) {
+                } catch (InterruptedException ignore) {
                 }
             }
             if (retry >= MAX_SHUTDOWN_RETRY) {
@@ -273,7 +295,7 @@ public class FileTransactionStoreManager implements TransactionStoreManager {
     }
 
     @Override
-    public List<TransactionWriteStore> readWriteStoreFromFile(int readSize, boolean isHistory) {
+    public List<TransactionWriteStore> readWriteStore(int readSize, boolean isHistory) {
         File file = null;
         long currentOffset = 0;
         if (isHistory) {
@@ -305,7 +327,7 @@ public class FileTransactionStoreManager implements TransactionStoreManager {
             raf = new RandomAccessFile(file, "r");
             return currentOffset < raf.length();
 
-        } catch (IOException exx) {
+        } catch (IOException ignore) {
         } finally {
             closeFile(raf);
         }
@@ -512,7 +534,7 @@ public class FileTransactionStoreManager implements TransactionStoreManager {
                     StoreRequest storeRequest = storeRequests.poll(MAX_WAIT_TIME_MILLS, TimeUnit.MILLISECONDS);
                     handleStoreRequest(storeRequest);
                 } catch (Exception exx) {
-                    LOGGER.error("write file error", exx.getMessage());
+                    LOGGER.error("write file error: {}", exx.getMessage(), exx);
                 }
             }
             handleRestRequest();
diff --git a/server/src/main/resources/META-INF/services/io.seata.core.lock.Locker b/server/src/main/resources/META-INF/services/io.seata.core.lock.Locker
new file mode 100644
index 0000000000000000000000000000000000000000..d8b311d6e939d90cf4e63c6c0c4f16b0f1167a58
--- /dev/null
+++ b/server/src/main/resources/META-INF/services/io.seata.core.lock.Locker
@@ -0,0 +1,2 @@
+io.seata.server.lock.memory.MemoryLocker
+io.seata.server.lock.db.DataBaseLocker
\ No newline at end of file
diff --git a/server/src/main/resources/META-INF/services/io.seata.core.store.db.DataSourceGenerator b/server/src/main/resources/META-INF/services/io.seata.core.store.db.DataSourceGenerator
new file mode 100644
index 0000000000000000000000000000000000000000..68b9548e561d4ec4dd3cc8eee59007740b286e9e
--- /dev/null
+++ b/server/src/main/resources/META-INF/services/io.seata.core.store.db.DataSourceGenerator
@@ -0,0 +1,2 @@
+io.seata.server.store.db.DbcpDataSourceGenerator
+io.seata.server.store.db.DruidDataSourceGenerator
\ No newline at end of file
diff --git a/server/src/main/resources/META-INF/services/io.seata.server.session.SessionManager b/server/src/main/resources/META-INF/services/io.seata.server.session.SessionManager
new file mode 100644
index 0000000000000000000000000000000000000000..9d3f0808a601dc62c5fde38ddd466c2fd8d363ae
--- /dev/null
+++ b/server/src/main/resources/META-INF/services/io.seata.server.session.SessionManager
@@ -0,0 +1,3 @@
+io.seata.server.session.file.FileBasedSessionManager
+io.seata.server.session.db.DataBaseSessionManager
+io.seata.server.session.DefaultSessionManager
\ No newline at end of file
diff --git a/server/src/main/resources/META-INF/services/io.seata.server.store.TransactionStoreManager b/server/src/main/resources/META-INF/services/io.seata.server.store.TransactionStoreManager
new file mode 100644
index 0000000000000000000000000000000000000000..948d6c079dd7e5069225bdd0dc297f9c47d263cb
--- /dev/null
+++ b/server/src/main/resources/META-INF/services/io.seata.server.store.TransactionStoreManager
@@ -0,0 +1,2 @@
+io.seata.server.store.db.DatabaseTransactionStoreManager
+io.seata.server.store.file.FileTransactionStoreManager
\ No newline at end of file
diff --git a/server/src/main/resources/db_store.sql b/server/src/main/resources/db_store.sql
new file mode 100644
index 0000000000000000000000000000000000000000..78b4fa01871b0213c99309239ca3a6f119c4119a
--- /dev/null
+++ b/server/src/main/resources/db_store.sql
@@ -0,0 +1,52 @@
+-- the table to store GlobalSession data
+drop table `global_table`;
+create table `global_table` (
+  `xid` varchar(128)  not null,
+  `transaction_id` bigint,
+  `status` tinyint not null,
+  `application_id` varchar(32),
+  `transaction_service_group` varchar(32),
+  `transaction_name` varchar(64),
+  `timeout` int,
+  `begin_time` bigint,
+  `application_data` varchar(2000),
+  `gmt_create` datetime,
+  `gmt_modified` datetime,
+  primary key (`xid`),
+  key `idx_gmt_modified_status` (`gmt_modified`, `status`),
+  key `idx_transaction_id` (`transaction_id`)
+);
+
+-- the table to store BranchSession data
+drop table `branch_table`;
+create table `branch_table` (
+  `branch_id` bigint not null,
+  `xid` varchar(128) not null,
+  `transaction_id` bigint ,
+  `resource_group_id` varchar(32),
+  `resource_id` varchar(256) ,
+  `lock_key` varchar(128) ,
+  `branch_type` varchar(8) ,
+  `status` tinyint,
+  `client_id` varchar(64),
+  `application_data` varchar(2000),
+  `gmt_create` datetime,
+  `gmt_modified` datetime,
+  primary key (`branch_id`),
+  key `idx_xid` (`xid`)
+);
+
+-- the table to store lock data
+drop table `lock_table`;
+create table `lock_table` (
+  `row_key` varchar(128) not null,
+  `xid` varchar(96),
+  `transaction_id` long ,
+  `branch_id` long,
+  `resource_id` varchar(256) ,
+  `table_name` varchar(32) ,
+  `pk` varchar(32) ,
+  `gmt_create` datetime ,
+  `gmt_modified` datetime,
+  primary key(`row_key`)
+);
diff --git a/server/src/main/resources/file.conf b/server/src/main/resources/file.conf
index dc908a344ef9b8c7b3583b2838c284f7c0a69199..59e2143329929434139540affcc1c16127b2dce7 100644
--- a/server/src/main/resources/file.conf
+++ b/server/src/main/resources/file.conf
@@ -29,6 +29,9 @@ service {
   enableDegrade = false
   #disable
   disable = false
+  #unit ms,s,m,h,d represents milliseconds, seconds, minutes, hours, days, default permanent
+  max.commit.retry.timeout = "-1"
+  max.rollback.retry.timeout = "-1"
 }
 
 client {
@@ -63,10 +66,44 @@ store {
 
   ## database store
   db {
-    driver_class = ""
-    url = ""
-    user = ""
-    password = ""
-  }
+      ## the implement of javax.sql.DataSource, such as DruidDataSource(druid)/BasicDataSource(dbcp) etc.
+      datasource = "dbcp"
+      ## mysql/oracle/h2/oceanbase etc.
+      db-type = "mysql"
+      url = "jdbc:mysql://127.0.0.1:3306/seata"
+      user = "mysql"
+      password = "mysql"
+      min-conn = 1
+      max-conn = 3
+      global.table = "global_table"
+      branch.table = "branch_table"
+      query-limit = 100
+    }
+}
+lock {
+    ## the data row lock store mode: local_db、memory or db
+    mode = "memory"
+
+    memory{
+         ## store lock in memory of server
+    }
 
+    db{
+        ## use db of server to store lock, the db is ${store.db.url}
+        lock-table= "lock_table"
+    }
+
+    local_db {
+        ## store lock in local db
+    }
+}
+recovery{
+    committing-retry-delay = 5
+    asyn-committing-retry-delay = 5
+    rollbacking-retry-delay = 5
+    timeout-retry-delay = 5
 }
+
+transaction {
+  undo.data.validation = true
+}
\ No newline at end of file
diff --git a/server/src/main/resources/logback.xml b/server/src/main/resources/logback.xml
index 62d9e1acd56c81223fc52e0328e430f78e223c6a..4f2b1d02edc5aa07ea63baf4e05f25281d7015fd 100644
--- a/server/src/main/resources/logback.xml
+++ b/server/src/main/resources/logback.xml
@@ -41,7 +41,7 @@
         </encoder>
     </appender>
 
-    <logger name="io.seata.server.store.FileTransactionStoreManager" additivity="false">
+    <logger name="io.seata.server.store.file.FileTransactionStoreManager" additivity="false">
         <level value="INFO"/>
         <appender-ref ref="seata-default"/>
     </logger>
diff --git a/server/src/main/resources/nacos-config.txt b/server/src/main/resources/nacos-config.txt
index 254a8db09d4370a1e920dac62759ae76ee73ffb8..b80827982df3026b004d37eca1ad91dd4dc955c5 100644
--- a/server/src/main/resources/nacos-config.txt
+++ b/server/src/main/resources/nacos-config.txt
@@ -13,6 +13,8 @@ transport.thread-factory.worker-thread-size=8
 service.vgroup_mapping.my_test_tx_group=default
 service.enableDegrade=false
 service.disable=false
+service.max.commit.retry.timeout=-1
+service.max.rollback.retry.timeout=-1
 client.async.commit.buffer.limit=10000
 client.lock.retry.internal=10
 client.lock.retry.times=30
@@ -23,7 +25,21 @@ store.file.max-global-session-size=512
 store.file.file-write-buffer-cache-size=16384
 store.file.flush-disk-mode=async
 store.file.session.reload.read_size=100
-store.db.driver_class=com.mysql.jdbc.Driver
-store.db.url=jdbc:mysql://localhost:3306/seata_demo
-store.db.user=user
-store.db.password=password
\ No newline at end of file
+store.db.datasource=dbcp
+store.db.db-type=mysql
+store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true
+store.db.user=mysql
+store.db.password=mysql
+store.db.min-conn=1
+store.db.max-conn=3
+store.db.global.table=global_table
+store.db.branch.table=branch_table
+store.db.query-limit=100
+lock.mode=memory
+lock.db.lock-table=lock_table
+recovery.committing-retry-delay = 5
+recovery.asyn-committing-retry-delay = 5
+recovery.rollbacking-retry-delay = 5
+recovery.timeout-retry-delay = 5
+transaction.undo.data.validation=true
+
diff --git a/server/src/main/resources/registry.conf b/server/src/main/resources/registry.conf
index 1cddea7219444a8f50ee5bdc7f7170de40884356..66b963d139a7255e99a5212ba47015e831058c44 100644
--- a/server/src/main/resources/registry.conf
+++ b/server/src/main/resources/registry.conf
@@ -45,7 +45,7 @@ registry {
 }
 
 config {
-  # file、nacos 、apollo、zk、consul
+  # file、nacos 、apollo、zk、consul、etcd3
   type = "file"
 
   nacos {
@@ -65,6 +65,9 @@ config {
     session.timeout = 6000
     connect.timeout = 2000
   }
+  etcd3 {
+    serverAddr = "http://localhost:2379"
+  }
   file {
     name = "file.conf"
   }
diff --git a/server/src/test/java/WriteStoreMultithreadTest.java b/server/src/test/java/WriteStoreMultithreadTest.java
index 94eb5c8877069c078feeecb49be2999ec73ce7ff..360759f5b69f78f9b95858b1dc8fcda5cab3ee43 100644
--- a/server/src/test/java/WriteStoreMultithreadTest.java
+++ b/server/src/test/java/WriteStoreMultithreadTest.java
@@ -20,8 +20,8 @@ import io.seata.server.session.BranchSession;
 import io.seata.server.session.GlobalSession;
 import io.seata.server.session.SessionCondition;
 import io.seata.server.session.SessionManager;
-import io.seata.server.store.FileTransactionStoreManager;
 import io.seata.server.store.TransactionStoreManager;
+import io.seata.server.store.file.FileTransactionStoreManager;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -55,10 +55,11 @@ public class WriteStoreMultithreadTest {
                     }
 
                     @Override
-                    public GlobalSession findGlobalSession(Long transactionId) {
+                    public GlobalSession findGlobalSession(String xid)  {
                         return null;
                     }
 
+
                     @Override
                     public void updateGlobalSessionStatus(GlobalSession session, GlobalStatus status)
                             throws TransactionException {
diff --git a/server/src/test/java/WriteStoreTest.java b/server/src/test/java/WriteStoreTest.java
index 9f9964d1b868156b382d7dd3accf1f971e8b9d69..d2056f75f63421b0bd322368d4f5a8a08cbbf512 100644
--- a/server/src/test/java/WriteStoreTest.java
+++ b/server/src/test/java/WriteStoreTest.java
@@ -27,11 +27,13 @@ import io.seata.server.session.BranchSession;
 import io.seata.server.session.GlobalSession;
 import io.seata.server.session.SessionCondition;
 import io.seata.server.session.SessionManager;
-import io.seata.server.store.FileTransactionStoreManager;
+import io.seata.server.store.ReloadableStore;
 import io.seata.server.store.SessionStorable;
 import io.seata.server.store.TransactionStoreManager;
 import io.seata.server.store.TransactionStoreManager.LogOperation;
 import io.seata.server.store.TransactionWriteStore;
+import io.seata.server.store.file.FileTransactionStoreManager;
+
 
 /**
  * The type Write store test.
@@ -71,7 +73,7 @@ public class WriteStoreTest {
                 }
 
                 @Override
-                public GlobalSession findGlobalSession(Long transactionId) {
+                public GlobalSession findGlobalSession(String xid)  {
                     return null;
                 }
 
@@ -220,8 +222,8 @@ public class WriteStoreTest {
 
     private static Map<SessionStorable, LogOperation> readAll(TransactionStoreManager transactionStoreManager) {
         Map<SessionStorable, LogOperation> resultMap = new HashMap<>(65535 * 5 * 9);
-        while (transactionStoreManager.hasRemaining(true)) {
-            List<TransactionWriteStore> transactionWriteStores = transactionStoreManager.readWriteStoreFromFile(2000,
+        while (((ReloadableStore)transactionStoreManager).hasRemaining(true)) {
+            List<TransactionWriteStore> transactionWriteStores = ((ReloadableStore)transactionStoreManager).readWriteStore(2000,
                 true);
             if (null != transactionWriteStores) {
                 for (TransactionWriteStore transactionWriteStore : transactionWriteStores) {
@@ -230,8 +232,8 @@ public class WriteStoreTest {
                 }
             }
         }
-        while (transactionStoreManager.hasRemaining(false)) {
-            List<TransactionWriteStore> transactionWriteStores = transactionStoreManager.readWriteStoreFromFile(2000,
+        while (((ReloadableStore)transactionStoreManager).hasRemaining(false)) {
+            List<TransactionWriteStore> transactionWriteStores = ((ReloadableStore)transactionStoreManager).readWriteStore(2000,
                 false);
             if (null != transactionWriteStores) {
                 for (TransactionWriteStore transactionWriteStore : transactionWriteStores) {
diff --git a/server/src/test/java/io/seata/server/coordinator/DefaultCoordinatorTest.java b/server/src/test/java/io/seata/server/coordinator/DefaultCoordinatorTest.java
index d68dcf16bb5cd4622c9f1df36e7fc1fe1ec07b0b..d5a03ece98313ab5f94c451669d2a646f9ca9fa5 100644
--- a/server/src/test/java/io/seata/server/coordinator/DefaultCoordinatorTest.java
+++ b/server/src/test/java/io/seata/server/coordinator/DefaultCoordinatorTest.java
@@ -31,6 +31,8 @@ import io.seata.server.session.SessionHolder;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -76,7 +78,7 @@ public class DefaultCoordinatorTest {
         SessionHolder.init(null);
         serverMessageSender = new MockServerMessageSender();
         defaultCoordinator = new DefaultCoordinator(serverMessageSender);
-        defaultCoordinator.init();
+//        defaultCoordinator.init();
     }
 
     @ParameterizedTest
@@ -105,6 +107,23 @@ public class DefaultCoordinatorTest {
         Assertions.assertEquals(result, BranchStatus.PhaseTwo_Rollbacked);
     }
 
+
+    @Test
+    public void test_handleRetryRollbacking() throws TransactionException, InterruptedException {
+
+        String xid = core.begin(applicationId, txServiceGroup, txName, 10);
+        Long branchId = core.branchRegister(BranchType.AT, "abcd", clientId, xid, applicationData, lockKeys_2);
+
+        Thread.sleep(100);
+
+        defaultCoordinator.timeoutCheck();
+        defaultCoordinator.handleRetryRollbacking();
+
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        Assertions.assertNull(globalSession);
+
+    }
+
     @AfterAll
     public static void afterClass() throws Exception {
 
@@ -164,4 +183,4 @@ public class DefaultCoordinatorTest {
 
         }
     }
-}
+}
\ No newline at end of file
diff --git a/server/src/test/java/io/seata/server/coordinator/DefaultCoreTest.java b/server/src/test/java/io/seata/server/coordinator/DefaultCoreTest.java
index 42b33e4ff5a4baf8ec36e0bfb4dc7b4b42b3c7a7..8569001e89a9ed038f70147c035337c860673ae4 100644
--- a/server/src/test/java/io/seata/server/coordinator/DefaultCoreTest.java
+++ b/server/src/test/java/io/seata/server/coordinator/DefaultCoreTest.java
@@ -23,6 +23,7 @@ import io.seata.core.model.GlobalStatus;
 import io.seata.core.model.ResourceManagerInbound;
 import io.seata.server.session.BranchSession;
 import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionHelper;
 import io.seata.server.session.SessionHolder;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
@@ -84,7 +85,7 @@ public class DefaultCoreTest {
     public void branchRegisterTest(String xid) throws Exception {
         core.branchRegister(BranchType.AT, resourceId, clientId, xid, "abc", lockKeys_1);
         long transactionId = XID.getTransactionId(xid);
-        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         Assertions.assertEquals(globalSession.getSortedBranches().size(), 1);
 
         //clear
@@ -103,7 +104,7 @@ public class DefaultCoreTest {
     public void branchReportTest(String xid, Long branchId) throws Exception {
         core.branchReport(BranchType.AT, xid, branchId, BranchStatus.PhaseOne_Done, applicationData);
         long transactionId = XID.getTransactionId(xid);
-        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         BranchSession branchSession = globalSession.getBranch(branchId);
         Assertions.assertEquals(branchSession.getStatus(), BranchStatus.PhaseOne_Done);
 
@@ -120,8 +121,12 @@ public class DefaultCoreTest {
     public void beginTest() throws Exception {
         String xid = core.begin(applicationId, txServiceGroup, txName, timeout);
         long transactionId = XID.getTransactionId(xid);
-        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
         Assertions.assertNotNull(globalSession);
+
+        //clear
+        globalSession.end();
+
     }
 
     /**
@@ -146,8 +151,9 @@ public class DefaultCoreTest {
     @ParameterizedTest
     @MethodSource("xidProvider")
     public void doGlobalCommitCommitTest(String xid) throws Exception {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
-        BranchSession branchSession = new BranchSession();
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, resourceId,
+                applicationData, "t1:1", clientId);
         globalSession.addBranch(branchSession);
         globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseOne_Done);
         core.setResourceManagerInbound(new MockResourceManagerInbound(BranchStatus.PhaseTwo_Committed, BranchStatus.PhaseOne_Done));
@@ -168,8 +174,9 @@ public class DefaultCoreTest {
     @ParameterizedTest
     @MethodSource("xidProvider")
     public void doGlobalCommitUnretryableTest(String xid) throws Exception {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
-        BranchSession branchSession = new BranchSession();
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, resourceId,
+                applicationData, "t1:1", clientId);
         globalSession.addBranch(branchSession);
         globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseOne_Done);
         core.setResourceManagerInbound(new MockResourceManagerInbound(BranchStatus.PhaseTwo_CommitFailed_Unretryable, BranchStatus.PhaseOne_Done));
@@ -189,8 +196,9 @@ public class DefaultCoreTest {
     @ParameterizedTest
     @MethodSource("xidProvider")
     public void doGlobalCommitExpTest(String xid) throws Exception {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
-        BranchSession branchSession = new BranchSession();
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, resourceId,
+                applicationData, "t1:1", clientId);
         globalSession.addBranch(branchSession);
         globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseOne_Done);
         core.setResourceManagerInbound(new MockResourceManagerInbound(BranchStatus.PhaseOne_Timeout, BranchStatus.PhaseOne_Done));
@@ -223,8 +231,9 @@ public class DefaultCoreTest {
     @ParameterizedTest
     @MethodSource("xidProvider")
     public void doGlobalRollBackRollbackedTest(String xid) throws Exception {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
-        BranchSession branchSession = new BranchSession();
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, resourceId,
+                applicationData, "t1:1", clientId);
         globalSession.addBranch(branchSession);
         globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseOne_Done);
         core.setResourceManagerInbound(new MockResourceManagerInbound(BranchStatus.PhaseTwo_Committed, BranchStatus.PhaseTwo_Rollbacked));
@@ -245,8 +254,9 @@ public class DefaultCoreTest {
     @ParameterizedTest
     @MethodSource("xidProvider")
     public void doGlobalRollBackUnretryableTest(String xid) throws Exception {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
-        BranchSession branchSession = new BranchSession();
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, resourceId,
+                applicationData, "t1:1", clientId);
         globalSession.addBranch(branchSession);
         globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseOne_Done);
         core.setResourceManagerInbound(new MockResourceManagerInbound(BranchStatus.PhaseTwo_Committed, BranchStatus.PhaseTwo_RollbackFailed_Unretryable));
@@ -266,14 +276,16 @@ public class DefaultCoreTest {
     @ParameterizedTest
     @MethodSource("xidProvider")
     public void doGlobalRollBackRetryableExpTest(String xid) throws Exception {
-        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
-        BranchSession branchSession = new BranchSession();
+        GlobalSession globalSession = SessionHolder.findGlobalSession(xid);
+        BranchSession branchSession = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, resourceId,
+                applicationData, "t1:1", clientId);
         globalSession.addBranch(branchSession);
         globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseOne_Done);
         core.setResourceManagerInbound(new MockResourceManagerInbound(BranchStatus.PhaseTwo_Committed, BranchStatus.PhaseTwo_RollbackFailed_Retryable));
         core.doGlobalRollback(globalSession, false);
         Assertions.assertEquals(globalSession.getStatus(), GlobalStatus.RollbackRetrying);
 
+        //clear
         globalSession.end();
     }
 
diff --git a/server/src/test/java/io/seata/server/lock/LockManagerTest.java b/server/src/test/java/io/seata/server/lock/LockManagerTest.java
index 31084b1358ae24226a769d6dd89ae289e627713d..f420ebe7635d2da392938b0ac11df82ad222ed8c 100644
--- a/server/src/test/java/io/seata/server/lock/LockManagerTest.java
+++ b/server/src/test/java/io/seata/server/lock/LockManagerTest.java
@@ -17,6 +17,7 @@ package io.seata.server.lock;
 
 import io.seata.core.model.BranchType;
 import io.seata.server.UUIDGenerator;
+import io.seata.server.lock.memory.MemoryLockManagerForTest;
 import io.seata.server.session.BranchSession;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -42,7 +43,7 @@ public class LockManagerTest {
     @ParameterizedTest
     @MethodSource("branchSessionProvider")
     public void acquireLock_success(BranchSession branchSession) throws Exception {
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager = new MemoryLockManagerForTest();
         Assertions.assertTrue(lockManager.acquireLock(branchSession));
     }
 
@@ -56,7 +57,7 @@ public class LockManagerTest {
     @ParameterizedTest
     @MethodSource("branchSessionsProvider")
     public void acquireLock_failed(BranchSession branchSession1, BranchSession branchSession2) throws Exception {
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager = new MemoryLockManagerForTest();
         Assertions.assertTrue(lockManager.acquireLock(branchSession1));
         Assertions.assertFalse(lockManager.acquireLock(branchSession2));
     }
@@ -71,13 +72,13 @@ public class LockManagerTest {
     @MethodSource("branchSessionProvider")
     public void isLockableTest(BranchSession branchSession) throws Exception {
         branchSession.setLockKey("t:4");
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager = new MemoryLockManagerForTest();
         Assertions.assertTrue(lockManager
-                .isLockable(branchSession.getTransactionId(), branchSession.getResourceId(), branchSession.getLockKey()));
+                .isLockable(branchSession.getXid(), branchSession.getResourceId(), branchSession.getLockKey()));
         lockManager.acquireLock(branchSession);
         branchSession.setTransactionId(UUIDGenerator.generateUUID());
         Assertions.assertFalse(lockManager
-                .isLockable(branchSession.getTransactionId(), branchSession.getResourceId(), branchSession.getLockKey()));
+                .isLockable(branchSession.getXid(), branchSession.getResourceId(), branchSession.getLockKey()));
     }
 
     /**
diff --git a/server/src/test/java/io/seata/server/lock/db/DataBaseLockManagerImplTest.java b/server/src/test/java/io/seata/server/lock/db/DataBaseLockManagerImplTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f11485d64083f98b05aede67b13d239475b05288
--- /dev/null
+++ b/server/src/test/java/io/seata/server/lock/db/DataBaseLockManagerImplTest.java
@@ -0,0 +1,301 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock.db;
+
+import io.seata.core.exception.TransactionException;
+import io.seata.core.lock.Locker;
+import io.seata.core.store.db.LockStoreDataBaseDAO;
+import io.seata.server.lock.DefaultLockManager;
+import io.seata.server.lock.LockManager;
+import io.seata.server.session.BranchSession;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+
+
+/**
+ * @author zhangsen
+ * @data 2019/4/28
+ */
+public class DataBaseLockManagerImplTest {
+
+    static LockManager lockManager = null;
+
+    static BasicDataSource dataSource = null;
+
+    static LockStoreDataBaseDAO dataBaseLockStoreDAO  = null;
+
+    @BeforeAll
+    public static void start(){
+        dataSource =  new BasicDataSource();
+        dataSource.setDriverClassName("org.h2.Driver");
+        dataSource.setUrl("jdbc:h2:./db_store/db_lock");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+
+        dataBaseLockStoreDAO = new LockStoreDataBaseDAO(dataSource);
+        dataBaseLockStoreDAO.setDbType("h2");
+        dataBaseLockStoreDAO.setLockTable("lock_table");
+
+        lockManager = new DBLockManagerForTest(dataBaseLockStoreDAO);
+
+        prepareTable(dataSource);
+    }
+
+    private static void prepareTable(BasicDataSource dataSource) {
+        Connection conn = null;
+        try {
+            conn = dataSource.getConnection();
+            Statement s = conn.createStatement();
+            try {
+                s.execute("drop table lock_table");
+            } catch (Exception e) {
+            }
+            s.execute("CREATE TABLE lock_table ( xid varchar(96),  transaction_id long , branch_id long, resource_id varchar(32) ,table_name varchar(32) ,pk varchar(32)  ,  row_key  varchar(128) primary key not null, gmt_create TIMESTAMP(6) ,gmt_modified TIMESTAMP(6)) ");
+            System.out.println("create table lock_table success.");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void acquireLock() throws TransactionException, SQLException {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setXid("abc-123:786756");
+        branchSession.setTransactionId(123543465);
+        branchSession.setBranchId(5756678);
+        branchSession.setResourceId("abcss");
+        branchSession.setLockKey("t1:13,14;t2:11,12");
+
+        Assertions.assertTrue(lockManager.acquireLock(branchSession));
+
+        String sql = "select * from lock_table where xid = 'abc-123:786756'"  ;
+        String sql2 = "select count(*) from lock_table where xid = 'abc-123:786756' " +
+                "and row_key in ('abcss^^^t1^^^13', 'abcss^^^t1^^^14', 'abcss^^^t2^^^11', 'abcss^^^t2^^^12')"  ;
+        String delSql = "delete from lock_table where xid = 'abc-123:786756'"  ;
+        Connection conn =  null;
+        try {
+            conn = dataSource.getConnection();
+
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            rs = conn.createStatement().executeQuery(sql2);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(4, rs.getInt(1));
+            }else {
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            conn.createStatement().execute(delSql);
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Test
+    public void re_acquireLock() throws TransactionException, SQLException {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setXid("abc-123:65867978");
+        branchSession.setTransactionId(123543465);
+        branchSession.setBranchId(5756678);
+        branchSession.setResourceId("abcss");
+        branchSession.setLockKey("t1:53,54;t2:21,32");
+
+        Assertions.assertTrue(lockManager.acquireLock(branchSession));
+
+        BranchSession branchSession2 = new BranchSession();
+        branchSession2.setXid("abc-123:65867978");
+        branchSession2.setTransactionId(123543465);
+        branchSession2.setBranchId(575667854);
+        branchSession2.setResourceId("abcss");
+        branchSession2.setLockKey("t1:13,14;t2:21,45");
+
+        Assertions.assertTrue(lockManager.acquireLock(branchSession2));
+
+        BranchSession branchSession3 = new BranchSession();
+        branchSession3.setXid("abc-123:5678789");
+        branchSession3.setTransactionId(334123);
+        branchSession3.setBranchId(5657);
+        branchSession3.setResourceId("abcss");
+        branchSession3.setLockKey("t1:53,14;t2:21,45");
+
+        Assertions.assertTrue(!lockManager.acquireLock(branchSession3));
+
+        String delSql = "delete from lock_table where xid in( 'abc-123:65867978' , 'abc-123:65867978' , 'abc-123:5678789'  )"  ;
+        Connection conn =  null;
+        try {
+            conn = dataSource.getConnection();
+
+            conn.createStatement().execute(delSql);
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    @Test
+    public void unLock() throws TransactionException, SQLException {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setXid("abc-123:56867");
+        branchSession.setTransactionId(1236765);
+        branchSession.setBranchId(204565);
+        branchSession.setResourceId("abcss");
+        branchSession.setLockKey("t1:3,4;t2:4,5");
+
+        Assertions.assertTrue(lockManager.acquireLock(branchSession));
+
+        String sql = "select * from lock_table where xid = 'abc-123:56867'"  ;
+        String sql2 = "select count(*) from lock_table where xid = 'abc-123:56867' " +
+                "and row_key in ('abcss^^^t1^^^3', 'abcss^^^t1^^^4', 'abcss^^^t2^^^4', 'abcss^^^t2^^^5')"  ;
+        Connection conn =  null;
+        try {
+            conn = dataSource.getConnection();
+
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else {
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            rs = conn.createStatement().executeQuery(sql2);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(4, rs.getInt(1));
+            }else {
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            //un lock
+            Assertions.assertTrue(lockManager.releaseLock(branchSession));
+
+            rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(false);
+            }else {
+                Assertions.assertTrue(true);
+            }
+            rs.close();
+
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+
+
+
+    }
+
+    @Test
+    public void isLockable() throws TransactionException, SQLException {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setXid("abc-123:56877898");
+        branchSession.setTransactionId(245686786);
+        branchSession.setBranchId(467568);
+        branchSession.setResourceId("abcss");
+        branchSession.setLockKey("t1:8,7;t2:1,2");
+
+        Assertions.assertTrue(lockManager.acquireLock(branchSession));
+
+        BranchSession branchSession2 = new BranchSession();
+        branchSession2.setXid("abc-123:56877898");
+        branchSession2.setTransactionId(245686786);
+        branchSession2.setBranchId(1242354576);
+        branchSession2.setResourceId("abcss");
+        branchSession2.setLockKey("t1:8");
+
+        Assertions.assertTrue(lockManager.isLockable(branchSession2.getXid(), branchSession2.getResourceId(), branchSession2.getLockKey()));
+
+        BranchSession branchSession3 = new BranchSession();
+        branchSession3.setXid("abc-123:4575614354");
+        branchSession3.setTransactionId(65867867);
+        branchSession3.setBranchId(123123);
+        branchSession3.setResourceId("abcss");
+        branchSession3.setLockKey("t2:1,12");
+
+        Assertions.assertTrue(!lockManager.isLockable(branchSession3.getXid(), branchSession3.getResourceId(), branchSession3.getLockKey()));
+
+        String delSql = "delete from lock_table where xid in( 'abc-123:56877898' , 'abc-123:56877898' , 'abc-123:4575614354'  )"  ;
+        Connection conn =  null;
+        try {
+            conn = dataSource.getConnection();
+
+            conn.createStatement().execute(delSql);
+        } finally {
+            if(conn != null){
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                }
+            }
+        }
+    }
+
+    public static class DBLockManagerForTest extends DefaultLockManager {
+
+        protected LockStoreDataBaseDAO lockStore;
+
+        public DBLockManagerForTest(LockStoreDataBaseDAO db){
+            lockStore = db;
+        }
+
+        @Override
+        protected Locker getLocker(BranchSession branchSession) {
+            DataBaseLocker locker =  new DataBaseLocker();
+            locker.setLockStore(lockStore);
+            return locker;
+        }
+    }
+}
\ No newline at end of file
diff --git a/server/src/test/java/io/seata/server/lock/memory/MemoryLockManagerForTest.java b/server/src/test/java/io/seata/server/lock/memory/MemoryLockManagerForTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1bdd7c0c0b7a9cbecbafac9e7ccb8b1d653f63ff
--- /dev/null
+++ b/server/src/test/java/io/seata/server/lock/memory/MemoryLockManagerForTest.java
@@ -0,0 +1,32 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.lock.memory;
+
+import io.seata.core.lock.Locker;
+import io.seata.server.lock.DefaultLockManager;
+import io.seata.server.session.BranchSession;
+
+/**
+ * @author zhangsen
+ * @data 2019-05-16
+ */
+public class MemoryLockManagerForTest extends DefaultLockManager {
+
+    @Override
+    protected Locker getLocker(BranchSession branchSession) {
+        return new MemoryLocker(branchSession);
+    }
+}
diff --git a/server/src/test/java/io/seata/server/lock/DefaultLockManagerImplTest.java b/server/src/test/java/io/seata/server/lock/memory/MemoryLockManagerImplTest.java
similarity index 87%
rename from server/src/test/java/io/seata/server/lock/DefaultLockManagerImplTest.java
rename to server/src/test/java/io/seata/server/lock/memory/MemoryLockManagerImplTest.java
index fbe0c216b420e65f1bad9de08a3210277ef004c7..7bf4148174e1d295843a5625ca73a3c9cb9f4f30 100644
--- a/server/src/test/java/io/seata/server/lock/DefaultLockManagerImplTest.java
+++ b/server/src/test/java/io/seata/server/lock/memory/MemoryLockManagerImplTest.java
@@ -13,10 +13,12 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
-package io.seata.server.lock;
+package io.seata.server.lock.memory;
 
+import io.seata.common.XID;
 import io.seata.core.model.BranchType;
 import io.seata.server.UUIDGenerator;
+import io.seata.server.lock.LockManager;
 import io.seata.server.session.BranchSession;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -25,15 +27,16 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 import java.util.stream.Stream;
 
+
 /**
  * The type Default lock manager impl test.
  *
  * @author zhimo.xiao @gmail.com
  * @since 2019 /1/23
  */
-public class DefaultLockManagerImplTest {
+public class MemoryLockManagerImplTest {
 
-    private LockManager lockManager = new DefaultLockManagerImpl();
+    private LockManager lockManager = new MemoryLockManagerForTest();;
 
     private static final long transactionId = UUIDGenerator.generateUUID();
 
@@ -50,6 +53,7 @@ public class DefaultLockManagerImplTest {
     @ParameterizedTest
     @MethodSource("branchSessionProvider")
     public void acquireLockTest(BranchSession branchSession) throws Exception {
+
         boolean result = lockManager.acquireLock(branchSession);
         Assertions.assertTrue(result);
         branchSession.unlock();
@@ -62,7 +66,8 @@ public class DefaultLockManagerImplTest {
      */
     @Test
     public void isLockableTest() throws Exception {
-        boolean resultOne = lockManager.isLockable(transactionId, resourceId, lockKey);
+        boolean resultOne = lockManager.isLockable(XID.generateXID(transactionId), resourceId, lockKey);
+
         Assertions.assertTrue(resultOne);
     }
 
@@ -73,6 +78,7 @@ public class DefaultLockManagerImplTest {
      */
     static Stream<BranchSession> branchSessionProvider() {
         BranchSession branchSession = new BranchSession();
+        branchSession.setXid(XID.generateXID(transactionId));
         branchSession.setBranchId(1L);
         branchSession.setTransactionId(transactionId);
         branchSession.setClientId("c1");
diff --git a/server/src/test/java/io/seata/server/session/DefaultSessionManagerTest.java b/server/src/test/java/io/seata/server/session/DefaultSessionManagerTest.java
index 33544245aa50756ecc6782aeb03dc29360cc7e65..69b12a0c2473bc3aba80c410ea3b771e8f84296f 100644
--- a/server/src/test/java/io/seata/server/session/DefaultSessionManagerTest.java
+++ b/server/src/test/java/io/seata/server/session/DefaultSessionManagerTest.java
@@ -15,6 +15,7 @@
  */
 package io.seata.server.session;
 
+import io.seata.common.XID;
 import io.seata.core.model.BranchStatus;
 import io.seata.core.model.BranchType;
 import io.seata.core.model.GlobalStatus;
@@ -61,7 +62,7 @@ public class DefaultSessionManagerTest {
     @MethodSource("globalSessionProvider")
     public void findGlobalSessionTest(GlobalSession globalSession) throws Exception {
         sessionManager.addGlobalSession(globalSession);
-        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getTransactionId());
+        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getXid());
         Assertions.assertNotNull(expected);
         Assertions.assertEquals(expected.getTransactionId(), globalSession.getTransactionId());
         Assertions.assertEquals(expected.getApplicationId(), globalSession.getApplicationId());
@@ -84,7 +85,7 @@ public class DefaultSessionManagerTest {
         sessionManager.addGlobalSession(globalSession);
         globalSession.setStatus(GlobalStatus.Finished);
         sessionManager.updateGlobalSessionStatus(globalSession, GlobalStatus.Finished);
-        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getTransactionId());
+        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getXid());
         Assertions.assertNotNull(expected);
         Assertions.assertEquals(GlobalStatus.Finished, expected.getStatus());
         sessionManager.removeGlobalSession(globalSession);
@@ -101,7 +102,7 @@ public class DefaultSessionManagerTest {
     public void removeGlobalSessionTest(GlobalSession globalSession) throws Exception {
         sessionManager.addGlobalSession(globalSession);
         sessionManager.removeGlobalSession(globalSession);
-        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getTransactionId());
+        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getXid());
         Assertions.assertNull(expected);
 
     }
@@ -301,6 +302,10 @@ public class DefaultSessionManagerTest {
      */
     static Stream<Arguments> globalSessionProvider() {
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
+
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+
         return Stream.of(
                 Arguments.of(globalSession)
         );
diff --git a/server/src/test/java/io/seata/server/session/FileBasedSessionManagerTest.java b/server/src/test/java/io/seata/server/session/FileBasedSessionManagerTest.java
index 803f1200c47376936c91e23e91ddbf041a3e6674..7c58a309b89be3df875be9b04f771eece58b5083 100644
--- a/server/src/test/java/io/seata/server/session/FileBasedSessionManagerTest.java
+++ b/server/src/test/java/io/seata/server/session/FileBasedSessionManagerTest.java
@@ -15,6 +15,11 @@
  */
 package io.seata.server.session;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import io.seata.common.XID;
 import io.seata.core.model.BranchStatus;
 import io.seata.core.model.BranchType;
 import io.seata.core.model.GlobalStatus;
@@ -24,11 +29,10 @@ import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
+import io.seata.server.session.file.FileBasedSessionManager;
 import java.util.stream.Stream;
 
+
 /**
  * The type File based session manager test.
  *
@@ -72,7 +76,7 @@ public class FileBasedSessionManagerTest {
     @MethodSource("globalSessionProvider")
     public void findGlobalSessionTest(GlobalSession globalSession) throws Exception {
         sessionManager.addGlobalSession(globalSession);
-        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getTransactionId());
+        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getXid());
         Assertions.assertNotNull(expected);
         Assertions.assertEquals(expected.getTransactionId(), globalSession.getTransactionId());
         Assertions.assertEquals(expected.getApplicationId(), globalSession.getApplicationId());
@@ -95,7 +99,7 @@ public class FileBasedSessionManagerTest {
         sessionManager.addGlobalSession(globalSession);
         globalSession.setStatus(GlobalStatus.Finished);
         sessionManager.updateGlobalSessionStatus(globalSession, GlobalStatus.Finished);
-        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getTransactionId());
+        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getXid());
         Assertions.assertNotNull(expected);
         Assertions.assertEquals(GlobalStatus.Finished, expected.getStatus());
         sessionManager.removeGlobalSession(globalSession);
@@ -112,7 +116,7 @@ public class FileBasedSessionManagerTest {
     public void removeGlobalSessionTest(GlobalSession globalSession) throws Exception {
         sessionManager.addGlobalSession(globalSession);
         sessionManager.removeGlobalSession(globalSession);
-        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getTransactionId());
+        GlobalSession expected = sessionManager.findGlobalSession(globalSession.getXid());
         Assertions.assertNull(expected);
 
     }
@@ -312,6 +316,10 @@ public class FileBasedSessionManagerTest {
      */
     static Stream<Arguments> globalSessionProvider() {
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
+
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+
         return Stream.of(
                 Arguments.of(globalSession)
         );
@@ -337,6 +345,7 @@ public class FileBasedSessionManagerTest {
      */
     static Stream<Arguments> branchSessionProvider() {
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
+        globalSession.setXid(XID.generateXID(globalSession.getTransactionId()));
         BranchSession branchSession = new BranchSession();
         branchSession.setTransactionId(globalSession.getTransactionId());
         branchSession.setBranchId(1L);
diff --git a/server/src/test/java/io/seata/server/session/db/DataBaseSessionManagerTest.java b/server/src/test/java/io/seata/server/session/db/DataBaseSessionManagerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..14b04c30b20e6e65200ffb38167335fdd178efc4
--- /dev/null
+++ b/server/src/test/java/io/seata/server/session/db/DataBaseSessionManagerTest.java
@@ -0,0 +1,565 @@
+/*
+ *  Copyright 1999-2019 Seata.io Group.
+ *
+ *  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.
+ */
+package io.seata.server.session.db;
+
+import io.seata.common.XID;
+import io.seata.core.exception.TransactionException;
+import io.seata.core.model.BranchStatus;
+import io.seata.core.model.BranchType;
+import io.seata.core.model.GlobalStatus;
+import io.seata.core.store.db.LogStoreDataBaseDAO;
+import io.seata.server.UUIDGenerator;
+import io.seata.server.session.BranchSession;
+import io.seata.server.session.GlobalSession;
+import io.seata.server.session.SessionCondition;
+import io.seata.server.session.SessionManager;
+import io.seata.server.store.db.DatabaseTransactionStoreManager;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.Assertions;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * The type Data base session manager test.
+ *
+ * @author zhangsen
+ * @data 2019 /4/28
+ */
+public class DataBaseSessionManagerTest {
+
+    static SessionManager sessionManager = null;
+
+    static LogStoreDataBaseDAO logStoreDataBaseDAO  = null;
+
+    static BasicDataSource dataSource = null;
+
+    @BeforeAll
+    public static void start() throws Exception {
+        DataBaseSessionManager tempSessionManager = new DataBaseSessionManager();
+        DatabaseTransactionStoreManager transactionStoreManager = new DatabaseTransactionStoreManager();
+
+        dataSource =  new BasicDataSource();
+        dataSource.setDriverClassName("org.h2.Driver");
+        dataSource.setUrl("jdbc:h2:./db_store/db_session");
+        dataSource.setUsername("sa");
+        dataSource.setPassword("");
+
+        logStoreDataBaseDAO = new LogStoreDataBaseDAO(dataSource);
+        logStoreDataBaseDAO.setDbType("h2");
+        logStoreDataBaseDAO.setGlobalTable("global_table");
+        logStoreDataBaseDAO.setBrachTable("branch_table");
+
+        transactionStoreManager.setLogQueryLimit(100);
+        transactionStoreManager.setLogStore(logStoreDataBaseDAO);
+
+        tempSessionManager.setTransactionStoreManager(transactionStoreManager);
+        sessionManager = tempSessionManager;
+
+        prepareTable(dataSource);
+    }
+
+    private static void prepareTable(BasicDataSource dataSource) {
+        Connection conn = null;
+        try {
+            conn = dataSource.getConnection();
+            Statement s = conn.createStatement();
+            try {
+                s.execute("drop table global_table");
+            } catch (Exception e) {
+            }
+            s.execute("CREATE TABLE global_table ( xid varchar(96),  transaction_id long , STATUS int,  application_id varchar(32), transaction_service_group varchar(32) ,transaction_name varchar(32) ,timeout int,  begin_time long, application_data varchar(500), gmt_create TIMESTAMP(6) ,gmt_modified TIMESTAMP(6) ) ");
+            System.out.println("create table global_table success.");
+
+            try {
+                s.execute("drop table branch_table");
+            } catch (Exception e) {
+            }
+            s.execute("CREATE TABLE branch_table ( xid varchar(96),  transaction_id long , branch_id long, resource_group_id varchar(32), resource_id varchar(32) ,lock_key varchar(64) ,branch_type varchar(32) ,  status int , client_id varchar(128),  application_data varchar(500),  gmt_create TIMESTAMP(6) ,gmt_modified TIMESTAMP(6) ) ");
+            System.out.println("create table branch_table success.");
+
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if (conn != null) {
+                try {
+                    conn.close();
+                } catch (SQLException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+    @Test
+    public void test_addGlobalSession() throws TransactionException, SQLException {
+        GlobalSession session = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(session.getTransactionId());
+        session.setXid(xid);
+        session.setTransactionId(146757978);
+        session.setBeginTime(System.currentTimeMillis());
+        session.setApplicationData("abc=878s");
+        session.setStatus(GlobalStatus.Begin);
+
+        sessionManager.addGlobalSession(session);
+
+        String sql = "select * from global_table where xid= '"+xid+"'";
+        String delSql = "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else{
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+
+    @Test
+    public void test_updateGlobalSessionStatus() throws TransactionException, SQLException {
+        GlobalSession session = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(session.getTransactionId());
+        session.setXid(xid);
+        session.setTransactionId(146757978);
+        session.setBeginTime(System.currentTimeMillis());
+        session.setApplicationData("abc=878s");
+        session.setStatus(GlobalStatus.Begin);
+
+        sessionManager.addGlobalSession(session);
+
+        session.setStatus(GlobalStatus.Committing);
+        sessionManager.updateGlobalSessionStatus(session, GlobalStatus.Committing);
+
+        String sql = "select * from global_table where xid= '"+xid+"'";
+        String delSql = "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(rs.getInt("status"), GlobalStatus.Committing.getCode());
+            }else{
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void test_removeGlobalSession() throws Exception {
+        GlobalSession session = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(session.getTransactionId());
+        session.setXid(xid);
+        session.setTransactionId(146757978);
+        session.setBeginTime(System.currentTimeMillis());
+        session.setApplicationData("abc=878s");
+        session.setStatus(GlobalStatus.Begin);
+
+        sessionManager.addGlobalSession(session);
+
+        String sql = "select * from global_table where xid= '"+xid+"'";
+        String delSql = "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else{
+                Assertions.assertTrue(false);
+            }
+            rs.close();
+
+            //delete
+            sessionManager.removeGlobalSession(session);
+
+            rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(false);
+            }else{
+                Assertions.assertTrue(true);
+            }
+            rs.close();
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void test_findGlobalSession() throws Exception {
+        GlobalSession session = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(session.getTransactionId());
+        session.setXid(xid);
+        session.setTransactionId(146757978);
+        session.setBeginTime(System.currentTimeMillis());
+        session.setApplicationData("abc=878s");
+        session.setStatus(GlobalStatus.Begin);
+
+        sessionManager.addGlobalSession(session);
+
+        GlobalSession globalSession_db = sessionManager.findGlobalSession(session.getXid());
+        Assertions.assertNotNull(globalSession_db);
+
+        Assertions.assertEquals(globalSession_db.getTransactionId(), session.getTransactionId());
+        Assertions.assertEquals(globalSession_db.getXid(), session.getXid());
+        Assertions.assertEquals(globalSession_db.getApplicationData(), session.getApplicationData());
+        Assertions.assertEquals(globalSession_db.getApplicationId(), session.getApplicationId());
+        Assertions.assertEquals(globalSession_db.getTransactionName(), session.getTransactionName());
+        Assertions.assertEquals(globalSession_db.getTransactionServiceGroup(), session.getTransactionServiceGroup());
+        Assertions.assertEquals(globalSession_db.getBeginTime(), session.getBeginTime());
+        Assertions.assertEquals(globalSession_db.getTimeout(), session.getTimeout());
+        Assertions.assertEquals(globalSession_db.getStatus(), session.getStatus());
+
+        String delSql = "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+
+    @Test
+    public void test_addBranchSession() throws Exception {
+        GlobalSession globalSession = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+        globalSession.setTransactionId(146757978);
+        globalSession.setBeginTime(System.currentTimeMillis());
+        globalSession.setApplicationData("abc=878s");
+        globalSession.setStatus(GlobalStatus.Begin);
+
+        BranchSession branchSession = new BranchSession();
+        branchSession.setBranchId(UUIDGenerator.generateUUID());
+        branchSession.setXid(xid);
+        branchSession.setTransactionId(globalSession.getTransactionId());
+        branchSession.setBranchId(1L);
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId("tb_1");
+        branchSession.setLockKey("t_1");
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+
+        sessionManager.addBranchSession(globalSession, branchSession);
+
+        String sql = "select * from branch_table where xid= '"+xid+"'";
+        String delSql = "delete from branch_table where xid= '"+xid+"'" + ";" + "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+            }else{
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+
+    @Test
+    public void test_updateBranchSessionStatus() throws Exception {
+        GlobalSession globalSession = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+        globalSession.setTransactionId(146757978);
+        globalSession.setBeginTime(System.currentTimeMillis());
+        globalSession.setApplicationData("abc=878s");
+        globalSession.setStatus(GlobalStatus.Begin);
+
+        BranchSession branchSession = new BranchSession();
+        branchSession.setBranchId(UUIDGenerator.generateUUID());
+        branchSession.setXid(xid);
+        branchSession.setTransactionId(globalSession.getTransactionId());
+        branchSession.setBranchId(1L);
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId("tb_1");
+        branchSession.setLockKey("t_1");
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setStatus(BranchStatus.PhaseOne_Done);
+
+        sessionManager.addBranchSession(globalSession, branchSession);
+
+        branchSession.setStatus(BranchStatus.PhaseOne_Timeout);
+        sessionManager.updateBranchSessionStatus(branchSession, BranchStatus.PhaseOne_Timeout);
+
+        String sql = "select * from branch_table where xid= '"+xid+"'";
+        String delSql = "delete from branch_table where xid= '"+xid+"'" + ";" + "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(true);
+                Assertions.assertEquals(rs.getInt("status"), BranchStatus.PhaseOne_Timeout.getCode());
+            }else{
+                Assertions.assertTrue(false);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void test_removeBranchSession() throws Exception {
+        GlobalSession globalSession = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+        globalSession.setTransactionId(146757978);
+        globalSession.setBeginTime(System.currentTimeMillis());
+        globalSession.setApplicationData("abc=878s");
+        globalSession.setStatus(GlobalStatus.Begin);
+
+        BranchSession branchSession = new BranchSession();
+        branchSession.setBranchId(UUIDGenerator.generateUUID());
+        branchSession.setXid(xid);
+        branchSession.setTransactionId(globalSession.getTransactionId());
+        branchSession.setBranchId(1L);
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId("tb_1");
+        branchSession.setLockKey("t_1");
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setStatus(BranchStatus.PhaseOne_Done);
+
+        sessionManager.addBranchSession(globalSession, branchSession);
+
+        sessionManager.removeBranchSession(globalSession, branchSession);
+
+        String sql = "select * from branch_table where xid= '"+xid+"'";
+        String delSql = "delete from branch_table where xid= '"+xid+"'" + ";" + "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            ResultSet rs = conn.createStatement().executeQuery(sql);
+            if(rs.next()){
+                Assertions.assertTrue(false);
+            }else{
+                Assertions.assertTrue(true);
+            }
+
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+
+    @Test
+    public void test_allSessions() throws Exception {
+        GlobalSession globalSession = GlobalSession.createGlobalSession("test",
+                "test", "test123", 100);
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+        globalSession.setTransactionId(146757978);
+        globalSession.setBeginTime(System.currentTimeMillis());
+        globalSession.setApplicationData("abc=878s");
+        globalSession.setStatus(GlobalStatus.Begin);
+
+        sessionManager.addGlobalSession(globalSession);
+
+        BranchSession branchSession = new BranchSession();
+        branchSession.setBranchId(UUIDGenerator.generateUUID());
+        branchSession.setXid(xid);
+        branchSession.setTransactionId(globalSession.getTransactionId());
+        branchSession.setBranchId(1L);
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId("tb_1");
+        branchSession.setLockKey("t_1");
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setClientId("abc-123");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setStatus(BranchStatus.PhaseOne_Done);
+
+        sessionManager.addBranchSession(globalSession, branchSession);
+
+
+        BranchSession branchSession2 = new BranchSession();
+        branchSession2.setBranchId(UUIDGenerator.generateUUID());
+        branchSession2.setXid(xid);
+        branchSession2.setTransactionId(globalSession.getTransactionId());
+        branchSession2.setBranchId(2L);
+        branchSession2.setResourceGroupId("my_test_tx_group");
+        branchSession2.setResourceId("tb_1");
+        branchSession2.setLockKey("t_1");
+        branchSession2.setBranchType(BranchType.TCC);
+        branchSession2.setClientId("abc-123");
+        branchSession2.setApplicationData("{\"data\":\"test\"}");
+        branchSession2.setStatus(BranchStatus.PhaseOne_Done);
+
+        sessionManager.addBranchSession(globalSession, branchSession2);
+
+        Collection<GlobalSession> rets = sessionManager.allSessions();
+        Assertions.assertNotNull(rets);
+        Assertions.assertEquals(1, rets.size());
+
+        GlobalSession globalSession_db = (io.seata.server.session.GlobalSession) new ArrayList(rets).get(0);
+
+        Assertions.assertNotNull(globalSession_db.getReverseSortedBranches());
+        Assertions.assertEquals(2, globalSession_db.getReverseSortedBranches().size());
+
+        Assertions.assertNotNull(globalSession_db.getBranch(1L));
+        Assertions.assertNotNull(globalSession_db.getBranch(2L));
+
+        String delSql = "delete from branch_table where xid= '"+xid+"'" + ";" + "delete from global_table where xid= '"+xid+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            conn.createStatement().execute(delSql);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+    @Test
+    public void test_findGlobalSessions() throws TransactionException, SQLException {
+        String xid = null;
+        {
+            GlobalSession globalSession = GlobalSession.createGlobalSession("test",
+                    "test", "test123", 100);
+            xid = XID.generateXID(globalSession.getTransactionId());
+            globalSession.setXid(xid);
+            globalSession.setTransactionId(146757978);
+            globalSession.setBeginTime(System.currentTimeMillis());
+            globalSession.setApplicationData("abc=878s");
+            globalSession.setStatus(GlobalStatus.Begin);
+
+            sessionManager.addGlobalSession(globalSession);
+
+            BranchSession branchSession = new BranchSession();
+            branchSession.setBranchId(UUIDGenerator.generateUUID());
+            branchSession.setXid(xid);
+            branchSession.setTransactionId(globalSession.getTransactionId());
+            branchSession.setBranchId(1L);
+            branchSession.setResourceGroupId("my_test_tx_group");
+            branchSession.setResourceId("tb_1");
+            branchSession.setLockKey("t_1");
+            branchSession.setBranchType(BranchType.AT);
+            branchSession.setClientId("abc-123");
+            branchSession.setApplicationData("{\"data\":\"test\"}");
+            branchSession.setStatus(BranchStatus.PhaseOne_Done);
+            sessionManager.addBranchSession(globalSession, branchSession);
+        }
+        String xid2 = null;
+        {
+            GlobalSession globalSession = GlobalSession.createGlobalSession("test",
+                    "test", "test123", 100);
+            xid2 = XID.generateXID(globalSession.getTransactionId());
+            globalSession.setXid(xid);
+            globalSession.setTransactionId(146757978);
+            globalSession.setBeginTime(System.currentTimeMillis());
+            globalSession.setApplicationData("abc=878s");
+            globalSession.setStatus(GlobalStatus.CommitRetrying);
+
+            sessionManager.addGlobalSession(globalSession);
+
+            BranchSession branchSession = new BranchSession();
+            branchSession.setBranchId(UUIDGenerator.generateUUID());
+            branchSession.setXid(xid2);
+            branchSession.setTransactionId(globalSession.getTransactionId());
+            branchSession.setBranchId(1L);
+            branchSession.setResourceGroupId("my_test_tx_group");
+            branchSession.setResourceId("tb_1");
+            branchSession.setLockKey("t_1");
+            branchSession.setBranchType(BranchType.AT);
+            branchSession.setClientId("abc-123");
+            branchSession.setApplicationData("{\"data\":\"test\"}");
+            branchSession.setStatus(BranchStatus.PhaseOne_Done);
+            sessionManager.addBranchSession(globalSession, branchSession);
+        }
+
+
+        Collection<GlobalSession> rets = sessionManager.findGlobalSessions(new SessionCondition( GlobalStatus.Begin));
+        Assertions.assertNotNull(rets);
+        Assertions.assertEquals(1, rets.size());
+
+        GlobalSession globalSession_db = (io.seata.server.session.GlobalSession) new ArrayList(rets).get(0);
+
+        Assertions.assertNotNull(globalSession_db.getReverseSortedBranches());
+        Assertions.assertEquals(1, globalSession_db.getReverseSortedBranches().size());
+
+        Assertions.assertNotNull(globalSession_db.getBranch(1L));
+
+        String delSql = "delete from branch_table where xid= '"+xid+"'" + ";" + "delete from global_table where xid= '"+xid+"'";
+        String delSql2 = "delete from branch_table where xid= '"+xid2+"'" + ";" + "delete from global_table where xid= '"+xid2+"'";
+        Connection conn = null;
+        try{
+            conn = dataSource.getConnection();
+            conn.createStatement().execute(delSql);
+            conn.createStatement().execute(delSql2);
+        }finally {
+            if(conn != null){
+                conn.close();
+            }
+        }
+    }
+
+
+
+
+}
\ No newline at end of file
diff --git a/server/src/test/java/io/seata/server/store/SessionStoreTest.java b/server/src/test/java/io/seata/server/store/SessionStoreTest.java
index 45048d7f63da748e082bb35c3b5c4198596de8fa..37fecd0d6c40400d7b539bf45df49664d680ce28 100644
--- a/server/src/test/java/io/seata/server/store/SessionStoreTest.java
+++ b/server/src/test/java/io/seata/server/store/SessionStoreTest.java
@@ -15,6 +15,9 @@
  */
 package io.seata.server.store;
 
+import java.io.File;
+
+import io.seata.common.XID;
 import io.seata.config.Configuration;
 import io.seata.config.ConfigurationFactory;
 import io.seata.core.constants.ConfigurationKeys;
@@ -22,7 +25,7 @@ import io.seata.core.model.BranchStatus;
 import io.seata.core.model.BranchType;
 import io.seata.core.model.GlobalStatus;
 import io.seata.server.lock.LockManager;
-import io.seata.server.lock.LockManagerFactory;
+import io.seata.server.lock.memory.MemoryLockManagerForTest;
 import io.seata.server.session.BranchSession;
 import io.seata.server.session.GlobalSession;
 import io.seata.server.session.SessionHelper;
@@ -31,7 +34,6 @@ import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.io.File;
 
 /**
  * The type Session store test.
@@ -63,7 +65,8 @@ public class SessionStoreTest {
         if (rootDataFileHis.exists()) {
             rootDataFileHis.delete();
         }
-        LockManagerFactory.get().cleanAllLocks();
+        LockManager lockManager = new MemoryLockManagerForTest();
+        lockManager.cleanAllLocks();
     }
 
     /**
@@ -75,43 +78,48 @@ public class SessionStoreTest {
     public void testRestoredFromFile() throws Exception {
         SessionHolder.init("file");
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
 
         globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         globalSession.begin();
 
         BranchSession branchSession1 = SessionHelper.newBranchByGlobal(globalSession, BranchType.AT, RESOURCE_ID,
                 "ta:1,2;tb:3", "xxx");
+        branchSession1.setXid(xid);
         branchSession1.lock();
         globalSession.addBranch(branchSession1);
 
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager = new MemoryLockManagerForTest();
 
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:2"));
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "tb:3"));
+        String otherXID = XID.generateXID(0L);
 
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:4"));
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "tb:5"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:2"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "tb:3"));
+
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:4"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "tb:5"));
 
         lockManager.cleanAllLocks();
 
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:2"));
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "tb:3"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:2"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "tb:3"));
 
         // Re-init SessionHolder: restore sessions from file
         SessionHolder.init("file");
 
         long tid = globalSession.getTransactionId();
-        GlobalSession reloadSession = SessionHolder.findGlobalSession(tid);
+        GlobalSession reloadSession = SessionHolder.findGlobalSession(globalSession.getXid());
         Assertions.assertNotNull(reloadSession);
         Assertions.assertFalse(globalSession == reloadSession);
         Assertions.assertEquals(globalSession.getApplicationId(), reloadSession.getApplicationId());
 
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:2"));
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "tb:3"));
-        Assertions.assertTrue(lockManager.isLockable(globalSession.getTransactionId(), RESOURCE_ID, "tb:3"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:2"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "tb:3"));
+        Assertions.assertTrue(lockManager.isLockable(xid, RESOURCE_ID, "tb:3"));
 
         //clear
         reloadSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
@@ -145,6 +153,9 @@ public class SessionStoreTest {
         SessionHolder.init("file");
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
 
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+
         globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         globalSession.begin();
 
@@ -153,29 +164,31 @@ public class SessionStoreTest {
         Assertions.assertTrue(branchSession1.lock());
         globalSession.addBranch(branchSession1);
 
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager = new MemoryLockManagerForTest();
+
+        String otherXID = XID.generateXID(0L);
 
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         globalSession.changeStatus(GlobalStatus.AsyncCommitting);
 
         lockManager.cleanAllLocks();
 
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         // Re-init SessionHolder: restore sessions from file
         SessionHolder.init("file");
 
         long tid = globalSession.getTransactionId();
-        GlobalSession reloadSession = SessionHolder.findGlobalSession(tid);
+        GlobalSession reloadSession = SessionHolder.findGlobalSession(globalSession.getXid());
         Assertions.assertEquals(reloadSession.getStatus(), GlobalStatus.AsyncCommitting);
 
         GlobalSession sessionInAsyncCommittingQueue = SessionHolder.getAsyncCommittingSessionManager()
-                .findGlobalSession(tid);
+                .findGlobalSession(globalSession.getXid());
         Assertions.assertTrue(reloadSession == sessionInAsyncCommittingQueue);
 
         // No locking for session in AsyncCommitting status
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         //clear
         reloadSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
@@ -192,6 +205,9 @@ public class SessionStoreTest {
         SessionHolder.init("file");
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
 
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+
         globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         globalSession.begin();
 
@@ -200,9 +216,11 @@ public class SessionStoreTest {
         branchSession1.lock();
         globalSession.addBranch(branchSession1);
 
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager =  new MemoryLockManagerForTest();
+
+        String otherXID = XID.generateXID(0L);
 
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         globalSession.changeStatus(GlobalStatus.Committing);
         globalSession.changeBranchStatus(branchSession1, BranchStatus.PhaseTwo_CommitFailed_Retryable);
@@ -210,23 +228,23 @@ public class SessionStoreTest {
 
         lockManager.cleanAllLocks();
 
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         // Re-init SessionHolder: restore sessions from file
         SessionHolder.init("file");
 
         long tid = globalSession.getTransactionId();
-        GlobalSession reloadSession = SessionHolder.findGlobalSession(tid);
+        GlobalSession reloadSession = SessionHolder.findGlobalSession(globalSession.getXid());
         Assertions.assertEquals(reloadSession.getStatus(), GlobalStatus.CommitRetrying);
 
         GlobalSession sessionInRetryCommittingQueue = SessionHolder.getRetryCommittingSessionManager()
-                .findGlobalSession(tid);
+                .findGlobalSession(globalSession.getXid());
         Assertions.assertTrue(reloadSession == sessionInRetryCommittingQueue);
         BranchSession reloadBranchSession = reloadSession.getBranch(branchSession1.getBranchId());
         Assertions.assertEquals(reloadBranchSession.getStatus(), BranchStatus.PhaseTwo_CommitFailed_Retryable);
 
         // Lock is held by session in CommitRetrying status
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         //clear
         reloadSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
@@ -244,6 +262,9 @@ public class SessionStoreTest {
 
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
 
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+
         globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         globalSession.begin();
 
@@ -252,9 +273,11 @@ public class SessionStoreTest {
         branchSession1.lock();
         globalSession.addBranch(branchSession1);
 
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager =  new MemoryLockManagerForTest();
 
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        String otherXID = XID.generateXID(0L);
+
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         globalSession.changeStatus(GlobalStatus.Rollbacking);
         globalSession.changeBranchStatus(branchSession1, BranchStatus.PhaseTwo_RollbackFailed_Retryable);
@@ -262,23 +285,23 @@ public class SessionStoreTest {
 
         lockManager.cleanAllLocks();
 
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         // Re-init SessionHolder: restore sessions from file
         SessionHolder.init("file");
 
         long tid = globalSession.getTransactionId();
-        GlobalSession reloadSession = SessionHolder.findGlobalSession(tid);
+        GlobalSession reloadSession = SessionHolder.findGlobalSession(globalSession.getXid());
         Assertions.assertEquals(reloadSession.getStatus(), GlobalStatus.RollbackRetrying);
 
         GlobalSession sessionInRetryRollbackingQueue = SessionHolder.getRetryRollbackingSessionManager()
-                .findGlobalSession(tid);
+                .findGlobalSession(globalSession.getXid());
         Assertions.assertTrue(reloadSession == sessionInRetryRollbackingQueue);
         BranchSession reloadBranchSession = reloadSession.getBranch(branchSession1.getBranchId());
         Assertions.assertEquals(reloadBranchSession.getStatus(), BranchStatus.PhaseTwo_RollbackFailed_Retryable);
 
         // Lock is held by session in RollbackRetrying status
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         //clear
         reloadSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
@@ -296,6 +319,9 @@ public class SessionStoreTest {
 
         GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
 
+        String xid = XID.generateXID(globalSession.getTransactionId());
+        globalSession.setXid(xid);
+
         globalSession.addSessionLifecycleListener(SessionHolder.getRootSessionManager());
         globalSession.begin();
 
@@ -304,26 +330,28 @@ public class SessionStoreTest {
         branchSession1.lock();
         globalSession.addBranch(branchSession1);
 
-        LockManager lockManager = LockManagerFactory.get();
+        LockManager lockManager =  new MemoryLockManagerForTest();
+
+        String otherXID = XID.generateXID(0L);
 
-        Assertions.assertFalse(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertFalse(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         globalSession.changeStatus(GlobalStatus.Rollbacking);
         globalSession.changeBranchStatus(branchSession1, BranchStatus.PhaseTwo_CommitFailed_Unretryable);
         SessionHelper.endRollbackFailed(globalSession);
 
         // Lock is released.
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         lockManager.cleanAllLocks();
 
-        Assertions.assertTrue(lockManager.isLockable(0L, RESOURCE_ID, "ta:1"));
+        Assertions.assertTrue(lockManager.isLockable(otherXID, RESOURCE_ID, "ta:1"));
 
         // Re-init SessionHolder: restore sessions from file
         SessionHolder.init("file");
 
         long tid = globalSession.getTransactionId();
-        GlobalSession reloadSession = SessionHolder.findGlobalSession(tid);
+        GlobalSession reloadSession = SessionHolder.findGlobalSession(globalSession.getXid());
         Assertions.assertNull(reloadSession);
     }
 }
diff --git a/tcc/src/main/java/io/seata/rm/tcc/TwoPhaseResult.java b/tcc/src/main/java/io/seata/rm/tcc/TwoPhaseResult.java
index dddd5e83c298988078a93667b5fef3c55bd8111b..0fe6860eb5aa082c77c240ad55048e459c94fa9d 100644
--- a/tcc/src/main/java/io/seata/rm/tcc/TwoPhaseResult.java
+++ b/tcc/src/main/java/io/seata/rm/tcc/TwoPhaseResult.java
@@ -17,9 +17,6 @@ package io.seata.rm.tcc;
 
 import io.seata.common.util.StringUtils;
 
-import java.util.HashMap;
-import java.util.Map;
-
 /**
  * the TCC method result
  *
diff --git a/tcc/src/main/java/io/seata/rm/tcc/remoting/RemotingParser.java b/tcc/src/main/java/io/seata/rm/tcc/remoting/RemotingParser.java
index a4cda53d59a97dda60acd3da5d7884149d707271..2ff32ca49801977613dfef0b431ea28ea77c8583 100644
--- a/tcc/src/main/java/io/seata/rm/tcc/remoting/RemotingParser.java
+++ b/tcc/src/main/java/io/seata/rm/tcc/remoting/RemotingParser.java
@@ -17,8 +17,6 @@ package io.seata.rm.tcc.remoting;
 
 import io.seata.common.exception.FrameworkException;
 
-import java.lang.reflect.InvocationTargetException;
-
 /**
  * extract remoting bean info
  *
diff --git a/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java b/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java
index d07050c5f348870ddfbbb102996221750c6214b7..c4764df599cf4d50f81aa601951d42104019b26b 100644
--- a/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java
+++ b/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java
@@ -20,7 +20,6 @@ import io.seata.common.util.ReflectionUtil;
 import io.seata.rm.tcc.api.LocalTCC;
 import io.seata.rm.tcc.remoting.Protocols;
 import io.seata.rm.tcc.remoting.RemotingDesc;
-import io.seata.rm.tcc.remoting.RemotingDesc;
 
 import java.util.Set;
 
diff --git a/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/SofaRpcRemotingParser.java b/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/SofaRpcRemotingParser.java
index ff1cc8349cfb0fc0eb226a8706c75857dc6aeac6..8af247f16f16dc55a4521cb5c2433b9bb6033b0d 100644
--- a/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/SofaRpcRemotingParser.java
+++ b/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/SofaRpcRemotingParser.java
@@ -19,8 +19,6 @@ import io.seata.common.exception.FrameworkException;
 import io.seata.common.util.ReflectionUtil;
 import io.seata.rm.tcc.remoting.Protocols;
 import io.seata.rm.tcc.remoting.RemotingDesc;
-import io.seata.rm.tcc.remoting.Protocols;
-import io.seata.rm.tcc.remoting.RemotingDesc;
 
 /**
  * sofa-rpc remoting bean parsing
diff --git a/test/src/test/java/io/seata/core/rpc/netty/TmRpcClientTest.java b/test/src/test/java/io/seata/core/rpc/netty/TmRpcClientTest.java
index dc5682b9b10f6ee89d182b0d85f97ee162bfb0a3..9f3a192b98fafcc2a4b3ce7e1d908d4458f2f51a 100644
--- a/test/src/test/java/io/seata/core/rpc/netty/TmRpcClientTest.java
+++ b/test/src/test/java/io/seata/core/rpc/netty/TmRpcClientTest.java
@@ -20,9 +20,6 @@ import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
-import io.seata.core.protocol.ResultCode;
-import io.seata.core.protocol.transaction.BranchRegisterRequest;
-import io.seata.core.protocol.transaction.BranchRegisterResponse;
 import io.seata.server.UUIDGenerator;
 import io.seata.server.coordinator.DefaultCoordinator;
 
diff --git a/test/src/test/resources/file.conf b/test/src/test/resources/file.conf
index 30801f29901834757ef6e68d5fbf6c4b1486a975..65573b25b31e86f066fcba04882ad8b1afb8488d 100644
--- a/test/src/test/resources/file.conf
+++ b/test/src/test/resources/file.conf
@@ -70,3 +70,7 @@ client {
   }
   report.retry.count = 5
 }
+
+transaction {
+  undo.data.validation = true
+}
\ No newline at end of file
diff --git a/test/src/test/resources/registry.conf b/test/src/test/resources/registry.conf
index 1cddea7219444a8f50ee5bdc7f7170de40884356..5115876d916fa5e59a5511796e5cc92622f5a442 100644
--- a/test/src/test/resources/registry.conf
+++ b/test/src/test/resources/registry.conf
@@ -45,7 +45,7 @@ registry {
 }
 
 config {
-  # file、nacos 、apollo、zk、consul
+  # file、nacos 、apollo、zk、consul、etcd3
   type = "file"
 
   nacos {
@@ -65,7 +65,10 @@ config {
     session.timeout = 6000
     connect.timeout = 2000
   }
+  etcd3 {
+    serverAddr = "http://localhost:2379"
+  }
   file {
     name = "file.conf"
   }
-}
+}
\ No newline at end of file
diff --git a/tm/src/main/java/io/seata/tm/TransactionManagerHolder.java b/tm/src/main/java/io/seata/tm/TransactionManagerHolder.java
index f4deba4aaf08507ee8f31d9706f8519bd3681f1c..9833634c61f28dc70623850b448c7039148c9212 100644
--- a/tm/src/main/java/io/seata/tm/TransactionManagerHolder.java
+++ b/tm/src/main/java/io/seata/tm/TransactionManagerHolder.java
@@ -17,16 +17,10 @@ package io.seata.tm;
 
 import io.seata.common.exception.ShouldNeverHappenException;
 import io.seata.common.loader.EnhancedServiceLoader;
-import io.seata.core.exception.TransactionException;
-import io.seata.core.exception.TransactionExceptionCode;
-import io.seata.core.model.GlobalStatus;
 import io.seata.core.model.TransactionManager;
-import io.seata.core.protocol.transaction.*;
-import io.seata.core.rpc.netty.TmRpcClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.concurrent.TimeoutException;
 
 /**
  * The type Default transaction manager.
diff --git a/tm/src/main/java/io/seata/tm/api/DefaultGlobalTransaction.java b/tm/src/main/java/io/seata/tm/api/DefaultGlobalTransaction.java
index 2736c79d28228478ae3e36e46e09621f91378b3f..78e85d66e7535f51bf581d6de0099613a145f695 100644
--- a/tm/src/main/java/io/seata/tm/api/DefaultGlobalTransaction.java
+++ b/tm/src/main/java/io/seata/tm/api/DefaultGlobalTransaction.java
@@ -20,7 +20,6 @@ import io.seata.core.context.RootContext;
 import io.seata.core.exception.TransactionException;
 import io.seata.core.model.GlobalStatus;
 import io.seata.core.model.TransactionManager;
-import io.seata.tm.DefaultTransactionManager;
 import io.seata.tm.TransactionManagerHolder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;