提交 5fd3ee9c 编写于 作者: T terrymanu

init version

上级
# maven ignore
target/
*.jar
*.war
*.zip
*.tar
*.tar.gz
# eclipse ignore
.settings/
.project
.classpath
# idea ignore
.idea/
*.ipr
*.iml
*.iws
# temp ignore
logs/
*.doc
*.log
*.cache
*.diff
*.patch
*.tmp
# system ignore
.DS_Store
Thumbs.db
# 主要贡献者
* 张亮    [当当](http://www.dangdang.com/) zhangliang@dangdang.com
* 高洪涛 [当当](http://www.dangdang.com/) gaohongtao@dangdang.com
* 曹昊    [当当](http://www.dangdang.com/) caohao@dangdang.com
* 岳令    [当当](http://www.dangdang.com/) yueling@dangdang.com
**讨论QQ群:**xxx(不限于Sharding-JDBC,包括分布式,数据库相关以及其他互联网技术交流)
# 简介
`Sharding-JDBC`是当当应用框架`ddframe`中,关系型数据库模块`dd-rdb`中分离出来的数据库水平扩展框架,即透明化数据库分库分表访问。
`Sharding-JDBC`直接封装`JDBC API`,可以理解为增强版的`JDBC`驱动,旧代码迁移成本几乎为零:
* 可适用于任何基于`java``ORM`框架,如:`JPA`, `Hibernate`, `Mybatis`, `Spring JDBC Template`或直接使用`JDBC`
* 可基于任何第三方的数据库连接池,如:`DBCP`, `C3P0`, `BoneCP`, `Druid`等。
* 理论上可支持任意实现`JDBC`规范的数据库。虽然目前仅支持`MySQL`,但已有支持`Oracle``SQLServer``DB2`等数据库的计划。
`Sharding-JDBC`定位为轻量级`java`框架,使用客户端直连数据库,以`jar`包形式提供服务,未使用中间层,无需额外部署,无其他依赖,`DBA`也无需改变原有的运维方式。`SQL`解析使用`Druid`解析器,是目前性能最高的`SQL`解析器。
`Sharding-JDBC`功能灵活且全面:
* 分片策略灵活,可支持`=``BETWEEN``IN`等多维度分片,也可支持多分片键共用。
* `SQL`解析功能完善,支持聚合,分组,排序,`Limit``OR`等查询,并且支持`Binding Table`以及笛卡尔积的表查询。
***
以下是常见的分库分表产品和`Sharding-JDBC`的对比:
| 功能 | Cobar(MyCAT) | Cobar-client | TDDL | Sharding-JDBC |
| ------------- |:-------------:| -------------:| -----------:|---------------:|
| 分库 | 有 | 有 | 未开源 | 有 |
| 分表 | 无 | 无 | 未开源 | 有 |
| 中间层 | 是 | 否 | 否 | 否 |
| ORM支持 | 任意 | 仅MyBatis | 任意 | 任意 |
| 数据库支持 | 仅MySQL | 任意 | 任意 | 任意 |
| 异构语言 | 可 | 仅Java | 仅Java | 仅Java |
| 外部依赖 | 无 | 无 | Diamond | 无 |
***
# 整体架构图
![整体架构图1](../img/architecture.png)
# Quick Start
## 引入maven依赖
```xml
<!-- 引入sharding-jdbc核心模块 -->
<dependency>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>1.0.0</version>
</dependency>
```
## 规则配置
`Sharding-JDBC`的分库分表通过规则配置描述,请简单浏览配置全貌:
```java
ShardingRule shardingRule = new ShardingRule(
dataSourceRule,
Arrays.asList(tableRule),
new DatabaseShardingStrategy("sharding_column_1", new XXXShardingAlgorithm()),
new TableShardingStrategy("sharding_column_2", new XXXShardingAlgorithm()));
```
规则配置包括数据源配置、表规则配置、分库策略和分表策略组成。这只是最简单的配置方式,实际使用可更加灵活,如:多分片键,分片策略直接和`tableRule`绑定等。
>详细的规则配置请参考[用户指南](post/user_guide)
## 使用基于ShardingDataSource的JDBC接口
通过规则配置对象获取`ShardingDataSource``ShardingDataSource`实现自`JDBC`的标准接口`DataSource`。然后可通过`DataSource`选择使用原生`JDBC`开发,或者使用`JPA`, `MyBatis``ORM`工具。
`JDBC`原生实现为例:
```java
DataSource dataSource = new ShardingDataSource(shardingRule);
String sql = "SELECT i.* FROM t_order o JOIN t_order_item i ON o.order_id=i.order_id WHERE o.user_id=? AND o.order_id=?";
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, 10);
pstmt.setInt(2, 1001);
try (ResultSet rs = pstmt.executeQuery()) {
while(rs.next()) {
System.out.println(rs.getInt(1));
System.out.println(rs.getInt(2));
System.out.println(rs.getInt(3));
}
}
}
```
此差异已折叠。
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.dangdang</groupId>
<artifactId>sharding-jdbc</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>sharding-jdbc-core</artifactId>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
\ No newline at end of file
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api;
import com.dangdang.ddframe.rdb.sharding.exception.DatabaseTypeUnsupportedException;
/**
* 支持的数据库类型.
*
* @author zhangliang
*/
public enum DatabaseType {
H2, MySQL, Oracle, SQLServer, DB2;
/**
* 获取数据库类型枚举.
*
* @param databaseProductName 数据库类型
* @return 数据库类型枚举
*/
public static DatabaseType valueFrom(final String databaseProductName) {
try {
return DatabaseType.valueOf(databaseProductName);
} catch (final IllegalArgumentException ex) {
throw new DatabaseTypeUnsupportedException(databaseProductName);
}
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import com.dangdang.ddframe.rdb.sharding.api.config.ShardingConfiguration;
import com.dangdang.ddframe.rdb.sharding.api.config.ShardingConfigurationConstant;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingConnection;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractDataSourceAdapter;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import com.google.common.base.Preconditions;
/**
* 支持分片的数据源.
*
* @author zhangliang
*/
public class ShardingDataSource extends AbstractDataSourceAdapter {
private final ShardingRule shardingRule;
private final DatabaseMetaData databaseMetaData;
private final ShardingConfiguration configuration;
private final MetricsContext metricsContext;
public ShardingDataSource(final ShardingRule shardingRule) {
this(shardingRule, new Properties());
}
public ShardingDataSource(final ShardingRule shardingRule, final Properties props) {
this.shardingRule = shardingRule;
databaseMetaData = getDatabaseMetaData();
configuration = new ShardingConfiguration(props);
metricsContext = new MetricsContext(configuration.getConfig(ShardingConfigurationConstant.METRICS_ENABLE, boolean.class),
configuration.getConfig(ShardingConfigurationConstant.METRICS_SECOND_PERIOD, long.class),
configuration.getConfig(ShardingConfigurationConstant.METRICS_PACKAGE_NAME, String.class));
}
private DatabaseMetaData getDatabaseMetaData() {
String databaseProductName = null;
DatabaseMetaData result = null;
for (DataSource each : shardingRule.getDataSourceRule().getDataSources()) {
String databaseProductNameInEach;
DatabaseMetaData metaDataInEach;
try {
metaDataInEach = each.getConnection().getMetaData();
databaseProductNameInEach = metaDataInEach.getDatabaseProductName();
} catch (final SQLException ex) {
throw new ShardingJdbcException("Can not get data source DatabaseProductName", ex);
}
Preconditions.checkState(null == databaseProductName || databaseProductName.equals(databaseProductNameInEach),
String.format("Database type inconsistent with '%s' and '%s'", databaseProductName, databaseProductNameInEach));
databaseProductName = databaseProductNameInEach;
result = metaDataInEach;
}
return result;
}
@Override
public ShardingConnection getConnection() throws SQLException {
metricsContext.register();
return new ShardingConnection(shardingRule, databaseMetaData);
}
@Override
public final Connection getConnection(final String username, final String password) throws SQLException {
return getConnection();
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api;
import java.util.Collection;
import java.util.Collections;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
import com.google.common.collect.Range;
/**
* 分片值.
*
* <p>
* 目前支持{@code =, IN, BETWEEN};
* 不支持{@code , >, <-, >=, LIKE, NOT, NOT IN}.
* </p>
*
* @author zhangliang
*/
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
@ToString
public final class ShardingValue<T extends Comparable<?>> {
private final String columnName;
private final T value;
private final Collection<T> values;
private final Range<T> valueRange;
public ShardingValue(final String columnName, final T value) {
this(columnName, value, Collections.<T>emptyList(), null);
}
public ShardingValue(final String columnName, final Collection<T> values) {
this(columnName, null, values, null);
}
public ShardingValue(final String columnName, final Range<T> valueRange) {
this(columnName, null, Collections.<T>emptyList(), valueRange);
}
/**
* 获取分片值类型.
*
* @return 分片值类型
*/
public ShardingValueType getType() {
if (null != value) {
return ShardingValueType.SINGLE;
}
if (!values.isEmpty()) {
return ShardingValueType.LIST;
}
return ShardingValueType.RANGE;
}
/**
* 分片值类型.
*
* @author zhangliang
*/
public enum ShardingValueType {
SINGLE, LIST, RANGE
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.config;
import java.util.Properties;
import lombok.RequiredArgsConstructor;
/**
* 配置类.
*
* @author gaohongtao
*/
@RequiredArgsConstructor
public final class ShardingConfiguration {
private final Properties props;
/**
* 获取字符串类型的配置.
*
* @param key 配置项的键值
* @return 配置值
*/
public String getConfig(final ShardingConfigurationConstant key) {
return props.getProperty(key.getKey(), key.getDefaultValue());
}
/**
* 获取制定类型的配置.
*
* @param key 配置项的键值
* @param type 配置值的类型
* @return 配置值
*/
public <T> T getConfig(final ShardingConfigurationConstant key, final Class<T> type) {
return convert(getConfig(key), type);
}
@SuppressWarnings("unchecked")
private <T> T convert(final String value, final Class<T> convertType) {
if (Boolean.class == convertType || boolean.class == convertType) {
return (T) Boolean.valueOf(value);
}
if (Integer.class == convertType || int.class == convertType) {
return (T) Integer.valueOf(value);
}
if (Long.class == convertType || long.class == convertType) {
return (T) Long.valueOf(value);
}
if (Double.class == convertType || double.class == convertType) {
return (T) Double.valueOf(value);
}
if (String.class == convertType) {
return (T) value;
}
throw new UnsupportedOperationException(String.format("unsupported config data type %s", convertType.getName()));
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.config;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 配置项常量.
*
* @author gaohongtao
*/
@RequiredArgsConstructor
@Getter
public enum ShardingConfigurationConstant {
/**
* 度量输出周期.
* 单位为秒
* 默认值:30秒
*/
METRICS_SECOND_PERIOD("metrics.second.period", "1"),
/**
* 是否开启度量采集.
* 默认值: 不开启
*/
METRICS_ENABLE("metrics.enable", Boolean.FALSE.toString()),
/**
* 度量输出在日志中的标识名称.
*/
METRICS_PACKAGE_NAME("metrics.package.name", "com.dangdang.ddframe.rdb.sharding.metrics");
private final String key;
private final String defaultValue;
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import java.util.Collection;
import java.util.List;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* Binding表规则配置对象.
*
* @author zhangliang
*/
@RequiredArgsConstructor
@Getter
public final class BindingTableRule {
private final List<TableRule> tableRules;
/**
* 判断此绑定表规则是否包含该逻辑表.
*
* @param logicTableName 逻辑表名称
* @return 此绑定表规则是否包含该逻辑表
*/
public boolean hasLogicTable(final String logicTableName) {
for (TableRule each : tableRules) {
if (each.getLogicTable().equals(logicTableName)) {
return true;
}
}
return false;
}
/**
* 根据其他Binding表真实表名称获取相应的真实Binding表名称.
*
* @param dataSource 数据源名称
* @param logicTable 逻辑表名称
* @param otherActualTable 其他真实Binding表名称
* @return 真实Binding表名称
*/
public String getBindingActualTable(final String dataSource, final String logicTable, final String otherActualTable) {
int index = -1;
for (TableRule each : tableRules) {
index = each.findActualTableIndex(dataSource, otherActualTable);
if (-1 != index) {
break;
}
}
Preconditions.checkState(-1 != index, String.format("Actual table [%s].[%s] is not in table config", dataSource, otherActualTable));
for (TableRule each : tableRules) {
if (each.getLogicTable().equals(logicTable)) {
return each.getActualTables().get(index).getTableName();
}
}
throw new IllegalStateException(String.format("Cannot find binding actual table, data source: %s, logic table: %s, other actual table: %s", dataSource, logicTable, otherActualTable));
}
Collection<String> getAllLogicTables() {
return Lists.transform(tableRules, new Function<TableRule, String>() {
@Override
public String apply(final TableRule input) {
return input.getLogicTable();
}
});
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
/**
* 分库分表数据单元.
*
* @author zhangliang
*/
@RequiredArgsConstructor
@Getter
@EqualsAndHashCode
@ToString
public final class DataNode {
private final String dataSourceName;
private final String tableName;
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import java.util.Collection;
import java.util.Map;
import javax.sql.DataSource;
import com.google.common.base.Preconditions;
/**
* 数据源配置对象.
*
* @author zhangliang
*/
public final class DataSourceRule {
private final Map<String, DataSource> dataSourceMap;
public DataSourceRule(final Map<String, DataSource> dataSourceMap) {
Preconditions.checkNotNull(dataSourceMap, "Must have one data source at least.");
Preconditions.checkState(!dataSourceMap.isEmpty(), "Must have one data source at least.");
this.dataSourceMap = dataSourceMap;
}
/**
* 获取数据源实例.
*
* @param name 数据源名称
* @return 数据源实例
*/
public DataSource getDataSource(final String name) {
return dataSourceMap.get(name);
}
/**
* 获取所有数据源名称.
*
* @return 所有数据源名称
*/
public Collection<String> getDataSourceNames() {
return dataSourceMap.keySet();
}
/**
* 获取所有数据源.
*
* @return 所有数据源
*/
public Collection<DataSource> getDataSources() {
return dataSourceMap.values();
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.NoneDatabaseShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.NoneTableShardingAlgorithm;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 分库分表规则配置对象.
*
* @author zhangliang
*/
@AllArgsConstructor
@Getter
public final class ShardingRule {
private final DataSourceRule dataSourceRule;
private final Collection<TableRule> tableRules;
private Collection<BindingTableRule> bindingTableRules;
private DatabaseShardingStrategy databaseShardingStrategy;
private TableShardingStrategy tableShardingStrategy;
public ShardingRule(final DataSourceRule dataSourceRule, final Collection<TableRule> tableRules) {
this(dataSourceRule, tableRules, Collections.<BindingTableRule>emptyList(),
new DatabaseShardingStrategy(Collections.<String>emptyList(), new NoneDatabaseShardingAlgorithm()),
new TableShardingStrategy(Collections.<String>emptyList(), new NoneTableShardingAlgorithm()));
}
public ShardingRule(final DataSourceRule dataSourceRule, final Collection<TableRule> tableRules, final Collection<BindingTableRule> bindingTableRules) {
this(dataSourceRule, tableRules, bindingTableRules,
new DatabaseShardingStrategy(Collections.<String>emptyList(), new NoneDatabaseShardingAlgorithm()),
new TableShardingStrategy(Collections.<String>emptyList(), new NoneTableShardingAlgorithm()));
}
public ShardingRule(final DataSourceRule dataSourceRule, final Collection<TableRule> tableRules, final DatabaseShardingStrategy databaseShardingStrategy) {
this(dataSourceRule, tableRules, Collections.<BindingTableRule>emptyList(),
databaseShardingStrategy, new TableShardingStrategy(Collections.<String>emptyList(), new NoneTableShardingAlgorithm()));
}
public ShardingRule(final DataSourceRule dataSourceRule, final Collection<TableRule> tableRules, final TableShardingStrategy tableShardingStrategy) {
this(dataSourceRule, tableRules, Collections.<BindingTableRule>emptyList(),
new DatabaseShardingStrategy(Collections.<String>emptyList(), new NoneDatabaseShardingAlgorithm()), tableShardingStrategy);
}
public ShardingRule(final DataSourceRule dataSourceRule, final Collection<TableRule> tableRules,
final DatabaseShardingStrategy databaseShardingStrategy, final TableShardingStrategy tableShardingStrategy) {
this(dataSourceRule, tableRules, Collections.<BindingTableRule>emptyList(), databaseShardingStrategy, tableShardingStrategy);
}
/**
* 根据逻辑表名称查找分片规则.
*
* @param logicTableName 逻辑表名称
* @return 该逻辑表的分片规则
*/
public Optional<TableRule> findTableRule(final String logicTableName) {
for (TableRule each : tableRules) {
if (each.getLogicTable().equals(logicTableName)) {
return Optional.of(each);
}
}
return Optional.absent();
}
/**
* 获取数据库分片策略.
*
* <p>
* 根据表规则配置对象获取分片策略, 如果获取不到则获取默认分片策略.
* </p>
*
* @param tableRule 表规则配置对象
* @return 数据库分片策略
*/
public DatabaseShardingStrategy getDatabaseShardingStrategy(final TableRule tableRule) {
DatabaseShardingStrategy result = tableRule.getDatabaseShardingStrategy();
if (null == result) {
result = databaseShardingStrategy;
}
Preconditions.checkNotNull(result, "no database sharding strategy");
return result;
}
/**
* 获取表分片策略.
*
* <p>
* 根据表规则配置对象获取分片策略, 如果获取不到则获取默认分片策略.
* </p>
*
* @param tableRule 表规则配置对象
* @return 表分片策略
*/
public TableShardingStrategy getTableShardingStrategy(final TableRule tableRule) {
TableShardingStrategy result = tableRule.getTableShardingStrategy();
if (null == result) {
result = tableShardingStrategy;
}
Preconditions.checkNotNull(result, "no table sharding strategy");
return result;
}
/**
* 根据逻辑表名称获取binding表配置的逻辑表名称集合.
*
* @param logicTable 逻辑表名称
* @return binding表配置的逻辑表名称集合
*/
public Optional<BindingTableRule> getBindingTableRule(final String logicTable) {
if (null == bindingTableRules) {
return Optional.absent();
}
for (BindingTableRule each : bindingTableRules) {
if (each.hasLogicTable(logicTable)) {
return Optional.of(each);
}
}
return Optional.absent();
}
/**
* 过滤出所有的Binding表名称.
*
* @param logicTables 逻辑表名称集合
* @return 所有的Binding表名称集合
*/
public Collection<String> filterAllBindingTables(final Collection<String> logicTables) {
if (logicTables.isEmpty()) {
return Collections.emptyList();
}
Optional<BindingTableRule> bindingTableRule = Optional.absent();
for (String each : logicTables) {
bindingTableRule = getBindingTableRule(each);
if (bindingTableRule.isPresent()) {
break;
}
}
if (!bindingTableRule.isPresent()) {
return Collections.emptyList();
}
Collection<String> result = new ArrayList<>(bindingTableRule.get().getAllLogicTables());
result.retainAll(logicTables);
return result;
}
/**
* 判断逻辑表名称集合是否全部属于Binding表.
*
* @param logicTables 逻辑表名称集合
* @return 是否全部属于Binding表
*/
public boolean isAllBindingTable(final Collection<String> logicTables) {
Collection<String> bindingTables = filterAllBindingTables(logicTables);
return !bindingTables.isEmpty() && bindingTables.containsAll(logicTables);
}
/**
* 获取所有的分片列名.
*
* @return 分片列名集合
*/
// TODO 目前使用分片列名称, 为了进一步提升解析性能,应考虑使用表名 + 列名
public Collection<String> getAllShardingColumns() {
Set<String> result = new HashSet<>();
if (null != databaseShardingStrategy) {
result.addAll(databaseShardingStrategy.getShardingColumns());
}
if (null != tableShardingStrategy) {
result.addAll(tableShardingStrategy.getShardingColumns());
}
for (TableRule each : tableRules) {
if (null != each.getDatabaseShardingStrategy()) {
result.addAll(each.getDatabaseShardingStrategy().getShardingColumns());
}
if (null != each.getTableShardingStrategy()) {
result.addAll(each.getTableShardingStrategy().getShardingColumns());
}
}
return result;
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.rule;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import com.dangdang.ddframe.rdb.sharding.api.strategy.database.DatabaseShardingStrategy;
import com.dangdang.ddframe.rdb.sharding.api.strategy.table.TableShardingStrategy;
import com.google.common.base.Splitter;
/**
* 表规则配置对象.
*
* @author zhangliang
*/
@AllArgsConstructor
@RequiredArgsConstructor
@Getter
@ToString
public final class TableRule {
private final String logicTable;
private final List<DataNode> actualTables;
private DatabaseShardingStrategy databaseShardingStrategy;
private TableShardingStrategy tableShardingStrategy;
public TableRule(final String logicTable, final List<String> actualTables, final DataSourceRule dataSourceRule,
final DatabaseShardingStrategy databaseShardingStrategy, final TableShardingStrategy tableShardingStrategy) {
this(logicTable, new ArrayList<DataNode>(actualTables.size() * dataSourceRule.getDataSourceNames().size()), databaseShardingStrategy, tableShardingStrategy);
generateDataNodes(actualTables, dataSourceRule);
}
public TableRule(final String logicTable, final List<String> actualTables, final DataSourceRule dataSourceRule) {
this(logicTable, actualTables, dataSourceRule, null, null);
}
public TableRule(final String logicTable, final List<String> actualTables, final DataSourceRule dataSourceRule, final DatabaseShardingStrategy databaseShardingStrategy) {
this(logicTable, actualTables, dataSourceRule, databaseShardingStrategy, null);
}
public TableRule(final String logicTable, final List<String> actualTables, final DataSourceRule dataSourceRule, final TableShardingStrategy tableShardingStrategy) {
this(logicTable, actualTables, dataSourceRule, null, tableShardingStrategy);
}
private void generateDataNodes(final List<String> actualTables, final DataSourceRule dataSourceRule) {
for (String actualTable : actualTables) {
if (actualTable.contains(".")) {
List<String> actualDatabaseTable = Splitter.on(".").splitToList(actualTable);
this.actualTables.add(new DataNode(actualDatabaseTable.get(0), actualDatabaseTable.get(1)));
} else {
for (String dataSourceName : dataSourceRule.getDataSourceNames()) {
this.actualTables.add(new DataNode(dataSourceName, actualTable));
}
}
}
}
/**
* 根据数据源名称过滤获取真实数据单元.
*
* @param targetDataSources 数据源名称集合
* @param targetTables 真实表名称集合
* @return 真实数据单元
*/
public Collection<DataNode> getActualDataNodes(final Collection<String> targetDataSources, final Collection<String> targetTables) {
Collection<DataNode> result = new LinkedHashSet<>(actualTables.size());
for (DataNode each : actualTables) {
if (targetDataSources.contains(each.getDataSourceName()) && targetTables.contains(each.getTableName())) {
result.add(each);
}
}
return result;
}
/**
* 根据数据源名称过滤获取真实表名称.
*
* @param targetDataSources 数据源名称
* @return 真实表名称
*/
public Collection<String> getActualTableNames(final Collection<String> targetDataSources) {
Collection<String> result = new LinkedHashSet<>(actualTables.size());
for (DataNode each : actualTables) {
if (targetDataSources.contains(each.getDataSourceName())) {
result.add(each.getTableName());
}
}
return result;
}
/**
* 根据数据源和真实表名称查找真实表顺序.
*
* @param dataSourceName 数据源名称
* @param actualTableName 真实表名称
* @return 真实表顺序
*/
public int findActualTableIndex(final String dataSourceName, final String actualTableName) {
int result = 0;
for (DataNode each : actualTables) {
if (each.getDataSourceName().equals(dataSourceName) && each.getTableName().equals(actualTableName)) {
return result;
}
result++;
}
return -1;
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.common;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
/**
* 多片键分片法接口.
*
* @author zhangliang
*/
public interface MultipleKeysShardingAlgorithm extends ShardingAlgorithm {
/**
* 根据分片值计算分片结果名称集合.
*
* @param availableTargetNames 所有的可用目标名称集合, 一般是数据源或表名称
* @param shardingValues 分片值集合
* @return 分片后指向的目标名称集合, 一般是数据源或表名称
*/
Collection<String> doSharding(Collection<String> availableTargetNames, Collection<ShardingValue<?>> shardingValues);
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.common;
/**
* 分片算法的标识接口.
*
* @author zhangliang
*/
public interface ShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.common;
import java.util.Arrays;
import java.util.Collection;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
/**
* 分片策略.
*
* @author zhangliang
*/
@RequiredArgsConstructor
public class ShardingStrategy {
@Getter
private final Collection<String> shardingColumns;
private final ShardingAlgorithm shardingAlgorithm;
public ShardingStrategy(final String shardingColumn, final ShardingAlgorithm shardingAlgorithm) {
this(Arrays.asList(shardingColumn), shardingAlgorithm);
}
/**
* 根据分片值计算数据源名称集合.
*
* @param availableTargetNames 所有的可用数据源名称集合
* @param shardingValues 分库片值集合
* @return 分库后指向的数据源名称集合
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<? extends Comparable<?>>> shardingValues) {
if (shardingValues.isEmpty()) {
return availableTargetNames;
}
if (shardingAlgorithm instanceof SingleKeyShardingAlgorithm) {
SingleKeyShardingAlgorithm<?> singleKeyShardingAlgorithm = (SingleKeyShardingAlgorithm<?>) shardingAlgorithm;
ShardingValue shardingValue = shardingValues.iterator().next();
switch (shardingValue.getType()) {
case SINGLE:
return Arrays.asList(singleKeyShardingAlgorithm.doEqualSharding(availableTargetNames, shardingValue));
case LIST:
return singleKeyShardingAlgorithm.doInSharding(availableTargetNames, shardingValue);
case RANGE:
return singleKeyShardingAlgorithm.doBetweenSharding(availableTargetNames, shardingValue);
default:
throw new UnsupportedOperationException(shardingValue.getType().getClass().getName());
}
}
if (shardingAlgorithm instanceof MultipleKeysShardingAlgorithm) {
return ((MultipleKeysShardingAlgorithm) shardingAlgorithm).doSharding(availableTargetNames, shardingValues);
}
throw new UnsupportedOperationException(shardingAlgorithm.getClass().getName());
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.common;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
/**
* 单片键分片法接口.
*
* @author zhangliang
*
* @param <T> 片键类型
*/
public interface SingleKeyShardingAlgorithm<T extends Comparable<?>> extends ShardingAlgorithm {
/**
* 根据分片值和SQL的=运算符计算分片结果名称集合.
*
* @param availableTargetNames 所有的可用目标名称集合, 一般是数据源或表名称
* @param shardingValue 分片值
* @return 分片后指向的目标名称, 一般是数据源或表名称
*/
String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<T> shardingValue);
/**
* 根据分片值和SQL的IN运算符计算分片结果名称集合.
*
* @param availableTargetNames 所有的可用目标名称集合, 一般是数据源或表名称
* @param shardingValue 分片值
* @return 分片后指向的目标名称集合, 一般是数据源或表名称
*/
Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<T> shardingValue);
/**
* 根据分片值和SQL的BETWEEN运算符计算分片结果名称集合.
*
* @param availableTargetNames 所有的可用目标名称集合, 一般是数据源或表名称
* @param shardingValue 分片值
* @return 分片后指向的目标名称集合, 一般是数据源或表名称
*/
Collection<String> doBetweenSharding(Collection<String> availableTargetNames, ShardingValue<T> shardingValue);
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.database;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingAlgorithm;
/**
* 分库算法接口.
*
* @author zhangliang
*/
public interface DatabaseShardingAlgorithm extends ShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.database;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingStrategy;
/**
* 分库策略.
*
* @author zhangliang
*/
public final class DatabaseShardingStrategy extends ShardingStrategy {
public DatabaseShardingStrategy(final String shardingColumn, final SingleKeyDatabaseShardingAlgorithm<?> databaseShardingAlgorithm) {
super(shardingColumn, databaseShardingAlgorithm);
}
public DatabaseShardingStrategy(final Collection<String> shardingColumns, final MultipleKeysDatabaseShardingAlgorithm databaseShardingAlgorithm) {
super(shardingColumns, databaseShardingAlgorithm);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.database;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.MultipleKeysShardingAlgorithm;
/**
* 多片键分库算法接口.
*
* @author zhangliang
*/
public interface MultipleKeysDatabaseShardingAlgorithm extends MultipleKeysShardingAlgorithm, DatabaseShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.database;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
/**
* 无需分库的分片算法.
*
* @author zhangliang
*/
public final class NoneDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<String>, MultipleKeysDatabaseShardingAlgorithm {
@Override
public Collection<String> doSharding(final Collection<String> availableTargetNames, final Collection<ShardingValue<?>> shardingValues) {
return availableTargetNames;
}
@Override
public String doEqualSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {
return availableTargetNames.isEmpty() ? null : availableTargetNames.iterator().next();
}
@Override
public Collection<String> doInSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {
return availableTargetNames;
}
@Override
public Collection<String> doBetweenSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {
return availableTargetNames;
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.database;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.SingleKeyShardingAlgorithm;
/**
* 单分片键的分库算法接口.
*
* @author zhangliang
*/
public interface SingleKeyDatabaseShardingAlgorithm<T extends Comparable<?>> extends SingleKeyShardingAlgorithm<T>, DatabaseShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.table;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.MultipleKeysShardingAlgorithm;
/**
* 多片键分表算法接口.
*
* @author zhangliang
*/
public interface MultipleKeysTableShardingAlgorithm extends MultipleKeysShardingAlgorithm, TableShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.table;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.api.ShardingValue;
/**
* 无需分表的分片算法.
*
* @author zhangliang
*/
public final class NoneTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<String>, MultipleKeysTableShardingAlgorithm {
@Override
public Collection<String> doSharding(final Collection<String> availableTableNames, final Collection<ShardingValue<?>> shardingValues) {
return availableTableNames;
}
@Override
public String doEqualSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {
return availableTargetNames.isEmpty() ? null : availableTargetNames.iterator().next();
}
@Override
public Collection<String> doInSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {
return availableTargetNames;
}
@Override
public Collection<String> doBetweenSharding(final Collection<String> availableTargetNames, final ShardingValue<String> shardingValue) {
return availableTargetNames;
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.table;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.SingleKeyShardingAlgorithm;
/**
* 单分片键的分表算法接口.
*
* @author zhangliang
*/
public interface SingleKeyTableShardingAlgorithm<T extends Comparable<?>> extends SingleKeyShardingAlgorithm<T>, TableShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.table;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingAlgorithm;
/**
* 分表算法接口.
*
* @author zhangliang
*/
public interface TableShardingAlgorithm extends ShardingAlgorithm {
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.api.strategy.table;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.api.strategy.common.ShardingStrategy;
/**
* 分表策略.
*
* @author zhangliang
*/
public final class TableShardingStrategy extends ShardingStrategy {
public TableShardingStrategy(final String shardingColumn, final SingleKeyTableShardingAlgorithm<?> tableShardingAlgorithm) {
super(shardingColumn, tableShardingAlgorithm);
}
public TableShardingStrategy(final Collection<String> shardingColumns, final MultipleKeysTableShardingAlgorithm tableShardingAlgorithm) {
super(shardingColumns, tableShardingAlgorithm);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.exception;
/**
* 不支持的数据库抛出的异常.
*
* @author zhangliang
*/
public class DatabaseTypeUnsupportedException extends RuntimeException {
private static final long serialVersionUID = -7807395469148925091L;
private static final String MESSAGE = "Can not support database type [%s].";
public DatabaseTypeUnsupportedException(final String databaseType) {
super(String.format(MESSAGE, databaseType));
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.exception;
/**
* SQL解析异常.
*
* @author gaohongtao
*/
public final class SQLParserException extends ShardingJdbcException {
private static final long serialVersionUID = -1498980479829506655L;
public SQLParserException(final String message, final Object... args) {
super(String.format(message, args));
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.exception;
/**
* JDBC分片抛出的异常基类.
*
* @author zhangliang
*/
public class ShardingJdbcException extends RuntimeException {
private static final long serialVersionUID = -1343739516839252250L;
public ShardingJdbcException(final String errorMessage, final Object... args) {
super(String.format(errorMessage, args));
}
public ShardingJdbcException(final Exception cause) {
super(cause);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.executor;
/**
* 执行单元.
*
* @author gaohongtao
*/
public interface ExecuteUnit<I, O> {
/**
* 执行任务.
*
* @param input 输入待处理数据
* @return 返回处理结果
* @throws Exception 执行期异常
*/
O execute(I input) throws Exception;
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.executor;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 多线程执行框架.
*
* @author gaohongtao
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public final class ExecutorEngine {
/**
* 多线程执行任务.
*
* @param inputs 输入参数
* @param executeUnit 执行单元
* @param <I> 入参类型
* @param <O> 出参类型
* @return 执行结果
*/
public static <I, O> List<O> execute(final Collection<I> inputs, final ExecuteUnit<I, O> executeUnit) {
ListenableFuture<List<O>> futures = submitFutures(inputs, executeUnit);
addCallback(futures);
return getFutureResults(futures);
}
/**
* 多线程执行任务并归并结果.
*
* @param inputs 执行入参
* @param executeUnit 执行单元
* @param mergeUnit 合并结果单元
* @param <I> 入参类型
* @param <M> 中间结果类型
* @param <O> 最终结果类型
* @return 执行结果
*/
public static <I, M, O> O execute(final Collection<I> inputs, final ExecuteUnit<I, M> executeUnit, final MergeUnit<M, O> mergeUnit) {
return mergeUnit.merge(execute(inputs, executeUnit));
}
private static <I, O> ListenableFuture<List<O>> submitFutures(final Collection<I> inputs, final ExecuteUnit<I, O> executeUnit) {
Set<ListenableFuture<O>> result = new HashSet<>(inputs.size());
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(inputs.size()));
for (final I each : inputs) {
result.add(service.submit(new Callable<O>() {
@Override
public O call() throws Exception {
return executeUnit.execute(each);
}
}));
}
service.shutdown();
return Futures.allAsList(result);
}
private static <T> void addCallback(final ListenableFuture<T> allFutures) {
Futures.addCallback(allFutures, new FutureCallback<T>() {
@Override
public void onSuccess(final T result) {
log.trace("Concurrent execute result success {}", result);
}
@Override
public void onFailure(final Throwable thrown) {
log.error("Concurrent execute result error {}", thrown);
}
});
}
private static <O> O getFutureResults(final ListenableFuture<O> futures) {
try {
return futures.get();
} catch (final InterruptedException | ExecutionException ex) {
throw new ShardingJdbcException(ex);
}
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.executor;
import java.util.List;
/**
* 合并执行单元.
*
* @author gaohongtao
*/
public interface MergeUnit<I, O> {
/**
* 合并执行结果.
*
* @param params 合并前数据
* @return 合并后结果
*/
O merge(final List<I> params);
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.executor;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import com.codahale.metrics.Timer.Context;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import lombok.RequiredArgsConstructor;
/**
* 多线程执行预编译语句对象请求的执行器.
*
* @author zhangliang
*/
@RequiredArgsConstructor
public final class PreparedStatementExecutor {
private final Collection<PreparedStatement> preparedStatements;
/**
* 执行SQL查询.
*
* @return 结果集列表
* @throws SQLException SQL异常
*/
public List<ResultSet> executeQuery() throws SQLException {
Context context = MetricsContext.start("ShardingPreparedStatement-executeQuery");
List<ResultSet> result;
if (1 == preparedStatements.size()) {
result = Arrays.asList(preparedStatements.iterator().next().executeQuery());
MetricsContext.stop(context);
return result;
}
result = ExecutorEngine.execute(preparedStatements, new ExecuteUnit<PreparedStatement, ResultSet>() {
@Override
public ResultSet execute(final PreparedStatement input) throws Exception {
return input.executeQuery();
}
});
MetricsContext.stop(context);
return result;
}
/**
* 执行SQL更新.
*
* @return 更新数量
* @throws SQLException SQL异常
*/
public int executeUpdate() throws SQLException {
Context context = MetricsContext.start("ShardingPreparedStatement-executeUpdate");
int result;
if (1 == preparedStatements.size()) {
result = preparedStatements.iterator().next().executeUpdate();
MetricsContext.stop(context);
return result;
}
result = ExecutorEngine.execute(preparedStatements, new ExecuteUnit<PreparedStatement, Integer>() {
@Override
public Integer execute(final PreparedStatement input) throws Exception {
return input.executeUpdate();
}
}, new MergeUnit<Integer, Integer>() {
@Override
public Integer merge(final List<Integer> results) {
int result = 0;
for (Integer each : results) {
result += each;
}
return result;
}
});
MetricsContext.stop(context);
return result;
}
/**
* 执行SQL请求.
*
* @return true表示执行DQL, false表示执行的DML
* @throws SQLException SQL异常
*/
public boolean execute() throws SQLException {
Context context = MetricsContext.start("ShardingPreparedStatement-execute");
if (1 == preparedStatements.size()) {
boolean result = preparedStatements.iterator().next().execute();
MetricsContext.stop(context);
return result;
}
List<Boolean> result = ExecutorEngine.execute(preparedStatements, new ExecuteUnit<PreparedStatement, Boolean>() {
@Override
public Boolean execute(final PreparedStatement input) throws Exception {
return input.execute();
}
});
MetricsContext.stop(context);
return result.get(0);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.executor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import com.codahale.metrics.Timer.Context;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import lombok.RequiredArgsConstructor;
/**
* 多线程执行静态语句对象请求的执行器.
*
* @author gaohongtao
*/
@RequiredArgsConstructor
public final class StatementExecutor {
private final Collection<StatementEntity> statements = new ArrayList<>();
/**
* 添加静态语句对象至执行上下文.
*
* @param sql 转换后的SQL语句
* @param statement 静态语句对象
*/
public void addStatement(final String sql, final Statement statement) {
statements.add(new StatementEntity(sql, statement));
}
/**
* 执行SQL查询.
*
* @return 结果集列表
* @throws SQLException SQL异常
*/
public List<ResultSet> executeQuery() throws SQLException {
Context context = MetricsContext.start("ShardingStatement-executeQuery");
List<ResultSet> result;
if (1 == statements.size()) {
StatementEntity entity = statements.iterator().next();
result = Arrays.asList(entity.statement.executeQuery(entity.sql));
MetricsContext.stop(context);
return result;
}
result = ExecutorEngine.execute(statements, new ExecuteUnit<StatementEntity, ResultSet>() {
@Override
public ResultSet execute(final StatementEntity input) throws Exception {
return input.statement.executeQuery(input.sql);
}
});
MetricsContext.stop(context);
return result;
}
/**
* 执行SQL更新.
*
* @return 更新数量
* @throws SQLException SQL异常
*/
public int executeUpdate() throws SQLException {
return executeUpdate(new Updater() {
@Override
public int executeUpdate(final Statement statement, final String sql) throws SQLException {
return statement.executeUpdate(sql);
}
});
}
public int executeUpdate(final int autoGeneratedKeys) throws SQLException {
return executeUpdate(new Updater() {
@Override
public int executeUpdate(final Statement statement, final String sql) throws SQLException {
return statement.executeUpdate(sql, autoGeneratedKeys);
}
});
}
public int executeUpdate(final int[] columnIndexes) throws SQLException {
return executeUpdate(new Updater() {
@Override
public int executeUpdate(final Statement statement, final String sql) throws SQLException {
return statement.executeUpdate(sql, columnIndexes);
}
});
}
public int executeUpdate(final String[] columnNames) throws SQLException {
return executeUpdate(new Updater() {
@Override
public int executeUpdate(final Statement statement, final String sql) throws SQLException {
return statement.executeUpdate(sql, columnNames);
}
});
}
private int executeUpdate(final Updater updater) throws SQLException {
Context context = MetricsContext.start("ShardingStatement-executeUpdate");
int result;
if (1 == statements.size()) {
StatementEntity entity = statements.iterator().next();
result = updater.executeUpdate(entity.statement, entity.sql);
MetricsContext.stop(context);
return result;
}
result = ExecutorEngine.execute(statements, new ExecuteUnit<StatementEntity, Integer>() {
@Override
public Integer execute(final StatementEntity input) throws Exception {
return updater.executeUpdate(input.statement, input.sql);
}
}, new MergeUnit<Integer, Integer>() {
@Override
public Integer merge(final List<Integer> results) {
int result = 0;
for (int each : results) {
result += each;
}
return result;
}
});
MetricsContext.stop(context);
return result;
}
/**
* 执行SQL请求.
*
* @return true表示执行DQL语句, false表示执行的DML语句
* @throws SQLException SQL异常
*/
public boolean execute() throws SQLException {
return execute(new Executor() {
@Override
public boolean execute(final Statement statement, final String sql) throws SQLException {
return statement.execute(sql);
}
});
}
public boolean execute(final int autoGeneratedKeys) throws SQLException {
return execute(new Executor() {
@Override
public boolean execute(final Statement statement, final String sql) throws SQLException {
return statement.execute(sql, autoGeneratedKeys);
}
});
}
public boolean execute(final int[] columnIndexes) throws SQLException {
return execute(new Executor() {
@Override
public boolean execute(final Statement statement, final String sql) throws SQLException {
return statement.execute(sql, columnIndexes);
}
});
}
public boolean execute(final String[] columnNames) throws SQLException {
return execute(new Executor() {
@Override
public boolean execute(final Statement statement, final String sql) throws SQLException {
return statement.execute(sql, columnNames);
}
});
}
private boolean execute(final Executor executor) throws SQLException {
Context context = MetricsContext.start("ShardingStatement-execute");
if (1 == statements.size()) {
StatementEntity entity = statements.iterator().next();
boolean result = executor.execute(entity.statement, entity.sql);
MetricsContext.stop(context);
return result;
}
List<Boolean> result = ExecutorEngine.execute(statements, new ExecuteUnit<StatementEntity, Boolean>() {
@Override
public Boolean execute(final StatementEntity input) throws Exception {
return executor.execute(input.statement, input.sql);
}
});
MetricsContext.stop(context);
return result.get(0);
}
private interface Updater {
int executeUpdate(Statement statement, String sql) throws SQLException;
}
private interface Executor {
boolean execute(Statement statement, String sql) throws SQLException;
}
@RequiredArgsConstructor
private class StatementEntity {
private final String sql;
private final Statement statement;
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractResultSetAdapter;
import com.dangdang.ddframe.rdb.sharding.parser.result.merger.Limit;
import lombok.extern.slf4j.Slf4j;
/**
* 支持分片的结果集抽象类.
*
* @author zhangliang
*/
@Slf4j
public abstract class AbstractShardingResultSet extends AbstractResultSetAdapter {
private final Limit limit;
private boolean offsetSkipped;
private int readCount;
protected AbstractShardingResultSet(final List<ResultSet> resultSets, final Limit limit) {
super(resultSets);
this.limit = limit;
setCurrentResultSet(resultSets.get(0));
}
@Override
public final boolean next() throws SQLException {
if (null != limit && !offsetSkipped) {
skipOffset();
}
return null == limit ? nextForSharding() : ++readCount <= limit.getRowCount() && nextForSharding();
}
private void skipOffset() {
for (int i = 0; i < limit.getOffset(); i++) {
try {
if (!nextForSharding()) {
break;
}
} catch (final SQLException ignored) {
log.warn("Skip result set error", ignored);
}
}
offsetSkipped = true;
}
/**
* 迭代结果集.
*
* @return true 可以继续访问 false 不能继续访问
* @throws SQLException
*/
protected abstract boolean nextForSharding() throws SQLException;
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import com.codahale.metrics.Timer.Context;
import com.dangdang.ddframe.rdb.sharding.api.DatabaseType;
import com.dangdang.ddframe.rdb.sharding.api.rule.ShardingRule;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractConnectionAdapter;
import com.dangdang.ddframe.rdb.sharding.metrics.MetricsContext;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteEngine;
/**
* 支持分片的数据库连接.
*
* @author zhangliang
*/
public final class ShardingConnection extends AbstractConnectionAdapter {
private final ShardingRule shardingRule;
private final DatabaseMetaData metaData;
private Map<String, Connection> connectionMap = new HashMap<>();
private SQLRouteEngine sqlRouteEngine;
public ShardingConnection(final ShardingRule shardingRule, final DatabaseMetaData metaData) throws SQLException {
this.shardingRule = shardingRule;
this.metaData = metaData;
sqlRouteEngine = new SQLRouteEngine(shardingRule, DatabaseType.valueFrom(metaData.getDatabaseProductName()));
}
/**
* 根据数据源名称获取相应的数据库连接.
*
* @param dataSourceName 数据源名称
* @return 数据库连接
*/
public Connection getConnection(final String dataSourceName) throws SQLException {
if (connectionMap.containsKey(dataSourceName)) {
return connectionMap.get(dataSourceName);
}
Context context = MetricsContext.start("ShardingConnection-getConnection", dataSourceName);
Connection connection = shardingRule.getDataSourceRule().getDataSource(dataSourceName).getConnection();
MetricsContext.stop(context);
replayMethodsInvovation(connection);
connectionMap.put(dataSourceName, connection);
return connection;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return metaData;
}
@Override
public PreparedStatement prepareStatement(final String sql) throws SQLException {
return new ShardingPreparedStatement(sqlRouteEngine, this, sql);
}
@Override
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
return new ShardingPreparedStatement(sqlRouteEngine, this, sql, resultSetType, resultSetConcurrency);
}
@Override
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
return new ShardingPreparedStatement(sqlRouteEngine, this, sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
return new ShardingPreparedStatement(sqlRouteEngine, this, sql, autoGeneratedKeys);
}
@Override
public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
return new ShardingPreparedStatement(sqlRouteEngine, this, sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
return new ShardingPreparedStatement(sqlRouteEngine, this, sql, columnNames);
}
@Override
public Statement createStatement() throws SQLException {
return new ShardingStatement(sqlRouteEngine, this);
}
@Override
public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
return new ShardingStatement(sqlRouteEngine, this, resultSetType, resultSetConcurrency);
}
@Override
public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
return new ShardingStatement(sqlRouteEngine, this, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public Collection<Connection> getConnections() {
return connectionMap.values();
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import com.dangdang.ddframe.rdb.sharding.executor.PreparedStatementExecutor;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractPreparedStatementAdapter;
import com.dangdang.ddframe.rdb.sharding.merger.ResultSetFactory;
import com.dangdang.ddframe.rdb.sharding.router.SQLExecutionUnit;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteEngine;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteResult;
import com.google.common.collect.Lists;
/**
* 支持分片的预编译语句对象.
*
* @author zhangliang
*/
public final class ShardingPreparedStatement extends AbstractPreparedStatementAdapter {
private final String sql;
private final Collection<PreparedStatement> cachedRoutedPreparedStatements = new LinkedList<>();
private Integer autoGeneratedKeys;
private int[] columnIndexes;
private String[] columnNames;
private boolean hasExecuted;
private final List<List<Object>> batchParameters = new ArrayList<>();
public ShardingPreparedStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection, final String sql) throws SQLException {
this(sqlRouteEngine, shardingConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
public ShardingPreparedStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection,
final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
this(sqlRouteEngine, shardingConnection, sql, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
public ShardingPreparedStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection,
final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
super(sqlRouteEngine, shardingConnection, resultSetType, resultSetConcurrency, resultSetHoldability);
this.sql = sql;
}
public ShardingPreparedStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection, final String sql, final int autoGeneratedKeys) throws SQLException {
this(sqlRouteEngine, shardingConnection, sql);
this.autoGeneratedKeys = autoGeneratedKeys;
}
public ShardingPreparedStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection, final String sql, final int[] columnIndexes) throws SQLException {
this(sqlRouteEngine, shardingConnection, sql);
this.columnIndexes = columnIndexes;
}
public ShardingPreparedStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection, final String sql, final String[] columnNames) throws SQLException {
this(sqlRouteEngine, shardingConnection, sql);
this.columnNames = columnNames;
}
@Override
public ResultSet executeQuery() throws SQLException {
hasExecuted = true;
setCurrentResultSet(ResultSetFactory.getResultSet(new PreparedStatementExecutor(getRoutedPreparedStatements()).executeQuery(), getMergeContext()));
return getCurrentResultSet();
}
@Override
public int executeUpdate() throws SQLException {
hasExecuted = true;
return new PreparedStatementExecutor(getRoutedPreparedStatements()).executeUpdate();
}
@Override
public boolean execute() throws SQLException {
hasExecuted = true;
return new PreparedStatementExecutor(getRoutedPreparedStatements()).execute();
}
@Override
public void addBatch() throws SQLException {
batchParameters.add(Lists.newArrayList(getParameters()));
getParameters().clear();
}
@Override
public void clearBatch() throws SQLException {
batchParameters.clear();
}
@Override
public int[] executeBatch() throws SQLException {
hasExecuted = true;
int[] result = new int[batchParameters.size()];
int i = 0;
for (List<Object> each : batchParameters) {
result[i++] = new PreparedStatementExecutor(routeSQL(each)).executeUpdate();
}
return result;
}
private Collection<PreparedStatement> getRoutedPreparedStatements() throws SQLException {
if (!hasExecuted) {
return Collections.emptyList();
}
routeIfNeed();
return cachedRoutedPreparedStatements;
}
@Override
public Collection<? extends Statement> getRoutedStatements() throws SQLException {
return getRoutedPreparedStatements();
}
private void routeIfNeed() throws SQLException {
if (!cachedRoutedPreparedStatements.isEmpty()) {
return;
}
cachedRoutedPreparedStatements.addAll(routeSQL(getParameters()));
}
private List<PreparedStatement> routeSQL(final List<Object> parameters) throws SQLException {
List<PreparedStatement> result = new ArrayList<>();
SQLRouteResult sqlRouteResult = getSqlRouteEngine().route(sql, parameters);
setMergeContext(sqlRouteResult.getMergeContext());
for (SQLExecutionUnit each : sqlRouteResult.getExecutionUnits()) {
PreparedStatement preparedStatement = generatePrepareStatement(getShardingConnection().getConnection(each.getDataSource()), each.getSql());
replayMethodsInvovation(preparedStatement);
setParameters(preparedStatement, parameters);
result.add(preparedStatement);
}
return result;
}
private PreparedStatement generatePrepareStatement(final Connection conn, final String shardingSql) throws SQLException {
if (null != autoGeneratedKeys) {
return conn.prepareStatement(shardingSql, autoGeneratedKeys);
}
if (null != columnIndexes) {
return conn.prepareStatement(shardingSql, columnIndexes);
}
if (null != columnNames) {
return conn.prepareStatement(shardingSql, columnNames);
}
if (0 != getResultSetHoldability()) {
return conn.prepareStatement(shardingSql, getResultSetType(), getResultSetConcurrency(), getResultSetHoldability());
}
return conn.prepareStatement(shardingSql, getResultSetType(), getResultSetConcurrency());
}
private void setParameters(final PreparedStatement preparedStatement, final List<Object> parameters) throws SQLException {
int i = 1;
for (Object each : parameters) {
preparedStatement.setObject(i++, each);
}
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.dangdang.ddframe.rdb.sharding.executor.StatementExecutor;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractStatementAdapter;
import com.dangdang.ddframe.rdb.sharding.merger.ResultSetFactory;
import com.dangdang.ddframe.rdb.sharding.parser.result.merger.MergeContext;
import com.dangdang.ddframe.rdb.sharding.router.SQLExecutionUnit;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteEngine;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteResult;
import com.google.common.base.Charsets;
import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
/**
* 支持分片的静态语句对象.
*
* @author gaohongtao
*/
public class ShardingStatement extends AbstractStatementAdapter {
@Getter(AccessLevel.PROTECTED)
private final ShardingConnection shardingConnection;
@Getter(AccessLevel.PROTECTED)
private final SQLRouteEngine sqlRouteEngine;
@Getter
private final int resultSetType;
@Getter
private final int resultSetConcurrency;
@Getter
private final int resultSetHoldability;
private final Map<HashCode, Statement> cachedRoutedStatements = new HashMap<>();
@Getter(AccessLevel.PROTECTED)
@Setter(AccessLevel.PROTECTED)
private MergeContext mergeContext;
@Getter(AccessLevel.PROTECTED)
@Setter(AccessLevel.PROTECTED)
private ResultSet currentResultSet;
public ShardingStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection) throws SQLException {
this(sqlRouteEngine, shardingConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
public ShardingStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection, final int resultSetType, final int resultSetConcurrency) throws SQLException {
this(sqlRouteEngine, shardingConnection, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}
public ShardingStatement(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection,
final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
super(Statement.class);
this.shardingConnection = shardingConnection;
this.sqlRouteEngine = sqlRouteEngine;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.resultSetHoldability = resultSetHoldability;
}
@Override
public Connection getConnection() throws SQLException {
return shardingConnection;
}
@Override
public ResultSet executeQuery(final String sql) throws SQLException {
if (null != currentResultSet && !currentResultSet.isClosed()) {
currentResultSet.close();
}
currentResultSet = ResultSetFactory.getResultSet(generateExecutor(sql).executeQuery(), mergeContext);
return currentResultSet;
}
@Override
public int executeUpdate(final String sql) throws SQLException {
return generateExecutor(sql).executeUpdate();
}
@Override
public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException {
return generateExecutor(sql).executeUpdate(autoGeneratedKeys);
}
@Override
public int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException {
return generateExecutor(sql).executeUpdate(columnIndexes);
}
@Override
public int executeUpdate(final String sql, final String[] columnNames) throws SQLException {
return generateExecutor(sql).executeUpdate(columnNames);
}
@Override
public boolean execute(final String sql) throws SQLException {
return generateExecutor(sql).execute();
}
@Override
public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException {
return generateExecutor(sql).execute(autoGeneratedKeys);
}
@Override
public boolean execute(final String sql, final int[] columnIndexes) throws SQLException {
return generateExecutor(sql).execute(columnIndexes);
}
@Override
public boolean execute(final String sql, final String[] columnNames) throws SQLException {
return generateExecutor(sql).execute(columnNames);
}
private StatementExecutor generateExecutor(final String sql) throws SQLException {
StatementExecutor result = new StatementExecutor();
SQLRouteResult sqlRouteResult = sqlRouteEngine.route(sql, Collections.emptyList());
mergeContext = sqlRouteResult.getMergeContext();
for (SQLExecutionUnit each : sqlRouteResult.getExecutionUnits()) {
result.addStatement(each.getSql(), generateStatement(each.getSql(), each.getDataSource()));
}
return result;
}
private Statement generateStatement(final String sql, final String dataSourceName) throws SQLException {
HashCode hashCode = Hashing.md5().newHasher().putString(sql, Charsets.UTF_8).putString(dataSourceName, Charsets.UTF_8).hash();
if (cachedRoutedStatements.containsKey(hashCode)) {
return cachedRoutedStatements.get(hashCode);
}
Connection connection = shardingConnection.getConnection(dataSourceName);
Statement result;
if (0 == resultSetHoldability) {
result = connection.createStatement(resultSetType, resultSetConcurrency);
} else {
result = connection.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
}
replayMethodsInvovation(result);
cachedRoutedStatements.put(hashCode, result);
return result;
}
@Override
public ResultSet getResultSet() throws SQLException {
if (null != currentResultSet) {
return currentResultSet;
}
List<ResultSet> resultSets = new ArrayList<>(getRoutedStatements().size());
for (Statement each : getRoutedStatements()) {
resultSets.add(each.getResultSet());
}
currentResultSet = ResultSetFactory.getResultSet(resultSets, mergeContext);
return currentResultSet;
}
@Override
public Collection<? extends Statement> getRoutedStatements() throws SQLException {
return cachedRoutedStatements.values();
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationConnection;
/**
* 数据库连接适配类.
*
* @author zhangliang
*/
public abstract class AbstractConnectionAdapter extends AbstractUnsupportedOperationConnection {
private boolean autoCommit = true;
private boolean readOnly = true;
private boolean closed;
private int transactionIsolation = TRANSACTION_READ_UNCOMMITTED;
protected abstract Collection<Connection> getConnections();
@Override
public final boolean getAutoCommit() throws SQLException {
return autoCommit;
}
@Override
public final void setAutoCommit(final boolean autoCommit) throws SQLException {
this.autoCommit = autoCommit;
if (getConnections().isEmpty()) {
recordMethodInvocation(Connection.class, "setAutoCommit", new Class[] {boolean.class}, new Object[] {autoCommit});
return;
}
for (Connection each : getConnections()) {
each.setAutoCommit(autoCommit);
}
}
@Override
public final void commit() throws SQLException {
for (Connection each : getConnections()) {
each.commit();
}
}
@Override
public final void rollback() throws SQLException {
for (Connection each : getConnections()) {
each.rollback();
}
}
@Override
public final void close() throws SQLException {
for (Connection each : getConnections()) {
each.close();
}
closed = true;
}
@Override
public final boolean isClosed() throws SQLException {
return closed;
}
@Override
public final boolean isReadOnly() throws SQLException {
return readOnly;
}
@Override
public final void setReadOnly(final boolean readOnly) throws SQLException {
this.readOnly = readOnly;
if (getConnections().isEmpty()) {
recordMethodInvocation(Connection.class, "setReadOnly", new Class[] {boolean.class}, new Object[] {readOnly});
return;
}
for (Connection each : getConnections()) {
each.setReadOnly(readOnly);
}
}
@Override
public final int getTransactionIsolation() throws SQLException {
return transactionIsolation;
}
@Override
public final void setTransactionIsolation(final int level) throws SQLException {
transactionIsolation = level;
if (getConnections().isEmpty()) {
recordMethodInvocation(Connection.class, "setTransactionIsolation", new Class[] {int.class}, new Object[] {level});
return;
}
for (Connection each : getConnections()) {
each.setTransactionIsolation(level);
}
}
// -------以下代码与MySQL实现保持一致.-------
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
@Override
public final int getHoldability() throws SQLException {
return ResultSet.CLOSE_CURSORS_AT_COMMIT;
}
@Override
public final void setHoldability(final int holdability) throws SQLException {
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.logging.Logger;
import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationDataSource;
import lombok.RequiredArgsConstructor;
/**
* 数据源适配类.
*
* @author zhangliang
*/
@RequiredArgsConstructor
public abstract class AbstractDataSourceAdapter extends AbstractUnsupportedOperationDataSource {
private PrintWriter logWriter = new PrintWriter(System.out);
@Override
public final PrintWriter getLogWriter() throws SQLException {
return logWriter;
}
@Override
public final void setLogWriter(final PrintWriter out) throws SQLException {
this.logWriter = out;
}
@Override
public final Logger getParentLogger() throws SQLFeatureNotSupportedException {
return Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.Ref;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import com.dangdang.ddframe.rdb.sharding.jdbc.ShardingConnection;
import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationPreparedStatement;
import com.dangdang.ddframe.rdb.sharding.router.SQLRouteEngine;
import lombok.Getter;
/**
* 预编译语句对象的适配类.
*
* <p>
* 封装与分片核心逻辑不相关的方法.
* </p>
*
* @author zhangliang
*/
public abstract class AbstractPreparedStatementAdapter extends AbstractUnsupportedOperationPreparedStatement {
@Getter
private final List<Object> parameters = new ArrayList<>();
public AbstractPreparedStatementAdapter(final SQLRouteEngine sqlRouteEngine, final ShardingConnection shardingConnection,
final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
super(sqlRouteEngine, shardingConnection, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public final void setNull(final int parameterIndex, final int sqlType) throws SQLException {
setParameter(parameterIndex, null);
}
@Override
public final void setNull(final int parameterIndex, final int sqlType, final String typeName) throws SQLException {
setParameter(parameterIndex, null);
}
@Override
public final void setBoolean(final int parameterIndex, final boolean x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setByte(final int parameterIndex, final byte x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setShort(final int parameterIndex, final short x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setInt(final int parameterIndex, final int x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setLong(final int parameterIndex, final long x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setFloat(final int parameterIndex, final float x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setDouble(final int parameterIndex, final double x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setString(final int parameterIndex, final String x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBigDecimal(final int parameterIndex, final BigDecimal x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setDate(final int parameterIndex, final Date x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setDate(final int parameterIndex, final Date x, final Calendar cal) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setTime(final int parameterIndex, final Time x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setTime(final int parameterIndex, final Time x, final Calendar cal) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setTimestamp(final int parameterIndex, final Timestamp x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setTimestamp(final int parameterIndex, final Timestamp x, final Calendar cal) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBytes(final int parameterIndex, final byte[] x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBlob(final int parameterIndex, final Blob x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBlob(final int parameterIndex, final InputStream x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBlob(final int parameterIndex, final InputStream x, final long length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setClob(final int parameterIndex, final Clob x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setClob(final int parameterIndex, final Reader x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setClob(final int parameterIndex, final Reader x, final long length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setAsciiStream(final int parameterIndex, final InputStream x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setAsciiStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setAsciiStream(final int parameterIndex, final InputStream x, final long length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setUnicodeStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBinaryStream(final int parameterIndex, final InputStream x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBinaryStream(final int parameterIndex, final InputStream x, final int length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setBinaryStream(final int parameterIndex, final InputStream x, final long length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setCharacterStream(final int parameterIndex, final Reader x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setCharacterStream(final int parameterIndex, final Reader x, final int length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setCharacterStream(final int parameterIndex, final Reader x, final long length) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setURL(final int parameterIndex, final URL x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setSQLXML(final int parameterIndex, final SQLXML x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setRef(final int parameterIndex, final Ref x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setObject(final int parameterIndex, final Object x) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setObject(final int parameterIndex, final Object x, final int targetSqlType) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void setObject(final int parameterIndex, final Object x, final int targetSqlType, final int scaleOrLength) throws SQLException {
setParameter(parameterIndex, x);
}
@Override
public final void clearParameters() throws SQLException {
parameters.clear();
}
private void setParameter(final int index, final Object x) {
int extendedSize = index - parameters.size();
if (extendedSize > 1) {
while (--extendedSize > 0) {
parameters.add(null);
}
}
parameters.add(index - 1, x);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.List;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* 处理多结果集的适配器.
*
* @author zhangliang
*/
@RequiredArgsConstructor
public abstract class AbstractResultSetAdapter extends AbstractResultSetGetterAdapter {
@Getter
private final List<ResultSet> resultSets;
private boolean closed;
@Override
public final void close() throws SQLException {
for (ResultSet each : resultSets) {
each.close();
}
closed = true;
}
@Override
public final boolean isClosed() throws SQLException {
return closed;
}
@Override
public final boolean wasNull() throws SQLException {
return getCurrentResultSet().wasNull();
}
@Override
public final int getFetchDirection() throws SQLException {
return getCurrentResultSet().getFetchDirection();
}
@Override
public final void setFetchDirection(final int direction) throws SQLException {
for (ResultSet each : resultSets) {
each.setFetchDirection(direction);
}
}
@Override
public final int getFetchSize() throws SQLException {
return getCurrentResultSet().getFetchSize();
}
@Override
public final void setFetchSize(final int rows) throws SQLException {
for (ResultSet each : resultSets) {
each.setFetchSize(rows);
}
}
@Override
public final int getType() throws SQLException {
return getCurrentResultSet().getType();
}
@Override
public final int getConcurrency() throws SQLException {
return getCurrentResultSet().getConcurrency();
}
@Override
public final Statement getStatement() throws SQLException {
return getCurrentResultSet().getStatement();
}
@Override
public final SQLWarning getWarnings() throws SQLException {
return getCurrentResultSet().getWarnings();
}
@Override
public final void clearWarnings() throws SQLException {
getCurrentResultSet().clearWarnings();
}
@Override
public final ResultSetMetaData getMetaData() throws SQLException {
return getCurrentResultSet().getMetaData();
}
@Override
public final int findColumn(final String columnLabel) throws SQLException {
return getCurrentResultSet().findColumn(columnLabel);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLXML;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Map;
import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationResultSet;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
/**
* 处理多结果集的适配器.
*
* @author zhangliang
*/
@RequiredArgsConstructor
public abstract class AbstractResultSetGetterAdapter extends AbstractUnsupportedOperationResultSet {
@Getter(AccessLevel.PROTECTED)
@Setter(AccessLevel.PROTECTED)
private ResultSet currentResultSet;
@Override
public final boolean getBoolean(final int columnIndex) throws SQLException {
return currentResultSet.getBoolean(columnIndex);
}
@Override
public final boolean getBoolean(final String columnLabel) throws SQLException {
return currentResultSet.getBoolean(columnLabel);
}
@Override
public final byte getByte(final int columnIndex) throws SQLException {
return currentResultSet.getByte(columnIndex);
}
@Override
public final byte getByte(final String columnLabel) throws SQLException {
return currentResultSet.getByte(columnLabel);
}
@Override
public final short getShort(final int columnIndex) throws SQLException {
return currentResultSet.getShort(columnIndex);
}
@Override
public final short getShort(final String columnLabel) throws SQLException {
return currentResultSet.getShort(columnLabel);
}
@Override
public final int getInt(final int columnIndex) throws SQLException {
return currentResultSet.getInt(columnIndex);
}
@Override
public final int getInt(final String columnLabel) throws SQLException {
return currentResultSet.getInt(columnLabel);
}
@Override
public final long getLong(final int columnIndex) throws SQLException {
return currentResultSet.getLong(columnIndex);
}
@Override
public final long getLong(final String columnLabel) throws SQLException {
return currentResultSet.getLong(columnLabel);
}
@Override
public final float getFloat(final int columnIndex) throws SQLException {
return currentResultSet.getFloat(columnIndex);
}
@Override
public final float getFloat(final String columnLabel) throws SQLException {
return currentResultSet.getFloat(columnLabel);
}
@Override
public final double getDouble(final int columnIndex) throws SQLException {
return currentResultSet.getDouble(columnIndex);
}
@Override
public final double getDouble(final String columnLabel) throws SQLException {
return currentResultSet.getDouble(columnLabel);
}
@Override
public final String getString(final int columnIndex) throws SQLException {
return currentResultSet.getString(columnIndex);
}
@Override
public final String getString(final String columnLabel) throws SQLException {
return currentResultSet.getString(columnLabel);
}
@Override
public final BigDecimal getBigDecimal(final int columnIndex) throws SQLException {
return currentResultSet.getBigDecimal(columnIndex);
}
@Override
public final BigDecimal getBigDecimal(final String columnLabel) throws SQLException {
return currentResultSet.getBigDecimal(columnLabel);
}
@SuppressWarnings("deprecation")
@Override
public final BigDecimal getBigDecimal(final int columnIndex, final int scale) throws SQLException {
return currentResultSet.getBigDecimal(columnIndex, scale);
}
@SuppressWarnings("deprecation")
@Override
public final BigDecimal getBigDecimal(final String columnLabel, final int scale) throws SQLException {
return currentResultSet.getBigDecimal(columnLabel, scale);
}
@Override
public final byte[] getBytes(final int columnIndex) throws SQLException {
return currentResultSet.getBytes(columnIndex);
}
@Override
public final byte[] getBytes(final String columnLabel) throws SQLException {
return currentResultSet.getBytes(columnLabel);
}
@Override
public final Date getDate(final int columnIndex) throws SQLException {
return currentResultSet.getDate(columnIndex);
}
@Override
public final Date getDate(final String columnLabel) throws SQLException {
return currentResultSet.getDate(columnLabel);
}
@Override
public final Date getDate(final int columnIndex, final Calendar cal) throws SQLException {
return currentResultSet.getDate(columnIndex, cal);
}
@Override
public final Date getDate(final String columnLabel, final Calendar cal) throws SQLException {
return currentResultSet.getDate(columnLabel, cal);
}
@Override
public final Time getTime(final int columnIndex) throws SQLException {
return currentResultSet.getTime(columnIndex);
}
@Override
public final Time getTime(final String columnLabel) throws SQLException {
return currentResultSet.getTime(columnLabel);
}
@Override
public final Time getTime(final int columnIndex, final Calendar cal) throws SQLException {
return currentResultSet.getTime(columnIndex, cal);
}
@Override
public final Time getTime(final String columnLabel, final Calendar cal) throws SQLException {
return currentResultSet.getTime(columnLabel, cal);
}
@Override
public final Timestamp getTimestamp(final int columnIndex) throws SQLException {
return currentResultSet.getTimestamp(columnIndex);
}
@Override
public final Timestamp getTimestamp(final String columnLabel) throws SQLException {
return currentResultSet.getTimestamp(columnLabel);
}
@Override
public final Timestamp getTimestamp(final int columnIndex, final Calendar cal) throws SQLException {
return currentResultSet.getTimestamp(columnIndex, cal);
}
@Override
public final Timestamp getTimestamp(final String columnLabel, final Calendar cal) throws SQLException {
return currentResultSet.getTimestamp(columnLabel, cal);
}
@Override
public final InputStream getAsciiStream(final int columnIndex) throws SQLException {
return currentResultSet.getAsciiStream(columnIndex);
}
@Override
public final InputStream getAsciiStream(final String columnLabel) throws SQLException {
return currentResultSet.getAsciiStream(columnLabel);
}
@SuppressWarnings("deprecation")
@Override
public final InputStream getUnicodeStream(final int columnIndex) throws SQLException {
return currentResultSet.getUnicodeStream(columnIndex);
}
@SuppressWarnings("deprecation")
@Override
public final InputStream getUnicodeStream(final String columnLabel) throws SQLException {
return currentResultSet.getUnicodeStream(columnLabel);
}
@Override
public final InputStream getBinaryStream(final int columnIndex) throws SQLException {
return currentResultSet.getBinaryStream(columnIndex);
}
@Override
public final InputStream getBinaryStream(final String columnLabel) throws SQLException {
return currentResultSet.getBinaryStream(columnLabel);
}
@Override
public final Reader getCharacterStream(final int columnIndex) throws SQLException {
return currentResultSet.getCharacterStream(columnIndex);
}
@Override
public final Reader getCharacterStream(final String columnLabel) throws SQLException {
return currentResultSet.getCharacterStream(columnLabel);
}
@Override
public final Blob getBlob(final int columnIndex) throws SQLException {
return currentResultSet.getBlob(columnIndex);
}
@Override
public final Blob getBlob(final String columnLabel) throws SQLException {
return currentResultSet.getBlob(columnLabel);
}
@Override
public final Clob getClob(final int columnIndex) throws SQLException {
return currentResultSet.getClob(columnIndex);
}
@Override
public final Clob getClob(final String columnLabel) throws SQLException {
return currentResultSet.getClob(columnLabel);
}
@Override
public final URL getURL(final int columnIndex) throws SQLException {
return currentResultSet.getURL(columnIndex);
}
@Override
public final URL getURL(final String columnLabel) throws SQLException {
return currentResultSet.getURL(columnLabel);
}
@Override
public final SQLXML getSQLXML(final int columnIndex) throws SQLException {
return currentResultSet.getSQLXML(columnIndex);
}
@Override
public final SQLXML getSQLXML(final String columnLabel) throws SQLException {
return currentResultSet.getSQLXML(columnLabel);
}
@Override
public final Object getObject(final int columnIndex) throws SQLException {
return currentResultSet.getObject(columnIndex);
}
@Override
public final Object getObject(final String columnLabel) throws SQLException {
return currentResultSet.getObject(columnLabel);
}
@Override
public final Object getObject(final int columnIndex, final Map<String, Class<?>> map) throws SQLException {
return currentResultSet.getObject(columnIndex, map);
}
@Override
public final Object getObject(final String columnLabel, final Map<String, Class<?>> map) throws SQLException {
return currentResultSet.getObject(columnLabel, map);
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.jdbc.unsupported.AbstractUnsupportedOperationStatement;
import lombok.RequiredArgsConstructor;
/**
* 静态语句对象适配类.
*
* @author gaohongtao
*/
@RequiredArgsConstructor
public abstract class AbstractStatementAdapter extends AbstractUnsupportedOperationStatement {
private final Class<? extends Statement> recordTargetClass;
private boolean closed;
private boolean poolable;
private int fetchSize;
@Override
public final void close() throws SQLException {
for (Statement each : getRoutedStatements()) {
each.close();
}
closed = true;
getRoutedStatements().clear();
}
@Override
public final boolean isClosed() throws SQLException {
return closed;
}
@Override
public final boolean isPoolable() throws SQLException {
return poolable;
}
@Override
public final void setPoolable(final boolean poolable) throws SQLException {
this.poolable = poolable;
if (getRoutedStatements().isEmpty()) {
recordMethodInvocation(recordTargetClass, "setPoolable", new Class[] {boolean.class}, new Object[] {poolable});
return;
}
for (Statement each : getRoutedStatements()) {
each.setPoolable(poolable);
}
}
@Override
public final int getFetchSize() throws SQLException {
return fetchSize;
}
@Override
public final void setFetchSize(final int rows) throws SQLException {
this.fetchSize = rows;
if (getRoutedStatements().isEmpty()) {
recordMethodInvocation(recordTargetClass, "setFetchSize", new Class[] {int.class}, new Object[] {rows});
return;
}
for (Statement each : getRoutedStatements()) {
each.setFetchSize(rows);
}
}
@Override
public final void setEscapeProcessing(final boolean enable) throws SQLException {
if (getRoutedStatements().isEmpty()) {
recordMethodInvocation(recordTargetClass, "setEscapeProcessing", new Class[] {boolean.class}, new Object[] {enable});
return;
}
for (Statement each : getRoutedStatements()) {
each.setEscapeProcessing(enable);
}
}
@Override
public final void cancel() throws SQLException {
for (Statement each : getRoutedStatements()) {
each.cancel();
}
}
@Override
public final void setCursorName(final String name) throws SQLException {
if (getRoutedStatements().isEmpty()) {
recordMethodInvocation(recordTargetClass, "setCursorName", new Class[] {String.class}, new Object[] {name});
return;
}
for (Statement each : getRoutedStatements()) {
each.setCursorName(name);
}
}
@Override
public final int getUpdateCount() throws SQLException {
int result = 0;
for (Statement each : getRoutedStatements()) {
result += each.getUpdateCount();
}
return result;
}
@Override
public SQLWarning getWarnings() throws SQLException {
return null;
}
@Override
public void clearWarnings() throws SQLException {
}
/*
* 只有存储过程会出现多结果集, 因此不支持.
*/
@Override
public final boolean getMoreResults() throws SQLException {
return false;
}
@Override
public final boolean getMoreResults(final int current) throws SQLException {
return false;
}
/**
* 获取路由的静态语句对象集合.
*
* @return 路由的静态语句对象集合
* @throws SQLException
*/
public abstract Collection<? extends Statement> getRoutedStatements() throws SQLException;
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.adapter;
import java.sql.SQLException;
import java.sql.Wrapper;
import java.util.ArrayList;
import java.util.Collection;
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import com.dangdang.ddframe.rdb.sharding.jdbc.util.JdbcMethodInvocation;
/**
* JDBC Wrapper适配类.
*
* @author zhangliang
*/
public class WrapperAdapter implements Wrapper {
private Collection<JdbcMethodInvocation> jdbcMethodInvocations = new ArrayList<>();
@SuppressWarnings("unchecked")
@Override
public final <T> T unwrap(final Class<T> iface) throws SQLException {
if (isWrapperFor(iface)) {
return (T) this;
}
throw new SQLException(String.format("[%s] cannot be unwrapped as [%s]", getClass().getName(), iface.getName()));
}
@Override
public final boolean isWrapperFor(final Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
/**
* 记录方法调用.
*
* @param targetClass 目标类
* @param methodName 方法名称
* @param argumentTypes 参数类型
* @param arguments 参数
*/
protected final void recordMethodInvocation(final Class<?> targetClass, final String methodName, final Class<?>[] argumentTypes, final Object[] arguments) {
try {
jdbcMethodInvocations.add(new JdbcMethodInvocation(targetClass.getMethod(methodName, argumentTypes), arguments));
} catch (final NoSuchMethodException ex) {
throw new ShardingJdbcException(ex);
}
}
/**
* 回放记录的方法调用.
*
* @param target 目标对象
*/
protected final void replayMethodsInvovation(final Object target) {
for (JdbcMethodInvocation each : jdbcMethodInvocations) {
each.invoke(target);
}
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.unsupported;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.NClob;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.WrapperAdapter;
/**
* 声明不支持操作的数据库连接对象.
*
* @author zhangliang
*/
public abstract class AbstractUnsupportedOperationConnection extends WrapperAdapter implements Connection {
@Override
public final CallableStatement prepareCall(final String sql) throws SQLException {
throw new SQLFeatureNotSupportedException("prepareCall");
}
@Override
public final CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
throw new SQLFeatureNotSupportedException("prepareCall");
}
@Override
public final CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
throw new SQLFeatureNotSupportedException("prepareCall");
}
@Override
public final String nativeSQL(final String sql) throws SQLException {
throw new SQLFeatureNotSupportedException("nativeSQL");
}
@Override
public final Savepoint setSavepoint() throws SQLException {
throw new SQLFeatureNotSupportedException("setSavepoint");
}
@Override
public final Savepoint setSavepoint(final String name) throws SQLException {
throw new SQLFeatureNotSupportedException("setSavepoint name");
}
@Override
public final void releaseSavepoint(final Savepoint savepoint) throws SQLException {
throw new SQLFeatureNotSupportedException("releaseSavepoint");
}
@Override
public final void rollback(final Savepoint savepoint) throws SQLException {
throw new SQLFeatureNotSupportedException("rollback savepoint");
}
@Override
public final void abort(final Executor executor) throws SQLException {
throw new SQLFeatureNotSupportedException("abort");
}
@Override
public final String getCatalog() throws SQLException {
throw new SQLFeatureNotSupportedException("getCatalog");
}
@Override
public final void setCatalog(final String catalog) throws SQLException {
throw new SQLFeatureNotSupportedException("setCatalog");
}
@Override
public final String getSchema() throws SQLException {
throw new SQLFeatureNotSupportedException("getSchema");
}
@Override
public final void setSchema(final String schema) throws SQLException {
throw new SQLFeatureNotSupportedException("setSchema");
}
@Override
public final Map<String, Class<?>> getTypeMap() throws SQLException {
throw new SQLFeatureNotSupportedException("getTypeMap");
}
@Override
public final void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
throw new SQLFeatureNotSupportedException("setTypeMap");
}
@Override
public final int getNetworkTimeout() throws SQLException {
throw new SQLFeatureNotSupportedException("getNetworkTimeout");
}
@Override
public final void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
throw new SQLFeatureNotSupportedException("setNetworkTimeout");
}
@Override
public final Clob createClob() throws SQLException {
throw new SQLFeatureNotSupportedException("createClob");
}
@Override
public final Blob createBlob() throws SQLException {
throw new SQLFeatureNotSupportedException("createBlob");
}
@Override
public final NClob createNClob() throws SQLException {
throw new SQLFeatureNotSupportedException("createNClob");
}
@Override
public final SQLXML createSQLXML() throws SQLException {
throw new SQLFeatureNotSupportedException("createSQLXML");
}
@Override
public final Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
throw new SQLFeatureNotSupportedException("createArrayOf");
}
@Override
public final Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
throw new SQLFeatureNotSupportedException("createStruct");
}
@Override
public final boolean isValid(final int timeout) throws SQLException {
throw new SQLFeatureNotSupportedException("isValid");
}
@Override
public final Properties getClientInfo() throws SQLException {
throw new SQLFeatureNotSupportedException("getClientInfo");
}
@Override
public final String getClientInfo(final String name) throws SQLException {
throw new SQLFeatureNotSupportedException("getClientInfo name");
}
@Override
public final void setClientInfo(final String name, final String value) throws SQLClientInfoException {
throw new UnsupportedOperationException("setClientInfo name value");
}
@Override
public final void setClientInfo(final Properties properties) throws SQLClientInfoException {
throw new UnsupportedOperationException("setClientInfo properties");
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.unsupported;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import javax.sql.DataSource;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.WrapperAdapter;
/**
* 声明不支持操作的数据源对象.
*
* @author zhangliang
*/
public abstract class AbstractUnsupportedOperationDataSource extends WrapperAdapter implements DataSource {
@Override
public final int getLoginTimeout() throws SQLException {
throw new SQLFeatureNotSupportedException("unsupported getLoginTimeout()");
}
@Override
public final void setLoginTimeout(final int seconds) throws SQLException {
throw new SQLFeatureNotSupportedException("unsupported setLoginTimeout(int seconds)");
}
}
/**
* Copyright 1999-2015 dangdang.com.
* <p>
* 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.
* </p>
*/
package com.dangdang.ddframe.rdb.sharding.jdbc.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.dangdang.ddframe.rdb.sharding.exception.ShardingJdbcException;
import lombok.RequiredArgsConstructor;
/**
* 反射调用JDBC相关方法的工具类.
*
* @author gaohongtao
*/
@RequiredArgsConstructor
public final class JdbcMethodInvocation {
private final Method method;
private final Object[] arguments;
/**
*  调用方法.
*
* @param target 目标对象
*/
public void invoke(final Object target) {
try {
method.invoke(target, arguments);
} catch (final IllegalAccessException | InvocationTargetException ex) {
throw new ShardingJdbcException("Invoke jdbc method exception", ex);
}
}
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册