featL 完善druid3兼容,完善javadoc
This commit is contained in:
parent
f5541d2b4e
commit
68a090fc99
41
README.md
41
README.md
@ -76,7 +76,9 @@ dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成
|
|||||||
1. 引入dynamic-datasource-spring-boot-starter。
|
1. 引入dynamic-datasource-spring-boot-starter。
|
||||||
|
|
||||||
spring-boot 1.5.x 2.x.x
|
spring-boot 1.5.x 2.x.x
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||||
@ -85,7 +87,9 @@ spring-boot 1.5.x 2.x.x
|
|||||||
```
|
```
|
||||||
|
|
||||||
spring-boot3及以上
|
spring-boot3及以上
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||||
@ -123,15 +127,33 @@ spring:
|
|||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# 多主多从 纯粹多库(记得设置primary) 混合配置
|
# 多主多从 纯粹多库(记得设置primary) 混合配置
|
||||||
spring: spring: spring:
|
spring:
|
||||||
datasource: datasource: datasource:
|
spring:
|
||||||
dynamic: dynamic: dynamic:
|
spring:
|
||||||
datasource: datasource: datasource:
|
datasource:
|
||||||
master_1: mysql: master:
|
datasource:
|
||||||
master_2: oracle: slave_1:
|
datasource:
|
||||||
slave_1: sqlserver: slave_2:
|
dynamic:
|
||||||
slave_2: postgresql: oracle_1:
|
dynamic:
|
||||||
slave_3: h2: oracle_2:
|
dynamic:
|
||||||
|
datasource:
|
||||||
|
datasource:
|
||||||
|
datasource:
|
||||||
|
master_1:
|
||||||
|
mysql:
|
||||||
|
master:
|
||||||
|
master_2:
|
||||||
|
oracle:
|
||||||
|
slave_1:
|
||||||
|
slave_1:
|
||||||
|
sqlserver:
|
||||||
|
slave_2:
|
||||||
|
slave_2:
|
||||||
|
postgresql:
|
||||||
|
oracle_1:
|
||||||
|
slave_3:
|
||||||
|
h2:
|
||||||
|
oracle_2:
|
||||||
```
|
```
|
||||||
|
|
||||||
3. 使用 **@DS** 切换数据源。
|
3. 使用 **@DS** 切换数据源。
|
||||||
@ -144,6 +166,7 @@ spring: spring: spri
|
|||||||
| @DS("dsName") | dsName可以为组名也可以为具体某个库的名称 |
|
| @DS("dsName") | dsName可以为组名也可以为具体某个库的名称 |
|
||||||
|
|
||||||
```java
|
```java
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@DS("slave")
|
@DS("slave")
|
||||||
public class UserServiceImpl implements UserService {
|
public class UserServiceImpl implements UserService {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource</artifactId>
|
<artifactId>dynamic-datasource</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dynamic-datasource-creator</artifactId>
|
<artifactId>dynamic-datasource-creator</artifactId>
|
||||||
|
@ -15,15 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.creator.atomikos;
|
package com.baomidou.dynamic.datasource.creator.atomikos;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Atomikos 配置
|
* Atomikos 配置
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
||||||
* @date 2023/03/02 10:20
|
|
||||||
*/
|
*/
|
||||||
@Data
|
@Getter
|
||||||
|
@Setter
|
||||||
public class AtomikosConfig {
|
public class AtomikosConfig {
|
||||||
/**
|
/**
|
||||||
* 设置最小池大小。连接的数量不会低于该值。池将在初始化期间打开此数量的连接。可选,默认为 1
|
* 设置最小池大小。连接的数量不会低于该值。池将在初始化期间打开此数量的连接。可选,默认为 1
|
||||||
|
@ -32,7 +32,6 @@ import java.util.Properties;
|
|||||||
* Atomikos数据源配置
|
* Atomikos数据源配置
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
||||||
* @date 2023/03/02 10:20
|
|
||||||
*/
|
*/
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.creator.beecp;
|
package com.baomidou.dynamic.datasource.creator.beecp;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -25,7 +26,8 @@ import java.util.Properties;
|
|||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
* @since 3.3.4
|
* @since 3.3.4
|
||||||
*/
|
*/
|
||||||
@Data
|
@Getter
|
||||||
|
@Setter
|
||||||
public class BeeCpConfig {
|
public class BeeCpConfig {
|
||||||
|
|
||||||
private String defaultCatalog;
|
private String defaultCatalog;
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.creator.dbcp;
|
package com.baomidou.dynamic.datasource.creator.dbcp;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -25,7 +26,8 @@ import java.util.Set;
|
|||||||
*
|
*
|
||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
*/
|
*/
|
||||||
@Data
|
@Getter
|
||||||
|
@Setter
|
||||||
public class Dbcp2Config {
|
public class Dbcp2Config {
|
||||||
|
|
||||||
private Boolean defaultAutoCommit;
|
private Boolean defaultAutoCommit;
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.creator.druid;
|
package com.baomidou.dynamic.datasource.creator.druid;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -26,8 +26,8 @@ import java.util.*;
|
|||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
@Data
|
@Getter
|
||||||
@Slf4j
|
@Setter
|
||||||
public class DruidConfig {
|
public class DruidConfig {
|
||||||
|
|
||||||
private Integer initialSize;
|
private Integer initialSize;
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.creator.druid;
|
package com.baomidou.dynamic.datasource.creator.druid;
|
||||||
|
|
||||||
|
import com.alibaba.druid.pool.DruidDataSource;
|
||||||
import com.baomidou.dynamic.datasource.toolkit.DsConfigUtil;
|
import com.baomidou.dynamic.datasource.toolkit.DsConfigUtil;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -35,7 +36,15 @@ import java.util.Set;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public final class DruidConfigUtil {
|
public final class DruidConfigUtil {
|
||||||
|
|
||||||
private static final Map<String, Method> METHODS = DsConfigUtil.getGetterMethods(DruidConfig.class);
|
private static final String FILTERS = "druid.filters";
|
||||||
|
|
||||||
|
private static final String CONFIG_STR = "config";
|
||||||
|
private static final String STAT_STR = "stat";
|
||||||
|
|
||||||
|
private static final Map<String, PropertyDescriptor> CONFIG_DESCRIPTOR_MAP = DsConfigUtil.getPropertyDescriptorMap(DruidConfig.class);
|
||||||
|
private static final Map<String, PropertyDescriptor> DATASOURCE_DESCRIPTOR_MAP = DsConfigUtil.getPropertyDescriptorMap(DruidDataSource.class);
|
||||||
|
|
||||||
|
private static final Class<?> CLAZZ = DruidDataSource.class;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据全局配置和本地配置结合转换为Properties
|
* 根据全局配置和本地配置结合转换为Properties
|
||||||
@ -44,16 +53,17 @@ public final class DruidConfigUtil {
|
|||||||
* @param c 当前配置
|
* @param c 当前配置
|
||||||
* @return Druid配置
|
* @return Druid配置
|
||||||
*/
|
*/
|
||||||
@SneakyThrows
|
|
||||||
public static Properties mergeConfig(DruidConfig g, @NonNull DruidConfig c) {
|
public static Properties mergeConfig(DruidConfig g, @NonNull DruidConfig c) {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
for (Map.Entry<String, Method> entry : METHODS.entrySet()) {
|
for (Map.Entry<String, PropertyDescriptor> entry : CONFIG_DESCRIPTOR_MAP.entrySet()) {
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
Method readMethod = entry.getValue();
|
PropertyDescriptor descriptor = entry.getValue();
|
||||||
|
Method readMethod = descriptor.getReadMethod();
|
||||||
Class<?> returnType = readMethod.getReturnType();
|
Class<?> returnType = readMethod.getReturnType();
|
||||||
if (List.class.isAssignableFrom(returnType) || Set.class.isAssignableFrom(returnType) || Map.class.isAssignableFrom(returnType) || Properties.class.isAssignableFrom(returnType)) {
|
if (List.class.isAssignableFrom(returnType) || Set.class.isAssignableFrom(returnType) || Map.class.isAssignableFrom(returnType) || Properties.class.isAssignableFrom(returnType)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
Object cValue = readMethod.invoke(c);
|
Object cValue = readMethod.invoke(c);
|
||||||
if (cValue != null) {
|
if (cValue != null) {
|
||||||
properties.setProperty("druid." + key, String.valueOf(cValue));
|
properties.setProperty("druid." + key, String.valueOf(cValue));
|
||||||
@ -65,19 +75,22 @@ public final class DruidConfigUtil {
|
|||||||
properties.setProperty("druid." + key, String.valueOf(gValue));
|
properties.setProperty("druid." + key, String.valueOf(gValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("druid current could not set [" + key + " ]", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//filters单独处理,默认了stat
|
//filters单独处理,默认了stat
|
||||||
String filters = getValue(g, c, "filter");
|
String filters = getValue(g, c, "filter");
|
||||||
if (filters == null) {
|
if (filters == null) {
|
||||||
filters = DruidConsts.STAT_STR;
|
filters = STAT_STR;
|
||||||
}
|
}
|
||||||
String publicKey = getValue(g, c, "publicKey");
|
String publicKey = getValue(g, c, "publicKey");
|
||||||
boolean configFilterExist = publicKey != null && publicKey.length() > 0;
|
boolean configFilterExist = publicKey != null && publicKey.length() > 0;
|
||||||
if (publicKey != null && publicKey.length() > 0 && !filters.contains(DruidConsts.CONFIG_STR)) {
|
if (publicKey != null && publicKey.length() > 0 && !filters.contains(CONFIG_STR)) {
|
||||||
filters += "," + DruidConsts.CONFIG_STR;
|
filters += "," + CONFIG_STR;
|
||||||
}
|
}
|
||||||
properties.setProperty(DruidConsts.FILTERS, filters);
|
properties.setProperty(FILTERS, filters);
|
||||||
|
|
||||||
Properties connectProperties = new Properties();
|
Properties connectProperties = new Properties();
|
||||||
Properties cConnectionProperties = c.getConnectionProperties();
|
Properties cConnectionProperties = c.getConnectionProperties();
|
||||||
@ -98,8 +111,18 @@ public final class DruidConfigUtil {
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param g 全局配置
|
||||||
|
* @param c 当前配置
|
||||||
|
* @param field 字段
|
||||||
|
* @return 字段值
|
||||||
|
*/
|
||||||
public static String getValue(DruidConfig g, @NonNull DruidConfig c, String field) {
|
public static String getValue(DruidConfig g, @NonNull DruidConfig c, String field) {
|
||||||
Method method = METHODS.get(field);
|
PropertyDescriptor propertyDescriptor = CONFIG_DESCRIPTOR_MAP.get(field);
|
||||||
|
if (propertyDescriptor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Method method = propertyDescriptor.getReadMethod();
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -120,4 +143,41 @@ public final class DruidConfigUtil {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置DruidDataSource的值
|
||||||
|
*
|
||||||
|
* @param dataSource DruidDataSource
|
||||||
|
* @param field 字段
|
||||||
|
* @param g 全局配置
|
||||||
|
* @param c 当前配置
|
||||||
|
*/
|
||||||
|
public static void setValue(DruidDataSource dataSource, String field, DruidConfig g, DruidConfig c) {
|
||||||
|
PropertyDescriptor descriptor = DATASOURCE_DESCRIPTOR_MAP.get(field);
|
||||||
|
if (descriptor == null) {
|
||||||
|
log.warn("druid current not support [" + field + " ]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Method writeMethod = descriptor.getWriteMethod();
|
||||||
|
if (writeMethod == null) {
|
||||||
|
log.warn("druid current could not set [" + field + " ]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Method configReadMethod = CONFIG_DESCRIPTOR_MAP.get(field).getReadMethod();
|
||||||
|
Object value = configReadMethod.invoke(c);
|
||||||
|
if (value != null) {
|
||||||
|
writeMethod.invoke(dataSource, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (g != null) {
|
||||||
|
value = configReadMethod.invoke(g);
|
||||||
|
if (value != null) {
|
||||||
|
writeMethod.invoke(dataSource, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("druid current set [" + field + " ] error");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,63 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2018 organization baomidou
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.baomidou.dynamic.datasource.creator.druid;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Druid 配置属性
|
|
||||||
*
|
|
||||||
* @author TaoYu
|
|
||||||
* @since 2020/1/27
|
|
||||||
*/
|
|
||||||
public interface DruidConsts {
|
|
||||||
|
|
||||||
String INITIAL_SIZE = "druid.initialSize";
|
|
||||||
String MAX_ACTIVE = "druid.maxActive";
|
|
||||||
String MIN_IDLE = "druid.minIdle";
|
|
||||||
String MAX_WAIT = "druid.maxWait";
|
|
||||||
|
|
||||||
String TIME_BETWEEN_EVICTION_RUNS_MILLIS = "druid.timeBetweenEvictionRunsMillis";
|
|
||||||
String TIME_BETWEEN_LOG_STATS_MILLIS = "druid.timeBetweenLogStatsMillis";
|
|
||||||
String MIN_EVICTABLE_IDLE_TIME_MILLIS = "druid.minEvictableIdleTimeMillis";
|
|
||||||
String MAX_EVICTABLE_IDLE_TIME_MILLIS = "druid.maxEvictableIdleTimeMillis";
|
|
||||||
String KEEPALIVE_BETWEEN_TIME_MILLIS = "druid.keepAliveBetweenTimeMillis";
|
|
||||||
|
|
||||||
String TEST_WHILE_IDLE = "druid.testWhileIdle";
|
|
||||||
String TEST_ON_BORROW = "druid.testOnBorrow";
|
|
||||||
String VALIDATION_QUERY = "druid.validationQuery";
|
|
||||||
String USE_GLOBAL_DATA_SOURCE_STAT = "druid.useGlobalDataSourceStat";
|
|
||||||
String ASYNC_INIT = "druid.asyncInit";
|
|
||||||
|
|
||||||
String FILTERS = "druid.filters";
|
|
||||||
String CLEAR_FILTERS_ENABLE = "druid.clearFiltersEnable";
|
|
||||||
String RESET_STAT_ENABLE = "druid.resetStatEnable";
|
|
||||||
String NOT_FULL_TIMEOUT_RETRY_COUNT = "druid.notFullTimeoutRetryCount";
|
|
||||||
String MAX_WAIT_THREAD_COUNT = "druid.maxWaitThreadCount";
|
|
||||||
|
|
||||||
String FAIL_FAST = "druid.failFast";
|
|
||||||
String PHY_TIMEOUT_MILLIS = "druid.phyTimeoutMillis";
|
|
||||||
String PHY_MAX_USE_COUNT = "druid.phyMaxUseCount";
|
|
||||||
String KEEP_ALIVE = "druid.keepAlive";
|
|
||||||
String POOL_PREPARED_STATEMENTS = "druid.poolPreparedStatements";
|
|
||||||
String INIT_VARIANTS = "druid.initVariants";
|
|
||||||
String INIT_GLOBAL_VARIANTS = "druid.initGlobalVariants";
|
|
||||||
String USE_UNFAIR_LOCK = "druid.useUnfairLock";
|
|
||||||
String KILL_WHEN_SOCKET_READ_TIMEOUT = "druid.killWhenSocketReadTimeout";
|
|
||||||
String MAX_POOL_PREPARED_STATEMENT_PER_CONNECTION_SIZE = "druid.maxPoolPreparedStatementPerConnectionSize";
|
|
||||||
String INIT_CONNECTION_SQLS = "druid.initConnectionSqls";
|
|
||||||
|
|
||||||
String CONFIG_STR = "config";
|
|
||||||
String STAT_STR = "stat";
|
|
||||||
}
|
|
@ -35,10 +35,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Druid数据源创建器
|
* Druid数据源创建器
|
||||||
@ -51,12 +48,33 @@ import java.util.Properties;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class DruidDataSourceCreator implements DataSourceCreator {
|
public class DruidDataSourceCreator implements DataSourceCreator {
|
||||||
|
|
||||||
|
private static final Set<String> PARAMS = new HashSet<>();
|
||||||
private static Method configMethod = null;
|
private static Method configMethod = null;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
fetchMethod();
|
fetchMethod();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARAMS.add("defaultCatalog");
|
||||||
|
PARAMS.add("defaultAutoCommit");
|
||||||
|
PARAMS.add("defaultReadOnly");
|
||||||
|
PARAMS.add("defaultTransactionIsolation");
|
||||||
|
PARAMS.add("testOnReturn");
|
||||||
|
PARAMS.add("validationQueryTimeout");
|
||||||
|
PARAMS.add("sharePreparedStatements");
|
||||||
|
PARAMS.add("connectionErrorRetryAttempts");
|
||||||
|
PARAMS.add("breakAfterAcquireFailure");
|
||||||
|
PARAMS.add("removeAbandonedTimeoutMillis");
|
||||||
|
PARAMS.add("removeAbandoned");
|
||||||
|
PARAMS.add("logAbandoned");
|
||||||
|
PARAMS.add("queryTimeout");
|
||||||
|
PARAMS.add("transactionQueryTimeout");
|
||||||
|
PARAMS.add("timeBetweenConnectErrorMillis");
|
||||||
|
PARAMS.add("connectTimeout");
|
||||||
|
PARAMS.add("socketTimeout");
|
||||||
|
}
|
||||||
|
|
||||||
// @Autowired(required = false)
|
// @Autowired(required = false)
|
||||||
// private ApplicationContext applicationContext;
|
// private ApplicationContext applicationContext;
|
||||||
private DruidConfig gConfig;
|
private DruidConfig gConfig;
|
||||||
@ -105,7 +123,9 @@ public class DruidDataSourceCreator implements DataSourceCreator {
|
|||||||
//连接参数单独设置
|
//连接参数单独设置
|
||||||
dataSource.setConnectProperties(config.getConnectionProperties());
|
dataSource.setConnectProperties(config.getConnectionProperties());
|
||||||
//设置druid内置properties不支持的的参数
|
//设置druid内置properties不支持的的参数
|
||||||
this.setParam(dataSource, config);
|
for (String param : PARAMS) {
|
||||||
|
DruidConfigUtil.setValue(dataSource, param, gConfig, config);
|
||||||
|
}
|
||||||
|
|
||||||
if (Boolean.FALSE.equals(dataSourceProperty.getLazy())) {
|
if (Boolean.FALSE.equals(dataSourceProperty.getLazy())) {
|
||||||
try {
|
try {
|
||||||
@ -157,106 +177,6 @@ public class DruidDataSourceCreator implements DataSourceCreator {
|
|||||||
return proxyFilters;
|
return proxyFilters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setParam(DruidDataSource dataSource, DruidConfig config) {
|
|
||||||
String defaultCatalog = config.getDefaultCatalog() == null ? gConfig.getDefaultCatalog() : config.getDefaultCatalog();
|
|
||||||
if (defaultCatalog != null) {
|
|
||||||
dataSource.setDefaultCatalog(defaultCatalog);
|
|
||||||
}
|
|
||||||
Boolean defaultAutoCommit = config.getDefaultAutoCommit() == null ? gConfig.getDefaultAutoCommit() : config.getDefaultAutoCommit();
|
|
||||||
if (defaultAutoCommit != null && !defaultAutoCommit) {
|
|
||||||
dataSource.setDefaultAutoCommit(false);
|
|
||||||
}
|
|
||||||
Boolean defaultReadOnly = config.getDefaultReadOnly() == null ? gConfig.getDefaultReadOnly() : config.getDefaultReadOnly();
|
|
||||||
if (defaultReadOnly != null) {
|
|
||||||
dataSource.setDefaultReadOnly(defaultReadOnly);
|
|
||||||
}
|
|
||||||
Integer defaultTransactionIsolation = config.getDefaultTransactionIsolation() == null ? gConfig.getDefaultTransactionIsolation() : config.getDefaultTransactionIsolation();
|
|
||||||
if (defaultTransactionIsolation != null) {
|
|
||||||
dataSource.setDefaultTransactionIsolation(defaultTransactionIsolation);
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean testOnReturn = config.getTestOnReturn() == null ? gConfig.getTestOnReturn() : config.getTestOnReturn();
|
|
||||||
if (testOnReturn != null && testOnReturn) {
|
|
||||||
dataSource.setTestOnReturn(true);
|
|
||||||
}
|
|
||||||
Integer validationQueryTimeout =
|
|
||||||
config.getValidationQueryTimeout() == null ? gConfig.getValidationQueryTimeout() : config.getValidationQueryTimeout();
|
|
||||||
if (validationQueryTimeout != null && !validationQueryTimeout.equals(-1)) {
|
|
||||||
dataSource.setValidationQueryTimeout(validationQueryTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean sharePreparedStatements =
|
|
||||||
config.getSharePreparedStatements() == null ? gConfig.getSharePreparedStatements() : config.getSharePreparedStatements();
|
|
||||||
if (sharePreparedStatements != null && sharePreparedStatements) {
|
|
||||||
dataSource.setSharePreparedStatements(true);
|
|
||||||
}
|
|
||||||
Integer connectionErrorRetryAttempts =
|
|
||||||
config.getConnectionErrorRetryAttempts() == null ? gConfig.getConnectionErrorRetryAttempts()
|
|
||||||
: config.getConnectionErrorRetryAttempts();
|
|
||||||
if (connectionErrorRetryAttempts != null && !connectionErrorRetryAttempts.equals(1)) {
|
|
||||||
dataSource.setConnectionErrorRetryAttempts(connectionErrorRetryAttempts);
|
|
||||||
}
|
|
||||||
Boolean breakAfterAcquireFailure =
|
|
||||||
config.getBreakAfterAcquireFailure() == null ? gConfig.getBreakAfterAcquireFailure() : config.getBreakAfterAcquireFailure();
|
|
||||||
if (breakAfterAcquireFailure != null && breakAfterAcquireFailure) {
|
|
||||||
dataSource.setBreakAfterAcquireFailure(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer timeout = config.getRemoveAbandonedTimeoutMillis() == null ? gConfig.getRemoveAbandonedTimeoutMillis()
|
|
||||||
: config.getRemoveAbandonedTimeoutMillis();
|
|
||||||
if (timeout != null) {
|
|
||||||
dataSource.setRemoveAbandonedTimeoutMillis(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean abandoned = config.getRemoveAbandoned() == null ? gConfig.getRemoveAbandoned() : config.getRemoveAbandoned();
|
|
||||||
if (abandoned != null) {
|
|
||||||
dataSource.setRemoveAbandoned(abandoned);
|
|
||||||
}
|
|
||||||
|
|
||||||
Boolean logAbandoned = config.getLogAbandoned() == null ? gConfig.getLogAbandoned() : config.getLogAbandoned();
|
|
||||||
if (logAbandoned != null) {
|
|
||||||
dataSource.setLogAbandoned(logAbandoned);
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer queryTimeOut = config.getQueryTimeout() == null ? gConfig.getQueryTimeout() : config.getQueryTimeout();
|
|
||||||
if (queryTimeOut != null) {
|
|
||||||
dataSource.setQueryTimeout(queryTimeOut);
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer transactionQueryTimeout =
|
|
||||||
config.getTransactionQueryTimeout() == null ? gConfig.getTransactionQueryTimeout() : config.getTransactionQueryTimeout();
|
|
||||||
if (transactionQueryTimeout != null) {
|
|
||||||
dataSource.setTransactionQueryTimeout(transactionQueryTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
Long timeBetweenConnectErrorMillis =
|
|
||||||
config.getTimeBetweenConnectErrorMillis() == null ? gConfig.getTimeBetweenConnectErrorMillis() : config.getTimeBetweenConnectErrorMillis();
|
|
||||||
if (timeBetweenConnectErrorMillis != null) {
|
|
||||||
dataSource.setTimeBetweenConnectErrorMillis(timeBetweenConnectErrorMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
// since druid 1.2.12
|
|
||||||
Integer connectTimeout = config.getConnectTimeout() == null ? gConfig.getConnectTimeout() : config.getConnectTimeout();
|
|
||||||
if (connectTimeout != null) {
|
|
||||||
try {
|
|
||||||
DruidDataSource.class.getMethod("setConnectTimeout", int.class);
|
|
||||||
dataSource.setConnectTimeout(connectTimeout);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
log.warn("druid current not support connectTimeout,please update druid 1.2.12 +");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Integer socketTimeout = config.getSocketTimeout() == null ? gConfig.getSocketTimeout() : config.getSocketTimeout();
|
|
||||||
if (socketTimeout != null) {
|
|
||||||
try {
|
|
||||||
DruidDataSource.class.getMethod("setSocketTimeout", int.class);
|
|
||||||
dataSource.setSocketTimeout(socketTimeout);
|
|
||||||
} catch (NoSuchMethodException e) {
|
|
||||||
log.warn("druid current not support setSocketTimeout,please update druid 1.2.12 +");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean support(DataSourceProperty dataSourceProperty) {
|
public boolean support(DataSourceProperty dataSourceProperty) {
|
||||||
Class<? extends DataSource> type = dataSourceProperty.getType();
|
Class<? extends DataSource> type = dataSourceProperty.getType();
|
||||||
|
@ -36,14 +36,15 @@ public final class DruidLogConfigUtil {
|
|||||||
/**
|
/**
|
||||||
* 根据当前的配置和全局的配置生成druid的日志filter
|
* 根据当前的配置和全局的配置生成druid的日志filter
|
||||||
*
|
*
|
||||||
|
* @param clazz 日志类
|
||||||
* @param c 当前配置
|
* @param c 当前配置
|
||||||
* @param g 全局配置
|
* @param g 全局配置
|
||||||
* @return 日志filter
|
* @return 日志filter
|
||||||
*/
|
*/
|
||||||
public static LogFilter initFilter(Class<? extends LogFilter> clazz, Map<String, Object> c, Map<String, Object> g) {
|
public static LogFilter initFilter(Class<? extends LogFilter> clazz, Map<String, Object> c, Map<String, Object> g) {
|
||||||
try {
|
try {
|
||||||
LogFilter filter = clazz.newInstance();
|
LogFilter filter = clazz.getDeclaredConstructor().newInstance();
|
||||||
Map<String, Object> params = DsConfigUtil.mergeConfig(c, g);
|
Map<String, Object> params = DsConfigUtil.mergeMap(c, g);
|
||||||
for (Map.Entry<String, Object> item : params.entrySet()) {
|
for (Map.Entry<String, Object> item : params.entrySet()) {
|
||||||
String key = DsConfigUtil.lineToUpper(item.getKey());
|
String key = DsConfigUtil.lineToUpper(item.getKey());
|
||||||
Method method = METHODS.get(key);
|
Method method = METHODS.get(key);
|
||||||
|
@ -49,7 +49,7 @@ public final class DruidStatConfigUtil {
|
|||||||
*/
|
*/
|
||||||
public static StatFilter toStatFilter(Map<String, Object> c, Map<String, Object> g) {
|
public static StatFilter toStatFilter(Map<String, Object> c, Map<String, Object> g) {
|
||||||
StatFilter filter = new StatFilter();
|
StatFilter filter = new StatFilter();
|
||||||
Map<String, Object> map = DsConfigUtil.mergeConfig(c, g);
|
Map<String, Object> map = DsConfigUtil.mergeMap(c, g);
|
||||||
for (Map.Entry<String, Object> item : map.entrySet()) {
|
for (Map.Entry<String, Object> item : map.entrySet()) {
|
||||||
String key = DsConfigUtil.lineToUpper(item.getKey());
|
String key = DsConfigUtil.lineToUpper(item.getKey());
|
||||||
Method method = METHODS.get(key);
|
Method method = METHODS.get(key);
|
||||||
|
@ -42,7 +42,7 @@ public final class DruidWallConfigUtil {
|
|||||||
*/
|
*/
|
||||||
public static WallConfig toWallConfig(Map<String, Object> c, Map<String, Object> g) {
|
public static WallConfig toWallConfig(Map<String, Object> c, Map<String, Object> g) {
|
||||||
WallConfig wallConfig = new WallConfig();
|
WallConfig wallConfig = new WallConfig();
|
||||||
Map<String, Object> map = DsConfigUtil.mergeConfig(c, g);
|
Map<String, Object> map = DsConfigUtil.mergeMap(c, g);
|
||||||
Object dir = map.get("dir");
|
Object dir = map.get("dir");
|
||||||
if (dir != null) {
|
if (dir != null) {
|
||||||
wallConfig.loadConfig(String.valueOf(dir));
|
wallConfig.loadConfig(String.valueOf(dir));
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.creator.hikaricp;
|
package com.baomidou.dynamic.datasource.creator.hikaricp;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -26,8 +26,8 @@ import java.util.Properties;
|
|||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
* @since 2.4.1
|
* @since 2.4.1
|
||||||
*/
|
*/
|
||||||
@Data
|
@Getter
|
||||||
@Slf4j
|
@Setter
|
||||||
public class HikariCpConfig {
|
public class HikariCpConfig {
|
||||||
|
|
||||||
private String catalog;
|
private String catalog;
|
||||||
@ -63,10 +63,20 @@ public class HikariCpConfig {
|
|||||||
private Long keepaliveTime;
|
private Long keepaliveTime;
|
||||||
private Boolean sealed;
|
private Boolean sealed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 最大连接数 maxPoolSize
|
||||||
|
*
|
||||||
|
* @param maximumPoolSize 最大链接数
|
||||||
|
*/
|
||||||
public void setMaximumPoolSize(Integer maximumPoolSize) {
|
public void setMaximumPoolSize(Integer maximumPoolSize) {
|
||||||
this.maxPoolSize = maximumPoolSize;
|
this.maxPoolSize = maximumPoolSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置 最小空闲连接数 minIdle
|
||||||
|
*
|
||||||
|
* @param minimumIdle 最小空闲连接数
|
||||||
|
*/
|
||||||
public void setMinimumIdle(Integer minimumIdle) {
|
public void setMinimumIdle(Integer minimumIdle) {
|
||||||
this.minIdle = minimumIdle;
|
this.minIdle = minimumIdle;
|
||||||
}
|
}
|
||||||
|
@ -21,21 +21,46 @@ import lombok.Getter;
|
|||||||
* 目前支持的XA数据源
|
* 目前支持的XA数据源
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
||||||
* @date 2023/03/02 23:05
|
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
public enum XADataSourceEnum {
|
public enum XADataSourceEnum {
|
||||||
|
/**
|
||||||
|
* mysql
|
||||||
|
*/
|
||||||
MYSQL("com.mysql.cj.jdbc.MysqlXADataSource"),
|
MYSQL("com.mysql.cj.jdbc.MysqlXADataSource"),
|
||||||
|
/**
|
||||||
|
* oracle
|
||||||
|
*/
|
||||||
ORACLE("oracle.jdbc.xa.client.OracleXADataSource"),
|
ORACLE("oracle.jdbc.xa.client.OracleXADataSource"),
|
||||||
|
/**
|
||||||
|
* postgresql
|
||||||
|
*/
|
||||||
POSTGRE_SQL("org.postgresql.xa.PGXADataSource"),
|
POSTGRE_SQL("org.postgresql.xa.PGXADataSource"),
|
||||||
|
/**
|
||||||
|
* h2
|
||||||
|
*/
|
||||||
H2("org.h2.jdbcx.JdbcDataSource");
|
H2("org.h2.jdbcx.JdbcDataSource");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xa数据源类名
|
||||||
|
*/
|
||||||
private final String xaDriverClassName;
|
private final String xaDriverClassName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法
|
||||||
|
*
|
||||||
|
* @param xaDriverClassName
|
||||||
|
*/
|
||||||
XADataSourceEnum(String xaDriverClassName) {
|
XADataSourceEnum(String xaDriverClassName) {
|
||||||
this.xaDriverClassName = xaDriverClassName;
|
this.xaDriverClassName = xaDriverClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否包含
|
||||||
|
*
|
||||||
|
* @param xaDataSourceClassName xa数据源类名
|
||||||
|
* @return boolean 包含
|
||||||
|
*/
|
||||||
public static boolean contains(String xaDataSourceClassName) {
|
public static boolean contains(String xaDataSourceClassName) {
|
||||||
for (XADataSourceEnum item : values()) {
|
for (XADataSourceEnum item : values()) {
|
||||||
if (item.getXaDriverClassName().equals(xaDataSourceClassName)) {
|
if (item.getXaDriverClassName().equals(xaDataSourceClassName)) {
|
||||||
|
@ -23,10 +23,21 @@ package com.baomidou.dynamic.datasource.exception;
|
|||||||
*/
|
*/
|
||||||
public class ErrorCreateDataSourceException extends RuntimeException {
|
public class ErrorCreateDataSourceException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for ErrorCreateDataSourceException.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
public ErrorCreateDataSourceException(String message) {
|
public ErrorCreateDataSourceException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for ErrorCreateDataSourceException.
|
||||||
|
*
|
||||||
|
* @param message message
|
||||||
|
* @param cause cause
|
||||||
|
*/
|
||||||
public ErrorCreateDataSourceException(String message, Throwable cause) {
|
public ErrorCreateDataSourceException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2018 organization baomidou
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.baomidou.dynamic.datasource.toolkit;
|
package com.baomidou.dynamic.datasource.toolkit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +49,7 @@ public class ConfigMergeCreator<C, T> {
|
|||||||
if (configClazz.equals(targetClazz) && global == null) {
|
if (configClazz.equals(targetClazz) && global == null) {
|
||||||
return (T) item;
|
return (T) item;
|
||||||
}
|
}
|
||||||
T result = targetClazz.newInstance();
|
T result = targetClazz.getDeclaredConstructor().newInstance();
|
||||||
BeanInfo beanInfo = Introspector.getBeanInfo(configClazz, Object.class);
|
BeanInfo beanInfo = Introspector.getBeanInfo(configClazz, Object.class);
|
||||||
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
||||||
for (PropertyDescriptor pd : propertyDescriptors) {
|
for (PropertyDescriptor pd : propertyDescriptors) {
|
||||||
@ -108,7 +108,7 @@ public class ConfigMergeCreator<C, T> {
|
|||||||
} catch (ReflectiveOperationException e1) {
|
} catch (ReflectiveOperationException e1) {
|
||||||
log.warn("dynamic-datasource set {} [{}] failed,please check your config or update {} to the latest version", configName, name, configName);
|
log.warn("dynamic-datasource set {} [{}] failed,please check your config or update {} to the latest version", configName, name, configName);
|
||||||
} finally {
|
} finally {
|
||||||
if (field != null && field.isAccessible()) {
|
if (field != null) {
|
||||||
field.setAccessible(false);
|
field.setAccessible(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,3 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2018 organization baomidou
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.baomidou.dynamic.datasource.toolkit;
|
package com.baomidou.dynamic.datasource.toolkit;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
@ -52,15 +37,36 @@ public class CryptoUtils {
|
|||||||
public static final String DEFAULT_PUBLIC_KEY_STRING = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ4o6sn4WoPmbs7DR9mGQzuuUQM9erQTVPpwxIzB0ETYkyKffO097qXVRLA6KPmaV+/siWewR7vpfYYjWajw5KkCAwEAAQ==";
|
public static final String DEFAULT_PUBLIC_KEY_STRING = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ4o6sn4WoPmbs7DR9mGQzuuUQM9erQTVPpwxIzB0ETYkyKffO097qXVRLA6KPmaV+/siWewR7vpfYYjWajw5KkCAwEAAQ==";
|
||||||
private static final String DEFAULT_PRIVATE_KEY_STRING = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAnijqyfhag+ZuzsNH2YZDO65RAz16tBNU+nDEjMHQRNiTIp987T3updVEsDoo+ZpX7+yJZ7BHu+l9hiNZqPDkqQIDAQABAkBgErbczRIewWFaE+GXTymUHUV01Gmu7XdXUhzy6+CZkIcEnyTpUgPilGUydiIyeiY8usvWKGjFWxLoKeJDY1wBAiEA5M9uqc9XpL5uitLWHiiq7pRxhnJb/B+wZyHqLVhCLekCIQCw9D/Fsx7vHRgymWYExHvCka7w5SyWUmNzQOOKjZUIwQIhAMqbo7JaF5GZzui+qTsrZ7C7YYtb2Hf414t7TJG6hV+BAiBXuZ7r+fL6A+h9HUNQVcAtI2AhGNxT4aBgAOlNRQd/gQIgCGqaZsOdnL9624SI1DwhBt4x24q3350pWwzgfl4Kbbo=";
|
private static final String DEFAULT_PRIVATE_KEY_STRING = "MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAnijqyfhag+ZuzsNH2YZDO65RAz16tBNU+nDEjMHQRNiTIp987T3updVEsDoo+ZpX7+yJZ7BHu+l9hiNZqPDkqQIDAQABAkBgErbczRIewWFaE+GXTymUHUV01Gmu7XdXUhzy6+CZkIcEnyTpUgPilGUydiIyeiY8usvWKGjFWxLoKeJDY1wBAiEA5M9uqc9XpL5uitLWHiiq7pRxhnJb/B+wZyHqLVhCLekCIQCw9D/Fsx7vHRgymWYExHvCka7w5SyWUmNzQOOKjZUIwQIhAMqbo7JaF5GZzui+qTsrZ7C7YYtb2Hf414t7TJG6hV+BAiBXuZ7r+fL6A+h9HUNQVcAtI2AhGNxT4aBgAOlNRQd/gQIgCGqaZsOdnL9624SI1DwhBt4x24q3350pWwzgfl4Kbbo=";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param cipherText 需要加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
* @throws Exception 加密过程中的异常信息
|
||||||
|
*/
|
||||||
public static String decrypt(String cipherText) throws Exception {
|
public static String decrypt(String cipherText) throws Exception {
|
||||||
return decrypt((String) null, cipherText);
|
return decrypt((String) null, cipherText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param publicKeyText 公钥
|
||||||
|
* @param cipherText 需要加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
* @throws Exception 加密过程中的异常信息
|
||||||
|
*/
|
||||||
public static String decrypt(String publicKeyText, String cipherText) throws Exception {
|
public static String decrypt(String publicKeyText, String cipherText) throws Exception {
|
||||||
PublicKey publicKey = getPublicKey(publicKeyText);
|
PublicKey publicKey = getPublicKey(publicKeyText);
|
||||||
return decrypt(publicKey, cipherText);
|
return decrypt(publicKey, cipherText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param x509File 公钥文件
|
||||||
|
* @return 加密后的字符串
|
||||||
|
*/
|
||||||
public static PublicKey getPublicKeyByX509(String x509File) {
|
public static PublicKey getPublicKeyByX509(String x509File) {
|
||||||
if (x509File == null || x509File.length() == 0) {
|
if (x509File == null || x509File.length() == 0) {
|
||||||
return getPublicKey(null);
|
return getPublicKey(null);
|
||||||
@ -85,6 +91,12 @@ public class CryptoUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param publicKeyText 公钥
|
||||||
|
* @return 加密后的字符串
|
||||||
|
*/
|
||||||
public static PublicKey getPublicKey(String publicKeyText) {
|
public static PublicKey getPublicKey(String publicKeyText) {
|
||||||
if (publicKeyText == null || publicKeyText.length() == 0) {
|
if (publicKeyText == null || publicKeyText.length() == 0) {
|
||||||
publicKeyText = DEFAULT_PUBLIC_KEY_STRING;
|
publicKeyText = DEFAULT_PUBLIC_KEY_STRING;
|
||||||
@ -102,6 +114,12 @@ public class CryptoUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param publicKeyFile 公钥文件
|
||||||
|
* @return 加密后的字符串
|
||||||
|
*/
|
||||||
public static PublicKey getPublicKeyByPublicKeyFile(String publicKeyFile) {
|
public static PublicKey getPublicKeyByPublicKeyFile(String publicKeyFile) {
|
||||||
if (publicKeyFile == null || publicKeyFile.length() == 0) {
|
if (publicKeyFile == null || publicKeyFile.length() == 0) {
|
||||||
return getPublicKey(null);
|
return getPublicKey(null);
|
||||||
@ -134,6 +152,14 @@ public class CryptoUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param publicKey 公钥
|
||||||
|
* @param cipherText 需要加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
* @throws Exception 加密过程中的异常信息
|
||||||
|
*/
|
||||||
public static String decrypt(PublicKey publicKey, String cipherText) throws Exception {
|
public static String decrypt(PublicKey publicKey, String cipherText) throws Exception {
|
||||||
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
|
||||||
try {
|
try {
|
||||||
@ -160,10 +186,25 @@ public class CryptoUtils {
|
|||||||
return new String(plainBytes);
|
return new String(plainBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param plainText 需要加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
* @throws Exception 加密过程中的异常信息
|
||||||
|
*/
|
||||||
public static String encrypt(String plainText) throws Exception {
|
public static String encrypt(String plainText) throws Exception {
|
||||||
return encrypt((String) null, plainText);
|
return encrypt((String) null, plainText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param key 加密的密钥
|
||||||
|
* @param plainText 需要加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
* @throws Exception 加密过程中的异常信息
|
||||||
|
*/
|
||||||
public static String encrypt(String key, String plainText) throws Exception {
|
public static String encrypt(String key, String plainText) throws Exception {
|
||||||
if (key == null) {
|
if (key == null) {
|
||||||
key = DEFAULT_PRIVATE_KEY_STRING;
|
key = DEFAULT_PRIVATE_KEY_STRING;
|
||||||
@ -173,6 +214,14 @@ public class CryptoUtils {
|
|||||||
return encrypt(keyBytes, plainText);
|
return encrypt(keyBytes, plainText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加密算法RSA
|
||||||
|
*
|
||||||
|
* @param keyBytes 加密的密钥
|
||||||
|
* @param plainText 需要加密的字符串
|
||||||
|
* @return 加密后的字符串
|
||||||
|
* @throws Exception 加密过程中的异常信息
|
||||||
|
*/
|
||||||
public static String encrypt(byte[] keyBytes, String plainText) throws Exception {
|
public static String encrypt(byte[] keyBytes, String plainText) throws Exception {
|
||||||
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
|
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
|
||||||
KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");
|
KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");
|
||||||
@ -192,6 +241,12 @@ public class CryptoUtils {
|
|||||||
return Base64.byteArrayToBase64(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)));
|
return Base64.byteArrayToBase64(cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成密钥对
|
||||||
|
*
|
||||||
|
* @param keySize 密钥对长度
|
||||||
|
* @return 密钥对
|
||||||
|
*/
|
||||||
public static byte[][] genKeyPairBytes(int keySize) {
|
public static byte[][] genKeyPairBytes(int keySize) {
|
||||||
byte[][] keyPairBytes = new byte[2][];
|
byte[][] keyPairBytes = new byte[2][];
|
||||||
try {
|
try {
|
||||||
@ -208,6 +263,12 @@ public class CryptoUtils {
|
|||||||
return keyPairBytes;
|
return keyPairBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成密钥对
|
||||||
|
*
|
||||||
|
* @param keySize 密钥对长度
|
||||||
|
* @return Base64编码后的密钥对
|
||||||
|
*/
|
||||||
public static String[] genKeyPair(int keySize) {
|
public static String[] genKeyPair(int keySize) {
|
||||||
byte[][] keyPairBytes = genKeyPairBytes(keySize);
|
byte[][] keyPairBytes = genKeyPairBytes(keySize);
|
||||||
String[] keyPairs = new String[2];
|
String[] keyPairs = new String[2];
|
||||||
|
@ -56,7 +56,7 @@ public final class DsConfigUtil {
|
|||||||
* @param g 全局配置
|
* @param g 全局配置
|
||||||
* @return 合并配置
|
* @return 合并配置
|
||||||
*/
|
*/
|
||||||
public static Map<String, Object> mergeConfig(Map<String, Object> c, Map<String, Object> g) {
|
public static Map<String, Object> mergeMap(Map<String, Object> c, Map<String, Object> g) {
|
||||||
int size = 1 + (int) ((c.size() + g.size()) / 0.75);
|
int size = 1 + (int) ((c.size() + g.size()) / 0.75);
|
||||||
Map<String, Object> map = new HashMap<>(size);
|
Map<String, Object> map = new HashMap<>(size);
|
||||||
map.putAll(g);
|
map.putAll(g);
|
||||||
@ -64,6 +64,19 @@ public final class DsConfigUtil {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<String, PropertyDescriptor> getPropertyDescriptorMap(Class<?> clazz) {
|
||||||
|
Map<String, PropertyDescriptor> methodMap = new HashMap<>();
|
||||||
|
try {
|
||||||
|
for (PropertyDescriptor pd : Introspector.getBeanInfo(clazz).getPropertyDescriptors()) {
|
||||||
|
if (!"class".equals(pd.getName())) {
|
||||||
|
methodMap.put(pd.getName(), pd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
}
|
||||||
|
return methodMap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过clazz获取对应的setter方法
|
* 通过clazz获取对应的setter方法
|
||||||
*
|
*
|
||||||
@ -109,7 +122,7 @@ public final class DsConfigUtil {
|
|||||||
*
|
*
|
||||||
* @param method 方法
|
* @param method 方法
|
||||||
* @param value 值
|
* @param value 值
|
||||||
* @return
|
* @return 对应值
|
||||||
*/
|
*/
|
||||||
public static Object convertValue(Method method, Object value) {
|
public static Object convertValue(Method method, Object value) {
|
||||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||||
@ -120,19 +133,19 @@ public final class DsConfigUtil {
|
|||||||
return propertyValue;
|
return propertyValue;
|
||||||
}
|
}
|
||||||
if (parameterType == Integer.class || parameterType == int.class) {
|
if (parameterType == Integer.class || parameterType == int.class) {
|
||||||
return Integer.valueOf(propertyValue).intValue();
|
return Integer.valueOf(propertyValue);
|
||||||
}
|
}
|
||||||
if (parameterType == Long.class || parameterType == long.class) {
|
if (parameterType == Long.class || parameterType == long.class) {
|
||||||
return Long.valueOf(propertyValue).longValue();
|
return Long.valueOf(propertyValue);
|
||||||
}
|
}
|
||||||
if (parameterType == Boolean.class || parameterType == boolean.class) {
|
if (parameterType == Boolean.class || parameterType == boolean.class) {
|
||||||
return Boolean.valueOf(propertyValue).booleanValue();
|
return Boolean.valueOf(propertyValue);
|
||||||
}
|
}
|
||||||
if (parameterType == Double.class || parameterType == double.class) {
|
if (parameterType == Double.class || parameterType == double.class) {
|
||||||
return Double.valueOf(propertyValue).doubleValue();
|
return Double.valueOf(propertyValue);
|
||||||
}
|
}
|
||||||
if (parameterType == Float.class || parameterType == float.class) {
|
if (parameterType == Float.class || parameterType == float.class) {
|
||||||
return Float.valueOf(propertyValue).floatValue();
|
return Float.valueOf(propertyValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
|
@ -15,16 +15,39 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.toolkit;
|
package com.baomidou.dynamic.datasource.toolkit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 常见字符串工具类
|
||||||
|
*
|
||||||
|
* @author TaoYu
|
||||||
|
*/
|
||||||
public abstract class DsStrUtils {
|
public abstract class DsStrUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否为空
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @return true: null or "" or " " false: "a"
|
||||||
|
*/
|
||||||
public static boolean hasLength(CharSequence str) {
|
public static boolean hasLength(CharSequence str) {
|
||||||
return (str != null && str.length() > 0);
|
return (str != null && str.length() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否为空
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @return true: null or "" or " " false: "a"
|
||||||
|
*/
|
||||||
public static boolean hasLength(String str) {
|
public static boolean hasLength(String str) {
|
||||||
return hasLength((CharSequence) str);
|
return hasLength((CharSequence) str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断字符串是否有内容
|
||||||
|
*
|
||||||
|
* @param str 字符串
|
||||||
|
* @return true: null or "" or " " false: "a"
|
||||||
|
*/
|
||||||
public static boolean hasText(CharSequence str) {
|
public static boolean hasText(CharSequence str) {
|
||||||
if (!hasLength(str)) {
|
if (!hasLength(str)) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource</artifactId>
|
<artifactId>dynamic-datasource</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
||||||
|
@ -29,6 +29,7 @@ import lombok.Getter;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.boot.context.properties.NestedConfigurationProperty;
|
||||||
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -86,26 +87,32 @@ public class DynamicDataSourceProperties {
|
|||||||
/**
|
/**
|
||||||
* Druid全局参数配置
|
* Druid全局参数配置
|
||||||
*/
|
*/
|
||||||
|
@NestedConfigurationProperty
|
||||||
private DruidConfig druid = new DruidConfig();
|
private DruidConfig druid = new DruidConfig();
|
||||||
/**
|
/**
|
||||||
* HikariCp全局参数配置
|
* HikariCp全局参数配置
|
||||||
*/
|
*/
|
||||||
|
@NestedConfigurationProperty
|
||||||
private HikariCpConfig hikari = new HikariCpConfig();
|
private HikariCpConfig hikari = new HikariCpConfig();
|
||||||
/**
|
/**
|
||||||
* BeeCp全局参数配置
|
* BeeCp全局参数配置
|
||||||
*/
|
*/
|
||||||
|
@NestedConfigurationProperty
|
||||||
private BeeCpConfig beecp = new BeeCpConfig();
|
private BeeCpConfig beecp = new BeeCpConfig();
|
||||||
/**
|
/**
|
||||||
* DBCP2全局参数配置
|
* DBCP2全局参数配置
|
||||||
*/
|
*/
|
||||||
|
@NestedConfigurationProperty
|
||||||
private Dbcp2Config dbcp2 = new Dbcp2Config();
|
private Dbcp2Config dbcp2 = new Dbcp2Config();
|
||||||
/**
|
/**
|
||||||
* atomikos全局参数配置
|
* atomikos全局参数配置
|
||||||
*/
|
*/
|
||||||
|
@NestedConfigurationProperty
|
||||||
private AtomikosConfig atomikos = new AtomikosConfig();
|
private AtomikosConfig atomikos = new AtomikosConfig();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* aop with default ds annotation
|
* aop with default ds annotation
|
||||||
*/
|
*/
|
||||||
|
@NestedConfigurationProperty
|
||||||
private DynamicDatasourceAopProperties aop = new DynamicDatasourceAopProperties();
|
private DynamicDatasourceAopProperties aop = new DynamicDatasourceAopProperties();
|
||||||
}
|
}
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource</artifactId>
|
<artifactId>dynamic-datasource</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
|
||||||
@ -19,6 +19,12 @@
|
|||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-starter</artifactId>
|
||||||
|
<version>1.2.18</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
|
||||||
|
|
||||||
|
|
||||||
|
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||||
|
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
||||||
|
import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidFilterConfiguration;
|
||||||
|
import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidSpringAopConfiguration;
|
||||||
|
import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidStatViewServletConfiguration;
|
||||||
|
import com.alibaba.druid.spring.boot.autoconfigure.stat.DruidWebStatFilterConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从原生DruidDataSourceAutoConfigure复制
|
||||||
|
*
|
||||||
|
* @author TaoYu
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(DruidDataSourceAutoConfigure.class)
|
||||||
|
@EnableConfigurationProperties({DruidStatProperties.class})
|
||||||
|
@Import({
|
||||||
|
DruidSpringAopConfiguration.class,
|
||||||
|
DruidStatViewServletConfiguration.class,
|
||||||
|
DruidWebStatFilterConfiguration.class,
|
||||||
|
DruidFilterConfiguration.class})
|
||||||
|
public class DruidDynamicDataSourceConfiguration {
|
||||||
|
|
||||||
|
}
|
@ -47,7 +47,7 @@ import java.util.List;
|
|||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
|
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
|
||||||
@AutoConfigureBefore(value = DataSourceAutoConfiguration.class, name = "com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure")
|
@AutoConfigureBefore(value = DataSourceAutoConfiguration.class, name = "com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure")
|
||||||
@Import(value = {DynamicDataSourceCreatorAutoConfiguration.class, DynamicDataSourceAopConfiguration.class, DynamicDataSourceAssistConfiguration.class})
|
@Import({DruidDynamicDataSourceConfiguration.class, DynamicDataSourceCreatorAutoConfiguration.class, DynamicDataSourceAopConfiguration.class, DynamicDataSourceAssistConfiguration.class})
|
||||||
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
public class DynamicDataSourceAutoConfiguration implements InitializingBean {
|
public class DynamicDataSourceAutoConfiguration implements InitializingBean {
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource</artifactId>
|
<artifactId>dynamic-datasource</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||||
@ -25,6 +25,12 @@
|
|||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.alibaba</groupId>
|
||||||
|
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||||
|
<version>1.2.18</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.baomidou.dynamic.datasource.spring.boot.autoconfigure;
|
||||||
|
|
||||||
|
import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure;
|
||||||
|
import com.alibaba.druid.spring.boot3.autoconfigure.properties.DruidStatProperties;
|
||||||
|
import com.alibaba.druid.spring.boot3.autoconfigure.stat.DruidFilterConfiguration;
|
||||||
|
import com.alibaba.druid.spring.boot3.autoconfigure.stat.DruidSpringAopConfiguration;
|
||||||
|
import com.alibaba.druid.spring.boot3.autoconfigure.stat.DruidStatViewServletConfiguration;
|
||||||
|
import com.alibaba.druid.spring.boot3.autoconfigure.stat.DruidWebStatFilterConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从原生DruidDataSourceAutoConfigure复制
|
||||||
|
*
|
||||||
|
* @author TaoYu
|
||||||
|
* @since 1.1.0
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@ConditionalOnClass(DruidDataSourceAutoConfigure.class)
|
||||||
|
@EnableConfigurationProperties({DruidStatProperties.class})
|
||||||
|
@Import({
|
||||||
|
DruidSpringAopConfiguration.class,
|
||||||
|
DruidStatViewServletConfiguration.class,
|
||||||
|
DruidWebStatFilterConfiguration.class,
|
||||||
|
DruidFilterConfiguration.class})
|
||||||
|
public class DruidDynamicDataSourceConfiguration {
|
||||||
|
|
||||||
|
}
|
@ -41,8 +41,13 @@ import java.util.List;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
|
@EnableConfigurationProperties(DynamicDataSourceProperties.class)
|
||||||
@AutoConfigureBefore(value = DataSourceAutoConfiguration.class, name = "com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure")
|
@AutoConfigureBefore(
|
||||||
@Import(value = {DynamicDataSourceCreatorAutoConfiguration.class, DynamicDataSourceAopConfiguration.class, DynamicDataSourceAssistConfiguration.class})
|
value = DataSourceAutoConfiguration.class,
|
||||||
|
name = {
|
||||||
|
"com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure",
|
||||||
|
"com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure"
|
||||||
|
})
|
||||||
|
@Import({DruidDynamicDataSourceConfiguration.class, DynamicDataSourceCreatorAutoConfiguration.class, DynamicDataSourceAopConfiguration.class, DynamicDataSourceAssistConfiguration.class})
|
||||||
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
|
||||||
public class DynamicDataSourceAutoConfiguration implements InitializingBean {
|
public class DynamicDataSourceAutoConfiguration implements InitializingBean {
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource</artifactId>
|
<artifactId>dynamic-datasource</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>dynamic-datasource-spring</artifactId>
|
<artifactId>dynamic-datasource-spring</artifactId>
|
||||||
<url>https://github.com/baomidou/dynamic-datasource-spring-boot-starter/tree/master/dynamic-datasource-spring</url>
|
<url>https://github.com/baomidou/dynamic-datasource-spring-boot-starter/tree/master/dynamic-datasource-spring</url>
|
||||||
|
@ -28,9 +28,25 @@ import java.lang.annotation.*;
|
|||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
public @interface DSTransactional {
|
public @interface DSTransactional {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回滚异常
|
||||||
|
*
|
||||||
|
* @return Class[]
|
||||||
|
*/
|
||||||
Class<? extends Throwable>[] rollbackFor() default {Exception.class};
|
Class<? extends Throwable>[] rollbackFor() default {Exception.class};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不回滚异常
|
||||||
|
*
|
||||||
|
* @return Class[]
|
||||||
|
*/
|
||||||
Class<? extends Throwable>[] noRollbackFor() default {};
|
Class<? extends Throwable>[] noRollbackFor() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务传播行为
|
||||||
|
*
|
||||||
|
* @return DsPropagation
|
||||||
|
*/
|
||||||
DsPropagation propagation() default DsPropagation.REQUIRED;
|
DsPropagation propagation() default DsPropagation.REQUIRED;
|
||||||
}
|
}
|
@ -37,17 +37,33 @@ import java.lang.reflect.Method;
|
|||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* DynamicDataSource Annotation Pointcut
|
||||||
|
*
|
||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
* @since 1.2.0
|
* @since 1.2.0
|
||||||
*/
|
*/
|
||||||
public class DynamicDataSourceAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
|
public class DynamicDataSourceAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the advice
|
||||||
|
*/
|
||||||
private final Advice advice;
|
private final Advice advice;
|
||||||
|
/**
|
||||||
|
* the pointcut
|
||||||
|
*/
|
||||||
private final Pointcut pointcut;
|
private final Pointcut pointcut;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the annotation
|
||||||
|
*/
|
||||||
private final Class<? extends Annotation> annotation;
|
private final Class<? extends Annotation> annotation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法
|
||||||
|
*
|
||||||
|
* @param advice 切面
|
||||||
|
* @param annotation 注解
|
||||||
|
*/
|
||||||
public DynamicDataSourceAnnotationAdvisor(@NonNull MethodInterceptor advice,
|
public DynamicDataSourceAnnotationAdvisor(@NonNull MethodInterceptor advice,
|
||||||
@NonNull Class<? extends Annotation> annotation) {
|
@NonNull Class<? extends Annotation> annotation) {
|
||||||
this.advice = advice;
|
this.advice = advice;
|
||||||
|
@ -37,6 +37,12 @@ public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor
|
|||||||
private final DataSourceClassResolver dataSourceClassResolver;
|
private final DataSourceClassResolver dataSourceClassResolver;
|
||||||
private final DsProcessor dsProcessor;
|
private final DsProcessor dsProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init
|
||||||
|
*
|
||||||
|
* @param allowedPublicOnly allowedPublicOnly
|
||||||
|
* @param dsProcessor dsProcessor
|
||||||
|
*/
|
||||||
public DynamicDataSourceAnnotationInterceptor(Boolean allowedPublicOnly, DsProcessor dsProcessor) {
|
public DynamicDataSourceAnnotationInterceptor(Boolean allowedPublicOnly, DsProcessor dsProcessor) {
|
||||||
dataSourceClassResolver = new DataSourceClassResolver(allowedPublicOnly);
|
dataSourceClassResolver = new DataSourceClassResolver(allowedPublicOnly);
|
||||||
this.dsProcessor = dsProcessor;
|
this.dsProcessor = dsProcessor;
|
||||||
@ -53,6 +59,12 @@ public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the key of the datasource
|
||||||
|
*
|
||||||
|
* @param invocation MethodInvocation
|
||||||
|
* @return dsKey
|
||||||
|
*/
|
||||||
private String determineDatasourceKey(MethodInvocation invocation) {
|
private String determineDatasourceKey(MethodInvocation invocation) {
|
||||||
String key = dataSourceClassResolver.findKey(invocation.getMethod(), invocation.getThis());
|
String key = dataSourceClassResolver.findKey(invocation.getMethod(), invocation.getThis());
|
||||||
return key.startsWith(DYNAMIC_PREFIX) ? dsProcessor.determineDatasource(invocation, key) : key;
|
return key.startsWith(DYNAMIC_PREFIX) ? dsProcessor.determineDatasource(invocation, key) : key;
|
||||||
|
@ -45,6 +45,11 @@ public class DynamicDatasourceNamedInterceptor implements MethodInterceptor {
|
|||||||
private final Map<String, String> nameMap = new HashMap<>();
|
private final Map<String, String> nameMap = new HashMap<>();
|
||||||
private final DsProcessor dsProcessor;
|
private final DsProcessor dsProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init
|
||||||
|
*
|
||||||
|
* @param dsProcessor dsProcessor
|
||||||
|
*/
|
||||||
public DynamicDatasourceNamedInterceptor(DsProcessor dsProcessor) {
|
public DynamicDatasourceNamedInterceptor(DsProcessor dsProcessor) {
|
||||||
this.dsProcessor = dsProcessor;
|
this.dsProcessor = dsProcessor;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,8 @@ import org.aopalliance.intercept.MethodInvocation;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Dynamic DataSource Transaction Interceptor
|
||||||
|
*
|
||||||
* @author funkye
|
* @author funkye
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -66,6 +66,12 @@ public class DefaultDataSourceCreator {
|
|||||||
|
|
||||||
private DataSourceInitEvent dataSourceInitEvent;
|
private DataSourceInitEvent dataSourceInitEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建数据源
|
||||||
|
*
|
||||||
|
* @param dataSourceProperty 数据源参数
|
||||||
|
* @return 数据源
|
||||||
|
*/
|
||||||
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
|
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
|
||||||
DataSourceCreator dataSourceCreator = null;
|
DataSourceCreator dataSourceCreator = null;
|
||||||
for (DataSourceCreator creator : this.creators) {
|
for (DataSourceCreator creator : this.creators) {
|
||||||
@ -96,6 +102,12 @@ public class DefaultDataSourceCreator {
|
|||||||
return wrapDataSource(dataSource, dataSourceProperty);
|
return wrapDataSource(dataSource, dataSourceProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行初始化脚本
|
||||||
|
*
|
||||||
|
* @param dataSource 数据源
|
||||||
|
* @param dataSourceProperty 数据源参数
|
||||||
|
*/
|
||||||
private void runScrip(DataSource dataSource, DataSourceProperty dataSourceProperty) {
|
private void runScrip(DataSource dataSource, DataSourceProperty dataSourceProperty) {
|
||||||
DatasourceInitProperties initProperty = dataSourceProperty.getInit();
|
DatasourceInitProperties initProperty = dataSourceProperty.getInit();
|
||||||
String schema = initProperty.getSchema();
|
String schema = initProperty.getSchema();
|
||||||
@ -111,6 +123,13 @@ public class DefaultDataSourceCreator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装数据源
|
||||||
|
*
|
||||||
|
* @param dataSource 数据源
|
||||||
|
* @param dataSourceProperty 数据源参数
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
private DataSource wrapDataSource(DataSource dataSource, DataSourceProperty dataSourceProperty) {
|
private DataSource wrapDataSource(DataSource dataSource, DataSourceProperty dataSourceProperty) {
|
||||||
String name = dataSourceProperty.getPoolName();
|
String name = dataSourceProperty.getPoolName();
|
||||||
DataSource targetDataSource = dataSource;
|
DataSource targetDataSource = dataSource;
|
||||||
|
@ -31,16 +31,16 @@ public class JndiDataSourceCreator implements DataSourceCreator {
|
|||||||
|
|
||||||
private static final JndiDataSourceLookup LOOKUP = new JndiDataSourceLookup();
|
private static final JndiDataSourceLookup LOOKUP = new JndiDataSourceLookup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建JNDI数据源
|
||||||
|
*
|
||||||
|
* @param jndiName jndi数据源名称
|
||||||
|
* @return 数据源
|
||||||
|
*/
|
||||||
public DataSource createDataSource(String jndiName) {
|
public DataSource createDataSource(String jndiName) {
|
||||||
return LOOKUP.getDataSource(jndiName);
|
return LOOKUP.getDataSource(jndiName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建JNDI数据源
|
|
||||||
*
|
|
||||||
* @param dataSourceProperty jndi数据源名称
|
|
||||||
* @return 数据源
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
|
public DataSource createDataSource(DataSourceProperty dataSourceProperty) {
|
||||||
return createDataSource(dataSourceProperty.getJndiName());
|
return createDataSource(dataSourceProperty.getJndiName());
|
||||||
|
@ -20,11 +20,16 @@ import java.io.PrintWriter;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for Spring's {@link javax.sql.DataSource}
|
||||||
|
*/
|
||||||
public abstract class AbstractDataSource implements DataSource {
|
public abstract class AbstractDataSource implements DataSource {
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns 0, indicating the default system timeout is to be used.
|
* Returns 0, indicating the default system timeout is to be used.
|
||||||
|
*
|
||||||
|
* @return 0
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int getLoginTimeout() throws SQLException {
|
public int getLoginTimeout() throws SQLException {
|
||||||
@ -32,7 +37,8 @@ public abstract class AbstractDataSource implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setting a login timeout is not supported.
|
* @param timeout ignored
|
||||||
|
* <p>Throws {@link UnsupportedOperationException} when called.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setLoginTimeout(int timeout) throws SQLException {
|
public void setLoginTimeout(int timeout) throws SQLException {
|
||||||
@ -41,6 +47,9 @@ public abstract class AbstractDataSource implements DataSource {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* LogWriter methods are not supported.
|
* LogWriter methods are not supported.
|
||||||
|
*
|
||||||
|
* @return not supported
|
||||||
|
* <p>Throws {@link UnsupportedOperationException} when called.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public PrintWriter getLogWriter() {
|
public PrintWriter getLogWriter() {
|
||||||
@ -49,6 +58,7 @@ public abstract class AbstractDataSource implements DataSource {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* LogWriter methods are not supported.
|
* LogWriter methods are not supported.
|
||||||
|
* <p>Throws {@link UnsupportedOperationException} when called.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setLogWriter(PrintWriter pw) throws SQLException {
|
public void setLogWriter(PrintWriter pw) throws SQLException {
|
||||||
|
@ -31,6 +31,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
@Data
|
@Data
|
||||||
public class GroupDataSource {
|
public class GroupDataSource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组名
|
||||||
|
*/
|
||||||
private String groupName;
|
private String groupName;
|
||||||
|
|
||||||
private DynamicDataSourceStrategy dynamicDataSourceStrategy;
|
private DynamicDataSourceStrategy dynamicDataSourceStrategy;
|
||||||
@ -47,6 +50,7 @@ public class GroupDataSource {
|
|||||||
*
|
*
|
||||||
* @param ds the name of the datasource
|
* @param ds the name of the datasource
|
||||||
* @param dataSource datasource
|
* @param dataSource datasource
|
||||||
|
* @return the previous value associated with ds, or null if there was no mapping for ds.
|
||||||
*/
|
*/
|
||||||
public DataSource addDatasource(String ds, DataSource dataSource) {
|
public DataSource addDatasource(String ds, DataSource dataSource) {
|
||||||
return dataSourceMap.put(ds, dataSource);
|
return dataSourceMap.put(ds, dataSource);
|
||||||
@ -59,14 +63,29 @@ public class GroupDataSource {
|
|||||||
return dataSourceMap.remove(ds);
|
return dataSourceMap.remove(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determineDsKey
|
||||||
|
*
|
||||||
|
* @return the name of the datasource
|
||||||
|
*/
|
||||||
public String determineDsKey() {
|
public String determineDsKey() {
|
||||||
return dynamicDataSourceStrategy.determineKey(new ArrayList<>(dataSourceMap.keySet()));
|
return dynamicDataSourceStrategy.determineKey(new ArrayList<>(dataSourceMap.keySet()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determineDataSource
|
||||||
|
*
|
||||||
|
* @return the datasource
|
||||||
|
*/
|
||||||
public DataSource determineDataSource() {
|
public DataSource determineDataSource() {
|
||||||
return dataSourceMap.get(determineDsKey());
|
return dataSourceMap.get(determineDsKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* size of this group
|
||||||
|
*
|
||||||
|
* @return the size of this group
|
||||||
|
*/
|
||||||
public int size() {
|
public int size() {
|
||||||
return dataSourceMap.size();
|
return dataSourceMap.size();
|
||||||
}
|
}
|
||||||
|
@ -23,10 +23,21 @@ package com.baomidou.dynamic.datasource.exception;
|
|||||||
*/
|
*/
|
||||||
public class CannotFindDataSourceException extends RuntimeException {
|
public class CannotFindDataSourceException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法
|
||||||
|
*
|
||||||
|
* @param message 异常信息
|
||||||
|
*/
|
||||||
public CannotFindDataSourceException(String message) {
|
public CannotFindDataSourceException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造方法
|
||||||
|
*
|
||||||
|
* @param message 异常信息
|
||||||
|
* @param cause 异常
|
||||||
|
*/
|
||||||
public CannotFindDataSourceException(String message, Throwable cause) {
|
public CannotFindDataSourceException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,27 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.exception;
|
package com.baomidou.dynamic.datasource.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务异常
|
||||||
|
*
|
||||||
|
* @author Hzh
|
||||||
|
*/
|
||||||
public class TransactionException extends RuntimeException {
|
public class TransactionException extends RuntimeException {
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param message 消息
|
||||||
|
*/
|
||||||
public TransactionException(String message) {
|
public TransactionException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造
|
||||||
|
*
|
||||||
|
* @param message 消息
|
||||||
|
* @param cause 异常
|
||||||
|
*/
|
||||||
public TransactionException(String message, Throwable cause) {
|
public TransactionException(String message, Throwable cause) {
|
||||||
super(message, cause);
|
super(message, cause);
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,7 @@ import org.apache.ibatis.mapping.SqlCommandType;
|
|||||||
import org.apache.ibatis.plugin.*;
|
import org.apache.ibatis.plugin.*;
|
||||||
import org.apache.ibatis.session.ResultHandler;
|
import org.apache.ibatis.session.ResultHandler;
|
||||||
import org.apache.ibatis.session.RowBounds;
|
import org.apache.ibatis.session.RowBounds;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,9 +42,6 @@ import java.util.Properties;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class MasterSlaveAutoRoutingPlugin implements Interceptor {
|
public class MasterSlaveAutoRoutingPlugin implements Interceptor {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
protected DataSource dynamicDataSource;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object intercept(Invocation invocation) throws Throwable {
|
public Object intercept(Invocation invocation) throws Throwable {
|
||||||
Object[] args = invocation.getArgs();
|
Object[] args = invocation.getArgs();
|
||||||
|
@ -18,13 +18,23 @@ package com.baomidou.dynamic.datasource.processor;
|
|||||||
import org.aopalliance.intercept.MethodInvocation;
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 数据源处理器
|
||||||
|
*
|
||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
* @since 2.5.0
|
* @since 2.5.0
|
||||||
*/
|
*/
|
||||||
public abstract class DsProcessor {
|
public abstract class DsProcessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下一个执行器
|
||||||
|
*/
|
||||||
private DsProcessor nextProcessor;
|
private DsProcessor nextProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置下一个执行器
|
||||||
|
*
|
||||||
|
* @param dsProcessor 执行器
|
||||||
|
*/
|
||||||
public void setNextProcessor(DsProcessor dsProcessor) {
|
public void setNextProcessor(DsProcessor dsProcessor) {
|
||||||
this.nextProcessor = dsProcessor;
|
this.nextProcessor = dsProcessor;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,8 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* SpEL表达式处理器
|
||||||
|
*
|
||||||
* @author TaoYu
|
* @author TaoYu
|
||||||
* @since 2.5.0
|
* @since 2.5.0
|
||||||
*/
|
*/
|
||||||
@ -84,10 +86,20 @@ public class DsSpelExpressionProcessor extends DsProcessor {
|
|||||||
return value == null ? null : value.toString();
|
return value == null ? null : value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置解析上下文
|
||||||
|
*
|
||||||
|
* @param parserContext 解析上下文
|
||||||
|
*/
|
||||||
public void setParserContext(ParserContext parserContext) {
|
public void setParserContext(ParserContext parserContext) {
|
||||||
this.parserContext = parserContext;
|
this.parserContext = parserContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置bean解析器
|
||||||
|
*
|
||||||
|
* @param beanResolver bean解析器
|
||||||
|
*/
|
||||||
public void setBeanResolver(BeanResolver beanResolver) {
|
public void setBeanResolver(BeanResolver beanResolver) {
|
||||||
this.beanResolver = beanResolver;
|
this.beanResolver = beanResolver;
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,12 @@ public abstract class AbstractDataSourceProvider implements DynamicDataSourcePro
|
|||||||
|
|
||||||
private final DefaultDataSourceCreator defaultDataSourceCreator;
|
private final DefaultDataSourceCreator defaultDataSourceCreator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建数据源
|
||||||
|
*
|
||||||
|
* @param dataSourcePropertiesMap 数据源参数Map
|
||||||
|
* @return 数据源Map
|
||||||
|
*/
|
||||||
protected Map<String, DataSource> createDataSourceMap(
|
protected Map<String, DataSource> createDataSourceMap(
|
||||||
Map<String, DataSourceProperty> dataSourcePropertiesMap) {
|
Map<String, DataSourceProperty> dataSourcePropertiesMap) {
|
||||||
Map<String, DataSource> dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size() * 2);
|
Map<String, DataSource> dataSourceMap = new HashMap<>(dataSourcePropertiesMap.size() * 2);
|
||||||
|
@ -53,10 +53,27 @@ public abstract class AbstractJdbcDataSourceProvider extends AbstractDataSourceP
|
|||||||
*/
|
*/
|
||||||
private final String password;
|
private final String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过默认数据源创建器创建数据源
|
||||||
|
*
|
||||||
|
* @param defaultDataSourceCreator 默认数据源创建器
|
||||||
|
* @param url 数据源url
|
||||||
|
* @param username 用户名
|
||||||
|
* @param password 密码
|
||||||
|
*/
|
||||||
public AbstractJdbcDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, String url, String username, String password) {
|
public AbstractJdbcDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, String url, String username, String password) {
|
||||||
this(defaultDataSourceCreator, null, url, username, password);
|
this(defaultDataSourceCreator, null, url, username, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过默认数据源创建器创建数据源
|
||||||
|
*
|
||||||
|
* @param defaultDataSourceCreator 默认数据源创建器
|
||||||
|
* @param driverClassName 驱动类名
|
||||||
|
* @param url 数据源url
|
||||||
|
* @param username 用户名
|
||||||
|
* @param password 密码
|
||||||
|
*/
|
||||||
public AbstractJdbcDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, String driverClassName, String url, String username, String password) {
|
public AbstractJdbcDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, String driverClassName, String url, String username, String password) {
|
||||||
super(defaultDataSourceCreator);
|
super(defaultDataSourceCreator);
|
||||||
this.driverClassName = driverClassName;
|
this.driverClassName = driverClassName;
|
||||||
@ -65,6 +82,11 @@ public abstract class AbstractJdbcDataSourceProvider extends AbstractDataSourceP
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭资源
|
||||||
|
*
|
||||||
|
* @param con 资源
|
||||||
|
*/
|
||||||
private static void closeResource(AutoCloseable con) {
|
private static void closeResource(AutoCloseable con) {
|
||||||
if (con != null) {
|
if (con != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -36,6 +36,12 @@ public class YmlDynamicDataSourceProvider extends AbstractDataSourceProvider {
|
|||||||
*/
|
*/
|
||||||
private final Map<String, DataSourceProperty> dataSourcePropertiesMap;
|
private final Map<String, DataSourceProperty> dataSourcePropertiesMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数
|
||||||
|
*
|
||||||
|
* @param defaultDataSourceCreator 默认数据源创建器
|
||||||
|
* @param dataSourcePropertiesMap 数据源参数
|
||||||
|
*/
|
||||||
public YmlDynamicDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, Map<String, DataSourceProperty> dataSourcePropertiesMap) {
|
public YmlDynamicDataSourceProvider(DefaultDataSourceCreator defaultDataSourceCreator, Map<String, DataSourceProperty> dataSourcePropertiesMap) {
|
||||||
super(defaultDataSourceCreator);
|
super(defaultDataSourceCreator);
|
||||||
this.dataSourcePropertiesMap = dataSourcePropertiesMap;
|
this.dataSourcePropertiesMap = dataSourcePropertiesMap;
|
||||||
|
@ -63,6 +63,7 @@ public final class DynamicDataSourceContextHolder {
|
|||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param ds 数据源名称
|
* @param ds 数据源名称
|
||||||
|
* @return 数据源名称
|
||||||
*/
|
*/
|
||||||
public static String push(String ds) {
|
public static String push(String ds) {
|
||||||
String dataSourceStr = StringUtils.isEmpty(ds) ? "" : ds;
|
String dataSourceStr = StringUtils.isEmpty(ds) ? "" : ds;
|
||||||
|
@ -27,7 +27,6 @@ import javax.sql.DataSource;
|
|||||||
* Atomikos事务适配-多数据源切换
|
* Atomikos事务适配-多数据源切换
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
* @author <a href="mailto:312290710@qq.com">jiazhifeng</a>
|
||||||
* @date 2023/03/02 10:20
|
|
||||||
*/
|
*/
|
||||||
public class AtomikosTransactionFactory extends SpringManagedTransactionFactory {
|
public class AtomikosTransactionFactory extends SpringManagedTransactionFactory {
|
||||||
|
|
||||||
|
@ -31,7 +31,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
* @author funkye zp
|
* @author funkye zp
|
||||||
*/
|
*/
|
||||||
public class ConnectionFactory {
|
public class ConnectionFactory {
|
||||||
|
/**
|
||||||
|
* connection holder
|
||||||
|
*/
|
||||||
private static final ThreadLocal<Map<String, Map<String, ConnectionProxy>>> CONNECTION_HOLDER =
|
private static final ThreadLocal<Map<String, Map<String, ConnectionProxy>>> CONNECTION_HOLDER =
|
||||||
new ThreadLocal<Map<String, Map<String, ConnectionProxy>>>() {
|
new ThreadLocal<Map<String, Map<String, ConnectionProxy>>>() {
|
||||||
@Override
|
@Override
|
||||||
@ -39,6 +41,9 @@ public class ConnectionFactory {
|
|||||||
return new ConcurrentHashMap<>();
|
return new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* savepoint connection holder
|
||||||
|
*/
|
||||||
private static final ThreadLocal<Map<String, List<SavePointHolder>>> SAVEPOINT_CONNECTION_HOLDER =
|
private static final ThreadLocal<Map<String, List<SavePointHolder>>> SAVEPOINT_CONNECTION_HOLDER =
|
||||||
new ThreadLocal<Map<String, List<SavePointHolder>>>() {
|
new ThreadLocal<Map<String, List<SavePointHolder>>>() {
|
||||||
@Override
|
@Override
|
||||||
@ -47,6 +52,13 @@ public class ConnectionFactory {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* put connection
|
||||||
|
*
|
||||||
|
* @param xid xid
|
||||||
|
* @param ds ds
|
||||||
|
* @param connection connection
|
||||||
|
*/
|
||||||
public static void putConnection(String xid, String ds, ConnectionProxy connection) {
|
public static void putConnection(String xid, String ds, ConnectionProxy connection) {
|
||||||
Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
|
Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
|
||||||
Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
|
Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
|
||||||
@ -64,6 +76,13 @@ public class ConnectionFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getConnection
|
||||||
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
|
* @param ds ds
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
public static ConnectionProxy getConnection(String xid, String ds) {
|
public static ConnectionProxy getConnection(String xid, String ds) {
|
||||||
Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
|
Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
|
||||||
Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
|
Map<String, ConnectionProxy> connectionProxyMap = concurrentHashMap.get(xid);
|
||||||
@ -73,6 +92,13 @@ public class ConnectionFactory {
|
|||||||
return connectionProxyMap.get(ds);
|
return connectionProxyMap.get(ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether there is a savepoint
|
||||||
|
*
|
||||||
|
* @param xid xid
|
||||||
|
* @param state state
|
||||||
|
* @throws Exception Exception
|
||||||
|
*/
|
||||||
public static void notify(String xid, Boolean state) throws Exception {
|
public static void notify(String xid, Boolean state) throws Exception {
|
||||||
Exception exception = null;
|
Exception exception = null;
|
||||||
Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
|
Map<String, Map<String, ConnectionProxy>> concurrentHashMap = CONNECTION_HOLDER.get();
|
||||||
@ -143,6 +169,12 @@ public class ConnectionFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether there is a savepoint
|
||||||
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
|
* @throws TransactionException TransactionException
|
||||||
|
*/
|
||||||
public static void createSavepoint(String xid) throws TransactionException {
|
public static void createSavepoint(String xid) throws TransactionException {
|
||||||
try {
|
try {
|
||||||
Map<String, List<SavePointHolder>> savePointMap = SAVEPOINT_CONNECTION_HOLDER.get();
|
Map<String, List<SavePointHolder>> savePointMap = SAVEPOINT_CONNECTION_HOLDER.get();
|
||||||
@ -180,6 +212,12 @@ public class ConnectionFactory {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether there is a savepoint
|
||||||
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
public static boolean hasSavepoint(String xid) {
|
public static boolean hasSavepoint(String xid) {
|
||||||
Map<String, List<SavePointHolder>> savePointMap = SAVEPOINT_CONNECTION_HOLDER.get();
|
Map<String, List<SavePointHolder>> savePointMap = SAVEPOINT_CONNECTION_HOLDER.get();
|
||||||
return !CollectionUtils.isEmpty(savePointMap.get(xid));
|
return !CollectionUtils.isEmpty(savePointMap.get(xid));
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.tx;
|
package com.baomidou.dynamic.datasource.tx;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
@ -27,6 +29,8 @@ import java.util.concurrent.Executor;
|
|||||||
* @author funkye
|
* @author funkye
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class ConnectionProxy implements Connection {
|
public class ConnectionProxy implements Connection {
|
||||||
|
|
||||||
private Connection connection;
|
private Connection connection;
|
||||||
@ -35,11 +39,23 @@ public class ConnectionProxy implements Connection {
|
|||||||
|
|
||||||
private int savepointCounter = 0;
|
private int savepointCounter = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* init
|
||||||
|
*
|
||||||
|
* @param connection 数据源链接
|
||||||
|
* @param ds 数据源名称
|
||||||
|
*/
|
||||||
public ConnectionProxy(Connection connection, String ds) {
|
public ConnectionProxy(Connection connection, String ds) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.ds = ds;
|
this.ds = ds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知事务管理器提交或回滚
|
||||||
|
*
|
||||||
|
* @param commit 是否提交
|
||||||
|
* @throws SQLException SQLException
|
||||||
|
*/
|
||||||
public void notify(Boolean commit) throws SQLException {
|
public void notify(Boolean commit) throws SQLException {
|
||||||
try {
|
try {
|
||||||
if (commit) {
|
if (commit) {
|
||||||
@ -349,28 +365,4 @@ public class ConnectionProxy implements Connection {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(connection, ds);
|
return Objects.hash(connection, ds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Connection getConnection() {
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setConnection(Connection connection) {
|
|
||||||
this.connection = connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDs() {
|
|
||||||
return ds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDs(String ds) {
|
|
||||||
this.ds = ds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSavepointCounter() {
|
|
||||||
return savepointCounter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSavepointCounter(int savepointCounter) {
|
|
||||||
this.savepointCounter = savepointCounter;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -18,18 +18,32 @@ package com.baomidou.dynamic.datasource.tx;
|
|||||||
|
|
||||||
|
|
||||||
public enum DsPropagation {
|
public enum DsPropagation {
|
||||||
//支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
|
/**
|
||||||
|
* 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
|
||||||
|
*/
|
||||||
REQUIRED,
|
REQUIRED,
|
||||||
//新建事务,如果当前存在事务,把当前事务挂起。
|
/**
|
||||||
|
* 新建事务,如果当前存在事务,把当前事务挂起。
|
||||||
|
*/
|
||||||
REQUIRES_NEW,
|
REQUIRES_NEW,
|
||||||
//以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
/**
|
||||||
|
* 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
|
||||||
|
*/
|
||||||
NOT_SUPPORTED,
|
NOT_SUPPORTED,
|
||||||
//支持当前事务,如果当前没有事务,就以非事务方式执行。
|
/**
|
||||||
|
* 支持当前事务,如果当前没有事务,就以非事务方式执行。
|
||||||
|
*/
|
||||||
SUPPORTS,
|
SUPPORTS,
|
||||||
//以非事务方式执行,如果当前存在事务,则抛出异常。
|
/**
|
||||||
|
* 以非事务方式执行,如果当前存在事务,则抛出异常。
|
||||||
|
*/
|
||||||
NEVER,
|
NEVER,
|
||||||
//支持当前事务,如果当前没有事务,就抛出异常。
|
/**
|
||||||
|
* 支持当前事务,如果当前没有事务,就抛出异常。
|
||||||
|
*/
|
||||||
MANDATORY,
|
MANDATORY,
|
||||||
//如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,就新建一个事务。
|
/**
|
||||||
|
* 如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,就新建一个事务。
|
||||||
|
*/
|
||||||
NESTED
|
NESTED
|
||||||
}
|
}
|
@ -21,7 +21,6 @@ import org.springframework.util.StringUtils;
|
|||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 本地事务工具类
|
* 本地事务工具类
|
||||||
*
|
*
|
||||||
@ -30,6 +29,10 @@ import java.util.UUID;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public final class LocalTxUtil {
|
public final class LocalTxUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SecureRandom instance used to generate UUIDs.
|
||||||
|
*/
|
||||||
private static final ThreadLocal<SecureRandom> SECURE_RANDOM_HOLDER = new ThreadLocal<SecureRandom>() {
|
private static final ThreadLocal<SecureRandom> SECURE_RANDOM_HOLDER = new ThreadLocal<SecureRandom>() {
|
||||||
@Override
|
@Override
|
||||||
protected SecureRandom initialValue() {
|
protected SecureRandom initialValue() {
|
||||||
@ -37,6 +40,11 @@ public final class LocalTxUtil {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机生成UUID
|
||||||
|
*
|
||||||
|
* @return UUID
|
||||||
|
*/
|
||||||
public static UUID randomUUID() {
|
public static UUID randomUUID() {
|
||||||
SecureRandom ng = SECURE_RANDOM_HOLDER.get();
|
SecureRandom ng = SECURE_RANDOM_HOLDER.get();
|
||||||
byte[] randomBytes = new byte[16];
|
byte[] randomBytes = new byte[16];
|
||||||
@ -62,6 +70,8 @@ public final class LocalTxUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动开启事务
|
* 手动开启事务
|
||||||
|
*
|
||||||
|
* @return 事务ID
|
||||||
*/
|
*/
|
||||||
public static String startTransaction() {
|
public static String startTransaction() {
|
||||||
String xid = TransactionContext.getXID();
|
String xid = TransactionContext.getXID();
|
||||||
@ -77,6 +87,8 @@ public final class LocalTxUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动提交事务
|
* 手动提交事务
|
||||||
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
*/
|
*/
|
||||||
public static void commit(String xid) throws Exception {
|
public static void commit(String xid) throws Exception {
|
||||||
boolean hasSavepoint = ConnectionFactory.hasSavepoint(xid);
|
boolean hasSavepoint = ConnectionFactory.hasSavepoint(xid);
|
||||||
@ -92,6 +104,8 @@ public final class LocalTxUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 手动回滚事务
|
* 手动回滚事务
|
||||||
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
*/
|
*/
|
||||||
public static void rollback(String xid) throws Exception {
|
public static void rollback(String xid) throws Exception {
|
||||||
boolean hasSavepoint = ConnectionFactory.hasSavepoint(xid);
|
boolean hasSavepoint = ConnectionFactory.hasSavepoint(xid);
|
||||||
|
@ -23,18 +23,39 @@ import java.util.LinkedList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Savepoint Holder
|
||||||
|
*
|
||||||
* @author zp
|
* @author zp
|
||||||
*/
|
*/
|
||||||
public class SavePointHolder {
|
public class SavePointHolder {
|
||||||
|
/**
|
||||||
|
* savepoint name prefix
|
||||||
|
*/
|
||||||
private static final String SAVEPOINT_NAME_PREFIX = "DYNAMIC_";
|
private static final String SAVEPOINT_NAME_PREFIX = "DYNAMIC_";
|
||||||
|
/**
|
||||||
|
* connection proxy
|
||||||
|
*/
|
||||||
private ConnectionProxy connectionProxy;
|
private ConnectionProxy connectionProxy;
|
||||||
|
/**
|
||||||
|
* savepoints
|
||||||
|
*/
|
||||||
private LinkedList<Savepoint> savepoints;
|
private LinkedList<Savepoint> savepoints;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*
|
||||||
|
* @param connectionProxy connection proxy
|
||||||
|
*/
|
||||||
public SavePointHolder(ConnectionProxy connectionProxy) {
|
public SavePointHolder(ConnectionProxy connectionProxy) {
|
||||||
this.connectionProxy = connectionProxy;
|
this.connectionProxy = connectionProxy;
|
||||||
this.savepoints = new LinkedList<>();
|
this.savepoints = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* conversion savepoint holder
|
||||||
|
*
|
||||||
|
* @throws SQLException SQLException
|
||||||
|
*/
|
||||||
public void conversionSavePointHolder() throws SQLException {
|
public void conversionSavePointHolder() throws SQLException {
|
||||||
if (connectionProxy == null) {
|
if (connectionProxy == null) {
|
||||||
throw new SQLTransientConnectionException();
|
throw new SQLTransientConnectionException();
|
||||||
@ -45,6 +66,12 @@ public class SavePointHolder {
|
|||||||
savepoints.addLast(savepoint);
|
savepoints.addLast(savepoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* release savepoint
|
||||||
|
*
|
||||||
|
* @return savepoint index
|
||||||
|
* @throws SQLException SQLException
|
||||||
|
*/
|
||||||
public int releaseSavepoint() throws SQLException {
|
public int releaseSavepoint() throws SQLException {
|
||||||
Savepoint savepoint = savepoints.pollLast();
|
Savepoint savepoint = savepoints.pollLast();
|
||||||
if (savepoint != null) {
|
if (savepoint != null) {
|
||||||
@ -55,6 +82,12 @@ public class SavePointHolder {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rollback savepoint
|
||||||
|
*
|
||||||
|
* @return savepoint index
|
||||||
|
* @throws SQLException SQLException
|
||||||
|
*/
|
||||||
public int rollbackSavePoint() throws SQLException {
|
public int rollbackSavePoint() throws SQLException {
|
||||||
Savepoint savepoint = savepoints.pollLast();
|
Savepoint savepoint = savepoints.pollLast();
|
||||||
if (savepoint != null) {
|
if (savepoint != null) {
|
||||||
@ -65,10 +98,20 @@ public class SavePointHolder {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get connection proxy
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public ConnectionProxy getConnectionProxy() {
|
public ConnectionProxy getConnectionProxy() {
|
||||||
return this.connectionProxy;
|
return this.connectionProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get savepoints
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public List<Savepoint> getSavePoints() {
|
public List<Savepoint> getSavePoints() {
|
||||||
return this.savepoints;
|
return this.savepoints;
|
||||||
}
|
}
|
||||||
|
@ -15,14 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.tx;
|
package com.baomidou.dynamic.datasource.tx;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
/**
|
||||||
|
* SuspendedResourcesHolder
|
||||||
|
*
|
||||||
|
* @author Hzh
|
||||||
|
*/
|
||||||
public class SuspendedResourcesHolder {
|
public class SuspendedResourcesHolder {
|
||||||
/**
|
/**
|
||||||
* The xid
|
* 事务ID
|
||||||
*/
|
*/
|
||||||
private String xid;
|
private String xid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new Suspended resources holder.
|
||||||
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
|
*/
|
||||||
public SuspendedResourcesHolder(String xid) {
|
public SuspendedResourcesHolder(String xid) {
|
||||||
if (xid == null) {
|
if (xid == null) {
|
||||||
throw new IllegalArgumentException("xid must be not null");
|
throw new IllegalArgumentException("xid must be not null");
|
||||||
@ -30,7 +38,11 @@ public class SuspendedResourcesHolder {
|
|||||||
this.xid = xid;
|
this.xid = xid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull
|
/**
|
||||||
|
* 获得事务ID.
|
||||||
|
*
|
||||||
|
* @return 事务ID
|
||||||
|
*/
|
||||||
public String getXid() {
|
public String getXid() {
|
||||||
return xid;
|
return xid;
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ public class TransactionContext {
|
|||||||
/**
|
/**
|
||||||
* Gets xid.
|
* Gets xid.
|
||||||
*
|
*
|
||||||
* @return the xid
|
* @return 事务ID
|
||||||
*/
|
*/
|
||||||
public static String getXID() {
|
public static String getXID() {
|
||||||
String xid = CONTEXT_HOLDER.get();
|
String xid = CONTEXT_HOLDER.get();
|
||||||
@ -40,6 +40,7 @@ public class TransactionContext {
|
|||||||
/**
|
/**
|
||||||
* Unbind string.
|
* Unbind string.
|
||||||
*
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
* @return the string
|
* @return the string
|
||||||
*/
|
*/
|
||||||
public static String unbind(String xid) {
|
public static String unbind(String xid) {
|
||||||
@ -48,8 +49,9 @@ public class TransactionContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bind string.
|
* bind xid.
|
||||||
*
|
*
|
||||||
|
* @param xid 事务ID
|
||||||
* @return the string
|
* @return the string
|
||||||
*/
|
*/
|
||||||
public static String bind(String xid) {
|
public static String bind(String xid) {
|
||||||
|
@ -15,10 +15,25 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.tx;
|
package com.baomidou.dynamic.datasource.tx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务执行器
|
||||||
|
*
|
||||||
|
* @author Hzh
|
||||||
|
*/
|
||||||
public interface TransactionalExecutor {
|
public interface TransactionalExecutor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
* @throws Throwable Throwable
|
||||||
|
*/
|
||||||
Object execute() throws Throwable;
|
Object execute() throws Throwable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取事务信息
|
||||||
|
*
|
||||||
|
* @return TransactionalInfo
|
||||||
|
*/
|
||||||
TransactionalInfo getTransactionInfo();
|
TransactionalInfo getTransactionInfo();
|
||||||
}
|
}
|
@ -15,35 +15,30 @@
|
|||||||
*/
|
*/
|
||||||
package com.baomidou.dynamic.datasource.tx;
|
package com.baomidou.dynamic.datasource.tx;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务基础信息
|
||||||
|
*
|
||||||
|
* @author Hzh
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
public class TransactionalInfo {
|
public class TransactionalInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回滚异常
|
||||||
|
*/
|
||||||
Class<? extends Throwable>[] rollbackFor;
|
Class<? extends Throwable>[] rollbackFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不回滚异常
|
||||||
|
*/
|
||||||
Class<? extends Throwable>[] noRollbackFor;
|
Class<? extends Throwable>[] noRollbackFor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务传播行为
|
||||||
|
*/
|
||||||
DsPropagation propagation;
|
DsPropagation propagation;
|
||||||
|
|
||||||
public Class<? extends Throwable>[] getRollbackFor() {
|
|
||||||
return rollbackFor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRollbackFor(Class<? extends Throwable>[] rollbackFor) {
|
|
||||||
this.rollbackFor = rollbackFor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Class<? extends Throwable>[] getNoRollbackFor() {
|
|
||||||
return noRollbackFor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNoRollbackFor(Class<? extends Throwable>[] noRollbackFor) {
|
|
||||||
this.noRollbackFor = noRollbackFor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DsPropagation getPropagation() {
|
|
||||||
return propagation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPropagation(DsPropagation propagation) {
|
|
||||||
this.propagation = propagation;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,9 +22,21 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务模板
|
||||||
|
*
|
||||||
|
* @author Hzh
|
||||||
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class TransactionalTemplate {
|
public class TransactionalTemplate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute with transaction.
|
||||||
|
*
|
||||||
|
* @param transactionalExecutor TransactionalExecutor
|
||||||
|
* @return Object
|
||||||
|
* @throws Throwable Throwable
|
||||||
|
*/
|
||||||
public Object execute(TransactionalExecutor transactionalExecutor) throws Throwable {
|
public Object execute(TransactionalExecutor transactionalExecutor) throws Throwable {
|
||||||
TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo();
|
TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo();
|
||||||
DsPropagation propagation = transactionInfo.propagation;
|
DsPropagation propagation = transactionInfo.propagation;
|
||||||
@ -85,6 +97,13 @@ public class TransactionalTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在事务
|
||||||
|
*
|
||||||
|
* @param transactionalExecutor TransactionalExecutor
|
||||||
|
* @return 是否存在事务
|
||||||
|
* @throws Throwable Throwable
|
||||||
|
*/
|
||||||
private Object doExecute(TransactionalExecutor transactionalExecutor) throws Throwable {
|
private Object doExecute(TransactionalExecutor transactionalExecutor) throws Throwable {
|
||||||
TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo();
|
TransactionalInfo transactionInfo = transactionalExecutor.getTransactionInfo();
|
||||||
DsPropagation propagation = transactionInfo.propagation;
|
DsPropagation propagation = transactionInfo.propagation;
|
||||||
@ -109,6 +128,13 @@ public class TransactionalTemplate {
|
|||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否回滚
|
||||||
|
*
|
||||||
|
* @param e 异常
|
||||||
|
* @param transactionInfo 事务信息
|
||||||
|
* @return 是否回滚
|
||||||
|
*/
|
||||||
private boolean isRollback(Throwable e, TransactionalInfo transactionInfo) {
|
private boolean isRollback(Throwable e, TransactionalInfo transactionInfo) {
|
||||||
boolean isRollback = true;
|
boolean isRollback = true;
|
||||||
Class<? extends Throwable>[] rollbacks = transactionInfo.rollbackFor;
|
Class<? extends Throwable>[] rollbacks = transactionInfo.rollbackFor;
|
||||||
@ -132,6 +158,13 @@ public class TransactionalTemplate {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取深度
|
||||||
|
*
|
||||||
|
* @param exceptionClass 异常类
|
||||||
|
* @param rollback 回滚类
|
||||||
|
* @return 深度
|
||||||
|
*/
|
||||||
private int getDepth(Class<?> exceptionClass, Class<? extends Throwable> rollback) {
|
private int getDepth(Class<?> exceptionClass, Class<? extends Throwable> rollback) {
|
||||||
if (rollback == Throwable.class || rollback == Exception.class) {
|
if (rollback == Throwable.class || rollback == Exception.class) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -153,6 +186,11 @@ public class TransactionalTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 挂起资源
|
||||||
|
*
|
||||||
|
* @return 挂起资源
|
||||||
|
*/
|
||||||
public SuspendedResourcesHolder suspend() {
|
public SuspendedResourcesHolder suspend() {
|
||||||
String xid = TransactionContext.getXID();
|
String xid = TransactionContext.getXID();
|
||||||
if (xid != null) {
|
if (xid != null) {
|
||||||
@ -166,6 +204,11 @@ public class TransactionalTemplate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否存在事务
|
||||||
|
*
|
||||||
|
* @return 是否存在事务
|
||||||
|
*/
|
||||||
public boolean existingTransaction() {
|
public boolean existingTransaction() {
|
||||||
return !StringUtils.isEmpty(TransactionContext.getXID());
|
return !StringUtils.isEmpty(TransactionContext.getXID());
|
||||||
}
|
}
|
||||||
|
13
pom.xml
13
pom.xml
@ -4,7 +4,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource</artifactId>
|
<artifactId>dynamic-datasource</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>${project.artifactId}</name>
|
<name>${project.artifactId}</name>
|
||||||
<description>dynamic datasource</description>
|
<description>dynamic datasource</description>
|
||||||
@ -78,17 +78,17 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-creator</artifactId>
|
<artifactId>dynamic-datasource-creator</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring</artifactId>
|
<artifactId>dynamic-datasource-spring</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.baomidou</groupId>
|
<groupId>com.baomidou</groupId>
|
||||||
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
<artifactId>dynamic-datasource-spring-boot-common</artifactId>
|
||||||
<version>4.1.1</version>
|
<version>4.1.2</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
@ -211,6 +211,11 @@
|
|||||||
<includes>
|
<includes>
|
||||||
<include>src/main/java/**</include>
|
<include>src/main/java/**</include>
|
||||||
</includes>
|
</includes>
|
||||||
|
<excludes>
|
||||||
|
<exclude>src/main/java/com/**/**/Base64.java</exclude>
|
||||||
|
<exclude>src/main/java/com/**/**/CryptoUtils.java</exclude>
|
||||||
|
<exclude>src/main/java/com/**/**/DruidDynamicDataSourceConfiguration.java</exclude>
|
||||||
|
</excludes>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user