All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.shardingsphere.shardingjdbc.jdbc.adapter.AbstractConnectionAdapter Maven / Gradle / Ivy

There is a newer version: 3.1.0
Show newest version
/*
 * Copyright 2016-2018 shardingsphere.io.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *

*/ package io.shardingsphere.shardingjdbc.jdbc.adapter; import com.google.common.base.Preconditions; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import io.shardingsphere.core.constant.ConnectionMode; import io.shardingsphere.core.constant.transaction.TransactionOperationType; import io.shardingsphere.core.constant.transaction.TransactionType; import io.shardingsphere.core.event.ShardingEventBusInstance; import io.shardingsphere.core.event.transaction.xa.XATransactionEvent; import io.shardingsphere.core.hint.HintManagerHolder; import io.shardingsphere.core.routing.router.masterslave.MasterVisitedManager; import io.shardingsphere.shardingjdbc.jdbc.adapter.executor.ForceExecuteCallback; import io.shardingsphere.shardingjdbc.jdbc.adapter.executor.ForceExecuteTemplate; import io.shardingsphere.shardingjdbc.jdbc.unsupported.AbstractUnsupportedOperationConnection; import io.shardingsphere.shardingjdbc.transaction.TransactionTypeHolder; import io.shardingsphere.spi.root.RootInvokeHook; import io.shardingsphere.spi.root.SPIRootInvokeHook; import javax.sql.DataSource; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * Adapter for {@code Connection}. * * @author zhangliang * @author panjuan */ public abstract class AbstractConnectionAdapter extends AbstractUnsupportedOperationConnection { private final Multimap cachedConnections = HashMultimap.create(); private boolean autoCommit = true; private boolean readOnly = true; private boolean closed; private int transactionIsolation = TRANSACTION_READ_UNCOMMITTED; private final ForceExecuteTemplate forceExecuteTemplate = new ForceExecuteTemplate<>(); private final ForceExecuteTemplate> forceExecuteTemplateForClose = new ForceExecuteTemplate<>(); private final RootInvokeHook rootInvokeHook = new SPIRootInvokeHook(); protected AbstractConnectionAdapter() { rootInvokeHook.start(); } /** * Get database connection. * * @param dataSourceName data source name * @return database connection * @throws SQLException SQL exception */ public final Connection getConnection(final String dataSourceName) throws SQLException { return getConnections(ConnectionMode.MEMORY_STRICTLY, dataSourceName, 1).get(0); } /** * Get database connections. * * @param connectionMode connection mode * @param dataSourceName data source name * @param connectionSize size of connection list to be get * @return database connections * @throws SQLException SQL exception */ public final List getConnections(final ConnectionMode connectionMode, final String dataSourceName, final int connectionSize) throws SQLException { DataSource dataSource = getDataSourceMap().get(dataSourceName); Preconditions.checkState(null != dataSource, "Missing the data source name: '%s'", dataSourceName); Collection connections; synchronized (cachedConnections) { connections = cachedConnections.get(dataSourceName); } List result; if (connections.size() >= connectionSize) { result = new ArrayList<>(connections).subList(0, connectionSize); } else if (!connections.isEmpty()) { result = new ArrayList<>(connectionSize); result.addAll(connections); List newConnections = createConnections(connectionMode, dataSource, connectionSize - connections.size()); result.addAll(newConnections); synchronized (cachedConnections) { cachedConnections.putAll(dataSourceName, newConnections); } } else { result = new ArrayList<>(createConnections(connectionMode, dataSource, connectionSize)); synchronized (cachedConnections) { cachedConnections.putAll(dataSourceName, result); } } return result; } @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter") private List createConnections(final ConnectionMode connectionMode, final DataSource dataSource, final int connectionSize) throws SQLException { if (1 == connectionSize) { return Collections.singletonList(createConnection(dataSource)); } if (ConnectionMode.CONNECTION_STRICTLY == connectionMode) { return createConnections(dataSource, connectionSize); } synchronized (dataSource) { return createConnections(dataSource, connectionSize); } } private List createConnections(final DataSource dataSource, final int connectionSize) throws SQLException { List result = new ArrayList<>(connectionSize); for (int i = 0; i < connectionSize; i++) { result.add(createConnection(dataSource)); } return result; } private Connection createConnection(final DataSource dataSource) throws SQLException { Connection result = dataSource.getConnection(); replayMethodsInvocation(result); return result; } protected abstract Map getDataSourceMap(); protected final void removeCache(final Connection connection) { cachedConnections.values().remove(connection); } @Override public final boolean getAutoCommit() { return autoCommit; } @Override public final void setAutoCommit(final boolean autoCommit) throws SQLException { this.autoCommit = autoCommit; if (TransactionType.LOCAL == TransactionTypeHolder.get()) { recordMethodInvocation(Connection.class, "setAutoCommit", new Class[]{boolean.class}, new Object[]{autoCommit}); forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallback() { @Override public void execute(final Connection connection) throws SQLException { connection.setAutoCommit(autoCommit); } }); } else if (TransactionType.XA == TransactionTypeHolder.get()) { ShardingEventBusInstance.getInstance().post(new XATransactionEvent(TransactionOperationType.BEGIN)); } } @Override public final void commit() throws SQLException { if (TransactionType.LOCAL == TransactionTypeHolder.get()) { forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallback() { @Override public void execute(final Connection connection) throws SQLException { connection.commit(); } }); } else if (TransactionType.XA == TransactionTypeHolder.get()) { ShardingEventBusInstance.getInstance().post(new XATransactionEvent(TransactionOperationType.COMMIT)); } } @Override public final void rollback() throws SQLException { if (TransactionType.LOCAL == TransactionTypeHolder.get()) { forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallback() { @Override public void execute(final Connection connection) throws SQLException { connection.rollback(); } }); } else if (TransactionType.XA == TransactionTypeHolder.get()) { ShardingEventBusInstance.getInstance().post(new XATransactionEvent(TransactionOperationType.ROLLBACK)); } } @Override public final void close() throws SQLException { if (closed) { return; } closed = true; HintManagerHolder.clear(); MasterVisitedManager.clear(); TransactionTypeHolder.clear(); int connectionSize = cachedConnections.size(); try { forceExecuteTemplateForClose.execute(cachedConnections.entries(), new ForceExecuteCallback>() { @Override public void execute(final Entry cachedConnections) throws SQLException { cachedConnections.getValue().close(); } }); } finally { rootInvokeHook.finish(connectionSize); } } @Override public final boolean isClosed() { return closed; } @Override public final boolean isReadOnly() { return readOnly; } @Override public final void setReadOnly(final boolean readOnly) throws SQLException { this.readOnly = readOnly; recordMethodInvocation(Connection.class, "setReadOnly", new Class[]{boolean.class}, new Object[]{readOnly}); forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallback() { @Override public void execute(final Connection connection) throws SQLException { connection.setReadOnly(readOnly); } }); } @Override public final int getTransactionIsolation() throws SQLException { if (cachedConnections.values().isEmpty()) { return transactionIsolation; } return cachedConnections.values().iterator().next().getTransactionIsolation(); } @Override public final void setTransactionIsolation(final int level) throws SQLException { transactionIsolation = level; recordMethodInvocation(Connection.class, "setTransactionIsolation", new Class[]{int.class}, new Object[]{level}); forceExecuteTemplate.execute(cachedConnections.values(), new ForceExecuteCallback() { @Override public void execute(final Connection connection) throws SQLException { connection.setTransactionIsolation(level); } }); } // ------- Consist with MySQL driver implementation ------- @Override public final SQLWarning getWarnings() { return null; } @Override public void clearWarnings() { } @Override public final int getHoldability() { return ResultSet.CLOSE_CURSORS_AT_COMMIT; } @Override public final void setHoldability(final int holdability) { } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy