Skip to content

Commit

Permalink
fixed #196
Browse files Browse the repository at this point in the history
  • Loading branch information
terrymanu committed Aug 29, 2017
1 parent 097d4d8 commit a1606a3
Show file tree
Hide file tree
Showing 7 changed files with 350 additions and 5 deletions.
6 changes: 6 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.6.0

### 功能提升

1. [ISSUE #196](https://github.com/dangdangdotcom/sharding-jdbc/issues/196) 读写分离与分库分表配置独立

## 1.5.3

### 缺陷修正
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public abstract class AbstractConnectionAdapter extends AbstractUnsupportedOpera

private int transactionIsolation = TRANSACTION_READ_UNCOMMITTED;

protected abstract Collection<Connection> getConnections();
protected abstract Collection<Connection> getConnections() throws SQLException;

@Override
public final boolean getAutoCommit() throws SQLException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* 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.core.connection;

import com.dangdang.ddframe.rdb.sharding.constant.SQLType;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractConnectionAdapter;
import com.dangdang.ddframe.rdb.sharding.jdbc.core.datasource.MasterSlaveDataSource;
import com.dangdang.ddframe.rdb.sharding.jdbc.core.statement.MasterSlaveStatement;
import com.dangdang.ddframe.rdb.sharding.parsing.SQLJudgeEngine;
import com.dangdang.ddframe.rdb.sharding.parsing.parser.sql.SQLStatement;
import lombok.RequiredArgsConstructor;

import javax.sql.DataSource;
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.LinkedList;

/**
* Connection that support master-slave.
*
* @author zhangliang
*/
@RequiredArgsConstructor
public final class MasterSlaveConnection extends AbstractConnectionAdapter {

private final MasterSlaveDataSource masterSlaveDataSource;

/**
* Get database connections via SQL.
*
* <p>DDL, DQL and DML will return different database connections.</p>
*
* @param sql SQL
* @return database connections via SQL
* @throws SQLException SQL exception
*/
public Collection<Connection> getConnection(final String sql) throws SQLException {
Collection<DataSource> dataSources = new LinkedList<>();
SQLStatement sqlStatement = new SQLJudgeEngine(sql).judge();
if (SQLType.DDL == sqlStatement.getType()) {
dataSources.add(masterSlaveDataSource.getMasterDataSource());
dataSources.addAll(masterSlaveDataSource.getSlaveDataSources());
} else {
dataSources.add(masterSlaveDataSource.getDataSource(sqlStatement.getType()));
}
Collection<Connection> result = new LinkedList<>();
for (DataSource each : dataSources) {
result.add(each.getConnection());
replayMethodsInvocation(result);
}
return result;
}

@Override
public DatabaseMetaData getMetaData() throws SQLException {
return masterSlaveDataSource.getDataSource(SQLType.DML).getConnection().getMetaData();
}

@Override
public PreparedStatement prepareStatement(final String sql) throws SQLException {
Collection<Connection> connections = getConnection(sql);
if (1 != connections.size()) {
throw new UnsupportedOperationException("Cannot support DDL for prepare statement and master-slave only.");
}
return connections.iterator().next().prepareStatement(sql);
}

@Override
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
Collection<Connection> connections = getConnection(sql);
if (1 != connections.size()) {
throw new UnsupportedOperationException("Cannot support DDL for prepare statement and master-slave only.");
}
return connections.iterator().next().prepareStatement(sql, resultSetType, resultSetConcurrency);
}

@Override
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
Collection<Connection> connections = getConnection(sql);
if (1 != connections.size()) {
throw new UnsupportedOperationException("Cannot support DDL for prepare statement and master-slave only.");
}
return connections.iterator().next().prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}

@Override
public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
Collection<Connection> connections = getConnection(sql);
if (1 != connections.size()) {
throw new UnsupportedOperationException("Cannot support DDL for prepare statement and master-slave only.");
}
return connections.iterator().next().prepareStatement(sql, autoGeneratedKeys);
}

@Override
public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
Collection<Connection> connections = getConnection(sql);
if (1 != connections.size()) {
throw new UnsupportedOperationException("Cannot support DDL for prepare statement and master-slave only.");
}
return connections.iterator().next().prepareStatement(sql, columnIndexes);
}

@Override
public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
Collection<Connection> connections = getConnection(sql);
if (1 != connections.size()) {
throw new UnsupportedOperationException("Cannot support DDL for prepare statement and master-slave only.");
}
return connections.iterator().next().prepareStatement(sql, columnNames);
}

@Override
public Statement createStatement() throws SQLException {
return new MasterSlaveStatement(this);
}

@Override
public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
return new MasterSlaveStatement(this, resultSetType, resultSetConcurrency);
}

@Override
public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
return new MasterSlaveStatement(this, resultSetType, resultSetConcurrency, resultSetHoldability);
}

@Override
public Collection<Connection> getConnections() throws SQLException {
Collection<DataSource> dataSources = new LinkedList<>();
dataSources.add(masterSlaveDataSource.getMasterDataSource());
dataSources.addAll(masterSlaveDataSource.getSlaveDataSources());
Collection<Connection> result = new LinkedList<>();
for (DataSource each : dataSources) {
Connection connection = each.getConnection();
replayMethodsInvocation(connection);
result.add(connection);
}
return result;
}

@Override
public void close() throws SQLException {
HintManagerHolder.clear();
MasterSlaveDataSource.resetDMLFlag();
super.close();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ public Statement createStatement(final int resultSetType, final int resultSetCon
}

@Override
public Collection<Connection> getConnections() {
public Collection<Connection> getConnections() throws SQLException {
return connectionMap.values();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.dangdang.ddframe.rdb.sharding.constant.SQLType;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractDataSourceAdapter;
import com.dangdang.ddframe.rdb.sharding.jdbc.core.connection.MasterSlaveConnection;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import lombok.Getter;
Expand Down Expand Up @@ -118,7 +119,7 @@ public String getDatabaseProductName() throws SQLException {

@Override
public Connection getConnection() throws SQLException {
throw new UnsupportedOperationException("Master slave data source cannot support get connection directly.");
return new MasterSlaveConnection(this);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* 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.core.statement;

import com.dangdang.ddframe.rdb.sharding.jdbc.adapter.AbstractStatementAdapter;
import com.dangdang.ddframe.rdb.sharding.jdbc.core.connection.MasterSlaveConnection;
import com.google.common.base.Preconditions;
import lombok.AccessLevel;
import lombok.Getter;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Collection;

/**
* Statement that support master-slave.
*
* @author zhangliang
*/
public class MasterSlaveStatement extends AbstractStatementAdapter {

@Getter(AccessLevel.PROTECTED)
private final MasterSlaveConnection masterSlaveConnection;

@Getter
private final int resultSetType;

@Getter
private final int resultSetConcurrency;

@Getter
private final int resultSetHoldability;

private Statement statement;

public MasterSlaveStatement(final MasterSlaveConnection masterSlaveConnection) {
this(masterSlaveConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}

public MasterSlaveStatement(final MasterSlaveConnection masterSlaveConnection, final int resultSetType, final int resultSetConcurrency) {
this(masterSlaveConnection, resultSetType, resultSetConcurrency, ResultSet.HOLD_CURSORS_OVER_COMMIT);
}

public MasterSlaveStatement(final MasterSlaveConnection masterSlaveConnection, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) {
super(Statement.class);
this.masterSlaveConnection = masterSlaveConnection;
this.resultSetType = resultSetType;
this.resultSetConcurrency = resultSetConcurrency;
this.resultSetHoldability = resultSetHoldability;
}

@Override
public Connection getConnection() throws SQLException {
return masterSlaveConnection;
}

@Override
public ResultSet executeQuery(final String sql) throws SQLException {
Collection<Connection> connections = masterSlaveConnection.getConnection(sql);
Preconditions.checkState(1 == connections.size());
statement = connections.iterator().next().createStatement();
return statement.executeQuery(sql);
}

@Override
public int executeUpdate(final String sql) throws SQLException {
Collection<Connection> connections = masterSlaveConnection.getConnection(sql);
Preconditions.checkState(1 == connections.size());
statement = connections.iterator().next().createStatement();
return statement.executeUpdate(sql);
}

@Override
public int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException {
Collection<Connection> connections = masterSlaveConnection.getConnection(sql);
Preconditions.checkState(1 == connections.size());
statement = connections.iterator().next().createStatement();
return statement.executeUpdate(sql, autoGeneratedKeys);
}

@Override
public int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException {
Collection<Connection> connections = masterSlaveConnection.getConnection(sql);
Preconditions.checkState(1 == connections.size());
statement = connections.iterator().next().createStatement();
return statement.executeUpdate(sql, columnIndexes);
}

@Override
public int executeUpdate(final String sql, final String[] columnNames) throws SQLException {
Collection<Connection> connections = masterSlaveConnection.getConnection(sql);
Preconditions.checkState(1 == connections.size());
statement = connections.iterator().next().createStatement();
return statement.executeUpdate(sql, columnNames);
}

@Override
public boolean execute(final String sql) throws SQLException {
boolean result = false;
for (Connection each : masterSlaveConnection.getConnection(sql)) {
statement = each.createStatement();
result = statement.execute(sql);
}
return result;
}

@Override
public boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException {
boolean result = false;
for (Connection each : masterSlaveConnection.getConnection(sql)) {
statement = each.createStatement();
result = statement.execute(sql, autoGeneratedKeys);
}
return result;
}

@Override
public boolean execute(final String sql, final int[] columnIndexes) throws SQLException {
boolean result = false;
for (Connection each : masterSlaveConnection.getConnection(sql)) {
statement = each.createStatement();
result = statement.execute(sql, columnIndexes);
}
return result;
}

@Override
public boolean execute(final String sql, final String[] columnNames) throws SQLException {
boolean result = false;
for (Connection each : masterSlaveConnection.getConnection(sql)) {
statement = each.createStatement();
result = statement.execute(sql, columnNames);
}
return result;
}

@Override
public ResultSet getGeneratedKeys() throws SQLException {
return statement.getGeneratedKeys();
}

@Override
public ResultSet getResultSet() throws SQLException {
return statement.getResultSet();
}

@Override
protected Collection<? extends Statement> getRoutedStatements() {
return null;
}
}
Loading

0 comments on commit a1606a3

Please sign in to comment.