Browse Source

初始导入

yingp 8 years ago
commit
17f56590f5
32 changed files with 1483 additions and 0 deletions
  1. 44 0
      .gitignore
  2. 9 0
      README.md
  3. 63 0
      build.gradle
  4. 2 0
      gradle.properties
  5. 2 0
      settings.gradle
  6. 19 0
      src/main/java/com/uas/erp/database/UasDatabaseApplication.java
  7. 43 0
      src/main/java/com/uas/erp/database/api/v1/DBAController.java
  8. 36 0
      src/main/java/com/uas/erp/database/api/v1/ExecuteController.java
  9. 37 0
      src/main/java/com/uas/erp/database/api/v1/MasterController.java
  10. 41 0
      src/main/java/com/uas/erp/database/config/DBAConfig.java
  11. 48 0
      src/main/java/com/uas/erp/database/config/DataSourceConfig.java
  12. 23 0
      src/main/java/com/uas/erp/database/config/ExceptionConfig.java
  13. 9 0
      src/main/java/com/uas/erp/database/core/Constant.java
  14. 16 0
      src/main/java/com/uas/erp/database/datasource/Connectable.java
  15. 133 0
      src/main/java/com/uas/erp/database/datasource/DynamicDataSource.java
  16. 43 0
      src/main/java/com/uas/erp/database/datasource/DynamicDataSourceAspect.java
  17. 25 0
      src/main/java/com/uas/erp/database/datasource/DynamicDataSourceContextHolder.java
  18. 29 0
      src/main/java/com/uas/erp/database/datasource/DynamicDataSourceRegister.java
  19. 7 0
      src/main/java/com/uas/erp/database/datasource/README.md
  20. 14 0
      src/main/java/com/uas/erp/database/datasource/TargetDataSource.java
  21. 71 0
      src/main/java/com/uas/erp/database/domain/Executable.java
  22. 154 0
      src/main/java/com/uas/erp/database/domain/Master.java
  23. 30 0
      src/main/java/com/uas/erp/database/domain/MasterView.java
  24. 76 0
      src/main/java/com/uas/erp/database/entity/DBA.java
  25. 98 0
      src/main/java/com/uas/erp/database/repository/BaseRepository.java
  26. 15 0
      src/main/java/com/uas/erp/database/repository/DBARepository.java
  27. 84 0
      src/main/java/com/uas/erp/database/service/DBAService.java
  28. 43 0
      src/main/java/com/uas/erp/database/service/ExecuteService.java
  29. 66 0
      src/main/java/com/uas/erp/database/service/MasterService.java
  30. 97 0
      src/main/java/com/uas/erp/database/web/ResponseWrap.java
  31. 49 0
      src/main/resources/application.yml
  32. 57 0
      src/test/java/com/uas/erp/test/MasterTest.java

+ 44 - 0
.gitignore

@@ -0,0 +1,44 @@
+#idea
+.idea
+*.iml
+#maven
+target
+#gradle
+.gradle
+/build/
+
+# Created by .ignore support plugin (hsz.mobi)
+### Gradle database.template
+.gradle
+/build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
+
+# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
+# gradle/wrapper/gradle-wrapper.properties
+### Java database.template
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+*.zip
+*.tar.gz
+*.rar

+ 9 - 0
README.md

@@ -0,0 +1,9 @@
+# UAS数据库服务
+
+    将数据库连接池操作、多数据源切换、数据库监控以及数据库增删改查等数据库相关操作抽离出来,
+    以REST接口的方式提供服务。
+
+> 功能
+* 创建新数据库用户
+* 查找数据库用户
+* 执行SQL命令

+ 63 - 0
build.gradle

@@ -0,0 +1,63 @@
+group 'com.uas.erp'
+version '1.0.0'
+
+buildscript {
+    ext {
+        springBootVersion = '1.4.4.RELEASE'
+    }
+    repositories {
+        maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+        maven { url "https://plugins.gradle.org/m2/" }
+        maven { url "https://repo.spring.io/libs-release" }
+        mavenCentral()
+        jcenter()
+    }
+    dependencies {
+        classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+    }
+}
+
+apply plugin: 'java'
+apply plugin: 'idea'
+apply plugin: 'maven'
+apply plugin: 'org.springframework.boot'
+
+jar {
+    baseName = project.name
+    version = ''
+}
+
+sourceCompatibility = 1.7
+
+repositories {
+    mavenLocal()
+    maven { url "http://repo.spring.io/libs-milestone" }
+    maven { url "http://repo.spring.io/libs-release" }
+    maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+    mavenCentral()
+}
+
+dependencyManagement {
+    imports {
+        mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Camden.SR5'
+    }
+}
+
+dependencies {
+    compile 'org.springframework.boot:spring-boot-starter-data-jpa'
+    compile "org.springframework.boot:spring-boot-starter-web"
+    testCompile "org.springframework.boot:spring-boot-starter-test"
+    compile "com.h2database:h2"
+    compile "com.oracle:ojdbc6:11.2.0"
+    compile "com.alibaba:fastjson:$fastjsonVersion"
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            repository(url: "http://10.10.101.21:8081/artifactory/libs-release-local") {
+                authentication(userName: "yingp", password: "111111")
+            }
+        }
+    }
+}.dependsOn build

+ 2 - 0
gradle.properties

@@ -0,0 +1,2 @@
+org.gradle.jvmargs=-Xmx1024m
+fastjsonVersion=1.2.14

+ 2 - 0
settings.gradle

@@ -0,0 +1,2 @@
+rootProject.name = 'uas-database'
+

+ 19 - 0
src/main/java/com/uas/erp/database/UasDatabaseApplication.java

@@ -0,0 +1,19 @@
+package com.uas.erp.database;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+@EnableScheduling
+public class UasDatabaseApplication {
+
+    public static void main(String[] args) {
+        new SpringApplicationBuilder(UasDatabaseApplication.class).web(true).run(args);
+    }
+
+}

+ 43 - 0
src/main/java/com/uas/erp/database/api/v1/DBAController.java

@@ -0,0 +1,43 @@
+package com.uas.erp.database.api.v1;
+
+import com.uas.erp.database.entity.DBA;
+import com.uas.erp.database.service.DBAService;
+import com.uas.erp.database.service.MasterService;
+import com.uas.erp.database.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@RestController
+@RequestMapping(path = "/v1/dba")
+public class DBAController {
+
+    @Autowired
+    private DBAService dbaService;
+
+    @Autowired
+    private MasterService masterService;
+
+    @GetMapping(path = "/list")
+    public ResponseEntity getAll() {
+        return ResponseWrap.ok(dbaService.findAll());
+    }
+
+    @PostMapping
+    public ResponseEntity save(DBA dba) {
+        dbaService.save(dba);
+        masterService.scanAll();
+        return ResponseWrap.ok();
+    }
+
+    @DeleteMapping(path = "/{id}")
+    public ResponseEntity delete(@PathVariable("id") long id) {
+        dbaService.delete(id);
+        masterService.scanAll();
+        return ResponseWrap.ok();
+    }
+
+}

+ 36 - 0
src/main/java/com/uas/erp/database/api/v1/ExecuteController.java

@@ -0,0 +1,36 @@
+package com.uas.erp.database.api.v1;
+
+import com.uas.erp.database.domain.Executable;
+import com.uas.erp.database.domain.Master;
+import com.uas.erp.database.service.ExecuteService;
+import com.uas.erp.database.service.MasterService;
+import com.uas.erp.database.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.Assert;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@RestController
+@RequestMapping(path = "/v1/exec")
+public class ExecuteController {
+
+    @Autowired
+    private MasterService masterService;
+
+    @Autowired
+    private ExecuteService executeService;
+
+    @PostMapping
+    public ResponseEntity execute(@RequestBody Executable executable) {
+        Master master = masterService.findOne(executable.getQualifier());
+        Assert.notNull(master, "数据源不存在");
+        return ResponseWrap.ok(executeService.execute(master, executable));
+    }
+
+}

+ 37 - 0
src/main/java/com/uas/erp/database/api/v1/MasterController.java

@@ -0,0 +1,37 @@
+package com.uas.erp.database.api.v1;
+
+import com.uas.erp.database.service.MasterService;
+import com.uas.erp.database.web.ResponseWrap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@RestController
+@RequestMapping(path = "/v1/master")
+public class MasterController {
+
+    @Autowired
+    private MasterService masterService;
+
+    @GetMapping(path = "/list")
+    public ResponseEntity getAll() {
+        return ResponseWrap.ok(masterService.findAll());
+    }
+
+    @GetMapping(path = "/view")
+    public ResponseEntity getAllView() {
+        return ResponseWrap.ok(masterService.findAllView());
+    }
+
+    @RequestMapping(path = "/refresh")
+    public ResponseEntity refreshAll() {
+        masterService.scanAll();
+        return ResponseWrap.ok();
+    }
+
+}

+ 41 - 0
src/main/java/com/uas/erp/database/config/DBAConfig.java

@@ -0,0 +1,41 @@
+package com.uas.erp.database.config;
+
+import com.uas.erp.database.entity.DBA;
+import com.uas.erp.database.service.DBAService;
+import com.uas.erp.database.service.MasterService;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Created by Pro1 on 2017/10/2.
+ */
+@Configuration
+@EnableAutoConfiguration
+public class DBAConfig implements InitializingBean{
+
+    @Autowired
+    private DBAService dbaService;
+
+    @Autowired
+    private MasterService masterService;
+
+    @Bean
+    @ConfigurationProperties(prefix = "dba")
+    public DBA dba() {
+        DBA dba = new DBA();
+        return dba;
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        DBA dba = dba();
+        if (null != dba.getUrl() && null != dba.getPassword() && null != dba.getPassword()) {
+            dbaService.save(dba());
+        }
+        masterService.scanAll();
+    }
+}

+ 48 - 0
src/main/java/com/uas/erp/database/config/DataSourceConfig.java

@@ -0,0 +1,48 @@
+package com.uas.erp.database.config;
+
+import com.uas.erp.database.datasource.DynamicDataSource;
+import com.uas.erp.database.datasource.DynamicDataSourceRegister;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.sql.DataSource;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Configuration
+public class DataSourceConfig{
+
+    @Bean(name = "primaryDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.primary")
+    public DataSource primaryDataSource(){
+        return DataSourceBuilder.create().build();
+    }
+
+    @Bean(name = "dataSource")
+    public DynamicDataSource dynamicDataSource() {
+        DataSource primaryDataSource = this.primaryDataSource();
+        Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put("primaryDataSource", primaryDataSource);
+        DynamicDataSource dataSource = new DynamicDataSource();
+        dataSource.setDefaultTargetDataSource(primaryDataSource);
+        dataSource.setTargetDataSources(targetDataSources);
+        return dataSource;
+    }
+
+    @Bean
+    public JdbcTemplate jdbcTemplate() {
+        return new JdbcTemplate(this.dynamicDataSource());
+    }
+
+    @Bean
+    public DynamicDataSourceRegister register() {
+        return new DynamicDataSourceRegister(this.dynamicDataSource());
+    }
+
+}

+ 23 - 0
src/main/java/com/uas/erp/database/config/ExceptionConfig.java

@@ -0,0 +1,23 @@
+package com.uas.erp.database.config;
+
+import com.uas.erp.database.web.ResponseWrap;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * Created by Pro1 on 2017/6/22.
+ */
+@ControllerAdvice
+public class ExceptionConfig {
+
+    @ExceptionHandler(value = Exception.class)
+    @ResponseBody
+    public ResponseEntity defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
+        return ResponseWrap.badRequest(e.getMessage());
+    }
+
+}

+ 9 - 0
src/main/java/com/uas/erp/database/core/Constant.java

@@ -0,0 +1,9 @@
+package com.uas.erp.database.core;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+public class Constant {
+
+    public static final String DEFAULT_DATASOURCE_URL = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
+}

+ 16 - 0
src/main/java/com/uas/erp/database/datasource/Connectable.java

@@ -0,0 +1,16 @@
+package com.uas.erp.database.datasource;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+public interface Connectable {
+
+    String qualifier();
+
+    String url();
+
+    String username();
+
+    String password();
+
+}

+ 133 - 0
src/main/java/com/uas/erp/database/datasource/DynamicDataSource.java

@@ -0,0 +1,133 @@
+package com.uas.erp.database.datasource;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.jdbc.datasource.AbstractDataSource;
+import org.springframework.jdbc.datasource.lookup.DataSourceLookup;
+import org.springframework.jdbc.datasource.lookup.JndiDataSourceLookup;
+import org.springframework.util.Assert;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ * 基于{@AbstractRoutingDataSource},解决不能动态添加新数据源的问题
+ */
+public class DynamicDataSource extends AbstractDataSource implements InitializingBean {
+
+    private Map<Object, Object> targetDataSources;
+    private Object defaultTargetDataSource;
+    private boolean lenientFallback = true;
+    private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
+    private Map<Object, DataSource> resolvedDataSources;
+    private DataSource resolvedDefaultDataSource;
+
+    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
+        this.targetDataSources = targetDataSources;
+    }
+
+    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
+        this.defaultTargetDataSource = defaultTargetDataSource;
+    }
+
+    public void setLenientFallback(boolean lenientFallback) {
+        this.lenientFallback = lenientFallback;
+    }
+
+    public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
+        this.dataSourceLookup = (DataSourceLookup)(dataSourceLookup != null?dataSourceLookup:new JndiDataSourceLookup());
+    }
+
+    public void afterPropertiesSet() {
+        if(this.targetDataSources == null) {
+            throw new IllegalArgumentException("Property \'targetDataSources\' is required");
+        } else {
+            this.resolvedDataSources = new HashMap(this.targetDataSources.size());
+            Iterator var1 = this.targetDataSources.entrySet().iterator();
+
+            while(var1.hasNext()) {
+                Map.Entry entry = (Map.Entry)var1.next();
+                Object lookupKey = this.resolveSpecifiedLookupKey(entry.getKey());
+                DataSource dataSource = this.resolveSpecifiedDataSource(entry.getValue());
+                this.resolvedDataSources.put(lookupKey, dataSource);
+            }
+
+            if(this.defaultTargetDataSource != null) {
+                this.resolvedDefaultDataSource = this.resolveSpecifiedDataSource(this.defaultTargetDataSource);
+            }
+
+        }
+    }
+
+    protected Object resolveSpecifiedLookupKey(Object lookupKey) {
+        return lookupKey;
+    }
+
+    protected DataSource resolveSpecifiedDataSource(Object dataSource) throws IllegalArgumentException {
+        if(dataSource instanceof DataSource) {
+            return (DataSource)dataSource;
+        } else if(dataSource instanceof String) {
+            return this.dataSourceLookup.getDataSource((String)dataSource);
+        } else {
+            throw new IllegalArgumentException("Illegal data source value - only [javax.sql.DataSource] and String supported: " + dataSource);
+        }
+    }
+
+    public Connection getConnection() throws SQLException {
+        return this.determineTargetDataSource().getConnection();
+    }
+
+    public Connection getConnection(String username, String password) throws SQLException {
+        return this.determineTargetDataSource().getConnection(username, password);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T unwrap(Class<T> iface) throws SQLException {
+        if (iface.isInstance(this)) {
+            return (T) this;
+        }
+        return determineTargetDataSource().unwrap(iface);
+    }
+
+    @Override
+    public boolean isWrapperFor(Class<?> iface) throws SQLException {
+        return (iface.isInstance(this) || determineTargetDataSource().isWrapperFor(iface));
+    }
+
+    protected DataSource determineTargetDataSource() {
+        Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
+        Object lookupKey = this.determineCurrentLookupKey();
+        DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);
+        if(dataSource == null && (this.lenientFallback || lookupKey == null)) {
+            dataSource = this.resolvedDefaultDataSource;
+        }
+
+        if(dataSource == null) {
+            throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
+        } else {
+            return dataSource;
+        }
+    }
+
+    protected Object determineCurrentLookupKey() {
+        return DynamicDataSourceContextHolder.get();
+    }
+
+    public boolean containsDataSource(Object key) {
+        Object lookupKey = this.resolveSpecifiedLookupKey(key);
+        return this.resolvedDataSources.containsKey(lookupKey);
+    }
+
+    public void addDataSource(Object key, Object value) {
+        Object lookupKey = this.resolveSpecifiedLookupKey(key);
+        if (!containsDataSource(lookupKey)) {
+            DataSource dataSource = this.resolveSpecifiedDataSource(value);
+            this.resolvedDataSources.put(lookupKey, dataSource);
+        }
+    }
+}

+ 43 - 0
src/main/java/com/uas/erp/database/datasource/DynamicDataSourceAspect.java

@@ -0,0 +1,43 @@
+package com.uas.erp.database.datasource;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.After;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Aspect
+@Order(-1)
+@Component
+public class DynamicDataSourceAspect {
+
+    @Autowired
+    private DynamicDataSourceRegister dataSourceRegister;
+
+    @Before("@annotation(dataSource)")
+    public void changeDataSource(JoinPoint point, TargetDataSource dataSource) throws Throwable {
+        if (null != point.getArgs()) {
+            for (Object arg: point.getArgs()) {
+                // 按参数类型为Connectable的进行数据源切换
+                if (null != arg && arg instanceof Connectable) {
+                    Connectable connectable = (Connectable) arg;
+                    // 防止数据源未创建
+                    dataSourceRegister.createDataSource(connectable);
+                    DynamicDataSourceContextHolder.set(connectable);
+                    break;
+                }
+            }
+        }
+    }
+
+    @After("@annotation(dataSource)")
+    public void restoreDataSource(JoinPoint point, TargetDataSource dataSource) {
+        DynamicDataSourceContextHolder.clear();
+    }
+
+}

+ 25 - 0
src/main/java/com/uas/erp/database/datasource/DynamicDataSourceContextHolder.java

@@ -0,0 +1,25 @@
+package com.uas.erp.database.datasource;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+public class DynamicDataSourceContextHolder {
+
+    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
+
+    public static void set(String dataSource) {
+        contextHolder.set(dataSource);
+    }
+
+    public static void set(Connectable connectable) {
+        contextHolder.set(connectable.qualifier());
+    }
+
+    public static String get() {
+        return contextHolder.get();
+    }
+
+    public static void clear() {
+        contextHolder.remove();
+    }
+}

+ 29 - 0
src/main/java/com/uas/erp/database/datasource/DynamicDataSourceRegister.java

@@ -0,0 +1,29 @@
+package com.uas.erp.database.datasource;
+
+import org.apache.tomcat.jdbc.pool.DataSource;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+public class DynamicDataSourceRegister {
+
+    private DynamicDataSource dynamicDataSource;
+
+    public DynamicDataSourceRegister(DynamicDataSource dynamicDataSource) {
+        this.dynamicDataSource = dynamicDataSource;
+    }
+
+    public void createDataSource(Connectable connectable) {
+        if (!dynamicDataSource.containsDataSource(connectable.qualifier())) {
+            javax.sql.DataSource dataSource = DataSourceBuilder.create()
+                    .url(connectable.url())
+                    .username(connectable.username())
+                    .password(connectable.password())
+                    .type(DataSource.class)
+                    .build();
+            dynamicDataSource.addDataSource(connectable.qualifier(), dataSource);
+        }
+    }
+
+}

+ 7 - 0
src/main/java/com/uas/erp/database/datasource/README.md

@@ -0,0 +1,7 @@
+> 查找数据源
+* 按设置的默认账套查找Master表启用了的账套
+* 数据源在第一次使用时会添加到DynamicDataSource
+
+> 切换数据源
+* 在方法上加@TargetDataSource注解
+* 方法需包含一个实现了Connectable类型的参数

+ 14 - 0
src/main/java/com/uas/erp/database/datasource/TargetDataSource.java

@@ -0,0 +1,14 @@
+package com.uas.erp.database.datasource;
+
+import java.lang.annotation.*;
+
+/**
+ * 通过注解+AOP实现自动切换数据源
+ * <br/>
+ * 数据源取方法的第一个{Connectable}类型参数
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface TargetDataSource {
+}

+ 71 - 0
src/main/java/com/uas/erp/database/domain/Executable.java

@@ -0,0 +1,71 @@
+package com.uas.erp.database.domain;
+
+import java.util.Arrays;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+public class Executable {
+
+    // 数据源名称
+    private String qualifier;
+    // 可执行语句
+    private String[] execs;
+    // 参数
+    private Object[] args;
+    // 是否查询
+    private boolean isQuery;
+    // 返回字段
+    private String[] returnFields;
+
+    public String getQualifier() {
+        return qualifier;
+    }
+
+    public void setQualifier(String qualifier) {
+        this.qualifier = qualifier;
+    }
+
+    public String[] getExecs() {
+        return execs;
+    }
+
+    public void setExecs(String[] execs) {
+        this.execs = execs;
+    }
+
+    public Object[] getArgs() {
+        return args;
+    }
+
+    public void setArgs(Object[] args) {
+        this.args = args;
+    }
+
+    public boolean isQuery() {
+        return isQuery;
+    }
+
+    public void setQuery(boolean query) {
+        isQuery = query;
+    }
+
+    public String[] getReturnFields() {
+        return returnFields;
+    }
+
+    public void setReturnFields(String[] returnFields) {
+        this.returnFields = returnFields;
+    }
+
+    @Override
+    public String toString() {
+        return "Executable{" +
+                "qualifier='" + qualifier + '\'' +
+                ", execs=" + Arrays.toString(execs) +
+                ", args=" + Arrays.toString(args) +
+                ", isQuery=" + isQuery +
+                ", returnFields=" + Arrays.toString(returnFields) +
+                '}';
+    }
+}

+ 154 - 0
src/main/java/com/uas/erp/database/domain/Master.java

@@ -0,0 +1,154 @@
+package com.uas.erp.database.domain;
+
+import com.uas.erp.database.core.Constant;
+import com.uas.erp.database.datasource.Connectable;
+
+/**
+ * Created by Pro1 on 2017/7/26.
+ */
+public class Master implements Connectable, Comparable<Master>{
+
+    private int ma_id;
+    private String ma_user;// 数据库用户名
+    private String ms_pwd;// 数据库密码
+    private String ma_url;
+    private String ma_name;// 帐套名,与bean名一致
+    private String ma_function;
+    private String ma_accesssecret;// 密钥
+    private Short ma_enable;// 是否可使用
+    private Long ma_uu;// 企业UU
+    private Integer ma_b2benable;// 是否启用B2B,1启用,0未启用
+    private String ma_env;// 对应商城环境
+
+    public int getMa_id() {
+        return ma_id;
+    }
+
+    public void setMa_id(int ma_id) {
+        this.ma_id = ma_id;
+    }
+
+    public String getMa_user() {
+        return ma_user;
+    }
+
+    public void setMa_user(String ma_user) {
+        this.ma_user = ma_user;
+    }
+
+    public String getMs_pwd() {
+        return ms_pwd;
+    }
+
+    public void setMs_pwd(String ms_pwd) {
+        this.ms_pwd = ms_pwd;
+    }
+
+    public String getMa_name() {
+        return ma_name;
+    }
+
+    public void setMa_name(String ma_name) {
+        this.ma_name = ma_name;
+    }
+
+    public Long getMa_uu() {
+        return ma_uu;
+    }
+
+    public void setMa_uu(Long ma_uu) {
+        this.ma_uu = ma_uu;
+    }
+
+    public String getMa_function() {
+        return ma_function;
+    }
+
+    public void setMa_function(String ma_function) {
+        this.ma_function = ma_function;
+    }
+
+    public String getMa_accesssecret() {
+        return ma_accesssecret;
+    }
+
+    public void setMa_accesssecret(String ma_accesssecret) {
+        this.ma_accesssecret = ma_accesssecret;
+    }
+
+    public Short getMa_enable() {
+        return ma_enable;
+    }
+
+    public void setMa_enable(Short ma_enable) {
+        this.ma_enable = ma_enable;
+    }
+
+    public Integer getMa_b2benable() {
+        return ma_b2benable;
+    }
+
+    public void setMa_b2benable(Integer ma_b2benable) {
+        this.ma_b2benable = ma_b2benable;
+    }
+
+    public String getMa_env() {
+        return ma_env;
+    }
+
+    public void setMa_env(String ma_env) {
+        this.ma_env = ma_env;
+    }
+
+    public String getMa_url() {
+        return ma_url;
+    }
+
+    public void setMa_url(String ma_url) {
+        this.ma_url = ma_url;
+    }
+
+    @Override
+    public String qualifier() {
+        return this.username();
+    }
+
+    @Override
+    public String url() {
+        return this.ma_url == null ? Constant.DEFAULT_DATASOURCE_URL : this.ma_url;
+    }
+
+    @Override
+    public String username() {
+        return this.ma_user.toUpperCase();
+    }
+
+    @Override
+    public String password() {
+        return this.ms_pwd;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Master master = (Master) o;
+
+        if (ma_user != null ? !ma_user.equals(master.ma_user) : master.ma_user != null) return false;
+        return ma_url != null ? ma_url.equals(master.ma_url) : master.ma_url == null;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = ma_user != null ? ma_user.hashCode() : 0;
+        result = 31 * result + (ma_url != null ? ma_url.hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public int compareTo(Master master) {
+        return Integer.compare(this.ma_id, master.getMa_id());
+    }
+}

+ 30 - 0
src/main/java/com/uas/erp/database/domain/MasterView.java

@@ -0,0 +1,30 @@
+package com.uas.erp.database.domain;
+
+/**
+ * Created by Pro1 on 2017/8/22.
+ */
+public class MasterView {
+    private String name;
+    private String title;
+
+    public MasterView(Master master) {
+        this.name = master.getMa_user().toUpperCase();
+        this.title = master.getMa_function();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}

+ 76 - 0
src/main/java/com/uas/erp/database/entity/DBA.java

@@ -0,0 +1,76 @@
+package com.uas.erp.database.entity;
+
+import com.uas.erp.database.datasource.Connectable;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Entity
+public class DBA implements Connectable{
+
+    @Id
+    @GeneratedValue
+    private long id;
+
+    private String username;
+
+    private String password;
+
+    private String url;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    @Override
+    public String qualifier() {
+        return this.username();
+    }
+
+    @Override
+    public String url() {
+        return url;
+    }
+
+    @Override
+    public String username() {
+        return this.getUsername();
+    }
+
+    @Override
+    public String password() {
+        return this.getPassword();
+    }
+}

+ 98 - 0
src/main/java/com/uas/erp/database/repository/BaseRepository.java

@@ -0,0 +1,98 @@
+package com.uas.erp.database.repository;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.BeanPropertyRowMapper;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Repository;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Repository
+public class BaseRepository {
+
+    @Autowired
+    private JdbcTemplate jdbcTemplate;
+
+    public void execute(String exec, Object... args) {
+        jdbcTemplate.update(exec);
+    }
+
+    public void execute(String[] execs) {
+        jdbcTemplate.batchUpdate(execs);
+    }
+
+    public void execute(List<String> execs) {
+        jdbcTemplate.batchUpdate(execs.toArray(new String[]{}));
+    }
+
+    public <T> T queryForObject(String exec, Class<T> targetCls, Object... vars) {
+        try {
+            return jdbcTemplate.queryForObject(exec, targetCls, vars);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    public <T> T queryForBean(String exec, Class<T> targetCls, Object... vars) {
+        try {
+            return jdbcTemplate.queryForObject(exec, new BeanPropertyRowMapper<T>(targetCls), vars);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    public List<Map<String, Object>> queryForList(String exec, Object... vars) {
+        try {
+            return jdbcTemplate.queryForList(exec, vars);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    public List<Map<String, Object>> queryForFieldsList(String exec, final String[] fields, Object[] vars) {
+        try {
+            return jdbcTemplate.query(exec, new RowMapper<Map<String, Object>>() {
+                @Override
+                public Map<String, Object> mapRow(ResultSet rs, int i) throws SQLException {
+                    Map<String, Object> data = new HashMap<>();
+                    for (String field : fields) {
+                        try {
+                            data.put(field, rs.getObject(field));
+                        } catch (SQLException e) {
+                            // ignore non-exists fields
+                        }
+                    }
+                    return data;
+                }
+            }, vars);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    public <T> List<T> queryForList(String exec, Class<T> targetCls, Object... vars) {
+        try {
+            return jdbcTemplate.queryForList(exec, targetCls, vars);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+    public <T> List<T> queryForBeanList(String exec, Class<T> targetCls, Object... vars) {
+        try {
+            return jdbcTemplate.query(exec, new BeanPropertyRowMapper<T>(targetCls), vars);
+        } catch (EmptyResultDataAccessException e) {
+            return null;
+        }
+    }
+
+}

+ 15 - 0
src/main/java/com/uas/erp/database/repository/DBARepository.java

@@ -0,0 +1,15 @@
+package com.uas.erp.database.repository;
+
+import com.uas.erp.database.entity.DBA;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Repository
+public interface DBARepository extends JpaRepository<DBA, Long>{
+
+    DBA findByUrlAndUsername(String url, String username);
+
+}

+ 84 - 0
src/main/java/com/uas/erp/database/service/DBAService.java

@@ -0,0 +1,84 @@
+package com.uas.erp.database.service;
+
+import com.uas.erp.database.datasource.TargetDataSource;
+import com.uas.erp.database.domain.Master;
+import com.uas.erp.database.entity.DBA;
+import com.uas.erp.database.repository.BaseRepository;
+import com.uas.erp.database.repository.DBARepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Service
+public class DBAService {
+
+    @Autowired
+    private DBARepository dbaRepository;
+
+    @Autowired
+    private BaseRepository baseRepository;
+
+    public List<DBA> findAll() {
+        return dbaRepository.findAll();
+    }
+
+    public void save(DBA dba) {
+        DBA oldOne = dbaRepository.findByUrlAndUsername(dba.getUrl(), dba.getUsername());
+        if (null != oldOne) {
+            dba.setId(oldOne.getId());
+        }
+        dba.setUsername(dba.getUsername().toUpperCase());
+        dbaRepository.save(dba);
+    }
+
+    public void save(List<DBA> dbas) {
+        for (DBA dba : dbas) {
+            save(dba);
+        }
+    }
+
+    public void delete(DBA dba) {
+        dbaRepository.delete(dba);
+    }
+
+    public void delete(long id) {
+        dbaRepository.delete(id);
+    }
+
+    /**
+     * 查找dba同实例下的数据库用户,且配置在master表里面的
+     */
+    @TargetDataSource
+    public Set<Master> getMasters(DBA dba) {
+        List<Master> masters = new ArrayList<>();
+        Integer count = baseRepository.queryForObject("select count(1) from user_tables where table_name='MASTER'", Integer.class);
+        if (count == 1) {
+            // 本账套有Master表,说明是默认账套
+            masters.addAll(baseRepository.queryForBeanList("select * from master where ma_enable=1", Master.class));
+        } else {
+            // 说明是SYSTEM账号
+            List<String> users = baseRepository.queryForList("select owner from all_tables where table_name='MASTER'", String.class);
+            if (!CollectionUtils.isEmpty(users)) {
+                for (String user : users) {
+                    masters.addAll(baseRepository.queryForBeanList("select * from " + user + ".master where ma_enable=1", Master.class));
+                }
+            }
+        }
+        for (Master master : masters) {
+            if (StringUtils.isEmpty(master.getMa_url())) {
+                master.setMa_url(dba.url());
+            }
+        }
+        return new HashSet<>(masters);
+    }
+
+}

+ 43 - 0
src/main/java/com/uas/erp/database/service/ExecuteService.java

@@ -0,0 +1,43 @@
+package com.uas.erp.database.service;
+
+import com.uas.erp.database.datasource.TargetDataSource;
+import com.uas.erp.database.domain.Executable;
+import com.uas.erp.database.domain.Master;
+import com.uas.erp.database.repository.BaseRepository;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Service
+public class ExecuteService {
+
+    @Autowired
+    private BaseRepository baseRepository;
+
+    @TargetDataSource
+    public List<Map<String, Object>> execute(Master master, Executable executable) {
+        String[] execs = executable.getExecs();
+        if (null != execs && execs.length > 0) {
+            if (execs.length == 1) {
+                if (executable.isQuery()) {
+                    String[] returnFields = executable.getReturnFields();
+                    if (null != returnFields && returnFields.length > 0) {
+                        return baseRepository.queryForFieldsList(execs[0], returnFields, executable.getArgs());
+                    }
+                    return baseRepository.queryForList(execs[0], executable.getArgs());
+                }
+                baseRepository.execute(execs[0], executable.getArgs());
+            } else {
+                baseRepository.execute(execs);
+            }
+        }
+        return null;
+    }
+
+}

+ 66 - 0
src/main/java/com/uas/erp/database/service/MasterService.java

@@ -0,0 +1,66 @@
+package com.uas.erp.database.service;
+
+import com.uas.erp.database.domain.Master;
+import com.uas.erp.database.domain.MasterView;
+import com.uas.erp.database.entity.DBA;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+@Service
+public class MasterService implements InitializingBean{
+
+    @Autowired
+    private DBAService dbaService;
+
+    private Set<Master> masters;
+
+    /**
+     * 查找全部账套
+     */
+    public void scanAll() {
+        masters = new ConcurrentSkipListSet<>();
+        List<DBA> dbas = dbaService.findAll();
+        if (!CollectionUtils.isEmpty(dbas)) {
+            for (DBA dba : dbas) {
+                masters.addAll(dbaService.getMasters(dba));
+            }
+        }
+    }
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        this.scanAll();
+    }
+
+    public Set<Master> findAll() {
+        return masters;
+    }
+
+    public Set<MasterView> findAllView() {
+        Set<MasterView> views = new HashSet<>();
+        for (Master master : masters) {
+            views.add(new MasterView(master));
+        }
+        return views;
+    }
+
+    public Master findOne(String qualifier) {
+        for (Master master : masters) {
+            if (master.qualifier().equals(qualifier)) {
+                return master;
+            }
+        }
+        return null;
+    }
+}

+ 97 - 0
src/main/java/com/uas/erp/database/web/ResponseWrap.java

@@ -0,0 +1,97 @@
+package com.uas.erp.database.web;
+
+import com.alibaba.fastjson.JSON;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.ui.ModelMap;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Created by Pro1 on 2017/6/20.
+ */
+public class ResponseWrap {
+
+    private static final String successParam = "success";
+
+    private static final String responseCodeParam = "code";
+
+    private static final String responseMessageParam = "message";
+
+    private static final String responseContentParam = "content";
+
+    public static ModelMap success() {
+        return new ModelMap(successParam, true);
+    }
+
+    public static <T> ModelMap success(T content) {
+        return success().addAttribute(responseContentParam, content);
+    }
+
+    public static ModelMap error() {
+        return new ModelMap(successParam, false);
+    }
+
+    public static ModelMap error(String message) {
+        return error().addAttribute(responseMessageParam, message);
+    }
+
+    public static <T> ModelMap error(int code) {
+        return error().addAttribute(responseCodeParam, code);
+    }
+
+    public static <T> ModelMap error(int code, String message) {
+        return error(code).addAttribute(responseMessageParam, message);
+    }
+
+    public static ResponseEntity ok() {
+        return ResponseEntity.ok(success());
+    }
+
+    public static <T> ResponseEntity ok(T content) {
+        return ResponseEntity.ok(success(content));
+    }
+
+    public static <T> void ok(HttpServletResponse response, T content) throws IOException {
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
+        PrintWriter printWriter = response.getWriter();
+        printWriter.append(JSON.toJSONString(success(content)));
+        printWriter.flush();
+        printWriter.close();
+    }
+
+    public static <T> void ok(HttpServletResponse response) throws IOException {
+        ok(response, null);
+    }
+
+    public static ResponseEntity badRequest() {
+        // do not use ResponseEntity.badRequest()
+        return ResponseEntity.ok(error());
+    }
+
+    public static <T> ResponseEntity badRequest(String message) {
+        return ResponseEntity.ok(error(message));
+    }
+
+    public static <T> void badRequest(HttpServletResponse response, int code, String message) throws IOException {
+        response.setStatus(HttpStatus.OK.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8.toString());
+        PrintWriter printWriter = response.getWriter();
+        printWriter.append(JSON.toJSONString(error(code, message)));
+        printWriter.flush();
+        printWriter.close();
+    }
+
+    public static <T> void badRequest(HttpServletResponse response, String message) throws IOException {
+        badRequest(response, HttpStatus.BAD_REQUEST.value(), message);
+    }
+
+    public static <T> void badRequest(HttpServletResponse response) throws IOException {
+        badRequest(response, HttpStatus.BAD_REQUEST.value(), null);
+    }
+
+}

+ 49 - 0
src/main/resources/application.yml

@@ -0,0 +1,49 @@
+server:
+  port: 9002
+  contextPath: /uas_database
+  tomcat:
+    uri-encoding: UTF-8
+
+spring:
+  application:
+    name: uas-database
+  http:
+    encoding:
+      force: true
+      charset: utf-8
+      enabled: true
+  jpa:
+    show_sql: false
+    database: H2
+    hibernate:
+      ddl-auto: update
+  datasource:
+    driverClassName: oracle.jdbc.driver.OracleDriver
+    initial-size: 1
+    max-active: 20
+    min-idle: 1
+    pool-prepared-statements: true
+    max-open-prepared-statements: 20
+    test-on-borrow: true
+    test-on-return: false
+    test-while-idle: true
+    min-evictable-idle-time-millis: 300000
+    time-between-eviction-runs-millis: 60000
+    primary:
+      driverClassName: org.h2.Driver
+      url: jdbc:h2:mem:uas
+  profiles:
+      active: dev
+---
+spring:
+  profiles: dev
+dba:
+  url: jdbc:oracle:thin:@192.168.253.12:1521:orcl
+  username: UAS
+  password: select!#%*(
+---
+spring:
+  profiles: prod
+  datasource:
+    primary:
+      url: jdbc:h2:file:~/data/db;DB_CLOSE_ON_EXIT=FALSE

+ 57 - 0
src/test/java/com/uas/erp/test/MasterTest.java

@@ -0,0 +1,57 @@
+package com.uas.erp.test;
+
+import com.uas.erp.database.UasDatabaseApplication;
+import com.uas.erp.database.domain.Executable;
+import com.uas.erp.database.domain.Master;
+import com.uas.erp.database.entity.DBA;
+import com.uas.erp.database.service.DBAService;
+import com.uas.erp.database.service.ExecuteService;
+import com.uas.erp.database.service.MasterService;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.Assert;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Created by Pro1 on 2017/7/27.
+ */
+//@RunWith(SpringJUnit4ClassRunner.class)
+//@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = UasDatabaseApplication.class)
+public class MasterTest {
+
+    @Autowired
+    private DBAService dbaService;
+
+    @Autowired
+    private MasterService masterService;
+
+    @Autowired
+    private ExecuteService executeService;
+
+//    @Before
+    public void testScanMasters() {
+        DBA dba = new DBA();
+        dba.setUrl("jdbc:oracle:thin:@192.168.253.12:1521:orcl");
+        dba.setUsername("UAS");
+        dba.setPassword("select!#%*(");
+        dbaService.save(dba);
+        masterService.scanAll();
+    }
+
+//    @Test
+    public void testExec() {
+        Set<Master> masters = masterService.findAll();
+        Assert.notEmpty(masters);
+        Executable executable = new Executable();
+        executable.setQuery(true);
+        executable.setExecs(new String[]{ "select 1 from dual" });
+        executeService.execute(masters.iterator().next(), executable);
+    }
+
+}