/* * Copyright 2004-2015 the Seasar Foundation and the Others. * * 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 org.seasar.extension.jdbc.manager; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.seasar.extension.jdbc.JdbcContext; import org.seasar.extension.jdbc.StatementHandler; import org.seasar.extension.jdbc.util.ConnectionUtil; import org.seasar.extension.jdbc.util.StatementCache; import org.seasar.framework.log.Logger; /** * {@link JdbcContext}の実装クラスです。 * * @author higa * */ public class JdbcContextImpl implements JdbcContext { private static final Logger logger = Logger .getLogger(JdbcContextImpl.class); private Connection connection; private Statement statement; private boolean transactional; private int preparedStatementCacheSize = 10; private int cursorPreparedStatementCacheSize = 5; private int callableStatementCacheSize = 5; private StatementCache preparedStatementCache = new StatementCache( preparedStatementCacheSize); private StatementCache cursorPreparedStatementCache = new StatementCache( cursorPreparedStatementCacheSize); private StatementCache callableStatementCache = new StatementCache( callableStatementCacheSize); /** * {@link JdbcContextImpl}を作成します。 * * @param connection * コネクション * @param transactional * トランザクション中に作成されたかどうか */ public JdbcContextImpl(Connection connection, boolean transactional) { this.connection = connection; this.transactional = transactional; } public void destroy() { if (connection == null) { return; } if (statement != null) { try { statement.close(); } catch (SQLException e) { logger.log(e); } statement = null; } try { preparedStatementCache.destroy(); } catch (SQLException e) { logger.log(e); } try { cursorPreparedStatementCache.destroy(); } catch (SQLException e) { logger.log(e); } try { callableStatementCache.destroy(); } catch (SQLException e) { logger.log(e); } try { connection.close(); } catch (SQLException e) { logger.log(e); } connection = null; } public boolean isTransactional() { return transactional; } public Statement getStatement() { if (statement != null) { return statement; } statement = ConnectionUtil.createStatement(connection); return statement; } @SuppressWarnings("unchecked") public PreparedStatement getPreparedStatement(String sql) { PreparedStatement ps = (PreparedStatement) preparedStatementCache .get(sql); if (ps != null) { return ps; } ps = ConnectionUtil.prepareStatement(connection, sql); preparedStatementCache.put(sql, ps); return ps; } @SuppressWarnings("unchecked") public <T> T usingPreparedStatement(String sql, StatementHandler<T, ? super PreparedStatement> handler) { PreparedStatement ps = (PreparedStatement) preparedStatementCache .remove(sql); if (ps == null) { ps = ConnectionUtil.prepareStatement(connection, sql); } try { return handler.handle(ps); } finally { preparedStatementCache.put(sql, ps); } } @SuppressWarnings("unchecked") public PreparedStatement getPreparedStatement(String sql, int autoGeneratedKeys) { final String key = new String(new StringBuilder(sql.length() + 12) .append('[').append(autoGeneratedKeys).append(']').append(sql)); PreparedStatement ps = (PreparedStatement) preparedStatementCache .get(key); if (ps != null) { return ps; } ps = ConnectionUtil .prepareStatement(connection, sql, autoGeneratedKeys); preparedStatementCache.put(key, ps); return ps; } @SuppressWarnings("unchecked") public <T> T usingPreparedStatement(String sql, int autoGeneratedKeys, StatementHandler<T, ? super PreparedStatement> handler) { final String key = new String(new StringBuilder(sql.length() + 12) .append('[').append(autoGeneratedKeys).append(']').append(sql)); PreparedStatement ps = (PreparedStatement) preparedStatementCache .remove(key); if (ps == null) { ps = ConnectionUtil.prepareStatement(connection, sql, autoGeneratedKeys); } try { return handler.handle(ps); } finally { preparedStatementCache.put(key, ps); } } @SuppressWarnings("unchecked") public PreparedStatement getCursorPreparedStatement(String sql) { PreparedStatement ps = (PreparedStatement) cursorPreparedStatementCache .get(sql); if (ps != null) { return ps; } ps = ConnectionUtil.prepareStatement(connection, sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); cursorPreparedStatementCache.put(sql, ps); return ps; } @SuppressWarnings("unchecked") public <T> T usingCursorPreparedStatement(String sql, StatementHandler<T, ? super PreparedStatement> handler) { PreparedStatement ps = (PreparedStatement) cursorPreparedStatementCache .remove(sql); if (ps == null) { ps = ConnectionUtil.prepareStatement(connection, sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); } try { return handler.handle(ps); } finally { cursorPreparedStatementCache.put(sql, ps); } } @SuppressWarnings("unchecked") public CallableStatement getCallableStatement(String sql) { CallableStatement cs = (CallableStatement) callableStatementCache .get(sql); if (cs != null) { return cs; } cs = ConnectionUtil.prepareCall(connection, sql); callableStatementCache.put(sql, cs); return cs; } @SuppressWarnings("unchecked") public <T> T usingCallableStatement(String sql, StatementHandler<T, ? super CallableStatement> handler) { CallableStatement cs = (CallableStatement) callableStatementCache .remove(sql); if (cs == null) { cs = ConnectionUtil.prepareCall(connection, sql); } try { return handler.handle(cs); } finally { callableStatementCache.put(sql, cs); } } /** * JDBCコンテキストが破棄されたかどうかを返します。 * * @return JDBCコンテキストが破棄されたかどうか */ public boolean idDestroyed() { return isConnectionNull(); } /** * コネクションが<code>null</code>かどうかを返します。 * * @return コネクションが<code>null</code>かどうか */ public boolean isConnectionNull() { return connection == null; } /** * ステートメントが<code>null</code>かどうかを返します。 * * @return ステートメントが<code>null</code>かどうか */ public boolean isStatementNull() { return statement == null; } /** * 準備されたステートメントのキャッシュが空かどうかを返します。 * * @return 準備されたステートメントのキャッシュが空かどうか */ public boolean isPreparedStatementCacheEmpty() { return preparedStatementCache.isEmpty(); } /** * カーソルつきの準備されたステートメントのキャッシュが空かどうかを返します。 * * @return カーソルつきの準備されたステートメントのキャッシュが空かどうか */ public boolean isCursorPreparedStatementCacheEmpty() { return cursorPreparedStatementCache.isEmpty(); } /** * 呼び出し可能なステートメントのキャッシュが空かどうかを返します。 * * @return 呼び出し可能なステートメントのキャッシュが空かどうか */ public boolean isCallableStatementCacheEmpty() { return callableStatementCache.isEmpty(); } /** * 準備されたステートメントをキャッシュする数を返します。 * * @return 準備されたステートメントをキャッシュする数 */ public int getPreparedStatementCacheSize() { return preparedStatementCacheSize; } /** * 準備されたステートメントをキャッシュする数を設定します。 * * @param preparedStatementCacheSize * 準備されたステートメントをキャッシュする数 */ public void setPreparedStatementCacheSize(int preparedStatementCacheSize) { this.preparedStatementCacheSize = preparedStatementCacheSize; preparedStatementCache = new StatementCache(preparedStatementCacheSize); } /** * カーソルつきの準備されたステートメントをキャッシュする数を返します。 * * @return カーソルつきの準備されたステートメントをキャッシュする数 */ public int getCursorPreparedStatementCacheSize() { return cursorPreparedStatementCacheSize; } /** * カーソルつきの準備されたステートメントをキャッシュする数を設定します。 * * @param cursorPreparedStatementCacheSize * カーソルつきの準備されたステートメントをキャッシュする数 */ public void setCursorPreparedStatementCacheSize( int cursorPreparedStatementCacheSize) { this.cursorPreparedStatementCacheSize = cursorPreparedStatementCacheSize; cursorPreparedStatementCache = new StatementCache( cursorPreparedStatementCacheSize); } /** * 呼び出し可能なステートメントをキャッシュする数を返します。 * * @return 呼び出し可能なステートメントをキャッシュする数 */ public int getCallableStatementCacheSize() { return callableStatementCacheSize; } /** * 呼び出し可能なステートメントをキャッシュする数を設定します。 * * @param callableStatementCacheSize * 呼び出し可能なステートメントをキャッシュする数 */ public void setCallableStatementCacheSize(int callableStatementCacheSize) { this.callableStatementCacheSize = callableStatementCacheSize; callableStatementCache = new StatementCache(callableStatementCacheSize); } }