From 1ca7b9114d7b5d5799ea4019736390a6300a3040 Mon Sep 17 00:00:00 2001 From: zhouhao Date: Fri, 19 May 2017 10:28:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8A=A8=E6=80=81=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hsweb-datasource/hsweb-datasource-api/pom.xml | 9 +++ .../web/datasource/DataSourceHolder.java | 72 +++++++++++++++-- .../datasource/annotation/UseDataSource.java | 15 ++++ .../AbstractDynamicDataSourceService.java | 6 ++ ...opDataSourceSwitcherAutoConfiguration.java | 78 +++++++++++++++++++ .../switcher/DataSourceSwitcher.java | 8 +- .../switcher/DefaultDataSourceSwitcher.java | 10 ++- .../jta/AtomikosDataSourceConfig.java | 29 +++---- .../jta/JtaDynamicDataSourceService.java | 11 ++- .../datasource/jta/SimpleAtomikosTests.java | 75 +++++++++++++----- .../src/test/resources/application.yml | 8 +- 11 files changed, 269 insertions(+), 52 deletions(-) create mode 100644 hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/starter/AopDataSourceSwitcherAutoConfiguration.java diff --git a/hsweb-datasource/hsweb-datasource-api/pom.xml b/hsweb-datasource/hsweb-datasource-api/pom.xml index a1cc1857f..9cddb411b 100644 --- a/hsweb-datasource/hsweb-datasource-api/pom.xml +++ b/hsweb-datasource/hsweb-datasource-api/pom.xml @@ -22,9 +22,18 @@ org.springframework.boot spring-boot-starter + + org.aspectj + aspectjweaver + org.slf4j slf4j-api + + org.hswebframework.web + hsweb-boost-aop + ${project.version} + \ No newline at end of file diff --git a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DataSourceHolder.java b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DataSourceHolder.java index 3907b125e..407ca92fe 100644 --- a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DataSourceHolder.java +++ b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/DataSourceHolder.java @@ -1,37 +1,93 @@ package org.hswebframework.web.datasource; +import org.hswebframework.web.datasource.exception.DataSourceNotFoundException; import org.hswebframework.web.datasource.switcher.DataSourceSwitcher; /** - * TODO 完成注释 + * 用于操作动态数据源,如获取当前使用的数据源,使用switcher切换数据源等 * * @author zhouhao + * @see 3.0 */ public final class DataSourceHolder { + /** + * 动态数据源切换器 + */ static DataSourceSwitcher dataSourceSwitcher; + /** + * 动态数据源服务 + */ static DynamicDataSourceService dynamicDataSourceService; + /** + * @return 动态数据源切换器 + */ public static DataSourceSwitcher switcher() { return dataSourceSwitcher; } - public static DynamicDataSource getDefaultDataSource() { + /** + * @return 默认数据源 + */ + public static DynamicDataSource defaultDataSource() { return dynamicDataSourceService.getDefaultDataSource(); } - public static DynamicDataSource getActiveDataSource() { + /** + * @return 当前使用的数据源 + */ + public static DynamicDataSource currentDataSource() { String id = dataSourceSwitcher.currentDataSourceId(); - if (id == null) return getDefaultDataSource(); + if (id == null) return defaultDataSource(); return dynamicDataSourceService.getDataSource(id); } - public static DatabaseType getActiveDatabaseType() { - return getActiveDataSource().getType(); + /** + * @return 当前使用的数据源是否为默认数据源 + */ + public static boolean currentIsDefault() { + return dataSourceSwitcher.currentDataSourceId() == null; } - public static DatabaseType getDefaultDatabaseType() { - return getDefaultDataSource().getType(); + /** + * 判断指定id的数据源是否存在 + * + * @param id 数据源id {@link DynamicDataSource#getId()} + * @return 数据源是否存在 + */ + public static boolean existing(String id) { + try { + return dynamicDataSourceService.getDataSource(id) != null; + } catch (DataSourceNotFoundException e) { + return false; + } + } + + /** + * @return 当前使用的数据源是否存在 + */ + public static boolean currentExisting() { + if (currentIsDefault()) return true; + try { + return currentDataSource() != null; + } catch (DataSourceNotFoundException e) { + return false; + } + } + + /** + * @return 当前数据库类型 + */ + public static DatabaseType currentDatabaseType() { + return currentDataSource().getType(); + } + + /** + * @return 默认的数据库类型 + */ + public static DatabaseType defaultDatabaseType() { + return defaultDataSource().getType(); } } diff --git a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/annotation/UseDataSource.java b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/annotation/UseDataSource.java index 0876d0bfa..fbe3ba750 100644 --- a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/annotation/UseDataSource.java +++ b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/annotation/UseDataSource.java @@ -1,5 +1,8 @@ package org.hswebframework.web.datasource.annotation; +import org.hswebframework.web.datasource.DataSourceHolder; +import org.hswebframework.web.datasource.DynamicDataSource; + import java.lang.annotation.*; /** @@ -10,5 +13,17 @@ import java.lang.annotation.*; @Documented @Inherited public @interface UseDataSource { + /** + * @return 数据源ID ,支持表达式如 : ${#param.id} + * @see DynamicDataSource#getId() + */ String value(); + + /** + * @return 数据源不存在时, 是否使用默认数据源. + * 如果为{@code false},当数据源不存在的时候, + * 将抛出 {@link org.hswebframework.web.datasource.exception.DataSourceNotFoundException} + * @see DataSourceHolder#currentExisting() + */ + boolean fallbackDefault() default true; } diff --git a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/AbstractDynamicDataSourceService.java b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/AbstractDynamicDataSourceService.java index 5fd1b2445..dd6e235f9 100644 --- a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/AbstractDynamicDataSourceService.java +++ b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/service/AbstractDynamicDataSourceService.java @@ -4,6 +4,7 @@ import org.hswebframework.web.datasource.DynamicDataSource; import org.hswebframework.web.datasource.DynamicDataSourceProxy; import org.hswebframework.web.datasource.DynamicDataSourceService; +import javax.annotation.PreDestroy; import javax.sql.DataSource; import java.sql.SQLException; import java.util.Map; @@ -25,6 +26,11 @@ public abstract class AbstractDynamicDataSourceService implements DynamicDataSou this(dataSource instanceof DynamicDataSource ? (DynamicDataSource) dataSource : new DynamicDataSourceProxy(null, dataSource)); } + @PreDestroy + public void destroy() { + dataSourceStore.values().forEach(DataSourceCache::closeDataSource); + } + @Override public DynamicDataSource getDataSource(String dataSourceId) { DataSourceCache cache = dataSourceStore.get(dataSourceId); diff --git a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/starter/AopDataSourceSwitcherAutoConfiguration.java b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/starter/AopDataSourceSwitcherAutoConfiguration.java new file mode 100644 index 000000000..a61a660f3 --- /dev/null +++ b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/starter/AopDataSourceSwitcherAutoConfiguration.java @@ -0,0 +1,78 @@ +package org.hswebframework.web.datasource.starter; + +import org.aopalliance.intercept.MethodInterceptor; +import org.hswebframework.web.AopUtils; +import org.hswebframework.web.ExpressionUtils; +import org.hswebframework.web.boost.aop.context.MethodInterceptorHolder; +import org.hswebframework.web.datasource.DataSourceHolder; +import org.hswebframework.web.datasource.annotation.UseDataSource; +import org.hswebframework.web.datasource.annotation.UseDefaultDataSource; +import org.hswebframework.web.datasource.exception.DataSourceNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.lang.reflect.Method; + +/** + * 通过aop方式进行对注解方式切换数据源提供支持 + * + * @author zhouhao + * @since 3.0 + */ +@Configuration +public class AopDataSourceSwitcherAutoConfiguration { + + @Bean + public SwitcherMethodMatcherPointcutAdvisor switcherMethodMatcherPointcutAdvisor() { + return new SwitcherMethodMatcherPointcutAdvisor(); + } + + public static class SwitcherMethodMatcherPointcutAdvisor extends StaticMethodMatcherPointcutAdvisor { + private static final Logger logger = LoggerFactory.getLogger(SwitcherMethodMatcherPointcutAdvisor.class); + + public SwitcherMethodMatcherPointcutAdvisor() { + setAdvice((MethodInterceptor) methodInvocation -> { + logger.debug("switch datasource..."); + UseDataSource useDataSource = AopUtils.findAnnotation(methodInvocation.getThis().getClass(), + methodInvocation.getMethod(), UseDataSource.class); + if (useDataSource != null) { + String id = useDataSource.value(); + if (id.contains("${")) { + MethodInterceptorHolder holder = MethodInterceptorHolder.create(methodInvocation); + id = ExpressionUtils.analytical(id, holder.getArgs(), "spel"); + } + if (!DataSourceHolder.existing(id)) { + if (useDataSource.fallbackDefault()) { + DataSourceHolder.switcher().useDefault(); + } else { + throw new DataSourceNotFoundException(id); + } + } else { + DataSourceHolder.switcher().use(id); + } + } else { + UseDefaultDataSource useDefaultDataSource = AopUtils.findAnnotation(methodInvocation.getThis().getClass(), + methodInvocation.getMethod(), UseDefaultDataSource.class); + if (useDefaultDataSource == null) { + logger.warn("can't found annotation: UseDefaultDataSource !"); + } + DataSourceHolder.switcher().useDefault(); + } + try { + return methodInvocation.proceed(); + } finally { + DataSourceHolder.switcher().useLast(); + } + }); + } + + @Override + public boolean matches(Method method, Class aClass) { + return AopUtils.findAnnotation(aClass, method, UseDataSource.class) != null || + AopUtils.findAnnotation(aClass, method, UseDefaultDataSource.class) != null; + } + } +} diff --git a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DataSourceSwitcher.java b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DataSourceSwitcher.java index 224e181c6..10deba4d1 100644 --- a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DataSourceSwitcher.java +++ b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DataSourceSwitcher.java @@ -1,9 +1,11 @@ package org.hswebframework.web.datasource.switcher; /** - * TODO 完成注释 + * 动态数据源切换器,用于切换数据源操作 * * @author zhouhao + * @see 3.0 + * @see DefaultDataSourceSwitcher */ public interface DataSourceSwitcher { @@ -25,12 +27,12 @@ public interface DataSourceSwitcher { void useDefault(); /** - * @return 当前选择的数据源ID + * @return 当前选择的数据源ID, 如果为默认数据源则返回 {@code null} */ String currentDataSourceId(); /** - * 重置切换记录 + * 重置切换记录,重置后,使用默认数据源 */ void reset(); } diff --git a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcher.java b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcher.java index 40fbb9e9c..6e7fb17ed 100644 --- a/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcher.java +++ b/hsweb-datasource/hsweb-datasource-api/src/main/java/org/hswebframework/web/datasource/switcher/DefaultDataSourceSwitcher.java @@ -8,26 +8,31 @@ import java.util.Deque; import java.util.LinkedList; /** - * TODO 完成注释 + * 默认的动态数据源切换器,基于ThreadLocal,queue * * @author zhouhao + * @since 3.0 */ public class DefaultDataSourceSwitcher implements DataSourceSwitcher { + + //默认数据源标识 private static final String DEFAULT_DATASOURCE_ID = DataSourceSwitcher.class.getName() + "_default_"; private Logger logger = LoggerFactory.getLogger(this.getClass()); private Deque getUsedHistoryQueue() { + // 从ThreadLocal中获取一个使用记录 return ThreadLocalUtils.get(DefaultDataSourceSwitcher.class.getName() + "_queue", LinkedList::new); } @Override public void useLast() { + // 没有上一次了 if (getUsedHistoryQueue().size() == 0) { return; } + //移除队尾,则当前的队尾则为上一次的数据源 getUsedHistoryQueue().removeLast(); - if (logger.isDebugEnabled()) { String current = currentDataSourceId(); if (null != current) @@ -38,6 +43,7 @@ public class DefaultDataSourceSwitcher implements DataSourceSwitcher { @Override public void use(String dataSourceId) { + //添加对队尾 getUsedHistoryQueue().addLast(dataSourceId); if (logger.isDebugEnabled()) { logger.debug("try use data source : {}", dataSourceId); diff --git a/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/AtomikosDataSourceConfig.java b/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/AtomikosDataSourceConfig.java index 22500d1ed..4cb5f5cbe 100644 --- a/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/AtomikosDataSourceConfig.java +++ b/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/AtomikosDataSourceConfig.java @@ -11,9 +11,9 @@ import java.util.Properties; * @author zhouhao */ public class AtomikosDataSourceConfig { - private int minPoolSize = 1; - private int maxPoolSize = 20; - private int borrowConnectionTimeout = 30; + private int minPoolSize = 5; + private int maxPoolSize = 200; + private int borrowConnectionTimeout = 60; private int reapTimeout = 0; private int maxIdleTime = 60; private int maintenanceInterval = 60; @@ -23,7 +23,8 @@ public class AtomikosDataSourceConfig { private String testQuery = null; private int maxLifetime = 0; private Properties xaProperties = null; - private int initTimeOut = 10 * 1000; + //初始化超时时间 + private int initTimeout = 10; @Override public int hashCode() { @@ -50,7 +51,7 @@ public class AtomikosDataSourceConfig { ", testQuery='" + testQuery + '\'' + ", maxLifetime=" + maxLifetime + ", xaProperties=" + xaProperties + - ", initTimeOut=" + initTimeOut + + ", initTimeout=" + initTimeout + '}'; } @@ -150,12 +151,12 @@ public class AtomikosDataSourceConfig { this.maxLifetime = maxLifetime; } - public int getInitTimeOut() { - return initTimeOut; + public int getInitTimeout() { + return initTimeout; } - public void setInitTimeOut(int initTimeOut) { - this.initTimeOut = initTimeOut; + public void setInitTimeout(int initTimeout) { + this.initTimeout = initTimeout; } public void putProperties(AtomikosDataSourceBean atomikosDataSourceBean) { @@ -164,10 +165,12 @@ public class AtomikosDataSourceConfig { } atomikosDataSourceBean.setXaDataSourceClassName(getXaDataSourceClassName()); atomikosDataSourceBean.setBorrowConnectionTimeout(getBorrowConnectionTimeout()); - try { - atomikosDataSourceBean.setLoginTimeout(getLoginTimeout()); - } catch (SQLException e) { - e.printStackTrace(); + if (loginTimeout != 0) { + try { + atomikosDataSourceBean.setLoginTimeout(getLoginTimeout()); + } catch (SQLException e) { + e.printStackTrace(); + } } atomikosDataSourceBean.setMaxIdleTime(getMaxIdleTime()); atomikosDataSourceBean.setMaxPoolSize(getMaxPoolSize()); diff --git a/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/JtaDynamicDataSourceService.java b/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/JtaDynamicDataSourceService.java index 854f6c745..1fe5e479e 100644 --- a/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/JtaDynamicDataSourceService.java +++ b/hsweb-datasource/hsweb-datasource-jta/src/main/java/org/hswebframework/web/datasource/jta/JtaDynamicDataSourceService.java @@ -9,7 +9,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; -import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; import javax.sql.XADataSource; @@ -19,7 +18,6 @@ import java.sql.SQLException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.ForkJoinPool; import java.util.concurrent.atomic.AtomicInteger; /** @@ -83,7 +81,7 @@ public class JtaDynamicDataSourceService extends AbstractDynamicDataSourceServic logger.error("close xa datasource error", e); } } else { - logger.warn("XADataSource is not instanceof Closeable!", Thread.currentThread().getStackTrace()); + logger.warn("XADataSource is not instanceof Closeable!", (Object) Thread.currentThread().getStackTrace()); } } }; @@ -91,21 +89,22 @@ public class JtaDynamicDataSourceService extends AbstractDynamicDataSourceServic executor.execute(() -> { try { atomikosDataSourceBean.init(); - downLatch.countDown(); successCounter.incrementAndGet(); + downLatch.countDown(); } catch (Exception e) { + logger.error("init datasource {} error", id, e); //atomikosDataSourceBean.close(); } }); //初始化状态判断 executor.execute(() -> { try { - Thread.sleep(config.getInitTimeOut()); + Thread.sleep(config.getInitTimeout() * 1000); } catch (InterruptedException ignored) { } finally { if (successCounter.get() == 0) { // 初始化超时,认定为失败 - logger.error("init timeout ({}ms)", config.getInitTimeOut()); + logger.error("init timeout ({}ms)", config.getInitTimeout()); cache.closeDataSource(); if (downLatch.getCount() > 0) downLatch.countDown(); diff --git a/hsweb-datasource/hsweb-datasource-jta/src/test/java/org/hswebframework/web/datasource/jta/SimpleAtomikosTests.java b/hsweb-datasource/hsweb-datasource-jta/src/test/java/org/hswebframework/web/datasource/jta/SimpleAtomikosTests.java index e3735c1f2..e0cc61b7a 100644 --- a/hsweb-datasource/hsweb-datasource-jta/src/test/java/org/hswebframework/web/datasource/jta/SimpleAtomikosTests.java +++ b/hsweb-datasource/hsweb-datasource-jta/src/test/java/org/hswebframework/web/datasource/jta/SimpleAtomikosTests.java @@ -1,32 +1,52 @@ package org.hswebframework.web.datasource.jta; -import com.alibaba.druid.pool.DruidDataSource; import org.hsweb.ezorm.rdb.RDBDatabase; import org.hsweb.ezorm.rdb.executor.AbstractJdbcSqlExecutor; import org.hsweb.ezorm.rdb.executor.SQL; import org.hsweb.ezorm.rdb.executor.SqlExecutor; import org.hsweb.ezorm.rdb.meta.RDBDatabaseMetaData; +import org.hsweb.ezorm.rdb.meta.RDBTableMetaData; +import org.hsweb.ezorm.rdb.meta.parser.H2TableMetaParser; +import org.hsweb.ezorm.rdb.meta.parser.MysqlTableMetaParser; +import org.hsweb.ezorm.rdb.meta.parser.OracleTableMetaParser; +import org.hsweb.ezorm.rdb.meta.parser.TableMetaParser; import org.hsweb.ezorm.rdb.render.SqlRender; import org.hsweb.ezorm.rdb.render.dialect.Dialect; import org.hsweb.ezorm.rdb.render.dialect.H2RDBDatabaseMetaData; import org.hsweb.ezorm.rdb.render.dialect.MysqlRDBDatabaseMetaData; import org.hsweb.ezorm.rdb.render.dialect.OracleRDBDatabaseMetaData; import org.hsweb.ezorm.rdb.simple.SimpleDatabase; +import org.hswebframework.expands.script.engine.DynamicScriptEngine; +import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory; +import org.hswebframework.expands.script.engine.SpEL.SpElEngine; import org.hswebframework.web.datasource.DataSourceHolder; import org.hswebframework.web.datasource.DatabaseType; -import org.hswebframework.web.datasource.DynamicDataSourceProxy; -import org.hswebframework.web.datasource.service.DataSourceCache; +import org.hswebframework.web.datasource.annotation.UseDataSource; +import org.hswebframework.web.datasource.annotation.UseDefaultDataSource; +import org.hswebframework.web.datasource.starter.AopDataSourceSwitcherAutoConfiguration; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.beans.factory.config.BeanExpressionResolver; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.context.expression.*; +import org.springframework.core.convert.ConversionService; +import org.springframework.expression.spel.support.StandardTypeConverter; +import org.springframework.expression.spel.support.StandardTypeLocator; import org.springframework.jdbc.datasource.DataSourceUtils; import org.springframework.jms.annotation.EnableJms; import org.springframework.jms.core.JmsTemplate; +import org.springframework.messaging.simp.SimpSessionScope; import org.springframework.test.annotation.Rollback; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Propagation; @@ -36,7 +56,6 @@ import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.*; -import java.util.stream.Collectors; /** * TODO 完成注释 @@ -50,6 +69,8 @@ public class SimpleAtomikosTests { @Configuration @SpringBootApplication @EnableJms + @ImportAutoConfiguration(AopDataSourceSwitcherAutoConfiguration.class) + @EnableAspectJAutoProxy public static class Config { @Bean public SqlExecutor sqlExecutor() { @@ -63,12 +84,12 @@ public class SimpleAtomikosTests { @Override public Connection getConnection() { - return DataSourceUtils.getConnection(DataSourceHolder.getActiveDataSource()); + return DataSourceUtils.getConnection(DataSourceHolder.currentDataSource()); } @Override public void releaseConnection(Connection connection) throws SQLException { - DataSourceUtils.releaseConnection(connection, DataSourceHolder.getActiveDataSource()); + DataSourceUtils.releaseConnection(connection, DataSourceHolder.currentDataSource()); } }; } @@ -96,28 +117,45 @@ public class SimpleAtomikosTests { @Bean public DynDsTest transTest(SqlExecutor sqlExecutor) { - return new DynDsTest(new SimpleDatabase(new DynDatabaseMeta(), sqlExecutor)); + SimpleDatabase database = new SimpleDatabase(new DynDatabaseMeta(sqlExecutor), sqlExecutor); + database.setAutoParse(true); + return new DynDsTest(database); } public class DynDatabaseMeta extends RDBDatabaseMetaData { private Map dialectMap; private Map metaDataMap; + private Map parserMap; - public DynDatabaseMeta() { + public DynDatabaseMeta(SqlExecutor sqlExecutor) { dialectMap = new HashMap<>(); metaDataMap = new HashMap<>(); + parserMap = new HashMap<>(); dialectMap.put(DatabaseType.h2, Dialect.H2); dialectMap.put(DatabaseType.mysql, Dialect.MYSQL); dialectMap.put(DatabaseType.oracle, Dialect.ORACLE); - metaDataMap.put(DatabaseType.h2, new H2RDBDatabaseMetaData()); metaDataMap.put(DatabaseType.mysql, new MysqlRDBDatabaseMetaData()); metaDataMap.put(DatabaseType.oracle, new OracleRDBDatabaseMetaData()); + + parserMap.put(DatabaseType.h2, new H2TableMetaParser(sqlExecutor)); + parserMap.put(DatabaseType.mysql, new MysqlTableMetaParser(sqlExecutor)); + parserMap.put(DatabaseType.oracle, new OracleTableMetaParser(sqlExecutor)); + } + + @Override + public RDBTableMetaData putTable(RDBTableMetaData tableMetaData) { + return metaDataMap.get(DataSourceHolder.currentDatabaseType()).putTable(tableMetaData); + } + + @Override + public TableMetaParser getParser() { + return parserMap.get(DataSourceHolder.currentDatabaseType()); } @Override public Dialect getDialect() { - return dialectMap.get(DataSourceHolder.getActiveDatabaseType()); + return dialectMap.get(DataSourceHolder.currentDatabaseType()); } @Override @@ -127,12 +165,12 @@ public class SimpleAtomikosTests { @Override public SqlRender getRenderer(SqlRender.TYPE type) { - return metaDataMap.get(DataSourceHolder.getActiveDatabaseType()).getRenderer(type); + return metaDataMap.get(DataSourceHolder.currentDatabaseType()).getRenderer(type); } @Override public String getName() { - return metaDataMap.get(DataSourceHolder.getActiveDatabaseType()).getName(); + return metaDataMap.get(DataSourceHolder.currentDatabaseType()).getName(); } } } @@ -157,6 +195,8 @@ public class SimpleAtomikosTests { @Rollback(false) public void test() { try { + DataSourceHolder.switcher().reset(); + dynDsTest.testCreateTable(); dynDsTest.testInsert(); DataSourceHolder.switcher().use("test_ds"); @@ -166,22 +206,20 @@ public class SimpleAtomikosTests { DataSourceHolder.switcher().use("test_ds2"); dynDsTest.testCreateTable(); - System.out.println(DataSourceHolder.getActiveDatabaseType()); + System.out.println(DataSourceHolder.switcher().currentDataSourceId()); System.out.println(dynDsTest.testQuery()); DataSourceHolder.switcher().useLast(); - System.out.println(DataSourceHolder.getActiveDatabaseType()); + System.out.println(DataSourceHolder.switcher().currentDataSourceId()); System.out.println(dynDsTest.testQuery()); DataSourceHolder.switcher().useLast(); - System.out.println(DataSourceHolder.getActiveDatabaseType()); + System.out.println(DataSourceHolder.switcher().currentDataSourceId()); System.out.println(dynDsTest.testQuery()); jmsTemplate.convertAndSend("test", "hello"); Thread.sleep(1000); // throw new RuntimeException(); - } catch (SQLException e) { - e.printStackTrace(); - } catch (InterruptedException e) { + } catch (SQLException | InterruptedException e) { e.printStackTrace(); } } @@ -207,6 +245,7 @@ public class SimpleAtomikosTests { .exec(); } + public List testQuery() throws SQLException { return database.getTable("s_user").createQuery().list(); } diff --git a/hsweb-datasource/hsweb-datasource-jta/src/test/resources/application.yml b/hsweb-datasource/hsweb-datasource-jta/src/test/resources/application.yml index 03c2e0304..ff422c973 100644 --- a/hsweb-datasource/hsweb-datasource-jta/src/test/resources/application.yml +++ b/hsweb-datasource/hsweb-datasource-jta/src/test/resources/application.yml @@ -17,7 +17,7 @@ spring: activemq: broker-url: tcp://localhost:61616 - in-memory: false + in-memory: true logging: level: @@ -41,4 +41,8 @@ hsweb: username: sa password: max-pool-size: 20 - borrow-connection-timeout: 1000 \ No newline at end of file + borrow-connection-timeout: 1000 + init-timeout: 20 + +config: + test: 123 \ No newline at end of file