mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 00:58:24 +08:00
add multi datasource support
This commit is contained in:
parent
6c1ddc3ac1
commit
e89e8f3ef0
@ -36,9 +36,9 @@
|
||||
</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>target/generated-sources</directory>
|
||||
</resource>
|
||||
<!-- <resource>-->
|
||||
<!-- <directory>target/generated-sources</directory>-->
|
||||
<!-- </resource>-->
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
package com.mybatisflex.core;
|
||||
|
||||
import com.mybatisflex.core.datasource.RoutingDataSource;
|
||||
import com.mybatisflex.core.dialect.DbType;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
|
||||
import org.apache.ibatis.logging.Log;
|
||||
@ -64,7 +63,6 @@ public class MybatisFlexBootstrap {
|
||||
protected Configuration configuration;
|
||||
protected List<Class<?>> mappers;
|
||||
|
||||
protected DbType dbType;
|
||||
protected SqlSessionFactory sqlSessionFactory;
|
||||
protected Class<? extends Log> logImpl;
|
||||
|
||||
@ -115,7 +113,7 @@ public class MybatisFlexBootstrap {
|
||||
transactionFactory = new JdbcTransactionFactory();
|
||||
}
|
||||
|
||||
Environment environment = new Environment(environmentId, transactionFactory, new RoutingDataSource(environmentId, dataSource));
|
||||
Environment environment = new Environment(environmentId, transactionFactory, dataSource);
|
||||
configuration = new FlexConfiguration(environment);
|
||||
}
|
||||
|
||||
@ -126,8 +124,6 @@ public class MybatisFlexBootstrap {
|
||||
//init sqlSessionFactory
|
||||
this.sqlSessionFactory = new FlexSqlSessionFactoryBuilder().build(configuration);
|
||||
|
||||
//init dbType
|
||||
this.dbType = FlexGlobalConfig.getConfig(environmentId).getDbType();
|
||||
|
||||
//init mappers
|
||||
if (mappers != null) {
|
||||
@ -234,6 +230,18 @@ public class MybatisFlexBootstrap {
|
||||
return this;
|
||||
}
|
||||
|
||||
public MybatisFlexBootstrap addDataSource(String dataSourceKey, DataSource dataSource) {
|
||||
if (this.dataSource == null) {
|
||||
this.dataSource = new RoutingDataSource(dataSourceKey, dataSource);
|
||||
} else if (this.dataSource instanceof RoutingDataSource) {
|
||||
((RoutingDataSource) this.dataSource).addDataSource(dataSourceKey, dataSource);
|
||||
} else {
|
||||
this.dataSource = new RoutingDataSource("default", this.dataSource);
|
||||
((RoutingDataSource) this.dataSource).addDataSource(dataSourceKey, dataSource);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Configuration getConfiguration() {
|
||||
return configuration;
|
||||
}
|
||||
@ -249,15 +257,6 @@ public class MybatisFlexBootstrap {
|
||||
}
|
||||
|
||||
|
||||
public DbType getDbType() {
|
||||
return dbType;
|
||||
}
|
||||
|
||||
public MybatisFlexBootstrap setDbType(DbType dbType) {
|
||||
this.dbType = dbType;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SqlSessionFactory getSqlSessionFactory() {
|
||||
return sqlSessionFactory;
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.spring.boot;
|
||||
package com.mybatisflex.core.datasource;
|
||||
|
||||
import com.mybatisflex.core.table.ConvertUtil;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
@ -21,22 +21,22 @@ public class DataSourceKey {
|
||||
|
||||
private static ThreadLocal<String> keyThreadLocal = new ThreadLocal<>();
|
||||
|
||||
public static void use(String environmentId) {
|
||||
keyThreadLocal.set(environmentId);
|
||||
public static void use(String dataSourceKey) {
|
||||
keyThreadLocal.set(dataSourceKey);
|
||||
}
|
||||
|
||||
public static <T> T use(String environmentId, Supplier<T> supplier) {
|
||||
public static <T> T use(String dataSourceKey, Supplier<T> supplier) {
|
||||
try {
|
||||
use(environmentId);
|
||||
use(dataSourceKey);
|
||||
return supplier.get();
|
||||
} finally {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static void use(String environmentId, Runnable runnable) {
|
||||
public static void use(String dataSourceKey, Runnable runnable) {
|
||||
try {
|
||||
use(environmentId);
|
||||
use(dataSourceKey);
|
||||
runnable.run();
|
||||
} finally {
|
||||
clear();
|
||||
|
||||
@ -15,6 +15,8 @@
|
||||
*/
|
||||
package com.mybatisflex.core.datasource;
|
||||
|
||||
import com.mybatisflex.core.dialect.DbType;
|
||||
import com.mybatisflex.core.dialect.DbTypeUtil;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
@ -25,13 +27,23 @@ import java.util.Map;
|
||||
|
||||
public class RoutingDataSource extends AbstractDataSource {
|
||||
|
||||
private static Map<String, DataSource> dataSourceMap = new HashMap<>();
|
||||
private final Map<String, DataSource> dataSourceMap = new HashMap<>();
|
||||
private final Map<String, DbType> dbTypeHashMap = new HashMap<>();
|
||||
private final DataSource defaultDataSource;
|
||||
|
||||
private DataSource delegate;
|
||||
public RoutingDataSource(String dataSourceKey, DataSource dataSource) {
|
||||
this.defaultDataSource = dataSource;
|
||||
dataSourceMap.put(dataSourceKey, dataSource);
|
||||
dbTypeHashMap.put(dataSourceKey, DbTypeUtil.getDbType(dataSource));
|
||||
}
|
||||
|
||||
public RoutingDataSource(String environmentId, DataSource delegate) {
|
||||
this.delegate = delegate;
|
||||
dataSourceMap.put(environmentId, delegate);
|
||||
public void addDataSource(String dataSourceKey, DataSource dataSource) {
|
||||
dataSourceMap.put(dataSourceKey, dataSource);
|
||||
dbTypeHashMap.put(dataSourceKey, DbTypeUtil.getDbType(dataSource));
|
||||
}
|
||||
|
||||
public DbType getDbType(String dataSourceKey){
|
||||
return dbTypeHashMap.get(dataSourceKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -44,22 +56,33 @@ public class RoutingDataSource extends AbstractDataSource {
|
||||
return getDataSource().getConnection(username, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||
if (iface.isInstance(this)) {
|
||||
return (T) this;
|
||||
}
|
||||
return getDataSource().unwrap(iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
return (iface.isInstance(this) || getDataSource().isWrapperFor(iface));
|
||||
}
|
||||
|
||||
private DataSource getDataSource() {
|
||||
DataSource dataSource = delegate;
|
||||
DataSource dataSource = defaultDataSource;
|
||||
if (dataSourceMap.size() > 1) {
|
||||
String environmentId = DataSourceKey.get();
|
||||
if (StringUtil.isNotBlank(environmentId)) {
|
||||
dataSource = dataSourceMap.get(environmentId);
|
||||
String dataSourceKey = DataSourceKey.get();
|
||||
if (StringUtil.isNotBlank(dataSourceKey)) {
|
||||
dataSource = dataSourceMap.get(dataSourceKey);
|
||||
if (dataSource == null) {
|
||||
throw new IllegalStateException("Cannot get target DataSource for environmentId [" + environmentId + "]");
|
||||
throw new IllegalStateException("Cannot get target DataSource for dataSourceKey [" + dataSourceKey + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public DataSource getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -16,6 +16,12 @@
|
||||
package com.mybatisflex.core.dialect;
|
||||
|
||||
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@ -24,6 +30,56 @@ import java.util.regex.Pattern;
|
||||
public class DbTypeUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前配置的 DbType
|
||||
*/
|
||||
public static DbType getDbType(DataSource dataSource) {
|
||||
String jdbcUrl = getJdbcUrl(dataSource);
|
||||
|
||||
if (StringUtil.isNotBlank(jdbcUrl)) {
|
||||
return parseDbType(jdbcUrl);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot get dataSource jdbcUrl: " + dataSource.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过数据源中获取 jdbc 的 url 配置
|
||||
* 符合 HikariCP, druid, c3p0, DBCP, beecp 数据源框架 以及 MyBatis UnpooledDataSource 的获取规则
|
||||
* UnpooledDataSource 参考 @{@link UnpooledDataSource#getUrl()}
|
||||
*
|
||||
* @return jdbc url 配置
|
||||
*/
|
||||
private static String getJdbcUrl(DataSource dataSource) {
|
||||
String[] methodNames = new String[]{"getUrl", "getJdbcUrl"};
|
||||
for (String methodName : methodNames) {
|
||||
try {
|
||||
Method method = dataSource.getClass().getMethod(methodName);
|
||||
return (String) method.invoke(dataSource);
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
return connection.getMetaData().getURL();
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 参考 druid 和 MyBatis-plus 的 JdbcUtils
|
||||
* {@link com.alibaba.druid.util.JdbcUtils#getDbType(String, String)}
|
||||
@ -32,7 +88,7 @@ public class DbTypeUtil {
|
||||
* @param jdbcUrl jdbcURL
|
||||
* @return 返回数据库类型
|
||||
*/
|
||||
public static DbType parseDbType(String jdbcUrl) {
|
||||
private static DbType parseDbType(String jdbcUrl) {
|
||||
jdbcUrl = jdbcUrl.toLowerCase();
|
||||
if (jdbcUrl.contains(":mysql:") || jdbcUrl.contains(":cobar:")) {
|
||||
return DbType.MYSQL;
|
||||
|
||||
@ -19,20 +19,14 @@ import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.dialect.DbType;
|
||||
import com.mybatisflex.core.dialect.DbTypeUtil;
|
||||
import com.mybatisflex.core.exception.FlexExceptions;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
|
||||
import org.apache.ibatis.exceptions.ExceptionFactory;
|
||||
import org.apache.ibatis.executor.ErrorContext;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class FlexSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
|
||||
@ -64,8 +58,7 @@ public class FlexSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
|
||||
}
|
||||
|
||||
SqlSessionFactory sessionFactory = super.build(configuration);
|
||||
|
||||
DbType dbType = getDbType(configuration);
|
||||
DbType dbType = DbTypeUtil.getDbType(configuration.getEnvironment().getDataSource());
|
||||
|
||||
//设置全局配置的 sessionFactory 和 dbType
|
||||
initGlobalConfig(configuration, sessionFactory, dbType);
|
||||
@ -91,55 +84,5 @@ public class FlexSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前配置的 DbType
|
||||
*/
|
||||
private DbType getDbType(Configuration configuration) {
|
||||
DataSource dataSource = configuration.getEnvironment().getDataSource();
|
||||
|
||||
String jdbcUrl = getJdbcUrl(dataSource);
|
||||
|
||||
if (StringUtil.isNotBlank(jdbcUrl)) {
|
||||
return DbTypeUtil.parseDbType(jdbcUrl);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot get dataSource jdbcUrl: " + dataSource.getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过数据源中获取 jdbc 的 url 配置
|
||||
* 符合 HikariCP, druid, c3p0, DBCP, beecp 数据源框架 以及 MyBatis UnpooledDataSource 的获取规则
|
||||
* UnpooledDataSource 参考 @{@link UnpooledDataSource#getUrl()}
|
||||
* TODO: 2023/2/18 可能极个别特殊的数据源无法获取 JDBC 配置的 URL
|
||||
*
|
||||
* @return jdbc url 配置
|
||||
*/
|
||||
private String getJdbcUrl(DataSource dataSource) {
|
||||
String[] methodNames = new String[]{"getUrl", "getJdbcUrl"};
|
||||
for (String methodName : methodNames) {
|
||||
try {
|
||||
Method method = dataSource.getClass().getMethod(methodName);
|
||||
return (String) method.invoke(dataSource);
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = dataSource.getConnection();
|
||||
return connection.getMetaData().getURL();
|
||||
} catch (Exception e) {
|
||||
//ignore
|
||||
} finally {
|
||||
if (connection != null) {
|
||||
try {
|
||||
connection.close();
|
||||
} catch (SQLException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,22 +18,32 @@ package com.mybatisflex.core.mybatis;
|
||||
import com.mybatisflex.annotation.UseDataSource;
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.datasource.DataSourceKey;
|
||||
import com.mybatisflex.core.datasource.RoutingDataSource;
|
||||
import com.mybatisflex.core.dialect.DbType;
|
||||
import com.mybatisflex.core.dialect.DialectFactory;
|
||||
import com.mybatisflex.core.row.RowMapper;
|
||||
import com.mybatisflex.core.table.TableInfo;
|
||||
import com.mybatisflex.core.table.TableInfoFactory;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import org.apache.ibatis.session.Configuration;
|
||||
import org.apache.ibatis.util.MapUtil;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MapperInvocationHandler implements InvocationHandler {
|
||||
private static final String NONE_KEY = "!NONE";
|
||||
private static final Map<Method, String> methodDataSourceKeyMap = new ConcurrentHashMap<>();
|
||||
|
||||
private Object mapper;
|
||||
private Configuration configuration;
|
||||
private final Object mapper;
|
||||
private final DataSource dataSource;
|
||||
|
||||
public MapperInvocationHandler(Object mapper, Configuration configuration) {
|
||||
this.mapper = mapper;
|
||||
this.configuration = configuration;
|
||||
this.dataSource = configuration.getEnvironment().getDataSource();
|
||||
}
|
||||
|
||||
|
||||
@ -43,25 +53,26 @@ public class MapperInvocationHandler implements InvocationHandler {
|
||||
boolean clearDbType = false;
|
||||
try {
|
||||
//获取用户动态指定,由用户指定数据源,则应该有用户清除
|
||||
String environmentId = DataSourceKey.get();
|
||||
String dataSourceKey = DataSourceKey.get();
|
||||
|
||||
//通过 方法 的注解去获取
|
||||
if (StringUtil.isBlank(environmentId)) {
|
||||
environmentId = getMethodEnvironmentId(method);
|
||||
if (StringUtil.isNotBlank(environmentId)) {
|
||||
DataSourceKey.use(environmentId);
|
||||
if (StringUtil.isBlank(dataSourceKey)) {
|
||||
String methodKey = getMethodDataSource(method, proxy);
|
||||
if (!NONE_KEY.equals(methodKey)) {
|
||||
dataSourceKey = methodKey;
|
||||
DataSourceKey.use(dataSourceKey);
|
||||
clearDsKey = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtil.isBlank(environmentId)) {
|
||||
environmentId = configuration.getEnvironment().getId();
|
||||
}
|
||||
|
||||
//优先获取用户自己配置的 dbType
|
||||
DbType dbType = DialectFactory.getHintDbType();
|
||||
if (dbType == null) {
|
||||
dbType = FlexGlobalConfig.getConfig(environmentId).getDbType();
|
||||
if (dataSourceKey != null && dataSource instanceof RoutingDataSource) {
|
||||
dbType = ((RoutingDataSource) dataSource).getDbType(dataSourceKey);
|
||||
}
|
||||
if (dbType == null) {
|
||||
dbType = FlexGlobalConfig.getDefaultConfig().getDbType();
|
||||
}
|
||||
DialectFactory.setHintDbType(dbType);
|
||||
clearDbType = true;
|
||||
}
|
||||
@ -77,9 +88,26 @@ public class MapperInvocationHandler implements InvocationHandler {
|
||||
}
|
||||
|
||||
|
||||
private String getMethodEnvironmentId(Method method) {
|
||||
UseDataSource useDataSource = method.getAnnotation(UseDataSource.class);
|
||||
return useDataSource != null ? useDataSource.value() : null;
|
||||
private static String getMethodDataSource(Method method, Object proxy) {
|
||||
return MapUtil.computeIfAbsent(methodDataSourceKeyMap, method, method1 -> {
|
||||
UseDataSource useDataSource = method1.getAnnotation(UseDataSource.class);
|
||||
if (useDataSource != null && StringUtil.isNotBlank(useDataSource.value())) {
|
||||
return useDataSource.value();
|
||||
}
|
||||
|
||||
Class<?>[] interfaces = proxy.getClass().getInterfaces();
|
||||
if (interfaces[0] != RowMapper.class) {
|
||||
TableInfo tableInfo = TableInfoFactory.ofMapperClass(interfaces[0]);
|
||||
if (tableInfo != null) {
|
||||
String dataSourceKey = tableInfo.getDataSource();
|
||||
if (StringUtil.isNotBlank(dataSourceKey)) {
|
||||
return dataSourceKey;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NONE_KEY;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.mybatisflex.core.row;
|
||||
|
||||
import com.mybatisflex.core.FlexGlobalConfig;
|
||||
import com.mybatisflex.core.dialect.DbType;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.apache.ibatis.executor.BatchResult;
|
||||
@ -32,12 +30,10 @@ import java.util.function.Function;
|
||||
public class RowMapperInvoker {
|
||||
|
||||
private final SqlSessionFactory sqlSessionFactory;
|
||||
private final DbType dbType;
|
||||
private RowSessionManager rowSessionManager = RowSessionManager.DEFAULT;
|
||||
|
||||
public RowMapperInvoker(SqlSessionFactory sqlSessionFactory) {
|
||||
this.sqlSessionFactory = sqlSessionFactory;
|
||||
this.dbType = FlexGlobalConfig.getConfig(sqlSessionFactory.getConfiguration()).getDbType();
|
||||
}
|
||||
|
||||
public RowSessionManager getRowSessionManager() {
|
||||
|
||||
@ -66,7 +66,7 @@ public class TableInfoFactory {
|
||||
|
||||
public static TableInfo ofMapperClass(Class<?> mapperClass) {
|
||||
return MapUtil.computeIfAbsent(tableInfoMap, mapperClass, key -> {
|
||||
Class<?> entityClass = getEntityClass(key);
|
||||
Class<?> entityClass = getEntityClass(mapperClass);
|
||||
return entityClass != null ? ofEntityClass(entityClass) : null;
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.test;
|
||||
package com.mybatisflex.coretest;
|
||||
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.test;
|
||||
package com.mybatisflex.coretest;
|
||||
|
||||
import com.mybatisflex.core.dialect.CommonsDialectImpl;
|
||||
import com.mybatisflex.core.dialect.IDialect;
|
||||
@ -13,8 +13,8 @@ import org.junit.Test;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.mybatisflex.core.query.QueryMethods.*;
|
||||
import static com.mybatisflex.test.table.Tables.ACCOUNT;
|
||||
import static com.mybatisflex.test.table.Tables.ARTICLE;
|
||||
import static com.mybatisflex.coretest.table.Tables.ACCOUNT;
|
||||
import static com.mybatisflex.coretest.table.Tables.ARTICLE;
|
||||
|
||||
public class AccountSqlTester {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.test;
|
||||
package com.mybatisflex.coretest;
|
||||
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.annotation.Id;
|
||||
@ -1,4 +1,4 @@
|
||||
package com.mybatisflex.test;
|
||||
package com.mybatisflex.coretest;
|
||||
|
||||
import com.mybatisflex.core.dialect.CommonsDialectImpl;
|
||||
import com.mybatisflex.core.dialect.IDialect;
|
||||
@ -8,7 +8,7 @@ import com.mybatisflex.core.table.TableInfoFactory;
|
||||
import com.mybatisflex.core.util.CollectionUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
import static com.mybatisflex.test.table.Tables.ARTICLE;
|
||||
import static com.mybatisflex.coretest.table.Tables.ARTICLE;
|
||||
|
||||
public class ArticleSqlTester {
|
||||
|
||||
@ -15,36 +15,19 @@
|
||||
*/
|
||||
package com.mybatisflex.spring.boot;
|
||||
|
||||
import com.mybatisflex.core.datasource.DataSourceBuilder;
|
||||
import com.mybatisflex.core.datasource.RoutingDataSource;
|
||||
import com.mybatisflex.spring.FlexSqlSessionFactoryBean;
|
||||
import org.apache.ibatis.mapping.DatabaseIdProvider;
|
||||
import org.apache.ibatis.plugin.Interceptor;
|
||||
import org.apache.ibatis.scripting.LanguageDriver;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.type.TypeHandler;
|
||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
/**
|
||||
@ -54,116 +37,35 @@ import java.util.stream.Stream;
|
||||
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
|
||||
@ConditionalOnPropertyEmpty("spring.datasource.url")
|
||||
@EnableConfigurationProperties(MybatisFlexProperties.class)
|
||||
@AutoConfigureAfter({MybatisLanguageDriverAutoConfiguration.class})
|
||||
@AutoConfigureBefore({DataSourceAutoConfiguration.class})
|
||||
public class MultiDataSourceAutoConfiguration extends MybatisFlexAutoConfiguration {
|
||||
public class MultiDataSourceAutoConfiguration {
|
||||
|
||||
private List<SqlSessionFactory> sqlSessionFactories = new ArrayList<>();
|
||||
private List<DataSource> dataSources = new ArrayList<>();
|
||||
private Map<String, Map<String, String>> dataSourceProperties;
|
||||
|
||||
|
||||
public MultiDataSourceAutoConfiguration(MybatisFlexProperties properties
|
||||
, ObjectProvider<Interceptor[]> interceptorsProvider
|
||||
, ObjectProvider<TypeHandler[]> typeHandlersProvider
|
||||
, ObjectProvider<LanguageDriver[]> languageDriversProvider
|
||||
, ResourceLoader resourceLoader
|
||||
, ObjectProvider<DatabaseIdProvider> databaseIdProvider
|
||||
, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider
|
||||
, ObjectProvider<List<SqlSessionFactoryBeanCustomizer>> sqlSessionFactoryBeanCustomizers) {
|
||||
super(properties, interceptorsProvider, typeHandlersProvider, languageDriversProvider, resourceLoader, databaseIdProvider, configurationCustomizersProvider, sqlSessionFactoryBeanCustomizers);
|
||||
|
||||
initDataSources(properties.getDatasource());
|
||||
}
|
||||
|
||||
|
||||
private void initDataSources(Map<String, Map<String, String>> datasourceMap) {
|
||||
if (datasourceMap != null) {
|
||||
datasourceMap.forEach((s, dsp) -> {
|
||||
DataSource dataSource = new DataSourceBuilder(dsp).build();
|
||||
SqlSessionFactory sqlSessionFactory = buildSqlSessionFactory(s, dataSource);
|
||||
sqlSessionFactories.add(sqlSessionFactory);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public SqlSessionFactory buildSqlSessionFactory(String environmentId, DataSource dataSource) {
|
||||
// SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
|
||||
SqlSessionFactoryBean factory = new FlexSqlSessionFactoryBean();
|
||||
|
||||
dataSource = new RoutingDataSource(environmentId, dataSource);
|
||||
dataSources.add(dataSource);
|
||||
|
||||
factory.setDataSource(new RoutingDataSource(environmentId, dataSource));
|
||||
// factory.setEnvironment(environmentId);
|
||||
|
||||
if (properties.getConfiguration() == null || properties.getConfiguration().getVfsImpl() == null) {
|
||||
factory.setVfs(SpringBootVFS.class);
|
||||
}
|
||||
if (StringUtils.hasText(this.properties.getConfigLocation())) {
|
||||
factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
|
||||
}
|
||||
applyConfiguration(factory);
|
||||
if (this.properties.getConfigurationProperties() != null) {
|
||||
factory.setConfigurationProperties(this.properties.getConfigurationProperties());
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(this.interceptors)) {
|
||||
factory.setPlugins(this.interceptors);
|
||||
}
|
||||
if (this.databaseIdProvider != null) {
|
||||
factory.setDatabaseIdProvider(this.databaseIdProvider);
|
||||
}
|
||||
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
|
||||
factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
|
||||
}
|
||||
if (this.properties.getTypeAliasesSuperType() != null) {
|
||||
factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
|
||||
}
|
||||
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
|
||||
factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
|
||||
}
|
||||
if (!ObjectUtils.isEmpty(this.typeHandlers)) {
|
||||
factory.setTypeHandlers(this.typeHandlers);
|
||||
}
|
||||
Resource[] mapperLocations = this.properties.resolveMapperLocations();
|
||||
if (!ObjectUtils.isEmpty(mapperLocations)) {
|
||||
factory.setMapperLocations(mapperLocations);
|
||||
}
|
||||
Set<String> factoryPropertyNames = Stream
|
||||
.of(new BeanWrapperImpl(SqlSessionFactoryBean.class).getPropertyDescriptors()).map(PropertyDescriptor::getName)
|
||||
.collect(Collectors.toSet());
|
||||
Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
|
||||
if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
|
||||
// Need to mybatis-spring 2.0.2+
|
||||
factory.setScriptingLanguageDrivers(this.languageDrivers);
|
||||
if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
|
||||
defaultLanguageDriver = this.languageDrivers[0].getClass();
|
||||
}
|
||||
}
|
||||
if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
|
||||
// Need to mybatis-spring 2.0.2+
|
||||
factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
|
||||
}
|
||||
applySqlSessionFactoryBeanCustomizers(factory);
|
||||
try {
|
||||
return factory.getObject();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SqlSessionFactory sqlSessionFactory() {
|
||||
return sqlSessionFactories.isEmpty() ? null : sqlSessionFactories.get(0);
|
||||
public MultiDataSourceAutoConfiguration(MybatisFlexProperties properties) {
|
||||
dataSourceProperties = properties.getDatasource();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DataSource dataSource() {
|
||||
return dataSources.isEmpty() ? null : dataSources.get(0);
|
||||
|
||||
RoutingDataSource routingDataSource = null;
|
||||
|
||||
if (dataSourceProperties != null && !dataSourceProperties.isEmpty()) {
|
||||
for (String key : dataSourceProperties.keySet()) {
|
||||
DataSource dataSource = new DataSourceBuilder(dataSourceProperties.get(key)).build();
|
||||
if (routingDataSource == null) {
|
||||
routingDataSource = new RoutingDataSource(key, dataSource);
|
||||
} else {
|
||||
routingDataSource.addDataSource(key, dataSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return routingDataSource;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -40,7 +40,6 @@ import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@ -81,7 +80,6 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
@org.springframework.context.annotation.Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
|
||||
@ConditionalOnProperty("spring.datasource.url")
|
||||
@ConditionalOnSingleCandidate(DataSource.class)
|
||||
@EnableConfigurationProperties(MybatisFlexProperties.class)
|
||||
@AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
package com.mybatisflex.spring;
|
||||
|
||||
import com.mybatisflex.core.FlexConsts;
|
||||
import com.mybatisflex.core.datasource.RoutingDataSource;
|
||||
import com.mybatisflex.core.mybatis.FlexConfiguration;
|
||||
import com.mybatisflex.core.mybatis.FlexSqlSessionFactoryBuilder;
|
||||
import com.mybatisflex.core.mybatis.FlexXMLConfigBuilder;
|
||||
@ -583,8 +582,7 @@ public class FlexSqlSessionFactoryBean extends SqlSessionFactoryBean
|
||||
}
|
||||
|
||||
targetConfiguration.setEnvironment(new Environment(this.environment,
|
||||
this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory,
|
||||
dataSource instanceof RoutingDataSource ? dataSource : new RoutingDataSource(environment, this.dataSource)));
|
||||
this.transactionFactory == null ? new SpringManagedTransactionFactory() : this.transactionFactory, dataSource));
|
||||
|
||||
if (this.mapperLocations != null) {
|
||||
if (this.mapperLocations.length == 0) {
|
||||
|
||||
@ -44,8 +44,12 @@ public class EntityTestStarter {
|
||||
// System.out.println(account);
|
||||
|
||||
AccountMapper accountMapper = bootstrap.getMapper(AccountMapper.class);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
Account account = accountMapper.selectOneById(1);
|
||||
System.out.println(account);
|
||||
}
|
||||
|
||||
// System.out.println(account);
|
||||
//
|
||||
// List<Account> allAccount = bootstrap.execute(AccountMapper.class, accountMapper ->
|
||||
// accountMapper.selectListByQuery(QueryWrapper.create()));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user