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

org.jooq.tools.jdbc.BatchedConnection Maven / Gradle / Ivy

There is a newer version: 3.19.18
Show newest version
/*
 * 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.
 *
 * Other licenses:
 * -----------------------------------------------------------------------------
 * Commercial licenses for this work are available. These replace the above
 * Apache-2.0 license and offer limited warranties, support, maintenance, and
 * commercial database integrations.
 *
 * For more information, please visit: http://www.jooq.org/licenses
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package org.jooq.tools.jdbc;

import static java.util.Collections.emptyMap;
import static org.jooq.tools.jdbc.JDBCUtils.safeClose;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;

/**
 * A batching connection.
 * 

* This connection buffers consecutive identical prepared statements for * DELETE, INSERT, MERGE, * UPDATE statements, instead of allowing for them to be executed * directly. *

* Calls to {@link PreparedStatement#executeUpdate()} or * {@link PreparedStatement#execute()} are replaced by * {@link PreparedStatement#addBatch()}. The update count of such operations is * always zero, and cannot be retrieved later on. When any of the following * events happen, the batch is executed using {@link Statement#executeBatch()}: *

    *
  • The {@link BatchedConnection#close} method is called (the call is not * delegated to the wrapped connection).
  • *
  • A {@link Connection#prepareStatement(String)} call is made with a * different SQL string.
  • *
  • Any other type of statement is created or other API is called, such as * {@link #commit()}.
  • *
* * @author Lukas Eder */ public class BatchedConnection extends DefaultConnection { final int batchSize; String lastSQL; BatchedPreparedStatement lastStatement; public BatchedConnection(Connection delegate) { this(delegate, Integer.MAX_VALUE); } public BatchedConnection(Connection delegate, int batchSize) { super(delegate); this.batchSize = batchSize; } // ------------------------------------------------------------------------- // XXX: Wrappers // ------------------------------------------------------------------------- @SuppressWarnings("unchecked") @Override public T unwrap(Class iface) throws SQLException { return BatchedConnection.class == iface ? (T) this : super.unwrap(iface); } @Override public boolean isWrapperFor(Class iface) throws SQLException { return BatchedConnection.class == iface || super.isWrapperFor(iface); } // ------------------------------------------------------------------------- // XXX: Utilities // ------------------------------------------------------------------------- void executeLastBatch(String sql) throws SQLException { if (!sql.equals(lastSQL)) executeLastBatch(); } void executeLastBatch() throws SQLException { if (lastStatement != null) { if (lastStatement.batches > 0) lastStatement.executeBatch(); safeClose(lastStatement); } clearLastBatch(); } void clearLastBatch() { lastStatement = null; lastSQL = null; } void setBatch(BatchedPreparedStatement s) throws SQLException { if (lastStatement == s) return; if (lastStatement != null) executeLastBatch(); lastStatement = s; lastSQL = s.sql; } // ------------------------------------------------------------------------- // XXX: Creating non-batchable statements // ------------------------------------------------------------------------- @Override public Statement createStatement() throws SQLException { executeLastBatch(); return super.createStatement(); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { executeLastBatch(); return super.createStatement(resultSetType, resultSetConcurrency); } @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { executeLastBatch(); return super.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { executeLastBatch(); return super.prepareStatement(sql, resultSetType, resultSetConcurrency); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { executeLastBatch(); return super.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { executeLastBatch(); return super.prepareStatement(sql, autoGeneratedKeys); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { executeLastBatch(); return super.prepareStatement(sql, columnIndexes); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { executeLastBatch(); return super.prepareStatement(sql, columnNames); } @Override public CallableStatement prepareCall(String sql) throws SQLException { executeLastBatch(); return super.prepareCall(sql); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { executeLastBatch(); return super.prepareCall(sql, resultSetType, resultSetConcurrency); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { executeLastBatch(); return super.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); } // ------------------------------------------------------------------------- // XXX: Creating non-batchable statements // ------------------------------------------------------------------------- @Override public PreparedStatement prepareStatement(String sql) throws SQLException { executeLastBatch(sql); return lastStatement != null ? lastStatement : prepareStatement0(sql); } // TODO: Can we implement this in a more sophisticated way without invoking the costly parser? static final Pattern P_DML = Pattern.compile("\\s*(?i:delete|insert|merge|update).*"); private PreparedStatement prepareStatement0(String sql) throws SQLException { PreparedStatement result = super.prepareStatement(sql); if (P_DML.matcher(sql).matches()) { lastSQL = sql; return lastStatement = new BatchedPreparedStatement(sql, this, result); } else return result; } // ------------------------------------------------------------------------- // XXX: Ignored operations // ------------------------------------------------------------------------- @Override public void commit() throws SQLException { executeLastBatch(); super.commit(); } @Override public void rollback() throws SQLException { executeLastBatch(); super.rollback(); } @Override public void rollback(Savepoint savepoint) throws SQLException { executeLastBatch(); super.rollback(savepoint); } @Override public void close() throws SQLException { executeLastBatch(); } @Override public Savepoint setSavepoint() throws SQLException { executeLastBatch(); return super.setSavepoint(); } @Override public Savepoint setSavepoint(String name) throws SQLException { executeLastBatch(); return super.setSavepoint(name); } @Override public void releaseSavepoint(Savepoint savepoint) throws SQLException { executeLastBatch(); super.releaseSavepoint(savepoint); } @Override public void setAutoCommit(boolean autoCommit) throws SQLException { executeLastBatch(); super.setAutoCommit(autoCommit); } @Override public boolean getAutoCommit() throws SQLException { executeLastBatch(); return super.getAutoCommit(); } @Override public void setReadOnly(boolean readOnly) throws SQLException { executeLastBatch(); super.setReadOnly(readOnly); } @Override public boolean isReadOnly() throws SQLException { executeLastBatch(); return super.isReadOnly(); } @Override public void setCatalog(String catalog) throws SQLException { executeLastBatch(); super.setCatalog(catalog); } @Override public String getCatalog() throws SQLException { executeLastBatch(); return super.getCatalog(); } @Override public SQLWarning getWarnings() throws SQLException { executeLastBatch(); return super.getWarnings(); } @Override public void clearWarnings() throws SQLException { executeLastBatch(); super.clearWarnings(); } @Override public void setTransactionIsolation(int level) throws SQLException { executeLastBatch(); super.setTransactionIsolation(level); } @Override public int getTransactionIsolation() throws SQLException { executeLastBatch(); return super.getTransactionIsolation(); } @Override public void setTypeMap(Map> map) throws SQLException { executeLastBatch(); super.setTypeMap(map); } @Override public Map> getTypeMap() throws SQLException { executeLastBatch(); return super.getTypeMap(); } @Override public void setHoldability(int holdability) throws SQLException { executeLastBatch(); super.setHoldability(holdability); } @Override public int getHoldability() throws SQLException { executeLastBatch(); return super.getHoldability(); } @Override public boolean isValid(int timeout) throws SQLException { executeLastBatch(); return super.isValid(timeout); } @Override public void setClientInfo(String name, String value) throws SQLClientInfoException { try { executeLastBatch(); } catch (SQLException e) { throw new SQLClientInfoException(emptyMap(), e); } super.setClientInfo(name, value); } @Override public void setClientInfo(Properties properties) throws SQLClientInfoException { try { executeLastBatch(); } catch (SQLException e) { throw new SQLClientInfoException(emptyMap(), e); } super.setClientInfo(properties); } @Override public String getClientInfo(String name) throws SQLException { executeLastBatch(); return super.getClientInfo(name); } @Override public Properties getClientInfo() throws SQLException { executeLastBatch(); return super.getClientInfo(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy