Repository: alibaba/fescar
Pull request #294 (2019-01-25 10:51:16)

release 0.1.2
<!-- Please make sure you have read and understood the contributing guidelines -->

### Ⅰ. Describe what this PR did
release 0.1.2

### Ⅱ. Does this pull request fix one issue?


### Ⅲ. Why don't you add test cases (unit test/integration test)? 


### Ⅳ. Describe how to verify it


### Ⅴ. Special notes for reviews




Patch:
diff --git a/changeVersion.sh b/changeVersion.sh
new file mode 100644
index 000000000..6a2347f19
--- /dev/null
+++ b/changeVersion.sh
@@ -0,0 +1,5 @@
+echo "./changeVersion.sh oldVersion newVersion"
+echo $1
+echo $2
+find ./ -name pom.xml | grep -v target | xargs perl -pi -e "s|$1|$2|g"
+#find ./ -name Version.java | grep -v target | xargs perl -pi -e "s|$1|$2|g"
\ No newline at end of file
diff --git a/common/pom.xml b/common/pom.xml
index ff9f6b10b..226fccd89 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-common</artifactId>
diff --git a/config/pom.xml b/config/pom.xml
index 4c72a14d3..13ca41633 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-config</artifactId>
@@ -51,6 +51,12 @@
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 </project>
diff --git a/config/src/main/java/com/alibaba/fescar/config/ConfigChangeListener.java b/config/src/main/java/com/alibaba/fescar/config/ConfigChangeListener.java
index a491f7e6e..a7073ecd2 100644
--- a/config/src/main/java/com/alibaba/fescar/config/ConfigChangeListener.java
+++ b/config/src/main/java/com/alibaba/fescar/config/ConfigChangeListener.java
@@ -16,7 +16,7 @@
 
 package com.alibaba.fescar.config;
 
-import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
 
 /**
  * The interface Config change listener.
@@ -34,7 +34,7 @@ public interface ConfigChangeListener {
      *
      * @return the executor
      */
-    Executor getExecutor();
+    ExecutorService getExecutor();
 
     /**
      * Receive config info.
diff --git a/config/src/main/java/com/alibaba/fescar/config/Configuration.java b/config/src/main/java/com/alibaba/fescar/config/Configuration.java
index 76cabd738..1d4ae232e 100644
--- a/config/src/main/java/com/alibaba/fescar/config/Configuration.java
+++ b/config/src/main/java/com/alibaba/fescar/config/Configuration.java
@@ -16,11 +16,13 @@
 
 package com.alibaba.fescar.config;
 
+import java.util.List;
+
 /**
  * The interface Configuration.
  *
  * @Author: jimin.jm @alibaba-inc.com
- * @Project: fescar-all
+ * @Project: fescar -all
  * @DateTime: 2018 /12/20 14:22
  * @FileName: Configuration
  * @Description:
@@ -215,4 +217,12 @@ public interface Configuration {
      */
     void removeConfigListener(String dataId, ConfigChangeListener listener);
 
+    /**
+     * Gets config listeners.
+     *
+     * @param dataId the data id
+     * @return the config listeners
+     */
+    List<ConfigChangeListener> getConfigListeners(String dataId);
+
 }
diff --git a/config/src/main/java/com/alibaba/fescar/config/FileConfiguration.java b/config/src/main/java/com/alibaba/fescar/config/FileConfiguration.java
index 0e30681b9..0a28e7f82 100644
--- a/config/src/main/java/com/alibaba/fescar/config/FileConfiguration.java
+++ b/config/src/main/java/com/alibaba/fescar/config/FileConfiguration.java
@@ -16,6 +16,11 @@
 
 package com.alibaba.fescar.config;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+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;
@@ -33,7 +38,7 @@ import org.slf4j.LoggerFactory;
  * The type FileConfiguration.
  *
  * @Author: jimin.jm @alibaba-inc.com
- * @Project: fescar-all
+ * @Project: fescar -all
  * @DateTime: 2018 /9/10 11:34
  * @FileName: FileConfiguration
  * @Description:
@@ -46,19 +51,33 @@ public class FileConfiguration implements Configuration {
 
     private ExecutorService configOperateExecutor;
 
+    private ExecutorService configChangeExecutor;
+
     private static final int CORE_CONFIG_OPERATE_THREAD = 1;
 
+    private static final int CORE_CONFIG_CHANGE_THREAD = 1;
+
     private static final int MAX_CONFIG_OPERATE_THREAD = 2;
 
     private static final long DEFAULT_CONFIG_TIMEOUT = 5 * 1000;
 
+    private static final long LISTENER_CONFIG_INTERNAL = 1 * 1000;
+
+    private final ConcurrentMap<String, List<ConfigChangeListener>> configListenersMap = new ConcurrentHashMap<>();
+
+    private final ConcurrentMap<String, String> listenedConfigMap = new ConcurrentHashMap<>();
+
     /**
      * Instantiates a new File configuration.
      */
     public FileConfiguration() {
         configOperateExecutor = new ThreadPoolExecutor(CORE_CONFIG_OPERATE_THREAD, MAX_CONFIG_OPERATE_THREAD,
             Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
-            new NamedThreadFactory("configOperate", MAX_CONFIG_OPERATE_THREAD, true));
+            new NamedThreadFactory("configOperate", MAX_CONFIG_OPERATE_THREAD));
+        configChangeExecutor = new ThreadPoolExecutor(CORE_CONFIG_CHANGE_THREAD, CORE_CONFIG_CHANGE_THREAD,
+            Integer.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(),
+            new NamedThreadFactory("configChange", CORE_CONFIG_CHANGE_THREAD));
+        configChangeExecutor.submit(new ConfigChangeRunnable());
     }
 
     @Override
@@ -113,7 +132,7 @@ public class FileConfiguration implements Configuration {
     public String getConfig(String dataId, String defaultValue, long timeoutMills) {
         ConfigFuture configFuture = new ConfigFuture(dataId, defaultValue, ConfigOperation.GET, timeoutMills);
         configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
-        return (String)configFuture.get();
+        return (String)configFuture.get(timeoutMills, TimeUnit.MILLISECONDS);
     }
 
     @Override
@@ -147,7 +166,7 @@ public class FileConfiguration implements Configuration {
     public boolean putConfigIfAbsent(String dataId, String content, long timeoutMills) {
         ConfigFuture configFuture = new ConfigFuture(dataId, content, ConfigOperation.PUTIFABSENT, timeoutMills);
         configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
-        return (Boolean)configFuture.get();
+        return (Boolean)configFuture.get(timeoutMills, TimeUnit.MILLISECONDS);
     }
 
     @Override
@@ -159,7 +178,7 @@ public class FileConfiguration implements Configuration {
     public boolean removeConfig(String dataId, long timeoutMills) {
         ConfigFuture configFuture = new ConfigFuture(dataId, null, ConfigOperation.REMOVE, timeoutMills);
         configOperateExecutor.submit(new ConfigOperateRunnable(configFuture));
-        return (Boolean)configFuture.get();
+        return (Boolean)configFuture.get(timeoutMills, TimeUnit.MILLISECONDS);
     }
 
     @Override
@@ -169,12 +188,36 @@ public class FileConfiguration implements Configuration {
 
     @Override
     public void addConfigListener(String dataId, ConfigChangeListener listener) {
-
+        configListenersMap.putIfAbsent(dataId, new ArrayList<ConfigChangeListener>());
+        configListenersMap.get(dataId).add(listener);
+        if (null != listener.getExecutor()) {
+            ConfigChangeRunnable configChangeTask = new ConfigChangeRunnable(dataId, listener);
+            listener.getExecutor().submit(configChangeTask);
+        }
     }
 
     @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();
+        }
+
+    }
 
+    @Override
+    public List<ConfigChangeListener> getConfigListeners(String dataId) {
+        return configListenersMap.get(dataId);
     }
 
     /**
@@ -198,6 +241,7 @@ public class FileConfiguration implements Configuration {
             if (null != configFuture) {
                 if (configFuture.isTimeout()) {
                     setFailResult(configFuture);
+                    return;
                 }
                 if (configFuture.getOperation() == ConfigOperation.GET) {
                     String result = CONFIG.getString(configFuture.getDataId());
@@ -226,4 +270,81 @@ public class FileConfiguration implements Configuration {
 
     }
 
+    /**
+     * The type Config change runnable.
+     */
+    class ConfigChangeRunnable implements Runnable {
+
+        private String dataId;
+        private ConfigChangeListener listener;
+
+        /**
+         * Instantiates a new Config change runnable.
+         */
+        public ConfigChangeRunnable() {}
+
+        /**
+         * Instantiates a new Config change runnable.
+         *
+         * @param dataId   the data id
+         * @param listener the listener
+         */
+        public ConfigChangeRunnable(String dataId, ConfigChangeListener listener) {
+
+            if (null == listener.getExecutor()) {
+                throw new IllegalArgumentException("getExecutor is null.");
+            }
+            this.dataId = dataId;
+            this.listener = listener;
+        }
+
+        @Override
+        public void run() {
+            while (true) {
+                try {
+                    Map<String, List<ConfigChangeListener>> configListenerMap;
+                    if (null != dataId && null != listener) {
+                        configListenerMap = new ConcurrentHashMap<>();
+                        configListenerMap.put(dataId, new ArrayList<ConfigChangeListener>());
+                        configListenerMap.get(dataId).add(listener);
+                    } else {
+                        configListenerMap = configListenersMap;
+                    }
+                    for (Map.Entry<String, List<ConfigChangeListener>> entry : configListenerMap.entrySet()) {
+                        String configId = entry.getKey();
+                        String currentConfig = getConfig(configId);
+                        if (null != currentConfig && currentConfig.equals(listenedConfigMap.get(configId))) {
+                            listenedConfigMap.put(configId, currentConfig);
+                            notifyAllListener(configId, configListenerMap.get(configId));
+
+                        } else if (null == currentConfig && null != listenedConfigMap.get(configId)) {
+                            notifyAllListener(configId, configListenerMap.get(configId));
+                        }
+                    }
+                    Thread.sleep(LISTENER_CONFIG_INTERNAL);
+                } catch (Exception exx) {
+                    LOGGER.error(exx.getMessage());
+                }
+
+            }
+        }
+
+        private void notifyAllListener(String dataId, List<ConfigChangeListener> configChangeListeners) {
+            List<ConfigChangeListener> needNotifyListeners = new ArrayList<>();
+            if (null != dataId && null != listener) {
+                needNotifyListeners.addAll(configChangeListeners);
+            } else {
+                for (ConfigChangeListener configChangeListener : configChangeListeners) {
+                    if (null == configChangeListener.getExecutor()) {
+                        needNotifyListeners.add(configChangeListener);
+                    }
+                }
+            }
+            for (ConfigChangeListener configChangeListener : needNotifyListeners) {
+                configChangeListener.receiveConfigInfo(listenedConfigMap.get(dataId));
+            }
+        }
+
+    }
+
 }
diff --git a/core/pom.xml b/core/pom.xml
index 3fee8593e..42434e308 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-core</artifactId>
@@ -57,6 +57,11 @@
             <groupId>commons-pool</groupId>
             <artifactId>commons-pool</artifactId>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <extensions>
diff --git a/core/src/main/java/com/alibaba/fescar/core/exception/TransactionExceptionCode.java b/core/src/main/java/com/alibaba/fescar/core/exception/TransactionExceptionCode.java
index 6a320b70f..903789edc 100644
--- a/core/src/main/java/com/alibaba/fescar/core/exception/TransactionExceptionCode.java
+++ b/core/src/main/java/com/alibaba/fescar/core/exception/TransactionExceptionCode.java
@@ -16,6 +16,9 @@
 
 package com.alibaba.fescar.core.exception;
 
+import java.util.HashMap;
+import java.util.Map;
+
 public enum TransactionExceptionCode {
 
     //
@@ -66,17 +69,26 @@ public enum TransactionExceptionCode {
 
     ;
 
+    private static final Map<Integer, TransactionExceptionCode> MAP = new HashMap<>(values().length);
+
+    static {
+        for (TransactionExceptionCode code : values()) {
+            MAP.put(code.ordinal(), code);
+        }
+    }
 
     public static TransactionExceptionCode get(byte ordinal) {
         return get((int) ordinal);
     }
+
     public static TransactionExceptionCode get(int ordinal) {
-        for (TransactionExceptionCode value : TransactionExceptionCode.values()) {
-            if (value.ordinal() == ordinal) {
-                return value;
-            }
+        TransactionExceptionCode code = MAP.get(ordinal);
+
+        if (null == code) {
+            throw new IllegalArgumentException("Unknown TransactionExceptionCode[" + ordinal + "]");
         }
-        throw new IllegalArgumentException("Unknown TransactionExceptionCode[" + ordinal + "]");
+
+        return code;
     }
 
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/model/BranchStatus.java b/core/src/main/java/com/alibaba/fescar/core/model/BranchStatus.java
index c6774651b..a3d0d1412 100644
--- a/core/src/main/java/com/alibaba/fescar/core/model/BranchStatus.java
+++ b/core/src/main/java/com/alibaba/fescar/core/model/BranchStatus.java
@@ -16,11 +16,11 @@
 
 package com.alibaba.fescar.core.model;
 
-import com.alibaba.fescar.common.exception.ShouldNeverHappenException;
-
 import java.util.HashMap;
 import java.util.Map;
 
+import com.alibaba.fescar.common.exception.ShouldNeverHappenException;
+
 /**
  * Status of branch transaction.
  */
@@ -59,11 +59,11 @@ public enum BranchStatus {
     // Rollback logic is failed but NOT retryable.
     PhaseTwo_RollbackFailed_Unretryable;
 
-    private static final Map<Integer, BranchStatus> map = new HashMap<>(values().length);
+    private static final Map<Integer, BranchStatus> MAP = new HashMap<>(values().length);
 
     static {
         for (BranchStatus status : values()) {
-            map.put(status.ordinal(), status);
+            MAP.put(status.ordinal(), status);
         }
     }
 
@@ -72,7 +72,7 @@ public enum BranchStatus {
     }
 
     public static BranchStatus get(int ordinal) {
-        BranchStatus status = map.get(ordinal);
+        BranchStatus status = MAP.get(ordinal);
 
         if (null == status) {
             throw new ShouldNeverHappenException("Unknown BranchStatus[" + ordinal + "]");
diff --git a/core/src/main/java/com/alibaba/fescar/core/model/GlobalStatus.java b/core/src/main/java/com/alibaba/fescar/core/model/GlobalStatus.java
index 30e5b42ac..ef9b3ba33 100644
--- a/core/src/main/java/com/alibaba/fescar/core/model/GlobalStatus.java
+++ b/core/src/main/java/com/alibaba/fescar/core/model/GlobalStatus.java
@@ -16,6 +16,9 @@
 
 package com.alibaba.fescar.core.model;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Status of global transaction.
  */
@@ -69,19 +72,28 @@ public enum GlobalStatus {
     // Finally: failed to rollback since timeout
     TimeoutRollbackFailed,
 
-    // Not managed in session map any more
+    // Not managed in session MAP any more
     Finished;
 
+    private static final Map<Integer, GlobalStatus> MAP = new HashMap<>(values().length);
+
+    static {
+        for (GlobalStatus status : values()) {
+            MAP.put(status.ordinal(), status);
+        }
+    }
+
     public static GlobalStatus get(byte ordinal) {
         return get((int) ordinal);
     }
 
     public static GlobalStatus get(int ordinal) {
-        for (GlobalStatus globalStatus : GlobalStatus.values()) {
-            if (globalStatus.ordinal() == ordinal) {
-                return globalStatus;
-            }
+        GlobalStatus status = MAP.get(ordinal);
+
+        if (null == status) {
+            throw new IllegalArgumentException("Unknown GlobalStatus[" + ordinal + "]");
         }
-        throw new IllegalArgumentException("Unknown GlobalStatus[" + ordinal + "]");
+
+        return status;
     }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractMessage.java b/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractMessage.java
index 55adca3bc..019415caf 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractMessage.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/AbstractMessage.java
@@ -115,21 +115,22 @@ public abstract class AbstractMessage implements MessageCodec, Serializable {
                 msgCodec = new BranchRollbackRequest();
                 break;
             default:
-                msgCodec = null;
                 break;
         }
+
         if (null != msgCodec) {
             return msgCodec;
-        } else {
-            try {
-                msgCodec = (MessageCodec)getMergeRequestInstanceByCode(typeCode);
-            } catch (Exception exx) {}
-            if (null != msgCodec) {
-                return msgCodec;
-            } else {
-                return (MessageCodec)getMergeResponseInstanceByCode(typeCode);
-            }
         }
+
+        try {
+            msgCodec = (MessageCodec) getMergeRequestInstanceByCode(typeCode);
+        } catch (Exception exx) {}
+
+        if (null != msgCodec) {
+            return msgCodec;
+        }
+
+        return (MessageCodec) getMergeResponseInstanceByCode(typeCode);
     }
 
     public static MergedMessage getMergeRequestInstanceByCode(int typeCode) {
@@ -149,7 +150,7 @@ public abstract class AbstractMessage implements MessageCodec, Serializable {
             case AbstractMessage.TYPE_BRANCH_STATUS_REPORT:
                 return new BranchReportRequest();
             default:
-                throw new RuntimeException("not support typeCode," + typeCode);
+                throw new IllegalArgumentException("not support typeCode," + typeCode);
         }
     }
 
@@ -174,7 +175,7 @@ public abstract class AbstractMessage implements MessageCodec, Serializable {
             case AbstractMessage.TYPE_BRANCH_ROLLBACK_RESULT:
                 return new BranchRollbackResponse();
             default:
-                throw new RuntimeException("not support typeCode," + typeCode);
+                throw new IllegalArgumentException("not support typeCode," + typeCode);
         }
     }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java b/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
index 8ec8c7725..e6d963aa9 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/Version.java
@@ -16,15 +16,16 @@
 
 package com.alibaba.fescar.core.protocol;
 
-import com.alibaba.fescar.common.util.NetUtil;
-import io.netty.channel.Channel;
-
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
+import com.alibaba.fescar.common.util.NetUtil;
+
+import io.netty.channel.Channel;
+
 public class Version {
 
-    public static final String CURRENT = "0.1.0";
+    public static final String CURRENT = "0.1.2";
 
     public static final Map<String, String> VERSION_MAP = new ConcurrentHashMap<String, String>();
 
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndRequest.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndRequest.java
index e1385d587..d74e297ef 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndRequest.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndRequest.java
@@ -170,4 +170,25 @@ public abstract class AbstractBranchEndRequest extends AbstractTransactionReques
 
         return true;
     }
+    
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("xid=");
+        result.append(xid);
+        result.append(",");
+        result.append("branchId=");
+        result.append(branchId);
+        result.append(",");
+        result.append("branchType=");
+        result.append(branchType);
+        result.append(",");
+        result.append("resourceId=");
+        result.append(resourceId);
+        result.append(",");
+        result.append("applicationData=");
+        result.append(applicationData);
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndResponse.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndResponse.java
index 7eb79ab06..d77f14b27 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndResponse.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractBranchEndResponse.java
@@ -55,4 +55,19 @@ public abstract class AbstractBranchEndResponse extends AbstractTransactionRespo
         branchStatus = BranchStatus.get(in.readByte());
         return true;
     }
+    
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("branchStatus=");
+        result.append(branchStatus);
+        result.append(",");
+        result.append("result code =");
+        result.append(getResultCode());
+        result.append(",");
+        result.append("getMsg =");
+        result.append(getMsg());
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndRequest.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndRequest.java
index be008e279..a57f23809 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndRequest.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndRequest.java
@@ -72,4 +72,16 @@ public abstract class AbstractGlobalEndRequest extends AbstractTransactionReques
             this.setExtraData(new String(bs, UTF8));
         }
     }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("transactionId=");
+        result.append(transactionId);
+        result.append(",");
+        result.append("extraData=");
+        result.append(extraData);
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndResponse.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndResponse.java
index 28767a384..e2036654d 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndResponse.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/AbstractGlobalEndResponse.java
@@ -45,4 +45,18 @@ public abstract class AbstractGlobalEndResponse extends AbstractTransactionRespo
         globalStatus = GlobalStatus.get(byteBuffer.get());
     }
 
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("globalStatus=");
+        result.append(globalStatus);
+        result.append(",");
+        result.append("ResultCode=");
+        result.append(getResultCode());
+        result.append(",");
+        result.append("Msg=");
+        result.append(getMsg());
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterRequest.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterRequest.java
index dc0509dd2..f17f21a49 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterRequest.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchRegisterRequest.java
@@ -136,4 +136,22 @@ public class BranchRegisterRequest extends AbstractTransactionRequestToTC implem
     public AbstractTransactionResponse handle(RpcContext rpcContext) {
         return handler.handle(this, rpcContext);
     }
+    
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("transactionId=");
+        result.append(transactionId);
+        result.append(",");
+        result.append("branchType=");
+        result.append(branchType);
+        result.append(",");
+        result.append("resourceId=");
+        result.append(resourceId);
+        result.append(",");
+        result.append("lockKey=");
+        result.append(lockKey);
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchReportRequest.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchReportRequest.java
index 4fdc53cc3..974e17ab7 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchReportRequest.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/BranchReportRequest.java
@@ -146,4 +146,25 @@ public class BranchReportRequest extends AbstractTransactionRequestToTC implemen
     public AbstractTransactionResponse handle(RpcContext rpcContext) {
         return handler.handle(this, rpcContext);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("transactionId=");
+        result.append(transactionId);
+        result.append(",");
+        result.append("branchId=");
+        result.append(branchId);
+        result.append(",");
+        result.append("resourceId=");
+        result.append(resourceId);
+        result.append(",");
+        result.append("status=");
+        result.append(status);
+        result.append(",");
+        result.append("applicationData=");
+        result.append(applicationData);
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginRequest.java b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginRequest.java
index c6f4d6faa..64d6e4309 100644
--- a/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginRequest.java
+++ b/core/src/main/java/com/alibaba/fescar/core/protocol/transaction/GlobalBeginRequest.java
@@ -87,4 +87,16 @@ public class GlobalBeginRequest extends AbstractTransactionRequestToTC implement
     public AbstractTransactionResponse handle(RpcContext rpcContext) {
         return handler.handle(this, rpcContext);
     }
+
+    @Override
+    public String toString() {
+        StringBuilder result = new StringBuilder();
+        result.append("timeout=");
+        result.append(timeout);
+        result.append(",");
+        result.append("transactionName=");
+        result.append(transactionName);
+
+        return result.toString();
+    }
 }
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/DefaultServerMessageListenerImpl.java b/core/src/main/java/com/alibaba/fescar/core/rpc/DefaultServerMessageListenerImpl.java
index 58a8917a9..c92e8c5b3 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/DefaultServerMessageListenerImpl.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/DefaultServerMessageListenerImpl.java
@@ -24,8 +24,16 @@ import java.util.concurrent.TimeUnit;
 
 import com.alibaba.fescar.common.thread.NamedThreadFactory;
 import com.alibaba.fescar.common.util.NetUtil;
-import com.alibaba.fescar.core.protocol.*;
+import com.alibaba.fescar.core.protocol.AbstractMessage;
+import com.alibaba.fescar.core.protocol.AbstractResultMessage;
+import com.alibaba.fescar.core.protocol.HeartbeatMessage;
+import com.alibaba.fescar.core.protocol.MergeResultMessage;
+import com.alibaba.fescar.core.protocol.MergedWarpMessage;
+import com.alibaba.fescar.core.protocol.RegisterRMRequest;
+import com.alibaba.fescar.core.protocol.RegisterRMResponse;
 import com.alibaba.fescar.core.protocol.RegisterTMRequest;
+import com.alibaba.fescar.core.protocol.RegisterTMResponse;
+import com.alibaba.fescar.core.protocol.Version;
 import com.alibaba.fescar.core.rpc.netty.RegisterCheckAuthHandler;
 
 import io.netty.channel.ChannelHandlerContext;
@@ -94,8 +102,7 @@ public class DefaultServerMessageListenerImpl implements ServerMessageListener {
 
         boolean isSuccess = false;
         try {
-            if (null == checkAuthHandler || null != checkAuthHandler && checkAuthHandler.regResourceManagerCheckAuth(
-                message)) {
+            if (null == checkAuthHandler || checkAuthHandler.regResourceManagerCheckAuth(message)) {
                 ChannelManager.registerRMChannel(message, ctx.channel());
                 Version.putChannelVersion(ctx.channel(), message.getVersion());
                 isSuccess = true;
@@ -117,8 +124,7 @@ public class DefaultServerMessageListenerImpl implements ServerMessageListener {
         Version.putChannelVersion(ctx.channel(), message.getVersion());
         boolean isSuccess = false;
         try {
-            if (null == checkAuthHandler || null != checkAuthHandler && checkAuthHandler.regTransactionManagerCheckAuth(
-                message)) {
+            if (null == checkAuthHandler || checkAuthHandler.regTransactionManagerCheckAuth(message)) {
                 ChannelManager.registerTMChannel(message, ctx.channel());
                 Version.putChannelVersion(ctx.channel(), message.getVersion());
                 isSuccess = true;
diff --git a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemoting.java b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemoting.java
index 60bff51f2..6e8a0441b 100644
--- a/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemoting.java
+++ b/core/src/main/java/com/alibaba/fescar/core/rpc/netty/AbstractRpcRemoting.java
@@ -96,7 +96,7 @@ public abstract class AbstractRpcRemoting extends ChannelDuplexHandler {
     /**
      * The Is sending.
      */
-    protected boolean isSending = false;
+    protected volatile boolean isSending = false;
     private String group = "DEFAULT";
     /**
      * The Merge msg map.
diff --git a/distribution/pom.xml b/distribution/pom.xml
index a30f541a4..be83dd713 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-distribution</artifactId>
diff --git a/dubbo/pom.xml b/dubbo/pom.xml
index 0ac14dcdd..aef91b54a 100644
--- a/dubbo/pom.xml
+++ b/dubbo/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-dubbo</artifactId>
diff --git a/examples/pom.xml b/examples/pom.xml
index 6cec39167..2c77d7eeb 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-examples</artifactId>
@@ -47,6 +47,10 @@
             <groupId>${project.groupId}</groupId>
             <artifactId>fescar-dubbo</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.101tec</groupId>
+            <artifactId>zkclient</artifactId>
+        </dependency>
         <dependency>
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java
index 32db941b0..b646fbf1d 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java
+++ b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/AccountServiceImpl.java
@@ -17,7 +17,6 @@
 package com.alibaba.fescar.tm.dubbo.impl;
 
 import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.rm.RMClientAT;
 import com.alibaba.fescar.test.common.ApplicationKeeper;
 import com.alibaba.fescar.tm.dubbo.AccountService;
 import com.alibaba.fescar.tm.dubbo.OrderService;
@@ -52,13 +51,7 @@ public class AccountServiceImpl implements AccountService {
         LOGGER.info("Account Service End ... ");
     }
 
-    public static void main(String[] args) throws Throwable {
-
-        String applicationId = "dubbo-demo-account-service";
-        String txServiceGroup = "my_test_tx_group";
-
-        RMClientAT.init(applicationId, txServiceGroup);
-
+    public static void main(String[] args) {
         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"dubbo-account-service.xml"});
         context.getBean("service");
         JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java
index c86a245f7..e47ccd104 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java
+++ b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/BusinessServiceImpl.java
@@ -42,6 +42,7 @@ public class BusinessServiceImpl implements BusinessService {
     @Override
     @GlobalTransactional(timeoutMills = 300000, name = "dubbo-demo-tx")
     public void purchase(String userId, String commodityCode, int orderCount) {
+        LOGGER.info("purchase begin ... xid: " + RootContext.getXID());
         storageService.deduct(commodityCode, orderCount);
         orderService.create(userId, commodityCode, orderCount);
         throw new RuntimeException("xxx");
@@ -60,9 +61,6 @@ public class BusinessServiceImpl implements BusinessService {
         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
             new String[] {"dubbo-business.xml"});
         final BusinessService business = (BusinessService)context.getBean("business");
-
-        LOGGER.info("Main business begin ... xid: " + RootContext.getXID());
         business.purchase("U100001", "C00321", 2);
-        LOGGER.info("Main business end ... xid: " + RootContext.getXID());
     }
 }
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java
index 5bed819cb..e56b4cdd7 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java
+++ b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/OrderServiceImpl.java
@@ -21,7 +21,6 @@ import java.sql.PreparedStatement;
 import java.sql.SQLException;
 
 import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.rm.RMClientAT;
 import com.alibaba.fescar.test.common.ApplicationKeeper;
 import com.alibaba.fescar.tm.dubbo.AccountService;
 import com.alibaba.fescar.tm.dubbo.Order;
@@ -84,7 +83,7 @@ public class OrderServiceImpl implements OrderService {
             }
         }, keyHolder);
 
-        order.id = (long)keyHolder.getKey();
+        order.id = keyHolder.getKey().longValue();
 
         LOGGER.info("Order Service End ... Created " + order);
 
@@ -103,16 +102,10 @@ public class OrderServiceImpl implements OrderService {
         return 200 * orderCount;
     }
 
-    public static void main(String[] args) throws Throwable {
-
-        String applicationId = "dubbo-demo-order-service";
-        String txServiceGroup = "my_test_tx_group";
-
-        RMClientAT.init(applicationId, txServiceGroup);
+    public static void main(String[] args) {
 
         ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"dubbo-order-service.xml"});
         context.getBean("service");
-        JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
         new ApplicationKeeper(context).keep();
     }
 }
diff --git a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java
index 8f1839740..c1e403e37 100644
--- a/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java
+++ b/examples/src/main/java/com/alibaba/fescar/tm/dubbo/impl/StorageServiceImpl.java
@@ -17,7 +17,6 @@
 package com.alibaba.fescar.tm.dubbo.impl;
 
 import com.alibaba.fescar.core.context.RootContext;
-import com.alibaba.fescar.rm.RMClientAT;
 import com.alibaba.fescar.test.common.ApplicationKeeper;
 import com.alibaba.fescar.tm.dubbo.StorageService;
 
@@ -45,23 +44,20 @@ public class StorageServiceImpl implements StorageService {
     @Override
     public void deduct(String commodityCode, int count) {
         LOGGER.info("Storage Service Begin ... xid: " + RootContext.getXID());
-        LOGGER.info("Deducting inventory SQL: update storage_tbl set count = count - {} where commodity_code = {}",count,commodityCode);
+        LOGGER.info("Deducting inventory SQL: update storage_tbl set count = count - {} where commodity_code = {}",
+            count, commodityCode);
 
-        jdbcTemplate.update("update storage_tbl set count = count - ? where commodity_code = ?", new Object[] {count, commodityCode});
+        jdbcTemplate.update("update storage_tbl set count = count - ? where commodity_code = ?",
+            new Object[] {count, commodityCode});
         LOGGER.info("Storage Service End ... ");
 
     }
 
-    public static void main(String[] args) throws Throwable {
-
-        String applicationId = "dubbo-demo-storage-service";
-        String txServiceGroup = "my_test_tx_group";
-
-        RMClientAT.init(applicationId, txServiceGroup);
-
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"dubbo-storage-service.xml"});
+    public static void main(String[] args) {
+        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
+            new String[] {"dubbo-storage-service.xml"});
         context.getBean("service");
-        JdbcTemplate jdbcTemplate = (JdbcTemplate) context.getBean("jdbcTemplate");
+        JdbcTemplate jdbcTemplate = (JdbcTemplate)context.getBean("jdbcTemplate");
         jdbcTemplate.update("delete from storage_tbl where commodity_code = 'C00321'");
         jdbcTemplate.update("insert into storage_tbl(commodity_code, count) values ('C00321', 100)");
         new ApplicationKeeper(context).keep();
diff --git a/examples/src/main/resources/dubbo-account-service.xml b/examples/src/main/resources/dubbo-account-service.xml
index 23d37b104..0dfa2f942 100755
--- a/examples/src/main/resources/dubbo-account-service.xml
+++ b/examples/src/main/resources/dubbo-account-service.xml
@@ -16,16 +16,20 @@
   -->
 
 <beans xmlns="http://www.springframework.org/schema/beans"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
-    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations" value="classpath:jdbc.properties" />
+    </bean>
 
     <bean name="accountDataSource" class="com.alibaba.druid.pool.DruidDataSource"
           init-method="init" destroy-method="close">
-        <property name="url" value="jdbc:mysql://xxx:3306/demo"/>
-        <property name="username" value="xxx"/>
-        <property name="password" value="xxx"/>
-        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
+        <property name="url" value="${jdbc.account.url}"/>
+        <property name="username" value="${jdbc.account.username}"/>
+        <property name="password" value="${jdbc.account.password}"/>
+        <property name="driverClassName" value="${jdbc.account.driver}" />
         <property name="initialSize" value="0" />
         <property name="maxActive" value="180" />
         <property name="minIdle" value="0" />
@@ -52,6 +56,8 @@
 
     <dubbo:application name="dubbo-demo-account-service"  />
     <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />
+    <!--support zk-->
+    <!--dubbo:registry address="zookeeper://test.zk1.cc:1234?backup=test.zk2.cc:1234,test.zk3.cc:1234" /-->
     <dubbo:protocol name="dubbo" port="20881" />
     <dubbo:service interface="com.alibaba.fescar.tm.dubbo.AccountService" ref="service" timeout="10000"/>
 
diff --git a/examples/src/main/resources/dubbo-order-service.xml b/examples/src/main/resources/dubbo-order-service.xml
index 6497f8137..2effb83e9 100755
--- a/examples/src/main/resources/dubbo-order-service.xml
+++ b/examples/src/main/resources/dubbo-order-service.xml
@@ -18,14 +18,18 @@
 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
-       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations" value="classpath:jdbc.properties" />
+    </bean>
 
     <bean name="orderDataSource" class="com.alibaba.druid.pool.DruidDataSource"
           init-method="init" destroy-method="close">
-        <property name="url" value="jdbc:mysql://xxx:3306/demo"/>
-        <property name="username" value="xxx"/>
-        <property name="password" value="xxx"/>
-        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
+        <property name="url" value="${jdbc.order.url}"/>
+        <property name="username" value="${jdbc.order.username}"/>
+        <property name="password" value="${jdbc.order.password}"/>
+        <property name="driverClassName" value="${jdbc.order.driver}"/>
         <property name="initialSize" value="0"/>
         <property name="maxActive" value="180"/>
         <property name="minIdle" value="0"/>
@@ -52,6 +56,8 @@
 
     <dubbo:application name="dubbo-demo-order-service"/>
     <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false"/>
+    <!--support zk-->
+    <!--dubbo:registry address="zookeeper://test.zk1.cc:1234?backup=test.zk2.cc:1234,test.zk3.cc:1234" /-->
     <dubbo:protocol name="dubbo" port="20883"/>
     <dubbo:service interface="com.alibaba.fescar.tm.dubbo.OrderService" ref="service" timeout="10000"/>
 
diff --git a/examples/src/main/resources/dubbo-storage-service.xml b/examples/src/main/resources/dubbo-storage-service.xml
index ed8b32f9b..eb397d647 100755
--- a/examples/src/main/resources/dubbo-storage-service.xml
+++ b/examples/src/main/resources/dubbo-storage-service.xml
@@ -16,16 +16,20 @@
   -->
 
 <beans xmlns="http://www.springframework.org/schema/beans"
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
-    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
+
+    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+        <property name="locations" value="classpath:jdbc.properties" />
+    </bean>
 
     <bean name="storageDataSource" class="com.alibaba.druid.pool.DruidDataSource"
           init-method="init" destroy-method="close">
-        <property name="url" value="jdbc:mysql://xxx:3306/demo"/>
-        <property name="username" value="xxx"/>
-        <property name="password" value="xxx"/>
-        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
+        <property name="url" value="${jdbc.storage.url}"/>
+        <property name="username" value="${jdbc.storage.username}"/>
+        <property name="password" value="${jdbc.storage.password}"/>
+        <property name="driverClassName" value="${jdbc.storage.driver}"/>
         <property name="initialSize" value="0" />
         <property name="maxActive" value="180" />
         <property name="minIdle" value="0" />
@@ -52,6 +56,8 @@
 
     <dubbo:application name="dubbo-demo-storage-service"  />
     <dubbo:registry address="multicast://224.5.6.7:1234?unicast=false" />
+    <!--support zk-->
+    <!--dubbo:registry address="zookeeper://test.zk1.cc:1234?backup=test.zk2.cc:1234,test.zk3.cc:1234" /-->
     <dubbo:protocol name="dubbo" port="20882" />
     <dubbo:service interface="com.alibaba.fescar.tm.dubbo.StorageService" ref="service" timeout="10000"/>
 
diff --git a/examples/src/main/resources/jdbc.properties b/examples/src/main/resources/jdbc.properties
new file mode 100644
index 000000000..fd2002322
--- /dev/null
+++ b/examples/src/main/resources/jdbc.properties
@@ -0,0 +1,17 @@
+# account db config
+jdbc.account.url=jdbc:mysql://localhost:3306/fescar_demo
+jdbc.account.username=root
+jdbc.account.password=111111
+jdbc.account.driver=com.mysql.jdbc.Driver
+
+# storage db config
+jdbc.storage.url=jdbc:mysql://localhost:3306/fescar_demo
+jdbc.storage.username=root
+jdbc.storage.password=111111
+jdbc.storage.driver=com.mysql.jdbc.Driver
+
+# order db config
+jdbc.order.url=jdbc:mysql://localhost:3306/fescar_demo
+jdbc.order.username=root
+jdbc.order.password=111111
+jdbc.order.driver=com.mysql.jdbc.Driver
\ No newline at end of file
diff --git a/examples/src/main/resources/sql/dubbo_biz.sql b/examples/src/main/resources/sql/dubbo_biz.sql
new file mode 100644
index 000000000..98a760143
--- /dev/null
+++ b/examples/src/main/resources/sql/dubbo_biz.sql
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS `storage_tbl`;
+CREATE TABLE `storage_tbl` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `commodity_code` varchar(255) DEFAULT NULL,
+  `count` int(11) DEFAULT 0,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY (`commodity_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+DROP TABLE IF EXISTS `order_tbl`;
+CREATE TABLE `order_tbl` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` varchar(255) DEFAULT NULL,
+  `commodity_code` varchar(255) DEFAULT NULL,
+  `count` int(11) DEFAULT 0,
+  `money` int(11) DEFAULT 0,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+
+DROP TABLE IF EXISTS `account_tbl`;
+CREATE TABLE `account_tbl` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `user_id` varchar(255) DEFAULT NULL,
+  `money` int(11) DEFAULT 0,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/examples/src/main/resources/sql/undo_log.sql b/examples/src/main/resources/sql/undo_log.sql
new file mode 100644
index 000000000..bede844bf
--- /dev/null
+++ b/examples/src/main/resources/sql/undo_log.sql
@@ -0,0 +1,12 @@
+CREATE TABLE `undo_log` (
+  `id` bigint(20) NOT NULL AUTO_INCREMENT,
+  `branch_id` bigint(20) NOT NULL,
+  `xid` varchar(100) NOT NULL,
+  `rollback_info` longblob NOT NULL,
+  `log_status` int(11) NOT NULL,
+  `log_created` datetime NOT NULL,
+  `log_modified` datetime NOT NULL,
+  `ext` varchar(100) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `idx_unionkey` (`xid`,`branch_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3cf225acf..4000df523 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
 
     <groupId>com.alibaba.fescar</groupId>
     <artifactId>fescar-all</artifactId>
-    <version>0.1.0-SNAPSHOT</version>
+    <version>0.1.2-SNAPSHOT</version>
     <modules>
         <module>config</module>
         <module>common</module>
@@ -49,6 +49,30 @@
             <distribution>repo</distribution>
         </license>
     </licenses>
+    <developers>
+        <developer>
+            <id>Alibaba Fescar</id>
+            <name>Fescar</name>
+            <url>http://fescar.io</url>
+        </developer>
+    </developers>
+
+    <organization>
+        <name>Alibaba Group</name>
+        <url>https://github.com/alibaba</url>
+    </organization>
+
+    <issueManagement>
+        <system>github</system>
+        <url>https://github.com/alibaba/fescar/issues</url>
+    </issueManagement>
+
+    <scm>
+        <url>git@github.com:alibaba/fescar.git</url>
+        <connection>scm:git@github.com:alibaba/fescar.git</connection>
+        <developerConnection>scm:git@github.com:alibaba/fescar.git</developerConnection>
+    </scm>
+
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
@@ -64,132 +88,206 @@
         <org.springframework.spring.version>2.5.6.SEC03</org.springframework.spring.version>
         <junit.version>4.12</junit.version>
         <dubbo.version>2.5.3</dubbo.version>
+        <zkclient.version>0.10</zkclient.version>
     </properties>
     <dependencyManagement>
-    <dependencies>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-common</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-config</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-client</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-server</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-core</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-rm-datasource</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-tm</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-spring</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-dubbo</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-test</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>fescar-examples</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>io.netty</groupId>
-            <artifactId>netty-all</artifactId>
-            <version>${netty4.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>fastjson</artifactId>
-            <version>1.2.48</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring</artifactId>
-            <version>${org.springframework.spring.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.typesafe</groupId>
-            <artifactId>config</artifactId>
-            <version>1.2.1</version>
-        </dependency>
-        <dependency>
-            <groupId>org.slf4j</groupId>
-            <artifactId>slf4j-api</artifactId>
-            <version>1.7.22</version>
-        </dependency>
-        <dependency>
-            <groupId>ch.qos.logback</groupId>
-            <artifactId>logback-classic</artifactId>
-            <version>1.1.6</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-lang</groupId>
-            <artifactId>commons-lang</artifactId>
-            <version>2.6</version>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-pool2</artifactId>
-            <version>2.4.2</version>
-        </dependency>
-        <dependency>
-            <groupId>commons-pool</groupId>
-            <artifactId>commons-pool</artifactId>
-            <version>1.6</version>
-        </dependency>
-        <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>${junit.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>dubbo</artifactId>
-            <version>${dubbo.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>cglib</groupId>
-            <artifactId>cglib</artifactId>
-            <version>3.1</version>
-        </dependency>
-        <dependency>
-            <groupId>aopalliance</groupId>
-            <artifactId>aopalliance</artifactId>
-            <version>1.0</version>
-        </dependency>
-    </dependencies>
+        <dependencies>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-common</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-config</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-core</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-rm-datasource</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-tm</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-spring</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-dubbo</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-test</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>fescar-examples</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>io.netty</groupId>
+                <artifactId>netty-all</artifactId>
+                <version>${netty4.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>1.2.48</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring</artifactId>
+                <version>${org.springframework.spring.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.typesafe</groupId>
+                <artifactId>config</artifactId>
+                <version>1.2.1</version>
+            </dependency>
+            <dependency>
+                <groupId>org.slf4j</groupId>
+                <artifactId>slf4j-api</artifactId>
+                <version>1.7.22</version>
+            </dependency>
+            <dependency>
+                <groupId>ch.qos.logback</groupId>
+                <artifactId>logback-classic</artifactId>
+                <version>1.1.6</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-lang</groupId>
+                <artifactId>commons-lang</artifactId>
+                <version>2.6</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.commons</groupId>
+                <artifactId>commons-pool2</artifactId>
+                <version>2.4.2</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-pool</groupId>
+                <artifactId>commons-pool</artifactId>
+                <version>1.6</version>
+            </dependency>
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>${junit.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.testng</groupId>
+                <artifactId>testng</artifactId>
+                <version>6.4</version>
+            </dependency>
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>dubbo</artifactId>
+                <version>${dubbo.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cglib</groupId>
+                <artifactId>cglib</artifactId>
+                <version>3.1</version>
+            </dependency>
+            <dependency>
+                <groupId>aopalliance</groupId>
+                <artifactId>aopalliance</artifactId>
+                <version>1.0</version>
+            </dependency>
+            <dependency>
+                <groupId>com.101tec</groupId>
+                <artifactId>zkclient</artifactId>
+                <version>${zkclient.version}</version>
+            </dependency>
+        </dependencies>
     </dependencyManagement>
 
+    <profiles>
+        <profile>
+            <id>release</id>
+            <build>
+                <plugins>
+                    <!-- Source -->
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <version>2.2.1</version>
+                        <executions>
+                            <execution>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>jar-no-fork</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <!-- Javadoc -->
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <version>2.9.1</version>
+                        <executions>
+                            <execution>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <!-- GPG -->
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-gpg-plugin</artifactId>
+                        <version>1.5</version>
+                        <executions>
+                            <execution>
+                                <id>sign-artifacts</id>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>sign</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+            <distributionManagement>
+                <snapshotRepository>
+                    <id>openSource</id>
+                    <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+                </snapshotRepository>
+                <repository>
+                    <id>openSource</id>
+                    <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+                </repository>
+            </distributionManagement>
+        </profile>
+    </profiles>
+
     <build>
         <extensions>
             <extension>
@@ -217,7 +315,7 @@
                         <format>html</format>
                         <format>xml</format>
                     </formats>
-                    <check />
+                    <check/>
                 </configuration>
             </plugin>
         </plugins>
diff --git a/rm-datasource/pom.xml b/rm-datasource/pom.xml
index fa048cf1c..6d5e84ebf 100644
--- a/rm-datasource/pom.xml
+++ b/rm-datasource/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-rm-datasource</artifactId>
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/DataSourceManager.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/DataSourceManager.java
index 61dd4e961..bd9e539f4 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/DataSourceManager.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/DataSourceManager.java
@@ -31,8 +31,12 @@ import com.alibaba.fescar.core.model.Resource;
 import com.alibaba.fescar.core.model.ResourceManager;
 import com.alibaba.fescar.core.model.ResourceManagerInbound;
 import com.alibaba.fescar.core.protocol.ResultCode;
-import com.alibaba.fescar.core.protocol.transaction.*;
 import com.alibaba.fescar.core.protocol.transaction.BranchRegisterRequest;
+import com.alibaba.fescar.core.protocol.transaction.BranchRegisterResponse;
+import com.alibaba.fescar.core.protocol.transaction.BranchReportRequest;
+import com.alibaba.fescar.core.protocol.transaction.BranchReportResponse;
+import com.alibaba.fescar.core.protocol.transaction.GlobalLockQueryRequest;
+import com.alibaba.fescar.core.protocol.transaction.GlobalLockQueryResponse;
 import com.alibaba.fescar.core.rpc.netty.RmRpcClient;
 import com.alibaba.fescar.rm.datasource.undo.UndoLogManager;
 
@@ -53,6 +57,7 @@ public class DataSourceManager implements ResourceManager {
             request.setTransactionId(XID.getTransactionId(xid));
             request.setLockKey(lockKeys);
             request.setResourceId(resourceId);
+            request.setBranchType(branchType);
 
             BranchRegisterResponse response = (BranchRegisterResponse) RmRpcClient.getInstance().sendMsgWithResponse(request);
             if (response.getResultCode() == ResultCode.Failed) {
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java
index 8e1e33721..56cd8c021 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/BaseTransactionalExecutor.java
@@ -16,10 +16,6 @@
 
 package com.alibaba.fescar.rm.datasource.exec;
 
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.List;
-
 import com.alibaba.fescar.core.context.RootContext;
 import com.alibaba.fescar.rm.datasource.StatementProxy;
 import com.alibaba.fescar.rm.datasource.sql.SQLRecognizer;
@@ -27,6 +23,10 @@ import com.alibaba.fescar.rm.datasource.sql.struct.Field;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableMeta;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableMetaCache;
 
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
 public abstract class BaseTransactionalExecutor<T, S extends Statement> implements Executor {
 
     protected StatementProxy<S> statementProxy;
@@ -56,7 +56,7 @@ public abstract class BaseTransactionalExecutor<T, S extends Statement> implemen
         StringBuffer whereConditionAppender = new StringBuffer();
         for (int i = 0; i < pkRows.size(); i++) {
             Field field = pkRows.get(i);
-            whereConditionAppender.append(field.getName() + " = ?");
+            whereConditionAppender.append(getColumnNameInSQL(field.getName()) + " = ?");
             if (i < (pkRows.size() - 1)) {
                 whereConditionAppender.append(" OR ");
             }
@@ -64,6 +64,25 @@ public abstract class BaseTransactionalExecutor<T, S extends Statement> implemen
         return whereConditionAppender.toString();
     }
 
+    protected String getColumnNameInSQL(String columnName) {
+        String tableAlias = sqlRecognizer.getTableAlias();
+        if (tableAlias == null) {
+            return columnName;
+        } else {
+            return tableAlias + "." + columnName;
+        }
+    }
+
+    protected String getFromTableInSQL() {
+        String tableName = sqlRecognizer.getTableName();
+        String tableAlias = sqlRecognizer.getTableAlias();
+        if (tableAlias == null) {
+            return tableName;
+        } else {
+            return tableName + " " + tableAlias;
+        }
+    }
+
     protected TableMeta getTableMeta() {
         return getTableMeta(sqlRecognizer.getTableName());
     }
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java
index 222afd349..d5c997ca2 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/DeleteExecutor.java
@@ -16,13 +16,6 @@
 
 package com.alibaba.fescar.rm.datasource.exec;
 
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.util.ArrayList;
-import java.util.List;
-
 import com.alibaba.fescar.rm.datasource.ParametersHolder;
 import com.alibaba.fescar.rm.datasource.StatementProxy;
 import com.alibaba.fescar.rm.datasource.sql.SQLDeleteRecognizer;
@@ -30,6 +23,13 @@ import com.alibaba.fescar.rm.datasource.sql.SQLRecognizer;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableMeta;
 import com.alibaba.fescar.rm.datasource.sql.struct.TableRecords;
 
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
 public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecutor<T, S> {
 
     public DeleteExecutor(StatementProxy statementProxy, StatementCallback statementCallback, SQLRecognizer sqlRecognizer) {
@@ -39,6 +39,7 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
     @Override
     protected TableRecords beforeImage() throws SQLException {
         SQLDeleteRecognizer visitor = (SQLDeleteRecognizer) sqlRecognizer;
+
         TableMeta tmeta = getTableMeta(visitor.getTableName());
         List<String> columns = new ArrayList<>();
         for (String column : tmeta.getAllColumns().keySet()) {
@@ -48,7 +49,7 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
         StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
 
         for (int i = 0; i < columns.size(); i++) {
-            selectSQLAppender.append(columns.get(i));
+            selectSQLAppender.append(getColumnNameInSQL(columns.get(i)));
             if (i < (columns.size() - 1)) {
                 selectSQLAppender.append(", ");
             }
@@ -60,7 +61,7 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
         } else {
             whereCondition = visitor.getWhereCondition();
         }
-        selectSQLAppender.append(" FROM " + tmeta.getTableName() + " WHERE " + whereCondition + " FOR UPDATE");
+        selectSQLAppender.append(" FROM " + getFromTableInSQL() + " WHERE " + whereCondition + " FOR UPDATE");
         String selectSQL = selectSQLAppender.toString();
 
         TableRecords beforeImage = null;
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/ExecuteTemplate.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/ExecuteTemplate.java
index 17eab9dea..46375e7f9 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/ExecuteTemplate.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/ExecuteTemplate.java
@@ -48,22 +48,26 @@ public class ExecuteTemplate {
                     statementProxy.getConnectionProxy().getDbType());
         }
         Executor<T> executor = null;
-        switch (sqlRecognizer.getSQLType()) {
-            case INSERT:
-                executor = new InsertExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
-                break;
-            case UPDATE:
-                executor = new UpdateExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
-                break;
-            case DELETE:
-                executor = new DeleteExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
-                break;
-            case SELECT_FOR_UPDATE:
-                executor = new SelectForUpdateExecutor(statementProxy, statementCallback, sqlRecognizer);
-                break;
-            default:
-                executor = new PlainExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
-                break;
+        if (sqlRecognizer == null) {
+            executor = new PlainExecutor<T, S>(statementProxy, statementCallback);
+        } else {
+            switch (sqlRecognizer.getSQLType()) {
+                case INSERT:
+                    executor = new InsertExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
+                    break;
+                case UPDATE:
+                    executor = new UpdateExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
+                    break;
+                case DELETE:
+                    executor = new DeleteExecutor<T, S>(statementProxy, statementCallback, sqlRecognizer);
+                    break;
+                case SELECT_FOR_UPDATE:
+                    executor = new SelectForUpdateExecutor(statementProxy, statementCallback, sqlRecognizer);
+                    break;
+                default:
+                    executor = new PlainExecutor<T, S>(statementProxy, statementCallback);
+                    break;
+            }
         }
         T rs = null;
         try {
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/InsertExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/InsertExecutor.java
index 4e3e1b1ec..7701497e7 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/InsertExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/InsertExecutor.java
@@ -47,8 +47,8 @@ public class InsertExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
 
     @Override
     protected TableRecords afterImage(TableRecords beforeImage) throws SQLException {
-        SQLInsertRecognizer visitor = (SQLInsertRecognizer) sqlRecognizer;
-        List<String> insertColumns = visitor.getInsertColumns();
+        SQLInsertRecognizer recogizier = (SQLInsertRecognizer) sqlRecognizer;
+        List<String> insertColumns = recogizier.getInsertColumns();
         TableMeta tmeta = getTableMeta();
         TableRecords afterImage = null;
         if (tmeta.containsPK(insertColumns)) {
@@ -60,7 +60,7 @@ public class InsertExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
                     if (statementProxy instanceof PreparedStatementProxy) {
                         pkValues = ((PreparedStatementProxy) statementProxy).getParamsByIndex(paramIdx);
                     } else {
-                        List<List<Object>> insertRows = visitor.getInsertRows();
+                        List<List<Object>> insertRows = recogizier.getInsertRows();
                         pkValues = new ArrayList<>(insertRows.size());
                         for (List<Object> row : insertRows) {
                             pkValues.add(row.get(paramIdx));
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/PlainExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/PlainExecutor.java
index 14a2f3455..db7f4c1ce 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/PlainExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/PlainExecutor.java
@@ -27,12 +27,9 @@ public class PlainExecutor<T, S extends Statement> implements Executor {
 
     private StatementCallback<T, S> statementCallback;
 
-    private SQLRecognizer sqlRecognizer;
-
-    public PlainExecutor(StatementProxy<S> statementProxy, StatementCallback<T, S> statementCallback, SQLRecognizer sqlRecognizer) {
+    public PlainExecutor(StatementProxy<S> statementProxy, StatementCallback<T, S> statementCallback) {
         this.statementProxy = statementProxy;
         this.statementCallback = statementCallback;
-        this.sqlRecognizer = sqlRecognizer;
     }
 
     @Override
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java
index 2cd9b66ae..8d72ab540 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/SelectForUpdateExecutor.java
@@ -47,8 +47,8 @@ public class SelectForUpdateExecutor<S extends Statement> extends BaseTransactio
         boolean originalAutoCommit = conn.getAutoCommit();
 
         StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
-        selectSQLAppender.append(getTableMeta().getPkName());
-        selectSQLAppender.append(" FROM " + getTableMeta().getTableName());
+        selectSQLAppender.append(getColumnNameInSQL(getTableMeta().getPkName()));
+        selectSQLAppender.append(" FROM " + getFromTableInSQL());
         String whereCondition = null;
         ArrayList<Object> paramAppender = new ArrayList<>();
         if (statementProxy instanceof ParametersHolder) {
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/UpdateExecutor.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/UpdateExecutor.java
index 623c207a4..93f22f64f 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/UpdateExecutor.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/exec/UpdateExecutor.java
@@ -39,14 +39,15 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
 
     @Override
     protected TableRecords beforeImage() throws SQLException {
-        SQLUpdateRecognizer visitor = (SQLUpdateRecognizer) sqlRecognizer;
+        SQLUpdateRecognizer recognizer = (SQLUpdateRecognizer) sqlRecognizer;
+
         TableMeta tmeta = getTableMeta();
-        List<String> updateColumns = visitor.getUpdateColumns();
+        List<String> updateColumns = recognizer.getUpdateColumns();
 
         StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
         if (!tmeta.containsPK(updateColumns)) {
             // PK should be included.
-            selectSQLAppender.append(tmeta.getPkName() + ", ");
+            selectSQLAppender.append(getColumnNameInSQL(tmeta.getPkName()) + ", ");
         }
         for (int i = 0; i < updateColumns.size(); i++) {
             selectSQLAppender.append(updateColumns.get(i));
@@ -57,11 +58,11 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
         String whereCondition = null;
         ArrayList<Object> paramAppender = new ArrayList<>();
         if (statementProxy instanceof ParametersHolder) {
-            whereCondition = visitor.getWhereCondition((ParametersHolder) statementProxy, paramAppender);
+            whereCondition = recognizer.getWhereCondition((ParametersHolder) statementProxy, paramAppender);
         } else {
-            whereCondition = visitor.getWhereCondition();
+            whereCondition = recognizer.getWhereCondition();
         }
-        selectSQLAppender.append(" FROM " + tmeta.getTableName() + " WHERE " + whereCondition + " FOR UPDATE");
+        selectSQLAppender.append(" FROM " + getFromTableInSQL() + " WHERE " + whereCondition + " FOR UPDATE");
         String selectSQL = selectSQLAppender.toString();
 
         TableRecords beforeImage = null;
@@ -97,17 +98,18 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
 
     @Override
     protected TableRecords afterImage(TableRecords beforeImage) throws SQLException {
-        SQLUpdateRecognizer visitor = (SQLUpdateRecognizer) sqlRecognizer;
+        SQLUpdateRecognizer recognizer = (SQLUpdateRecognizer) sqlRecognizer;
+
         TableMeta tmeta = getTableMeta();
         if (beforeImage == null || beforeImage.size() == 0) {
             return TableRecords.empty(getTableMeta());
         }
-        List<String> updateColumns = visitor.getUpdateColumns();
+        List<String> updateColumns = recognizer.getUpdateColumns();
 
         StringBuffer selectSQLAppender = new StringBuffer("SELECT ");
         if (!tmeta.containsPK(updateColumns)) {
             // PK should be included.
-            selectSQLAppender.append(tmeta.getPkName() + ", ");
+            selectSQLAppender.append(getColumnNameInSQL(tmeta.getPkName()) + ", ");
         }
         for (int i = 0; i < updateColumns.size(); i++) {
             selectSQLAppender.append(updateColumns.get(i));
@@ -116,7 +118,7 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu
             }
         }
         List<Field> pkRows = beforeImage.pkRows();
-        selectSQLAppender.append(" FROM " + tmeta.getTableName() + " WHERE " + buildWhereConditionByPKs(pkRows) + " FOR UPDATE");
+        selectSQLAppender.append(" FROM " + getFromTableInSQL() + " WHERE " + buildWhereConditionByPKs(pkRows) + " FOR UPDATE");
         String selectSQL = selectSQLAppender.toString();
 
         TableRecords afterImage = null;
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLRecognizer.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLRecognizer.java
index f481d5c08..36a64d676 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLRecognizer.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLRecognizer.java
@@ -28,18 +28,18 @@ public interface SQLRecognizer {
     /**
      * TableRecords source related in the SQL, including alias if any.
      * SELECT id, name FROM user u WHERE ...
-     * TableRecords source should be 'user u' for this SQL.
+     * Alias should be 'u' for this SQL.
      *
      * @return table source.
      */
-    String getTableSource();
+    String getTableAlias();
 
     /**
      * TableRecords name related in the SQL.
      * SELECT id, name FROM user u WHERE ...
      * TableRecords name should be 'user' for this SQL, without alias 'u'.
      *
-     * @see #getTableSource()
+     * @see #getTableAlias()
      * @return table name.
      */
     String getTableName();
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLVisitorFactory.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLVisitorFactory.java
index 3976064c4..708e991ca 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLVisitorFactory.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/SQLVisitorFactory.java
@@ -35,7 +35,7 @@ public class SQLVisitorFactory {
     public static SQLRecognizer get(String sql, String dbType) {
         List<SQLStatement> asts = SQLUtils.parseStatements(sql, dbType);
         if (asts == null || asts.size() != 1) {
-            throw new UnsupportedOperationException("xxx");
+            throw new UnsupportedOperationException("Unsupported SQL: " + sql);
         }
         SQLRecognizer recognizer = null;
         SQLStatement ast = asts.get(0);
@@ -47,7 +47,9 @@ public class SQLVisitorFactory {
             } else if (ast instanceof SQLDeleteStatement) {
                 recognizer = new MySQLDeleteRecognizer(sql, ast);
             } else if (ast instanceof SQLSelectStatement) {
-                recognizer = new MySQLSelectForUpdateRecognizer(sql, ast);
+                if (((SQLSelectStatement)ast).getSelect().getQueryBlock().isForUpdate()) {
+                    recognizer = new MySQLSelectForUpdateRecognizer(sql, ast);
+                }
             }
         } else {
             throw new UnsupportedOperationException("Just support MySQL by now!");
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizer.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizer.java
index 10771bd4e..7f3cf5fa3 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizer.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizer.java
@@ -44,11 +44,8 @@ public class MySQLDeleteRecognizer extends BaseRecognizer implements SQLDeleteRe
     }
 
     @Override
-    public String getTableSource() {
-        StringBuffer sb = new StringBuffer();
-        MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb);
-        visitor.visit((SQLExprTableSource)ast.getTableSource());
-        return sb.toString();
+    public String getTableAlias() {
+        return ast.getTableSource().getAlias();
     }
 
     @Override
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizer.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizer.java
index d9a8d8802..3136a59e5 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizer.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizer.java
@@ -46,11 +46,8 @@ public class MySQLInsertRecognizer extends BaseRecognizer implements SQLInsertRe
     }
 
     @Override
-    public String getTableSource() {
-        StringBuffer sb = new StringBuffer();
-        MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb);
-        visitor.visit(ast.getTableSource());
-        return sb.toString();
+    public String getTableAlias() {
+        return ast.getTableSource().getAlias();
     }
 
     @Override
@@ -78,7 +75,7 @@ public class MySQLInsertRecognizer extends BaseRecognizer implements SQLInsertRe
         List<String> list = new ArrayList<>(columnSQLExprs.size());
         for (SQLExpr expr : columnSQLExprs) {
             if (expr instanceof SQLIdentifierExpr) {
-                list.add(((SQLIdentifierExpr) expr).getName().toUpperCase());
+                list.add(((SQLIdentifierExpr) expr).getName());
             } else {
                 throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
             }
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizer.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizer.java
index 05b0be04b..3c41defc2 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizer.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizer.java
@@ -16,23 +16,19 @@
 
 package com.alibaba.fescar.rm.datasource.sql.druid;
 
-import java.util.ArrayList;
-
 import com.alibaba.druid.sql.ast.SQLExpr;
 import com.alibaba.druid.sql.ast.SQLStatement;
 import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
 import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
-import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
-import com.alibaba.druid.sql.ast.statement.SQLSelect;
-import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
-import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
-import com.alibaba.druid.sql.ast.statement.SQLTableSource;
+import com.alibaba.druid.sql.ast.statement.*;
 import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
 import com.alibaba.fescar.rm.datasource.ParametersHolder;
 import com.alibaba.fescar.rm.datasource.sql.SQLParsingException;
 import com.alibaba.fescar.rm.datasource.sql.SQLSelectRecognizer;
 import com.alibaba.fescar.rm.datasource.sql.SQLType;
 
+import java.util.ArrayList;
+
 public class MySQLSelectForUpdateRecognizer extends BaseRecognizer implements SQLSelectRecognizer {
 
     private final SQLSelectStatement ast;
@@ -96,13 +92,10 @@ public class MySQLSelectForUpdateRecognizer extends BaseRecognizer implements SQ
     }
 
     @Override
-    public String getTableSource() {
+    public String getTableAlias() {
         SQLSelectQueryBlock selectQueryBlock = getSelect();
         SQLTableSource tableSource = selectQueryBlock.getFrom();
-        StringBuffer sb = new StringBuffer();
-        MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb);
-        visitor.visit((SQLExprTableSource)tableSource);
-        return sb.toString();
+        return tableSource.getAlias();
     }
 
     @Override
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizer.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizer.java
index 801a283c0..34c8fa3fa 100644
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizer.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizer.java
@@ -30,6 +30,7 @@ import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
 import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
 import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
 import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
+import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
 import com.alibaba.fescar.rm.datasource.ParametersHolder;
 import com.alibaba.fescar.rm.datasource.sql.SQLParsingException;
 import com.alibaba.fescar.rm.datasource.sql.SQLType;
@@ -122,12 +123,8 @@ public class MySQLUpdateRecognizer extends BaseRecognizer implements SQLUpdateRe
     }
 
     @Override
-    public String getTableSource() {
-        StringBuffer sb = new StringBuffer();
-        MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb);
-        SQLExprTableSource tableSource = (SQLExprTableSource) ast.getTableSource();
-        visitor.visit(tableSource);
-        return sb.toString();
+    public String getTableAlias() {
+        return ast.getTableSource().getAlias();
     }
 
     @Override
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMeta.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMeta.java
index 2e6c44b49..7313ef8b2 100755
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMeta.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMeta.java
@@ -39,7 +39,7 @@ public class TableMeta {
     }
 
     public ColumnMeta getColumnMeta(String colName) {
-        String s = colName.toUpperCase();
+        String s = colName;
         ColumnMeta col = allColumns.get(s);
         if (col == null) {
             if (colName.charAt(0) == '`') {
@@ -74,7 +74,7 @@ public class TableMeta {
             IndexMeta index = entry.getValue();
             if (index.getIndextype().value() == IndexType.PRIMARY.value()) {
                 for (ColumnMeta col : index.getValues()) {
-                    pk.put(col.getColumnName().toUpperCase(), col);
+                    pk.put(col.getColumnName(), col);
                 }
             }
         }
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaCache.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaCache.java
index e498135bb..f4487ce1b 100755
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaCache.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableMetaCache.java
@@ -95,7 +95,7 @@ public class TableMetaCache {
 			ResultSetMetaData rsmd = rs.getMetaData();
 			DatabaseMetaData dbmd = conn.getMetaData();
 
-			return resultSetMetaToSchema(rsmd, dbmd);
+			return resultSetMetaToSchema(rsmd, dbmd, tableName);
 		} catch (Exception e) {
 			if (e instanceof SQLException) {
 				throw ((SQLException) e);
@@ -123,7 +123,7 @@ public class TableMetaCache {
 		while (rs2.next()) {
 			ColumnMeta col = new ColumnMeta();
 			col.setTableName(tableName);
-			col.setColumnName(rs2.getString("COLUMN_NAME").toUpperCase());
+			col.setColumnName(rs2.getString("COLUMN_NAME"));
 			String datatype = rs2.getString("DATA_TYPE");
 			if (StringUtils.equalsIgnoreCase(datatype, "NUMBER")) {
 				col.setDataType(java.sql.Types.BIGINT);
@@ -149,7 +149,7 @@ public class TableMetaCache {
 							+ tableName + "'");
 			while (rs1.next()) {
 				String indexName = rs1.getString(1);
-				String colName = rs1.getString(2).toUpperCase();
+				String colName = rs1.getString(2);
 				ColumnMeta col = tm.getAllColumns().get(colName);
 
 				if (tm.getAllIndexes().containsKey(indexName)) {
@@ -176,8 +176,7 @@ public class TableMetaCache {
 		return tm;
 	}
 
-	private static TableMeta resultSetMetaToSchema(ResultSetMetaData rsmd, DatabaseMetaData dbmd) throws SQLException {
-		String tableName = rsmd.getTableName(1);
+	private static TableMeta resultSetMetaToSchema(ResultSetMetaData rsmd, DatabaseMetaData dbmd, String tableName) throws SQLException {
 		String schemaName = rsmd.getSchemaName(1);
 		String catalogName = rsmd.getCatalogName(1);
 
@@ -190,7 +189,7 @@ public class TableMetaCache {
 			col.setTableCat(rs1.getString("TABLE_CAT"));
 			col.setTableSchemaName(rs1.getString("TABLE_SCHEM"));
 			col.setTableName(rs1.getString("TABLE_NAME"));
-			col.setColumnName(rs1.getString("COLUMN_NAME").toUpperCase());
+			col.setColumnName(rs1.getString("COLUMN_NAME"));
 			col.setDataType(rs1.getInt("DATA_TYPE"));
 			col.setDataTypeName(rs1.getString("TYPE_NAME"));
 			col.setColumnSize(rs1.getInt("COLUMN_SIZE"));
@@ -213,7 +212,7 @@ public class TableMetaCache {
 		String indexName = "";
 		while (rs2.next()) {
 			indexName = rs2.getString("INDEX_NAME");
-			String colName = rs2.getString("COLUMN_NAME").toUpperCase();
+			String colName = rs2.getString("COLUMN_NAME");
 			ColumnMeta col = tm.getAllColumns().get(colName);
 
 			if (tm.getAllIndexes().containsKey(indexName)) {
diff --git a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableRecords.java b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableRecords.java
index 0c6683444..71037b8d4 100755
--- a/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableRecords.java
+++ b/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/sql/struct/TableRecords.java
@@ -127,7 +127,7 @@ public class TableRecords {
         while (resultSet.next()) {
             List<Field> fields = new ArrayList<>(columnCount);
             for (int i = 1; i <= columnCount; i++) {
-                String colName = resultSetMetaData.getColumnName(i).toUpperCase();
+                String colName = resultSetMetaData.getColumnName(i);
                 ColumnMeta col = tmeta.getColumnMeta(colName);
                 Field field = new Field();
                 field.setName(col.getColumnName());
diff --git a/server/pom.xml b/server/pom.xml
index 31001faa5..ea8953b30 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-server</artifactId>
@@ -39,6 +39,11 @@
             <groupId>commons-lang</groupId>
             <artifactId>commons-lang</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.testng</groupId>
+            <artifactId>testng</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
@@ -46,7 +51,7 @@
             <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>appassembler-maven-plugin</artifactId>
-                <version>1.1.1</version>
+                <version>1.10</version>
                 <executions>
                     <execution>
                         <id>make-assembly</id>
@@ -71,6 +76,13 @@
                         <program>
                             <mainClass>com.alibaba.fescar.server.Server</mainClass>
                             <name>fescar-server</name>
+                            <jvmSettings>
+                                <extraArguments>
+                                    <extraArgument>-server</extraArgument>
+                                    <extraArgument>-XX:MaxDirectMemorySize=1024M</extraArgument>
+                                    <extraArgument>$EXTRA_JVM_ARGUMENTS</extraArgument>
+                                </extraArguments>
+                            </jvmSettings>
                         </program>
                     </programs>
                 </configuration>
diff --git a/server/src/main/java/com/alibaba/fescar/server/coordinator/CoreFactory.java b/server/src/main/java/com/alibaba/fescar/server/coordinator/CoreFactory.java
index e5d75e428..9e52240f8 100644
--- a/server/src/main/java/com/alibaba/fescar/server/coordinator/CoreFactory.java
+++ b/server/src/main/java/com/alibaba/fescar/server/coordinator/CoreFactory.java
@@ -23,13 +23,13 @@ public class CoreFactory {
     }
 
     public static final Core get() {
-        return CoreFactory.SingletonHolder.INSTANCE;
+        return SingletonHolder.INSTANCE;
     }
 
     /**
      * Just for test mocking
      */
     public static void set(Core core) {
-        CoreFactory.SingletonHolder.INSTANCE = core;
+        SingletonHolder.INSTANCE = core;
     }
 }
diff --git a/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCoordinator.java b/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCoordinator.java
index dcf8f3ca5..136f6783f 100644
--- a/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCoordinator.java
+++ b/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCoordinator.java
@@ -16,12 +16,6 @@
 
 package com.alibaba.fescar.server.coordinator;
 
-import java.io.IOException;
-import java.util.Collection;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
 import com.alibaba.fescar.common.XID;
 import com.alibaba.fescar.common.thread.NamedThreadFactory;
 import com.alibaba.fescar.core.exception.TransactionException;
@@ -61,6 +55,12 @@ import com.alibaba.fescar.server.session.SessionHolder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.util.Collection;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
 import static com.alibaba.fescar.core.exception.TransactionExceptionCode.FailedToSendBranchCommitRequest;
 import static com.alibaba.fescar.core.exception.TransactionExceptionCode.FailedToSendBranchRollbackRequest;
 
@@ -214,9 +214,8 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             try {
                 core.doGlobalRollback(rollbackingSession, true);
             } catch (TransactionException ex) {
-                LOGGER.info(
-                    "Failed to retry rollbacking [" + rollbackingSession.getTransactionId() + "] " + ex.getCode() + " "
-                        + ex.getMessage());
+                LOGGER.info("Failed to retry rollbacking [{}] {} {}",
+                        rollbackingSession.getTransactionId(), ex.getCode(), ex.getMessage());
             }
         }
     }
@@ -227,9 +226,8 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             try {
                 core.doGlobalCommit(committingSession, true);
             } catch (TransactionException ex) {
-                LOGGER.info(
-                    "Failed to retry committing [" + committingSession.getTransactionId() + "] " + ex.getCode() + " "
-                        + ex.getMessage());
+                LOGGER.info("Failed to retry committing [{}] {} {}",
+                        committingSession.getTransactionId(), ex.getCode(), ex.getMessage());
             }
         }
     }
@@ -241,9 +239,8 @@ public class DefaultCoordinator extends AbstractTCInboundHandler
             try {
                 core.doGlobalCommit(asyncCommittingSession, true);
             } catch (TransactionException ex) {
-                LOGGER.info(
-                    "Failed to async committing [" + asyncCommittingSession.getTransactionId() + "] " + ex.getCode()
-                        + " " + ex.getMessage());
+                LOGGER.info("Failed to async committing [{}] {} {}",
+                        asyncCommittingSession.getTransactionId(), ex.getCode(), ex.getMessage());
             }
         }
     }
diff --git a/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCore.java b/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCore.java
index 7a5a8c3b0..b47efcfca 100644
--- a/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCore.java
+++ b/server/src/main/java/com/alibaba/fescar/server/coordinator/DefaultCore.java
@@ -33,7 +33,11 @@ import com.alibaba.fescar.server.session.SessionHolder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static com.alibaba.fescar.core.exception.TransactionExceptionCode.*;
+import static com.alibaba.fescar.core.exception.TransactionExceptionCode.BranchTransactionNotExist;
+import static com.alibaba.fescar.core.exception.TransactionExceptionCode.FailedToAddBranch;
+import static com.alibaba.fescar.core.exception.TransactionExceptionCode.GlobalTransactionNotActive;
+import static com.alibaba.fescar.core.exception.TransactionExceptionCode.GlobalTransactionStatusInvalid;
+import static com.alibaba.fescar.core.exception.TransactionExceptionCode.LockKeyConflict;
 
 public class DefaultCore implements Core {
 
@@ -160,12 +164,13 @@ public class DefaultCore implements Core {
                         continue;
                     case PhaseTwo_CommitFailed_Unretryable:
                         if (globalSession.canBeCommittedAsync()) {
-                            LOGGER.error("By [" + branchStatus + "], failed to commit branch " + branchSession);
+                            LOGGER.error("By [{}], failed to commit branch {}", branchStatus, branchSession);
                             continue;
                         } else {
                             globalSession.changeStatus(GlobalStatus.CommitFailed);
                             globalSession.end();
-                            LOGGER.error("Finally, failed to commit global[" + globalSession.getTransactionId() + "] since branch[" + branchSession.getBranchId() + "] commit failed");
+                            LOGGER.error("Finally, failed to commit global[{}] since branch[{}] commit failed",
+                                    globalSession.getTransactionId(), branchSession.getBranchId());
                             return;
                         }
                     default:
@@ -174,17 +179,18 @@ public class DefaultCore implements Core {
                             return;
                         }
                         if (globalSession.canBeCommittedAsync()) {
-                            LOGGER.error("By [" + branchStatus + "], failed to commit branch " + branchSession);
+                            LOGGER.error("By [{}], failed to commit branch {}", branchStatus, branchSession);
                             continue;
                         } else {
-                            LOGGER.error("Failed to commit global[" + globalSession.getTransactionId() + "] since branch[" + branchSession.getBranchId() + "] commit failed, will retry later.");
+                            LOGGER.error("Failed to commit global[{}] since branch[{}] commit failed, will retry later.",
+                                    globalSession.getTransactionId(), branchSession.getBranchId());
                             return;
                         }
 
                 }
 
             } catch (Exception ex) {
-                LOGGER.info("Exception committing branch " + branchSession, ex);
+                LOGGER.info("Exception committing branch {}", branchSession, ex);
                 if (!retrying) {
                     queueToRetryCommit(globalSession);
                     if (ex instanceof TransactionException) {
@@ -198,12 +204,12 @@ public class DefaultCore implements Core {
 
         }
         if (globalSession.hasBranch()) {
-            LOGGER.info("Global[" + globalSession.getTransactionId() + "] committing is NOT done.");
+            LOGGER.info("Global[{}] committing is NOT done.", globalSession.getTransactionId());
             return;
         }
         globalSession.changeStatus(GlobalStatus.Committed);
         globalSession.end();
-        LOGGER.info("Global[" + globalSession.getTransactionId() + "] committing is successfully done.");
+        LOGGER.info("Global[{}] committing is successfully done.", globalSession.getTransactionId());
     }
 
     private void asyncCommit(GlobalSession globalSession) throws TransactionException {
@@ -255,7 +261,7 @@ public class DefaultCore implements Core {
             }
             try {
                 BranchStatus branchStatus = resourceManagerInbound.branchRollback(XID.generateXID(branchSession.getTransactionId()), branchSession.getBranchId(),
-                        branchSession.getResourceId(), branchSession.getApplicationData());
+                    branchSession.getResourceId(), branchSession.getApplicationData());
 
                 switch (branchStatus) {
                     case PhaseTwo_Rollbacked:
@@ -263,12 +269,7 @@ public class DefaultCore implements Core {
                         LOGGER.error("Successfully rolled back branch " + branchSession);
                         continue;
                     case PhaseTwo_RollbackFailed_Unretryable:
-                        GlobalStatus currentStatus = globalSession.getStatus();
-                        if (currentStatus.name().startsWith("Timeout")) {
-                            globalSession.changeStatus(GlobalStatus.TimeoutRollbackFailed);
-                        } else {
-                            globalSession.changeStatus(GlobalStatus.RollbackFailed);
-                        }
+                        changeToRollbackFailedStatus(globalSession);
                         globalSession.end();
                         LOGGER.error("Failed to rollback global[" + globalSession.getTransactionId() + "] since branch[" + branchSession.getBranchId() + "] rollback failed");
                         return;
@@ -294,13 +295,30 @@ public class DefaultCore implements Core {
             }
 
         }
+        if (globalSession.hasBranch()) {
+            changeToRollbackFailedStatus(globalSession);
+        } else {
+            changeToRollbackedStatus(globalSession);
+        }
+        globalSession.end();
+    }
+
+    private void changeToRollbackedStatus(GlobalSession globalSession) throws TransactionException {
         GlobalStatus currentStatus = globalSession.getStatus();
         if (currentStatus.name().startsWith("Timeout")) {
             globalSession.changeStatus(GlobalStatus.TimeoutRollbacked);
         } else {
             globalSession.changeStatus(GlobalStatus.Rollbacked);
         }
-        globalSession.end();
+    }
+
+    private void changeToRollbackFailedStatus(GlobalSession globalSession) throws TransactionException {
+        GlobalStatus currentStatus = globalSession.getStatus();
+        if (currentStatus.name().startsWith("Timeout")) {
+            globalSession.changeStatus(GlobalStatus.TimeoutRollbackFailed);
+        } else {
+            globalSession.changeStatus(GlobalStatus.RollbackFailed);
+        }
     }
 
     @Override
diff --git a/spring/pom.xml b/spring/pom.xml
index 075333225..cd6808f99 100644
--- a/spring/pom.xml
+++ b/spring/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-spring</artifactId>
@@ -44,11 +44,6 @@
             <artifactId>spring</artifactId>
             <scope>provided</scope>
         </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring</artifactId>
-            <scope>provided</scope>
-        </dependency>
         <dependency>
             <groupId>cglib</groupId>
             <artifactId>cglib</artifactId>
diff --git a/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScanner.java b/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScanner.java
index cc175c0ef..24f9edecf 100644
--- a/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScanner.java
+++ b/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScanner.java
@@ -26,6 +26,7 @@ import com.alibaba.fescar.common.exception.NotSupportYetException;
 import com.alibaba.fescar.config.ConfigurationFactory;
 import com.alibaba.fescar.rm.RMClientAT;
 import com.alibaba.fescar.tm.TMClient;
+import com.alibaba.fescar.tm.api.DefaultFailureHandlerImpl;
 import com.alibaba.fescar.tm.api.FailureHandler;
 
 import org.apache.commons.lang.StringUtils;
@@ -56,8 +57,10 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator implement
     private static final int MT_MODE = 2;
 
     private static final int ORDER_NUM = 1024;
+    private static final int DEFAULT_MODE = AT_MODE;
 
     private static final Set<String> PROXYED_SET = new HashSet<>();
+    private static final FailureHandler DEFAULT_FAIL_HANDLER = new DefaultFailureHandlerImpl();
 
     private GlobalTransactionalInterceptor interceptor;
 
@@ -67,8 +70,6 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator implement
     private final boolean disableGlobalTransaction =
         ConfigurationFactory.getInstance().getBoolean("service.disableGlobalTransaction", false);
 
-    private static final int DEFAULT_MODE = AT_MODE;
-
     private final FailureHandler failureHandlerHook;
 
     /**
@@ -108,7 +109,7 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator implement
      * @param mode           the mode
      */
     public GlobalTransactionScanner(String applicationId, String txServiceGroup, int mode) {
-        this(applicationId, txServiceGroup, mode, null);
+        this(applicationId, txServiceGroup, mode, DEFAULT_FAIL_HANDLER);
     }
 
     /**
@@ -180,10 +181,9 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator implement
                 if (PROXYED_SET.contains(beanName)) {
                     return bean;
                 }
-                PROXYED_SET.add(beanName);
                 Class<?> serviceInterface = findTargetClass(bean);
                 Method[] methods = serviceInterface.getMethods();
-                LinkedList<MethodDesc> methodDescList = new LinkedList<MethodDesc>();
+                LinkedList<MethodDesc> methodDescList = new LinkedList<>();
                 for (Method method : methods) {
                     GlobalTransactional anno = method.getAnnotation(GlobalTransactional.class);
                     if (anno != null) {
@@ -193,8 +193,9 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator implement
                 if (methodDescList.isEmpty()) {
                     return bean;
                 }
-
-                interceptor = new GlobalTransactionalInterceptor(failureHandlerHook);
+                if (interceptor == null) {
+                    interceptor = new GlobalTransactionalInterceptor(failureHandlerHook);
+                }
                 if (!AopUtils.isAopProxy(bean)) {
                     bean = super.wrapIfNecessary(bean, beanName, cacheKey);
                 } else {
@@ -204,6 +205,7 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator implement
                         advised.addAdvisor(0, avr);
                     }
                 }
+                PROXYED_SET.add(beanName);
                 return bean;
             }
         } catch (Exception exx) {
diff --git a/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java b/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java
index e3a7cbbda..84864b611 100644
--- a/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java
+++ b/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java
@@ -33,13 +33,14 @@ import org.slf4j.LoggerFactory;
 public class GlobalTransactionalInterceptor implements MethodInterceptor {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(GlobalTransactionalInterceptor.class);
+    private static final FailureHandler DEFAULT_FAIL_HANDLER = new DefaultFailureHandlerImpl();
 
     private final TransactionalTemplate transactionalTemplate = new TransactionalTemplate();
     private final FailureHandler failureHandler;
 
     public GlobalTransactionalInterceptor(FailureHandler failureHandler) {
         if (null == failureHandler) {
-            failureHandler = new DefaultFailureHandlerImpl();
+            failureHandler = DEFAULT_FAIL_HANDLER;
         }
         this.failureHandler = failureHandler;
     }
diff --git a/tm/pom.xml b/tm/pom.xml
index e0ae87422..2c30b5325 100644
--- a/tm/pom.xml
+++ b/tm/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-tm</artifactId>


Test patch:
diff --git a/config/src/test/java/com/alibaba/fescar/config/FileConfigurationTest.java b/config/src/test/java/com/alibaba/fescar/config/FileConfigurationTest.java
index cf1c61123..b932aebf8 100644
--- a/config/src/test/java/com/alibaba/fescar/config/FileConfigurationTest.java
+++ b/config/src/test/java/com/alibaba/fescar/config/FileConfigurationTest.java
@@ -16,89 +16,166 @@
 
 package com.alibaba.fescar.config;
 
+import java.util.concurrent.ExecutorService;
+
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
 /**
  * @Author: jimin.jm@alibaba-inc.com
- * @Project: fescar-all
- * @DateTime: 2018/12/21 14:03
+ * @Project: feats-all
+ * @DateTime: 2019/1/24 1:31 PM
  * @FileName: FileConfigurationTest
  * @Description:
  */
 public class FileConfigurationTest {
-
-    FileConfiguration fileConfiguration = new FileConfiguration();
-
-    @org.junit.Test
-    public void isRunAsClientProxy() throws Exception {
-
+    private static final Config CONFIG = ConfigFactory.load();
+    private static final Configuration FILE_CONFIG = ConfigurationFactory.getInstance();
+    private static final String INT_DATAID = "transport.thread-factory.client-selector-thread-size";
+    private static final String LONG_DATAID = "transport.thread-factory.worker-thread-size";
+    private static final String BOOLEAN_DATAID = "service.disable";
+    private static final String STRING_DATAID = "transport.type";
+    private static final String PUT_DATAID = "transport.mock";
+    private static final String NOT_EXIST_DATAID = "service.yyy.xxx";
+
+    @Test
+    public void testGetInt() {
+        Assert.assertEquals(FILE_CONFIG.getInt(INT_DATAID), CONFIG.getInt(INT_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getInt(NOT_EXIST_DATAID), 0);
     }
 
-    @org.junit.Test
-    public void isRunAsServerProxy() throws Exception {
-
+    @Test
+    public void testGetInt1() {
+        Assert.assertEquals(FILE_CONFIG.getInt(INT_DATAID, 999), CONFIG.getInt(INT_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getInt(NOT_EXIST_DATAID, 999), 999);
     }
 
-    @org.junit.Test
-    public void getConfig() throws Exception {
-
-        String server = fileConfiguration.getConfig("transport.server");
-        System.out.println(server);
-        //TRANSPORT_SERVER_TYPE = TransportServerType.valueOf(CONFIG.getConfig("transport.server"));
+    @Test
+    public void testGetInt2() {
+        Assert.assertEquals(FILE_CONFIG.getInt(INT_DATAID, 999, 1000), CONFIG.getInt(INT_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getInt(NOT_EXIST_DATAID, 999, 1000), 999);
     }
 
-    @org.junit.Test
-    public void getConfig1() throws Exception {
-        String shareBossWorker = fileConfiguration.getConfig("transport.thread-factory.share-boss-worker");
-        System.out.println(shareBossWorker);
+    @Test
+    public void testGetLong() {
+        Assert.assertEquals(FILE_CONFIG.getLong(LONG_DATAID), CONFIG.getLong(LONG_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getLong(NOT_EXIST_DATAID), 0);
     }
 
-    @org.junit.Test
-    public void getConfig2() throws Exception {
-
+    @Test
+    public void testGetLong1() {
+        Assert.assertEquals(FILE_CONFIG.getLong(LONG_DATAID, 999L), CONFIG.getLong(LONG_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getLong(NOT_EXIST_DATAID, 999L), 999L);
     }
 
-    @org.junit.Test
-    public void getConfig3() throws Exception {
-
+    @Test
+    public void testGetLong2() {
+        Assert.assertEquals(FILE_CONFIG.getLong(LONG_DATAID, 999L, 1000), CONFIG.getLong(LONG_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getLong(NOT_EXIST_DATAID, 999L, 1000), 999L);
     }
 
-    @org.junit.Test
-    public void putConfig() throws Exception {
-
+    @Test
+    public void testGetBoolean() {
+        Assert.assertEquals(FILE_CONFIG.getBoolean(BOOLEAN_DATAID), CONFIG.getBoolean(BOOLEAN_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getBoolean(NOT_EXIST_DATAID), false);
     }
 
-    @org.junit.Test
-    public void putConfig1() throws Exception {
+    @Test
+    public void testGetBoolean1() {
+        Assert.assertEquals(FILE_CONFIG.getBoolean(BOOLEAN_DATAID, true), CONFIG.getBoolean(BOOLEAN_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getBoolean(NOT_EXIST_DATAID, false), false);
+    }
 
+    @Test
+    public void testGetBoolean2() {
+        Assert.assertEquals(FILE_CONFIG.getBoolean(BOOLEAN_DATAID, true, 1000), CONFIG.getBoolean(BOOLEAN_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getBoolean(NOT_EXIST_DATAID, false, 1000), false);
     }
 
-    @org.junit.Test
-    public void putConfigIfAbsent() throws Exception {
+    @Test
+    public void testGetConfig() {
+        Assert.assertEquals(FILE_CONFIG.getConfig(STRING_DATAID), CONFIG.getString(STRING_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getConfig(NOT_EXIST_DATAID), null);
+    }
 
+    @Test
+    public void testGetConfig1() {
+        Assert.assertEquals(FILE_CONFIG.getConfig(STRING_DATAID, 1000), CONFIG.getString(STRING_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getConfig(NOT_EXIST_DATAID, 1000), null);
     }
 
-    @org.junit.Test
-    public void putConfigIfAbsent1() throws Exception {
+    @Test
+    public void testGetConfig2() {
+        Assert.assertEquals(FILE_CONFIG.getConfig(STRING_DATAID, "123"), CONFIG.getString(STRING_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getConfig(NOT_EXIST_DATAID, "123"), "123");
+    }
 
+    @Test
+    public void testGetConfig3() {
+        Assert.assertEquals(FILE_CONFIG.getConfig(STRING_DATAID, "123", 1000), CONFIG.getString(STRING_DATAID));
+        Assert.assertEquals(FILE_CONFIG.getConfig(NOT_EXIST_DATAID, "123", 1000), "123");
     }
 
-    @org.junit.Test
-    public void removeConfig() throws Exception {
+    @Test
+    public void testPutConfig() {
+        Assert.assertTrue(FILE_CONFIG.putConfig(PUT_DATAID, "123"));
+    }
 
+    @Test
+    public void testPutConfig1() {
+        Assert.assertTrue(FILE_CONFIG.putConfig(PUT_DATAID, "123", 5000));
     }
 
-    @org.junit.Test
-    public void removeConfig1() throws Exception {
+    @Test
+    public void testPutConfigIfAbsent() {
+        Assert.assertTrue(FILE_CONFIG.putConfigIfAbsent(PUT_DATAID, "123"));
+    }
 
+    @Test
+    public void testPutConfigIfAbsent1() {
+        Assert.assertTrue(FILE_CONFIG.putConfigIfAbsent(PUT_DATAID, "123", 5000));
     }
 
-    @org.junit.Test
-    public void addConfigListener() throws Exception {
+    @Test
+    public void testRemoveConfig() {
+        Assert.assertTrue(FILE_CONFIG.removeConfig(PUT_DATAID));
+    }
 
+    @Test
+    public void testRemoveConfig1() {
+        Assert.assertTrue(FILE_CONFIG.removeConfig(PUT_DATAID, 5000));
     }
 
-    @org.junit.Test
-    public void removeConfigListener() throws Exception {
+    @Test(dataProvider = "listenerProvider")
+    public void testAddConfigListener(ConfigChangeListener listener) {
+        FILE_CONFIG.addConfigListener(INT_DATAID, listener);
+        Assert.assertEquals(FILE_CONFIG.getConfigListeners(INT_DATAID).size(), 1);
+    }
 
+    @Test(dataProvider = "listenerProvider")
+    public void testRemoveConfigListener(ConfigChangeListener listener) {
+        int currSize = FILE_CONFIG.getConfigListeners(INT_DATAID).size();
+        FILE_CONFIG.addConfigListener(INT_DATAID, listener);
+        FILE_CONFIG.removeConfigListener(INT_DATAID, listener);
+        Assert.assertEquals(FILE_CONFIG.getConfigListeners(INT_DATAID).size(), currSize);
     }
 
-}
+    @DataProvider
+    public static Object[][] listenerProvider() {
+        ConfigChangeListener listener = new ConfigChangeListener() {
+            @Override
+            public ExecutorService getExecutor() {
+                return null;
+            }
+
+            @Override
+            public void receiveConfigInfo(String configInfo) {
+                System.out.print(configInfo);
+            }
+        };
+        return new Object[][] {{listener}};
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/BranchCommitRequestTest.java b/core/src/test/java/com/alibaba/fescar/core/message/BranchCommitRequestTest.java
new file mode 100644
index 000000000..63e94fae9
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/BranchCommitRequestTest.java
@@ -0,0 +1,44 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.core.protocol.transaction.BranchCommitRequest;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/23
+ */
+public class BranchCommitRequestTest {
+
+  @Test
+  public void toStringTest() throws Exception{
+    BranchCommitRequest branchCommitRequest = new BranchCommitRequest();
+
+    branchCommitRequest.setXid("127.0.0.1:9999:39875642");
+    branchCommitRequest.setBranchId(1);
+    branchCommitRequest.setBranchType(BranchType.AT);
+    branchCommitRequest.setResourceId("resource1");
+    branchCommitRequest.setApplicationData("app1");
+
+    Assert.assertEquals("xid=127.0.0.1:9999:39875642,branchId=1,branchType=AT,"
+                        + "resourceId=resource1,applicationData=app1", branchCommitRequest.toString());
+
+  }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/BranchCommitResponseTest.java b/core/src/test/java/com/alibaba/fescar/core/message/BranchCommitResponseTest.java
new file mode 100644
index 000000000..330807879
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/BranchCommitResponseTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import com.alibaba.fescar.core.model.BranchStatus;
+import com.alibaba.fescar.core.protocol.ResultCode;
+import com.alibaba.fescar.core.protocol.transaction.BranchCommitResponse;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/23
+ */
+public class BranchCommitResponseTest {
+  @Test
+  public void toStringTest() throws Exception{
+    BranchCommitResponse branchCommitResponse = new BranchCommitResponse();
+
+    branchCommitResponse.setBranchStatus(BranchStatus.PhaseOne_Done);
+    branchCommitResponse.setResultCode(ResultCode.Success);
+    branchCommitResponse.setMsg("");
+
+    System.out.println(branchCommitResponse.toString());
+
+    Assert.assertEquals("branchStatus=PhaseOne_Done,result code =Success,getMsg =", branchCommitResponse.toString());
+
+  }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/BranchRegisterRequestTest.java b/core/src/test/java/com/alibaba/fescar/core/message/BranchRegisterRequestTest.java
new file mode 100644
index 000000000..9ca153bab
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/BranchRegisterRequestTest.java
@@ -0,0 +1,43 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.core.protocol.transaction.BranchRegisterRequest;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/23
+ */
+public class BranchRegisterRequestTest {
+  @Test
+  public void toStringTest() throws Exception{
+    BranchRegisterRequest branchRegisterRequest = new BranchRegisterRequest();
+
+    branchRegisterRequest.setTransactionId(123456);
+    branchRegisterRequest.setBranchType(BranchType.AT);
+    branchRegisterRequest.setResourceId("resource1");
+    branchRegisterRequest.setLockKey("lock_key_1");
+
+    System.out.println(branchRegisterRequest.toString());
+
+    Assert.assertEquals("transactionId=123456,branchType=AT,resourceId=resource1,lockKey=lock_key_1", branchRegisterRequest.toString());
+
+  }
+}
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/BranchReportRequestTest.java b/core/src/test/java/com/alibaba/fescar/core/message/BranchReportRequestTest.java
new file mode 100644
index 000000000..df30f0fa9
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/BranchReportRequestTest.java
@@ -0,0 +1,95 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.alibaba.fescar.core.model.BranchStatus;
+import com.alibaba.fescar.core.protocol.transaction.BranchReportRequest;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/24
+ */
+public class BranchReportRequestTest {
+
+    @Test
+    public void testToString() throws Exception {
+        BranchReportRequest branchReportRequest = new BranchReportRequest();
+
+        branchReportRequest.setTransactionId(1249853);
+        branchReportRequest.setBranchId(3);
+        branchReportRequest.setResourceId("resource003");
+        branchReportRequest.setStatus(BranchStatus.PhaseOne_Timeout);
+        branchReportRequest.setApplicationData("test app data");
+
+        Assert.assertEquals(
+            "transactionId=1249853,branchId=3,resourceId=resource003,status=PhaseOne_Timeout,applicationData=test app"
+                + " data",
+            branchReportRequest.toString());
+    }
+
+    @Test
+    public void testEncode() throws Exception {
+        BranchReportRequest branchReportRequest = new BranchReportRequest();
+
+        branchReportRequest.setTransactionId(1249853);
+        branchReportRequest.setBranchId(3);
+        branchReportRequest.setResourceId("resource003");
+        branchReportRequest.setStatus(BranchStatus.PhaseOne_Timeout);
+        branchReportRequest.setApplicationData("test app data");
+
+        byte[] encodeResult = branchReportRequest.encode();
+        System.out.println(encodeResult);
+        String encodeResultStr = Arrays.toString(encodeResult);
+        System.out.println(encodeResultStr);
+
+        Assert.assertEquals(
+            "[0, 0, 0, 0, 0, 19, 18, 61, 0, 0, 0, 0, 0, 0, 0, 3, 4, 0, 11, 114, 101, 115, 111, 117, 114, 99, 101, 48,"
+                + " 48, 51, 0, 0, 0, 13, 116, 101, 115, 116, 32, 97, 112, 112, 32, 100, 97, 116, 97]",
+            encodeResultStr);
+    }
+
+    @Test
+    public void testDecode() throws Exception {
+        BranchReportRequest branchReportRequest = new BranchReportRequest();
+
+        branchReportRequest.setTransactionId(1249853);
+        branchReportRequest.setBranchId(3);
+        branchReportRequest.setResourceId("resource003");
+        branchReportRequest.setStatus(BranchStatus.PhaseOne_Timeout);
+        branchReportRequest.setApplicationData("test app data");
+
+        byte[] encodeResult = branchReportRequest.encode();
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(encodeResult.length);
+        byteBuffer.put(encodeResult);
+        byteBuffer.flip();
+
+        BranchReportRequest decodeBranchReportRequest = new BranchReportRequest();
+        decodeBranchReportRequest.decode(byteBuffer);
+        System.out.println(decodeBranchReportRequest);
+        Assert.assertEquals(branchReportRequest.getTransactionId(), decodeBranchReportRequest.getTransactionId());
+        Assert.assertEquals(branchReportRequest.getBranchId(), decodeBranchReportRequest.getBranchId());
+        Assert.assertEquals(branchReportRequest.getResourceId(), decodeBranchReportRequest.getResourceId());
+        Assert.assertEquals(branchReportRequest.getStatus(), decodeBranchReportRequest.getStatus());
+        Assert.assertEquals(branchReportRequest.getApplicationData(), decodeBranchReportRequest.getApplicationData());
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/CodecTest.java b/core/src/test/java/com/alibaba/fescar/core/message/CodecTest.java
index c033ce895..dae5a7c9e 100644
--- a/core/src/test/java/com/alibaba/fescar/core/message/CodecTest.java
+++ b/core/src/test/java/com/alibaba/fescar/core/message/CodecTest.java
@@ -16,17 +16,16 @@
 
 package com.alibaba.fescar.core.message;
 
-import java.nio.ByteBuffer;
-
 import com.alibaba.fescar.core.protocol.ResultCode;
 import com.alibaba.fescar.core.protocol.transaction.BranchRegisterResponse;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
+import java.nio.ByteBuffer;
+
 public class CodecTest {
 
-    @Test @Ignore
+    @Test
     public void testA() {
 
         long tid = 232323L;
@@ -41,6 +40,7 @@ public class CodecTest {
 
         ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
         byteBuffer.put(bytes);
+        byteBuffer.flip();
 
         BranchRegisterResponse rs = new BranchRegisterResponse();
         rs.decode(byteBuffer);
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/GlobalBeginRequestTest.java b/core/src/test/java/com/alibaba/fescar/core/message/GlobalBeginRequestTest.java
new file mode 100644
index 000000000..6f58591f1
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/GlobalBeginRequestTest.java
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.alibaba.fescar.core.protocol.transaction.GlobalBeginRequest;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/24
+ */
+public class GlobalBeginRequestTest {
+
+    @Test
+    public void testToString() throws Exception {
+        GlobalBeginRequest globalBeginRequest = new GlobalBeginRequest();
+        globalBeginRequest.setTransactionName("tran 1");
+        System.out.println(globalBeginRequest.toString());
+
+        Assert.assertEquals("timeout=60000,transactionName=tran 1", globalBeginRequest.toString());
+    }
+
+    @Test
+    public void testEncode() throws Exception {
+        GlobalBeginRequest globalBeginRequest = new GlobalBeginRequest();
+        globalBeginRequest.setTransactionName("tran 1");
+
+        byte[] encodeResult = globalBeginRequest.encode();
+        String encodeResultStr = Arrays.toString(encodeResult);
+
+        Assert.assertEquals("[0, 0, -22, 96, 0, 6, 116, 114, 97, 110, 32, 49]", encodeResultStr);
+    }
+
+    @Test
+    public void testDecode() throws Exception {
+        GlobalBeginRequest globalBeginRequest = new GlobalBeginRequest();
+        globalBeginRequest.setTransactionName("tran 1");
+
+        byte[] encodeResult = globalBeginRequest.encode();
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(encodeResult.length);
+        byteBuffer.put(encodeResult);
+        byteBuffer.flip();
+
+        GlobalBeginRequest decodeGlobalBeginRequest = new GlobalBeginRequest();
+        decodeGlobalBeginRequest.decode(byteBuffer);
+        System.out.println(decodeGlobalBeginRequest);
+        Assert.assertEquals(globalBeginRequest.getTimeout(), decodeGlobalBeginRequest.getTimeout());
+        Assert.assertEquals(globalBeginRequest.getTransactionName(), decodeGlobalBeginRequest.getTransactionName());
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/GlobalCommitResponseTest.java b/core/src/test/java/com/alibaba/fescar/core/message/GlobalCommitResponseTest.java
new file mode 100644
index 000000000..9e19b85a9
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/GlobalCommitResponseTest.java
@@ -0,0 +1,116 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.alibaba.fescar.core.model.GlobalStatus;
+import com.alibaba.fescar.core.protocol.ResultCode;
+import com.alibaba.fescar.core.protocol.transaction.GlobalCommitResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/24
+ */
+public class GlobalCommitResponseTest {
+
+    @Test
+    public void testToString() throws Exception {
+        GlobalCommitResponse globalCommitResponse = new GlobalCommitResponse();
+
+        globalCommitResponse.setGlobalStatus(GlobalStatus.Committed);
+        globalCommitResponse.setResultCode(ResultCode.Success);
+        globalCommitResponse.setMsg("OK");
+
+        System.out.println(globalCommitResponse.toString());
+
+        Assert.assertEquals("globalStatus=Committed,ResultCode=Success,Msg=OK", globalCommitResponse.toString());
+    }
+
+    @Test
+    public void testEncode() throws Exception {
+        GlobalCommitResponse globalCommitResponse = new GlobalCommitResponse();
+
+        globalCommitResponse.setGlobalStatus(GlobalStatus.Committed);
+        globalCommitResponse.setResultCode(ResultCode.Success);
+        globalCommitResponse.setMsg("OK");
+
+        System.out.println(globalCommitResponse.toString());
+
+        byte[] encodeResult = globalCommitResponse.encode();
+        System.out.println(encodeResult);
+        String encodeResultStr = Arrays.toString(encodeResult);
+        System.out.println(encodeResultStr);
+
+        Assert.assertEquals("[1, 0, 8]", encodeResultStr);
+    }
+
+    @Test
+    public void testDecodeNormal() throws Exception {
+        GlobalCommitResponse globalCommitResponse = new GlobalCommitResponse();
+
+        globalCommitResponse.setGlobalStatus(GlobalStatus.Committed);
+        globalCommitResponse.setResultCode(ResultCode.Success);
+        globalCommitResponse.setMsg("OK");
+
+        System.out.println(globalCommitResponse.toString());
+
+        byte[] encodeResult = globalCommitResponse.encode();
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(encodeResult.length);
+        byteBuffer.put(encodeResult);
+        byteBuffer.flip();
+        GlobalCommitResponse decodeGlobalCommitResponse = new GlobalCommitResponse();
+        decodeGlobalCommitResponse.decode(byteBuffer);
+
+        System.out.println(decodeGlobalCommitResponse.toString());
+
+        Assert.assertEquals(globalCommitResponse.getGlobalStatus(), decodeGlobalCommitResponse.getGlobalStatus());
+        Assert.assertEquals(globalCommitResponse.getResultCode(), decodeGlobalCommitResponse.getResultCode());
+        //success response do not have msg
+        Assert.assertTrue(StringUtils.isBlank(decodeGlobalCommitResponse.getMsg()));
+    }
+
+    @Test
+    public void testDecodeException() throws Exception {
+        GlobalCommitResponse globalCommitResponse = new GlobalCommitResponse();
+
+        globalCommitResponse.setGlobalStatus(GlobalStatus.CommitFailed);
+        globalCommitResponse.setResultCode(ResultCode.Failed);
+        globalCommitResponse.setMsg("error happened");
+
+        System.out.println(globalCommitResponse.toString());
+
+        byte[] encodeResult = globalCommitResponse.encode();
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(encodeResult.length);
+        byteBuffer.put(encodeResult);
+        byteBuffer.flip();
+        GlobalCommitResponse decodeGlobalCommitResponse = new GlobalCommitResponse();
+        decodeGlobalCommitResponse.decode(byteBuffer);
+
+        System.out.println(decodeGlobalCommitResponse.toString());
+
+        Assert.assertEquals(globalCommitResponse.getGlobalStatus(), decodeGlobalCommitResponse.getGlobalStatus());
+        Assert.assertEquals(globalCommitResponse.getResultCode(), decodeGlobalCommitResponse.getResultCode());
+        Assert.assertEquals(globalCommitResponse.getMsg(), decodeGlobalCommitResponse.getMsg());
+    }
+}
\ No newline at end of file
diff --git a/core/src/test/java/com/alibaba/fescar/core/message/GlobalRollbackRequestTest.java b/core/src/test/java/com/alibaba/fescar/core/message/GlobalRollbackRequestTest.java
new file mode 100644
index 000000000..dace51055
--- /dev/null
+++ b/core/src/test/java/com/alibaba/fescar/core/message/GlobalRollbackRequestTest.java
@@ -0,0 +1,82 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.core.message;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+import com.alibaba.fescar.core.protocol.transaction.GlobalRollbackRequest;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author xiajun.0706@163.com
+ * @since 2019/1/24
+ */
+public class GlobalRollbackRequestTest {
+
+    @Test
+    public void testToString() throws Exception {
+        GlobalRollbackRequest globalRollbackRequest = new GlobalRollbackRequest();
+
+        globalRollbackRequest.setTransactionId(1249853);
+        globalRollbackRequest.setExtraData("test_extra_data");
+
+        System.out.println(globalRollbackRequest.toString());
+
+        Assert.assertEquals("transactionId=1249853,extraData=test_extra_data", globalRollbackRequest.toString());
+    }
+
+    @Test
+    public void testEncode() throws Exception {
+        GlobalRollbackRequest globalRollbackRequest = new GlobalRollbackRequest();
+
+        globalRollbackRequest.setTransactionId(1249853);
+        globalRollbackRequest.setExtraData("test_extra_data");
+
+        System.out.println(globalRollbackRequest.toString());
+
+        byte[] encodeResult = globalRollbackRequest.encode();
+        System.out.println(encodeResult);
+        String encodeResultStr = Arrays.toString(encodeResult);
+        System.out.println(encodeResultStr);
+
+        Assert.assertEquals(
+            "[0, 0, 0, 0, 0, 19, 18, 61, 0, 15, 116, 101, 115, 116, 95, 101, 120, 116, 114, 97, 95, 100, 97, 116, 97]",
+            encodeResultStr);
+    }
+
+    @Test
+    public void testDecode() throws Exception {
+        GlobalRollbackRequest globalRollbackRequest = new GlobalRollbackRequest();
+
+        globalRollbackRequest.setTransactionId(1249853L);
+        globalRollbackRequest.setExtraData("test_extra_data");
+
+        byte[] encodeResult = globalRollbackRequest.encode();
+
+        ByteBuffer byteBuffer = ByteBuffer.allocate(encodeResult.length);
+        byteBuffer.put(encodeResult);
+        byteBuffer.flip();
+
+        GlobalRollbackRequest decodeGlobalRollbackRequest = new GlobalRollbackRequest();
+        decodeGlobalRollbackRequest.decode(byteBuffer);
+        System.out.println(decodeGlobalRollbackRequest);
+        Assert.assertEquals(globalRollbackRequest.getTransactionId(), decodeGlobalRollbackRequest.getTransactionId());
+        Assert.assertEquals(globalRollbackRequest.getExtraData(), decodeGlobalRollbackRequest.getExtraData());
+    }
+}
\ No newline at end of file
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/SQLVisitorFactoryTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/SQLVisitorFactoryTest.java
new file mode 100644
index 000000000..e578f4377
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/SQLVisitorFactoryTest.java
@@ -0,0 +1,23 @@
+package com.alibaba.fescar.rm.datasource;
+
+import com.alibaba.druid.util.JdbcConstants;
+import com.alibaba.fescar.rm.datasource.sql.SQLRecognizer;
+import com.alibaba.fescar.rm.datasource.sql.SQLVisitorFactory;
+import com.alibaba.fescar.rm.datasource.sql.druid.MySQLSelectForUpdateRecognizer;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class SQLVisitorFactoryTest {
+
+    @Test
+    public void testSqlRecognizing() {
+        String dbType = JdbcConstants.MYSQL;
+        String sql = "select a, b, c from t1 where id = 9";
+        SQLRecognizer recognizer = SQLVisitorFactory.get(sql, dbType);
+        Assert.assertNull(recognizer);
+
+        sql = sql + " for update";
+        recognizer = SQLVisitorFactory.get(sql, dbType);
+        Assert.assertTrue(recognizer instanceof MySQLSelectForUpdateRecognizer);
+    }
+}
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/AbstractMySQLRecognizerTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/AbstractMySQLRecognizerTest.java
new file mode 100644
index 000000000..2deac23c9
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/AbstractMySQLRecognizerTest.java
@@ -0,0 +1,35 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.rm.datasource.sql.druid;
+
+import java.util.List;
+
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+
+/**
+ * @author hanwen
+ * created at 2019-01-25
+ */
+public class AbstractMySQLRecognizerTest {
+
+    public SQLStatement getSQLStatement(String sql) {
+        List<SQLStatement> stats = SQLUtils.parseStatements(sql, "mysql");
+        return stats.get(0);
+    }
+
+}
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizerTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizerTest.java
new file mode 100644
index 000000000..cfae29109
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLDeleteRecognizerTest.java
@@ -0,0 +1,76 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.rm.datasource.sql.druid;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.fescar.rm.datasource.ParametersHolder;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author hanwen
+ * created at 2019-01-25
+ */
+public class MySQLDeleteRecognizerTest extends AbstractMySQLRecognizerTest {
+
+    @Test
+    public void deleteRecognizerTest_0() {
+
+        String sql = "DELETE FROM t1 WHERE id = 'id1'";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLDeleteRecognizer.getTableName());
+        Assert.assertEquals("id = 'id1'", mySQLDeleteRecognizer.getWhereCondition());
+    }
+
+    @Test
+    public void deleteRecognizerTest_1() {
+
+        String sql = "DELETE FROM t1 WHERE id = ?";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLDeleteRecognizer.getTableName());
+
+        // test overflow parameters
+        ArrayList<Object> paramAppender = new ArrayList<>();
+        String whereCondition = mySQLDeleteRecognizer.getWhereCondition(new ParametersHolder() {
+            @Override
+            public ArrayList<Object>[] getParameters() {
+                ArrayList<Object> idParam = new ArrayList<>();
+                idParam.add("id1");
+                ArrayList<Object> nameParam = new ArrayList<>();
+                nameParam.add("name1");
+                return new ArrayList[] {idParam, nameParam};
+            }
+        }, paramAppender);
+
+        Assert.assertEquals(Collections.singletonList("id1"), paramAppender);
+        Assert.assertEquals("id = ?", whereCondition);
+    }
+}
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizerTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizerTest.java
new file mode 100644
index 000000000..af5c91c69
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLInsertRecognizerTest.java
@@ -0,0 +1,83 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.rm.datasource.sql.druid;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import com.alibaba.druid.sql.ast.SQLStatement;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author hanwen
+ * created at 2019-01-25
+ */
+public class MySQLInsertRecognizerTest extends AbstractMySQLRecognizerTest {
+
+    @Test
+    public void insertRecognizerTest_0() {
+
+        String sql = "INSERT INTO t1 (name) VALUES ('name1')";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLInsertRecognizer mySQLInsertRecognizer = new MySQLInsertRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLInsertRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLInsertRecognizer.getTableName());
+        Assert.assertEquals(Collections.singletonList("name"), mySQLInsertRecognizer.getInsertColumns());
+        Assert.assertEquals(1, mySQLInsertRecognizer.getInsertRows().size());
+        Assert.assertEquals(Collections.singletonList("name1"), mySQLInsertRecognizer.getInsertRows().get(0));
+    }
+
+    @Test
+    public void insertRecognizerTest_1() {
+
+        String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2')";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLInsertRecognizer mySQLInsertRecognizer = new MySQLInsertRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLInsertRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLInsertRecognizer.getTableName());
+        Assert.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertColumns());
+        Assert.assertEquals(1, mySQLInsertRecognizer.getInsertRows().size());
+        Assert.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertRows().get(0));
+    }
+
+    @Test
+    public void insertRecognizerTest_3() {
+
+        String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2'), ('name3', 'name4'), ('name5', 'name6')";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLInsertRecognizer mySQLInsertRecognizer = new MySQLInsertRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLInsertRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLInsertRecognizer.getTableName());
+        Assert.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertColumns());
+        Assert.assertEquals(3, mySQLInsertRecognizer.getInsertRows().size());
+        Assert.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertRows().get(0));
+        Assert.assertEquals(Arrays.asList("name3", "name4"), mySQLInsertRecognizer.getInsertRows().get(1));
+        Assert.assertEquals(Arrays.asList("name5", "name6"), mySQLInsertRecognizer.getInsertRows().get(2));
+    }
+
+}
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizerTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizerTest.java
new file mode 100644
index 000000000..9d82e3f71
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLSelectForUpdateRecognizerTest.java
@@ -0,0 +1,98 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.rm.datasource.sql.druid;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.fescar.rm.datasource.ParametersHolder;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MySQLSelectForUpdateRecognizerTest extends AbstractMySQLRecognizerTest {
+
+    @Test
+    public void selectForUpdateRecognizerTest_0() {
+
+        String sql = "SELECT name FROM t1 WHERE id = 'id1' FOR UPDATE";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
+        Assert.assertEquals("id = 'id1'", mySQLUpdateRecognizer.getWhereCondition());
+    }
+
+    @Test
+    public void selectForUpdateRecognizerTest_1() {
+
+        String sql = "SELECT name FROM t1 WHERE id = ? FOR UPDATE";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
+
+        ArrayList<Object> paramAppender = new ArrayList<>();
+        String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
+            @Override
+            public ArrayList<Object>[] getParameters() {
+                ArrayList<Object> idParam = new ArrayList<>();
+                idParam.add("id1");
+                return new ArrayList[] {idParam};
+            }
+        }, paramAppender);
+
+        Assert.assertEquals(Collections.singletonList("id1"), paramAppender);
+        Assert.assertEquals("id = ?", whereCondition);
+    }
+
+    @Test
+    public void selectForUpdateRecognizerTest_3() {
+
+        String sql = "SELECT name1, name2 FROM t1 WHERE id1 = ? FOR UPDATE";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
+
+        // test overflow parameters
+        ArrayList<Object> paramAppender = new ArrayList<>();
+        String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
+            @Override
+            public ArrayList<Object>[] getParameters() {
+                ArrayList<Object> id1Param = new ArrayList<>();
+                id1Param.add("id1");
+                ArrayList<Object> id2Param = new ArrayList<>();
+                id2Param.add("id2");
+                return new ArrayList[] {id1Param, id2Param};
+            }
+        }, paramAppender);
+
+        Assert.assertEquals(Collections.singletonList("id1"), paramAppender);
+        Assert.assertEquals("id1 = ?", whereCondition);
+    }
+}
diff --git a/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizerTest.java b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizerTest.java
new file mode 100644
index 000000000..dd8039b1a
--- /dev/null
+++ b/rm-datasource/src/test/java/com/alibaba/fescar/rm/datasource/sql/druid/MySQLUpdateRecognizerTest.java
@@ -0,0 +1,97 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package com.alibaba.fescar.rm.datasource.sql.druid;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.fescar.rm.datasource.ParametersHolder;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class MySQLUpdateRecognizerTest extends AbstractMySQLRecognizerTest {
+
+    @Test
+    public void updateRecognizerTest_0() {
+
+        String sql = "UPDATE t1 SET name = 'name1' WHERE id = 'id1'";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
+        Assert.assertEquals(1, mySQLUpdateRecognizer.getUpdateColumns().size());
+        Assert.assertEquals("name", mySQLUpdateRecognizer.getUpdateColumns().get(0));
+        Assert.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
+        Assert.assertEquals("id = 'id1'", mySQLUpdateRecognizer.getWhereCondition());
+    }
+
+    @Test
+    public void updateRecognizerTest_1() {
+
+        String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = 'id1'";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
+        Assert.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
+        Assert.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
+        Assert.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
+        Assert.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
+        Assert.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
+        Assert.assertEquals("id = 'id1'", mySQLUpdateRecognizer.getWhereCondition());
+    }
+
+    @Test
+    public void updateRecognizerTest_2() {
+
+        String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = ?";
+
+        SQLStatement statement = getSQLStatement(sql);
+
+        MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
+
+        Assert.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
+        Assert.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
+        Assert.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
+        Assert.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
+        Assert.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
+        Assert.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
+        Assert.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
+
+        ArrayList<Object> paramAppender = new ArrayList<>();
+        String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
+            @Override
+            public ArrayList<Object>[] getParameters() {
+                ArrayList<Object> idParam = new ArrayList<>();
+                idParam.add("id1");
+                return new ArrayList[] {idParam};
+            }
+        }, paramAppender);
+
+        Assert.assertEquals(Collections.singletonList("id1"), paramAppender);
+
+        Assert.assertEquals("id = ?", whereCondition);
+    }
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/coordinator/DefaultCoreTest.java b/server/src/test/java/com/alibaba/fescar/server/coordinator/DefaultCoreTest.java
new file mode 100644
index 000000000..8aafcb42c
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/coordinator/DefaultCoreTest.java
@@ -0,0 +1,145 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.coordinator;
+
+import java.util.Collection;
+
+import com.alibaba.fescar.common.XID;
+import com.alibaba.fescar.core.model.BranchStatus;
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.core.model.GlobalStatus;
+import com.alibaba.fescar.server.session.BranchSession;
+import com.alibaba.fescar.server.session.GlobalSession;
+import com.alibaba.fescar.server.session.SessionHolder;
+
+import org.testng.Assert;
+import org.testng.annotations.AfterTest;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author zhimo.xiao@gmail.com
+ * @since 2019/1/23
+ */
+
+public class DefaultCoreTest {
+
+    private static Core core = new DefaultCore();
+
+    private static final String applicationId = "demo-child-app";
+
+    private static final String txServiceGroup = "my_test_tx_group";
+
+    private static final String txName = "tx-1";
+
+    private static final int timeout = 3000;
+
+    private static final String resourceId = "tb_1";
+
+    private static final String clientId = "c_1";
+
+    private static final String lockKeys_1 = "tb_1:11";
+
+    private static final String lockKeys_2 = "tb_1:12";
+
+    private static final String applicationData = "{\"data\":\"test\"}";
+
+    @BeforeTest
+    public void initSessionManager() throws Exception {
+        SessionHolder.init(null);
+    }
+
+    @Test(dataProvider = "xidProvider")
+    public void branchRegisterTest(String xid) throws Exception {
+        core.branchRegister(BranchType.AT, resourceId, clientId, xid, lockKeys_1);
+
+        long transactionId = XID.getTransactionId(xid);
+        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+        Assert.assertEquals(globalSession.getSortedBranches().size(), 1);
+    }
+
+    @Test(dataProvider = "xidAndBranchIdProvider")
+    public void branchReportTest(String xid, Long branchId) throws Exception {
+        core.branchReport(xid, branchId, BranchStatus.PhaseOne_Done, applicationData);
+
+        long transactionId = XID.getTransactionId(xid);
+        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+        BranchSession branchSession = globalSession.getBranch(branchId);
+        Assert.assertEquals(branchSession.getStatus(), BranchStatus.PhaseOne_Done);
+    }
+
+    @Test
+    public void beginTest() throws Exception {
+        String xid = core.begin(applicationId, txServiceGroup, txName, timeout);
+
+        long transactionId = XID.getTransactionId(xid);
+        GlobalSession globalSession = SessionHolder.findGlobalSession(transactionId);
+        Assert.assertNotNull(globalSession);
+    }
+
+    @Test(dataProvider = "xidProvider")
+    public void commitTest(String xid) throws Exception {
+        GlobalStatus globalStatus = core.commit(xid);
+        Assert.assertEquals(globalStatus, GlobalStatus.Begin);
+    }
+
+    @Test(dataProvider = "xidProvider")
+    public void doGlobalCommitTest(String xid) throws Exception {
+        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+        core.doGlobalCommit(globalSession, false);
+        Assert.assertEquals(globalSession.getStatus(), GlobalStatus.Committed);
+    }
+
+    @Test(dataProvider = "xidProvider")
+    public void rollBackTest(String xid) throws Exception {
+        GlobalStatus globalStatus = core.rollback(xid);
+        Assert.assertEquals(globalStatus, GlobalStatus.Rollbacked);
+    }
+
+    @Test(dataProvider = "xidProvider")
+    public void doGlobalRollBackTest(String xid) throws Exception {
+        GlobalSession globalSession = SessionHolder.findGlobalSession(XID.getTransactionId(xid));
+        core.doGlobalRollback(globalSession, false);
+        Assert.assertEquals(globalSession.getStatus(), GlobalStatus.Rollbacked);
+    }
+
+    @DataProvider
+    public static Object[][] xidProvider() throws Exception {
+        String xid = core.begin(applicationId, txServiceGroup, txName, timeout);
+        return new Object[][] {{xid}};
+    }
+
+    @DataProvider
+    public static Object[][] xidAndBranchIdProvider() throws Exception {
+        String xid = core.begin(applicationId, txServiceGroup, txName, timeout);
+        Long branchId = core.branchRegister(BranchType.AT, resourceId, clientId, xid, lockKeys_2);
+        return new Object[][] {{xid, branchId}};
+    }
+
+    @AfterTest
+    public void releaseSessionManager() throws Exception {
+        Collection<GlobalSession> globalSessions = SessionHolder.getRootSessionManager().allSessions();
+        Collection<GlobalSession> asyncGlobalSessions = SessionHolder.getAsyncCommittingSessionManager().allSessions();
+        for (GlobalSession asyncGlobalSession : asyncGlobalSessions) {
+            asyncGlobalSession.closeAndClean();
+        }
+        for (GlobalSession globalSession : globalSessions) {
+            globalSession.closeAndClean();
+        }
+    }
+
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/lock/DefaultLockManagerImplTest.java b/server/src/test/java/com/alibaba/fescar/server/lock/DefaultLockManagerImplTest.java
new file mode 100644
index 000000000..f69537469
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/lock/DefaultLockManagerImplTest.java
@@ -0,0 +1,71 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.lock;
+
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.server.UUIDGenerator;
+import com.alibaba.fescar.server.session.BranchSession;
+
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author zhimo.xiao@gmail.com
+ * @since 2019/1/23
+ */
+
+public class DefaultLockManagerImplTest {
+
+    private LockManager lockManager = new DefaultLockManagerImpl();
+
+    private static final long transactionId = UUIDGenerator.generateUUID();
+
+    private static final String resourceId = "tb_1";
+
+    private static final String lockKey = "tb_1:13";
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void acquireLockTest(BranchSession branchSession) throws Exception {
+        boolean result = lockManager.acquireLock(branchSession);
+        Assert.assertTrue(result);
+        branchSession.unlock();
+    }
+
+    @Test
+    public void isLockableTest() throws Exception {
+        boolean resultOne = lockManager.isLockable(transactionId, resourceId, lockKey);
+        Assert.assertTrue(resultOne);
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionProvider() {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setBranchId(1L);
+        branchSession.setTransactionId(transactionId);
+        branchSession.setClientId("c1");
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId(resourceId);
+        branchSession.setLockKey(lockKey);
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setBranchType(BranchType.AT);
+        return new Object[][] {{branchSession}};
+    }
+
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/lock/LockManagerTest.java b/server/src/test/java/com/alibaba/fescar/server/lock/LockManagerTest.java
new file mode 100644
index 000000000..c7fc63aaa
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/lock/LockManagerTest.java
@@ -0,0 +1,103 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.lock;
+
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.server.UUIDGenerator;
+import com.alibaba.fescar.server.session.BranchSession;
+
+import org.junit.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author tianming.xm@gmail.com
+ * @since 2019/1/23
+ */
+public class LockManagerTest {
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void acquireLock_success(BranchSession branchSession) throws Exception {
+        LockManager lockManager = LockManagerFactory.get();
+        Assert.assertTrue(lockManager.acquireLock(branchSession));
+    }
+
+    @Test(dataProvider = "branchSessionsProvider")
+    public void acquireLock_failed(BranchSession branchSession1, BranchSession branchSession2) throws Exception {
+        LockManager lockManager = LockManagerFactory.get();
+        Assert.assertTrue(lockManager.acquireLock(branchSession1));
+        Assert.assertFalse(lockManager.acquireLock(branchSession2));
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void isLockableTest(BranchSession branchSession) throws Exception {
+        branchSession.setLockKey("t:4");
+        LockManager lockManager = LockManagerFactory.get();
+        Assert.assertTrue(lockManager
+            .isLockable(branchSession.getTransactionId(), branchSession.getResourceId(), branchSession.getLockKey()));
+        lockManager.acquireLock(branchSession);
+        branchSession.setTransactionId(UUIDGenerator.generateUUID());
+        Assert.assertFalse(lockManager
+            .isLockable(branchSession.getTransactionId(), branchSession.getResourceId(), branchSession.getLockKey()));
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionProvider() {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setTransactionId(UUIDGenerator.generateUUID());
+        branchSession.setBranchId(0L);
+        branchSession.setClientId("c1");
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId("tb_1");
+        branchSession.setLockKey("t:0");
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setBranchType(BranchType.AT);
+        return new Object[][] {{branchSession}};
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionsProvider() {
+        BranchSession branchSession1 = new BranchSession();
+        branchSession1.setTransactionId(UUIDGenerator.generateUUID());
+        branchSession1.setBranchId(1L);
+        branchSession1.setClientId("c1");
+        branchSession1.setResourceGroupId("my_test_tx_group");
+        branchSession1.setResourceId("tb_1");
+        branchSession1.setLockKey("t:1,2");
+        branchSession1.setBranchType(BranchType.AT);
+        branchSession1.setApplicationId("demo-child-app");
+        branchSession1.setTxServiceGroup("my_test_tx_group");
+        branchSession1.setApplicationData("{\"data\":\"test\"}");
+        branchSession1.setBranchType(BranchType.AT);
+
+        BranchSession branchSession2 = new BranchSession();
+        branchSession2.setTransactionId(UUIDGenerator.generateUUID());
+        branchSession2.setBranchId(2L);
+        branchSession2.setClientId("c1");
+        branchSession2.setResourceGroupId("my_test_tx_group");
+        branchSession2.setResourceId("tb_1");
+        branchSession2.setLockKey("t:1,2");
+        branchSession2.setBranchType(BranchType.AT);
+        branchSession2.setApplicationId("demo-child-app");
+        branchSession2.setTxServiceGroup("my_test_tx_group");
+        branchSession2.setApplicationData("{\"data\":\"test\"}");
+        branchSession2.setBranchType(BranchType.AT);
+        return new Object[][] {{branchSession1, branchSession2}};
+    }
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/session/BranchSessionTest.java b/server/src/test/java/com/alibaba/fescar/server/session/BranchSessionTest.java
new file mode 100644
index 000000000..396057ae5
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/session/BranchSessionTest.java
@@ -0,0 +1,62 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.session;
+
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.server.UUIDGenerator;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author tianming.xm@gmail.com
+ * @since 2019/1/23
+ */
+public class BranchSessionTest {
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void codecTest(BranchSession branchSession){
+        byte[] result = branchSession.encode();
+        Assert.assertNotNull(result);
+        BranchSession expected = new BranchSession();
+        expected.decode(result);
+        Assert.assertEquals(branchSession.getTransactionId(),expected.getTransactionId());
+        Assert.assertEquals(branchSession.getBranchId(),expected.getBranchId());
+        Assert.assertEquals(branchSession.getResourceId(),expected.getResourceId());
+        Assert.assertEquals(branchSession.getLockKey(),expected.getLockKey());
+        Assert.assertEquals(branchSession.getApplicationId(),expected.getApplicationId());
+        Assert.assertEquals(branchSession.getTxServiceGroup(),expected.getTxServiceGroup());
+        Assert.assertEquals(branchSession.getClientId(),expected.getClientId());
+        Assert.assertEquals(branchSession.getApplicationData(),expected.getApplicationData());
+
+    }
+    @DataProvider
+    public static Object[][] branchSessionProvider() {
+        BranchSession branchSession = new BranchSession();
+        branchSession.setTransactionId(UUIDGenerator.generateUUID());
+        branchSession.setBranchId(1L);
+        branchSession.setClientId("c1");
+        branchSession.setResourceGroupId("my_test_tx_group");
+        branchSession.setResourceId("tb_1");
+        branchSession.setLockKey("t_1");
+        branchSession.setBranchType(BranchType.AT);
+        branchSession.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setBranchType(BranchType.AT);
+        return new Object[][] {{ branchSession}};
+    }
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/session/DefaultSessionManagerTest.java b/server/src/test/java/com/alibaba/fescar/server/session/DefaultSessionManagerTest.java
new file mode 100644
index 000000000..6c26b7f82
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/session/DefaultSessionManagerTest.java
@@ -0,0 +1,203 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.session;
+
+import com.alibaba.fescar.core.model.BranchStatus;
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.core.model.GlobalStatus;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author tianming.xm@gmail.com
+ * @since 2019/1/22
+ */
+
+public class DefaultSessionManagerTest {
+
+    private SessionManager sessionManager = new DefaultSessionManager("test");
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void addGlobalSessionTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void findGlobalSessionTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        GlobalSession expected =  sessionManager.findGlobalSession(globalSession.getTransactionId());
+        Assert.assertNotNull(expected);
+        Assert.assertEquals(expected.getTransactionId(),globalSession.getTransactionId());
+        Assert.assertEquals(expected.getApplicationId(),globalSession.getApplicationId());
+        Assert.assertEquals(expected.getTransactionServiceGroup(),globalSession.getTransactionServiceGroup());
+        Assert.assertEquals(expected.getTransactionName(),globalSession.getTransactionName());
+        Assert.assertEquals(expected.getTransactionId(),globalSession.getTransactionId());
+        Assert.assertEquals(expected.getStatus(),globalSession.getStatus());
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void updateGlobalSessionStatusTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        globalSession.setStatus(GlobalStatus.Finished);
+        sessionManager.updateGlobalSessionStatus(globalSession,GlobalStatus.Finished);
+        GlobalSession expected =  sessionManager.findGlobalSession(globalSession.getTransactionId());
+        Assert.assertNotNull(expected);
+        Assert.assertEquals(GlobalStatus.Finished,expected.getStatus());
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void removeGlobalSessionTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.removeGlobalSession(globalSession);
+        GlobalSession expected =  sessionManager.findGlobalSession(globalSession.getTransactionId());
+        Assert.assertNull(expected);
+
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void addBranchSessionTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.addBranchSession(globalSession,branchSession);
+        sessionManager.removeBranchSession(globalSession,branchSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void updateBranchSessionStatusTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.addBranchSession(globalSession,branchSession);
+        sessionManager.updateBranchSessionStatus(branchSession, BranchStatus.PhaseTwo_Committed);
+        sessionManager.removeBranchSession(globalSession,branchSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void removeBranchSessionTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.addBranchSession(globalSession,branchSession);
+        sessionManager.removeBranchSession(globalSession,branchSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionsProvider")
+    public void allSessionsTest(List<GlobalSession> globalSessions) throws Exception{
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.addGlobalSession(globalSession);
+        }
+        Collection<GlobalSession> expectedGlobalSessions =  sessionManager.allSessions();
+        Assert.assertNotNull(expectedGlobalSessions);
+        Assert.assertEquals(2,expectedGlobalSessions.size());
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.removeGlobalSession(globalSession);
+        }
+    }
+
+    @Test(dataProvider = "globalSessionsProvider")
+    public void findGlobalSessionsTest(List<GlobalSession> globalSessions) throws Exception{
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.addGlobalSession(globalSession);
+        }
+        SessionCondition sessionCondition = new SessionCondition(GlobalStatus.Begin,30*24*3600);
+        Collection<GlobalSession> expectedGlobalSessions =  sessionManager.findGlobalSessions(sessionCondition);
+        Assert.assertNotNull(expectedGlobalSessions);
+        Assert.assertEquals(2,expectedGlobalSessions.size());
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.removeGlobalSession(globalSession);
+        }
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onBeginTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onEnd(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onStatusChangeTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onStatusChange(globalSession,GlobalStatus.Finished);
+        sessionManager.onEnd(globalSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void onBranchStatusChangeTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onAddBranch(globalSession,branchSession);
+        sessionManager.onBranchStatusChange(globalSession,branchSession,BranchStatus.PhaseTwo_Committed);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void onAddBranchTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onAddBranch(globalSession,branchSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void onRemoveBranchTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onAddBranch(globalSession,branchSession);
+        sessionManager.onRemoveBranch(globalSession,branchSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onCloseTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onClose(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onEndTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onEnd(globalSession);
+    }
+
+    @DataProvider
+    public static Object[][] globalSessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        return new Object[][] {{ globalSession}};
+    }
+
+    @DataProvider
+    public static Object[][] globalSessionsProvider() {
+        GlobalSession globalSession1 = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        GlobalSession globalSession2 = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        return new Object[][] {{Arrays.asList(globalSession1,globalSession2)}};
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        BranchSession branchSession = new BranchSession();
+        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.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        return new Object[][] {{ globalSession,branchSession}};
+    }
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/session/FileBasedSessionManagerTest.java b/server/src/test/java/com/alibaba/fescar/server/session/FileBasedSessionManagerTest.java
new file mode 100644
index 000000000..b42d0f943
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/session/FileBasedSessionManagerTest.java
@@ -0,0 +1,210 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.session;
+
+
+
+import com.alibaba.fescar.core.model.BranchStatus;
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.core.model.GlobalStatus;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author tianming.xm@gmail.com
+ * @since 2019/1/22
+ */
+public class FileBasedSessionManagerTest {
+
+    private SessionManager sessionManager = null;
+
+    @BeforeClass
+    public void setUp() throws Exception{
+        sessionManager = new FileBasedSessionManager("root.data",".");
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void addGlobalSessionTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void findGlobalSessionTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        GlobalSession expected =  sessionManager.findGlobalSession(globalSession.getTransactionId());
+        Assert.assertNotNull(expected);
+        Assert.assertEquals(expected.getTransactionId(),globalSession.getTransactionId());
+        Assert.assertEquals(expected.getApplicationId(),globalSession.getApplicationId());
+        Assert.assertEquals(expected.getTransactionServiceGroup(),globalSession.getTransactionServiceGroup());
+        Assert.assertEquals(expected.getTransactionName(),globalSession.getTransactionName());
+        Assert.assertEquals(expected.getTransactionId(),globalSession.getTransactionId());
+        Assert.assertEquals(expected.getStatus(),globalSession.getStatus());
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void updateGlobalSessionStatusTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        globalSession.setStatus(GlobalStatus.Finished);
+        sessionManager.updateGlobalSessionStatus(globalSession,GlobalStatus.Finished);
+        GlobalSession expected =  sessionManager.findGlobalSession(globalSession.getTransactionId());
+        Assert.assertNotNull(expected);
+        Assert.assertEquals(GlobalStatus.Finished,expected.getStatus());
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void removeGlobalSessionTest(GlobalSession globalSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.removeGlobalSession(globalSession);
+        GlobalSession expected =  sessionManager.findGlobalSession(globalSession.getTransactionId());
+        Assert.assertNull(expected);
+
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void addBranchSessionTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.addBranchSession(globalSession,branchSession);
+        sessionManager.removeBranchSession(globalSession,branchSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void updateBranchSessionStatusTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.addBranchSession(globalSession,branchSession);
+        sessionManager.updateBranchSessionStatus(branchSession, BranchStatus.PhaseTwo_Committed);
+        sessionManager.removeBranchSession(globalSession,branchSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void removeBranchSessionTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.addGlobalSession(globalSession);
+        sessionManager.addBranchSession(globalSession,branchSession);
+        sessionManager.removeBranchSession(globalSession,branchSession);
+        sessionManager.removeGlobalSession(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionsProvider")
+    public void allSessionsTest(List<GlobalSession> globalSessions) throws Exception{
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.addGlobalSession(globalSession);
+        }
+        Collection<GlobalSession> expectedGlobalSessions =  sessionManager.allSessions();
+        Assert.assertNotNull(expectedGlobalSessions);
+        Assert.assertEquals(2,expectedGlobalSessions.size());
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.removeGlobalSession(globalSession);
+        }
+    }
+
+    @Test(dataProvider = "globalSessionsProvider")
+    public void findGlobalSessionsTest(List<GlobalSession> globalSessions) throws Exception{
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.addGlobalSession(globalSession);
+        }
+        SessionCondition sessionCondition = new SessionCondition(GlobalStatus.Begin,30*24*3600);
+        Collection<GlobalSession> expectedGlobalSessions =  sessionManager.findGlobalSessions(sessionCondition);
+        Assert.assertNotNull(expectedGlobalSessions);
+        Assert.assertEquals(2,expectedGlobalSessions.size());
+        for(GlobalSession globalSession:globalSessions){
+            sessionManager.removeGlobalSession(globalSession);
+        }
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onBeginTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onEnd(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onStatusChangeTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onStatusChange(globalSession,GlobalStatus.Finished);
+        sessionManager.onEnd(globalSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void onBranchStatusChangeTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onAddBranch(globalSession,branchSession);
+        sessionManager.onBranchStatusChange(globalSession,branchSession,BranchStatus.PhaseTwo_Committed);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void onAddBranchTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onAddBranch(globalSession,branchSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void onRemoveBranchTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onAddBranch(globalSession,branchSession);
+        sessionManager.onRemoveBranch(globalSession,branchSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onCloseTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onClose(globalSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void onEndTest(GlobalSession globalSession) throws Exception{
+        sessionManager.onBegin(globalSession);
+        sessionManager.onEnd(globalSession);
+    }
+
+    @DataProvider
+    public static Object[][] globalSessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        return new Object[][] {{ globalSession}};
+    }
+
+    @DataProvider
+    public static Object[][] globalSessionsProvider() {
+        GlobalSession globalSession1 = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        GlobalSession globalSession2 = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        return new Object[][] {{Arrays.asList(globalSession1,globalSession2)}};
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        BranchSession branchSession = new BranchSession();
+        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.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        return new Object[][] {{ globalSession,branchSession}};
+    }
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/session/GlobalSessionTest.java b/server/src/test/java/com/alibaba/fescar/server/session/GlobalSessionTest.java
new file mode 100644
index 000000000..062de0d35
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/session/GlobalSessionTest.java
@@ -0,0 +1,128 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.session;
+
+import com.alibaba.fescar.core.model.BranchStatus;
+import com.alibaba.fescar.core.model.BranchType;
+import com.alibaba.fescar.core.model.GlobalStatus;
+import org.testng.Assert;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author tianming.xm@gmail.com
+ * @since 2019/1/23
+ */
+public class GlobalSessionTest {
+
+    @Test(dataProvider = "branchSessionMTProvider")
+    public void canBeCommittedAsyncTest(GlobalSession globalSession){
+        Assert.assertFalse(globalSession.canBeCommittedAsync());
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void beginTest(GlobalSession globalSession) throws Exception{
+        globalSession.begin();
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void changeStatusTest(GlobalSession globalSession) throws Exception{
+        globalSession.changeStatus(GlobalStatus.Committed);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void changeBranchStatusTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        globalSession.changeBranchStatus(branchSession, BranchStatus.PhaseTwo_Committed);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void closeTest(GlobalSession globalSession) throws Exception{
+        globalSession.close();
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void endTest(GlobalSession globalSession) throws Exception{
+        globalSession.end();
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void addBranchTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        globalSession.addBranch(branchSession);
+    }
+
+    @Test(dataProvider = "branchSessionProvider")
+    public void removeBranchTest(GlobalSession globalSession,BranchSession branchSession) throws Exception{
+        globalSession.addBranch(branchSession);
+        globalSession.removeBranch(branchSession);
+    }
+
+    @Test(dataProvider = "globalSessionProvider")
+    public void codecTest(GlobalSession globalSession){
+        byte[] result = globalSession.encode();
+        Assert.assertNotNull(result);
+        GlobalSession expected = new GlobalSession();
+        expected.decode(result);
+        Assert.assertEquals(expected.getTransactionId(),globalSession.getTransactionId());
+        Assert.assertEquals(expected.getTimeout(),globalSession.getTimeout());
+        Assert.assertEquals(expected.getApplicationId(),globalSession.getApplicationId());
+        Assert.assertEquals(expected.getTransactionServiceGroup(),globalSession.getTransactionServiceGroup());
+        Assert.assertEquals(expected.getTransactionName(),globalSession.getTransactionName());
+    }
+
+    @DataProvider
+    public static Object[][] globalSessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        globalSession.setActive(true);
+        globalSession.addSessionLifecycleListener(new DefaultSessionManager("default"));
+        return new Object[][] {{ globalSession}};
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        BranchSession branchSession = new BranchSession();
+        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.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setBranchType(BranchType.AT);
+        globalSession.add(branchSession);
+        return new Object[][] {{ globalSession,branchSession}};
+    }
+
+    @DataProvider
+    public static Object[][] branchSessionMTProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app","my_test_tx_group","test",6000);
+        BranchSession branchSession = new BranchSession();
+        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.setApplicationId("demo-child-app");
+        branchSession.setTxServiceGroup("my_test_tx_group");
+        branchSession.setApplicationData("{\"data\":\"test\"}");
+        branchSession.setBranchType(BranchType.MT);
+        globalSession.add(branchSession);
+        return new Object[][] {{ globalSession}};
+    }
+}
diff --git a/server/src/test/java/com/alibaba/fescar/server/store/FileTransactionStoreManagerTest.java b/server/src/test/java/com/alibaba/fescar/server/store/FileTransactionStoreManagerTest.java
new file mode 100644
index 000000000..2da994f2c
--- /dev/null
+++ b/server/src/test/java/com/alibaba/fescar/server/store/FileTransactionStoreManagerTest.java
@@ -0,0 +1,69 @@
+/*
+ *  Copyright 1999-2018 Alibaba Group Holding Ltd.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.alibaba.fescar.server.store;
+
+import java.util.List;
+
+import com.alibaba.fescar.server.session.FileBasedSessionManager;
+import com.alibaba.fescar.server.session.GlobalSession;
+import com.alibaba.fescar.server.session.SessionManager;
+
+import org.junit.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+/**
+ * @author tianming.xm@gmail.com
+ * @since 2019/1/25
+ */
+public class FileTransactionStoreManagerTest {
+    private FileTransactionStoreManager fileTransactionStoreManager;
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        SessionManager sessionManager = new FileBasedSessionManager("default", "root.data");
+        fileTransactionStoreManager = new FileTransactionStoreManager("root.data", sessionManager);
+    }
+
+    @AfterClass
+    public void tearDown() {
+        fileTransactionStoreManager.shutdown();
+    }
+
+    @Test(dataProvider = "sessionProvider")
+    public void writeSessionTest(GlobalSession globalSession) {
+        boolean result = fileTransactionStoreManager.writeSession(TransactionStoreManager.LogOperation.GLOBAL_ADD,
+            globalSession);
+        Assert.assertTrue(result);
+    }
+
+    @Test(dataProvider = "sessionProvider")
+    public void readWriteStoreFromFileTest(GlobalSession globalSession) {
+        fileTransactionStoreManager.writeSession(TransactionStoreManager.LogOperation.GLOBAL_ADD, globalSession);
+        List<TransactionWriteStore> stores = fileTransactionStoreManager.readWriteStoreFromFile(100, false);
+        Assert.assertNotNull(stores);
+        Assert.assertTrue(stores.size() > 0);
+    }
+
+    @DataProvider
+    public static Object[][] sessionProvider() {
+        GlobalSession globalSession = new GlobalSession("demo-app", "my_test_tx_group", "test", 6000);
+        return new Object[][] {{globalSession}};
+    }
+
+}
diff --git a/test/pom.xml b/test/pom.xml
index 1163f5bd5..a58a846ad 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>fescar-all</artifactId>
         <groupId>com.alibaba.fescar</groupId>
-        <version>0.1.0-SNAPSHOT</version>
+        <version>0.1.2-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>fescar-test</artifactId>
@@ -106,7 +106,10 @@
             <artifactId>redisson</artifactId>
             <version>3.9.0</version>
         </dependency>
-
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
 
     </dependencies>
 
diff --git a/test/src/main/java/com/alibaba/fescar/test/DataSourceBasicTest.java b/test/src/main/java/com/alibaba/fescar/test/DataSourceBasicTest.java
index 190539339..bd32fa60e 100644
--- a/test/src/main/java/com/alibaba/fescar/test/DataSourceBasicTest.java
+++ b/test/src/main/java/com/alibaba/fescar/test/DataSourceBasicTest.java
@@ -22,35 +22,98 @@ import com.alibaba.fescar.core.model.BranchStatus;
 import com.alibaba.fescar.core.model.BranchType;
 import com.alibaba.fescar.core.model.Resource;
 import com.alibaba.fescar.rm.datasource.DataSourceManager;
-
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
 import org.springframework.context.support.ClassPathXmlApplicationContext;
 import org.springframework.jdbc.core.JdbcTemplate;
 
+import java.util.Date;
+
+@Ignore
 public class DataSourceBasicTest {
-    public void runBusiness(JdbcTemplate jdbcTemplate) {
-//        jdbcTemplate.update("insert into user0 (id, name, gmt) values (?, ?, ?)",
-//                new Object[] { 1, "xxx", new Date() });
-        jdbcTemplate.update("update user0 set name = 'yyyy' where id = ?", new Object[] {1});
-//        jdbcTemplate.update("delete from user0 where id = ?", new Object[] {1});
 
+    private static String TABLE_CREATE_SQL = "CREATE TABLE `user0` (\n"
+        + "  `id` int(11) NOT NULL,\n"
+        + "  `name` varchar(255) DEFAULT NULL,\n"
+        + "  `gmt` datetime DEFAULT NULL,\n"
+        + "  PRIMARY KEY (`id`)\n"
+        + ") ENGINE=InnoDB DEFAULT CHARSET=utf8";
+
+    private static ClassPathXmlApplicationContext context;
+    private static JdbcTemplate jdbcTemplate;
+    private static JdbcTemplate directJdbcTemplate;
+
+    @Test
+    public void testInsert() {
+        RootContext.bind("mock.xid");
+        jdbcTemplate.update("insert into user0 (id, name, gmt) values (?, ?, ?)",
+            new Object[] {2, "xxx", new Date()});
+    }
+
+    @Test
+    public void testUpdate() {
+        RootContext.bind("mock.xid");
+        jdbcTemplate.update("update user0 a set a.name = 'yyyy' where a.id = ?", new Object[] {1});
+    }
+
+    @Test
+    public void testUpdateWithAlias1() {
+
+        directJdbcTemplate.update("delete from User1 where Id = ?",
+            new Object[] {1});
+        directJdbcTemplate.update("insert into User1 (Id, Name, gMt) values (?, ?, ?)",
+            new Object[] {1, "xxx", new Date()});
+
+        RootContext.bind("mock.xid");
+        jdbcTemplate.update("update User1 a set a.Name = 'yyy' where a.Name = ?", new Object[] {"xxx"});
+    }
+
+    @Test
+    public void testUpdateWithAlias() {
+        RootContext.bind("mock.xid");
+        jdbcTemplate.update("update user0 a set a.name = 'yyyy' where a.name = ?", new Object[] {"yyyy"});
+    }
 
+    @Test
+    public void testDelete() {
+        RootContext.bind("mock.xid");
+        jdbcTemplate.update("delete from user0 where id = ?", new Object[] {2});
     }
 
-    public static void main(String[] args) {
+    @Test
+    public void testSelectForUpdate() {
+        RootContext.bind("mock.xid");
+        jdbcTemplate.queryForRowSet("select a.name from user0 a where a.id = ? for update", new Object[] {1});
+    }
+
+    @Test
+    public void testSelectForUpdateWithAlias() {
+        RootContext.bind("mock.xid");
+        jdbcTemplate.queryForRowSet("select a.name from user0 a where a.id = ? for update", new Object[] {1});
+    }
+
+    @BeforeClass
+    public static void before() {
+        // Mock DataSourceManager
         DataSourceManager.set(new DataSourceManager() {
 
             @Override
-            public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid, String lockKeys) throws TransactionException {
+            public Long branchRegister(BranchType branchType, String resourceId, String clientId, String xid,
+                                       String lockKeys) throws TransactionException {
                 return 123456L;
             }
 
             @Override
-            public void branchReport(String xid, long branchId, BranchStatus status, String applicationData) throws TransactionException {
+            public void branchReport(String xid, long branchId, BranchStatus status, String applicationData)
+                throws TransactionException {
 
             }
 
             @Override
-            public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys) throws TransactionException {
+            public boolean lockQuery(BranchType branchType, String resourceId, String xid, String lockKeys)
+                throws TransactionException {
                 return true;
             }
 
@@ -65,30 +128,31 @@ public class DataSourceBasicTest {
             }
 
             @Override
-            public BranchStatus branchCommit(String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
+            public BranchStatus branchCommit(String xid, long branchId, String resourceId, String applicationData)
+                throws TransactionException {
                 return BranchStatus.PhaseTwo_Committed;
             }
 
             @Override
-            public BranchStatus branchRollback(String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
+            public BranchStatus branchRollback(String xid, long branchId, String resourceId, String applicationData)
+                throws TransactionException {
                 return BranchStatus.PhaseTwo_Rollbacked;
             }
         });
 
-        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
-                "basic-test-context.xml");
-        final DataSourceBasicTest clientTest = (DataSourceBasicTest) context
-                .getBean("clientTest");
-        final JdbcTemplate jdbcTemplate = (JdbcTemplate) context
-                .getBean("jdbcTemplate");
-        final JdbcTemplate directJdbcTemplate = (JdbcTemplate) context
-                .getBean("directJdbcTemplate");
-//        directJdbcTemplate.execute("truncate table user0");
-
-        RootContext.bind("test_xid");
-        clientTest.runBusiness(jdbcTemplate);
-
-        context.close();
-        System.exit(0);
+        context = new ClassPathXmlApplicationContext(
+            "basic-test-context.xml");
+        jdbcTemplate = (JdbcTemplate)context
+            .getBean("jdbcTemplate");
+        directJdbcTemplate = (JdbcTemplate)context
+            .getBean("directJdbcTemplate");
+
+    }
+
+    @AfterClass
+    public static void after() {
+        if (context != null) {
+            context.close();
+        }
     }
 }