⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sqlcache.java

📁 Jena推理机
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 *  (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007 Hewlett-Packard Development Company, LP
 *  All rights reserved.
 *
 */

//=======================================================================
// Package
package com.hp.hpl.jena.db.impl;

//=======================================================================
// Imports
import java.sql.*;
import java.util.*;
import java.io.*;

import com.hp.hpl.jena.db.*;
import com.hp.hpl.jena.shared.JenaException;
import com.hp.hpl.jena.util.CollectionFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

//=======================================================================
/**
* Stores a set of sql statements loaded from a resource file.
* Caches prepared versions of the statements for a given db connection.
* <p>
* The resource file is located on the classpath and has the format:
* <pre>
* # comment at start of line
* operationName1
* sql code line 1
* ...
* sql code last line
*
* operationName2
* ...
* </pre>
* where the blank lines delimit one sql block from the next.
* <p>The sql code is typically a single SQL statement but some operations,
* specifically database initialization and cleanup may require a variable number
* of statments. To cater for this terminate each statement in those groups with
* the string ";;". Note that a single ";" is not used because these compound
* statements are often stored procedure definitions which end to have ";" line
* terminators!
*
* @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>.  Updated by hkuno to support GraphRDB.
* @version $Revision: 1.17 $ on $Date: 2007/01/02 11:50:42 $
*/

public class SQLCache {

//=======================================================================
// Variables

    /** Set of sql statements indexed by operation name. */
    protected Properties m_sql;

    /** Cache of prepared versions of the statements. Each map entry is a list
     *  of copies of the prepared statement for multi-threaded apps. */
    protected Map m_preparedStatements = CollectionFactory.createHashedMap();

	/** Track which cached, prepared statements are in use and the corresponding
	 *  list to which the statement should be returned. */
	protected Map m_cachedStmtInUse = CollectionFactory.createHashedMap();

    /** the packaged jdbc connection to the database itself. */
    protected IDBConnection m_connection;

    /** Maximum number of pre-prepared statements to keep for each operator. */
    protected static final int MAX_PS_CACHE = 4;

    /** Set to true to enable cache of pre-prepared statements. */
    protected boolean CACHE_PREPARED_STATEMENTS = true;

    static protected Log logger = LogFactory.getLog( SQLCache.class );
//=======================================================================
// Public interface

    /**
     * Constructor. Creates a new cache sql statements for interfacing to
     * a specific database.
     * @param sqlFile the name of the file of sql statements to load, this is
     * loaded from the classpath.
     * @param defaultOps Properties table which provides the default
     * sql statements, any definitions of a given operation in the loaded file
     * will override the default.
     * @param connection the jdbc connection to the database itself
     * @param idType the sql string to use for id types (substitutes for $id in files)
     */
    public SQLCache(String sqlFile, Properties defaultOps, IDBConnection connection, String idType) throws IOException {
        m_sql = loadSQLFile(sqlFile, defaultOps, idType);
        m_connection = connection;
    }

    /**
     * Set to true to enable cache of pre-prepared statements.
     */
    public void setCachePreparedStatements(boolean state) {
        CACHE_PREPARED_STATEMENTS = state;
    }

    /**
     * Return true if cache of pre-prepared statements is enabled.
     */
    public boolean getCachePreparedStatements() {
        return CACHE_PREPARED_STATEMENTS;
    }

    /**
     * Flush the cache of all currently prepared statements.
     */
    public void flushPreparedStatementCache() throws RDFRDBException {
        try {
            Iterator it = m_preparedStatements.values().iterator();
            while (it.hasNext()) {
                Iterator psit = ((List)it.next()).iterator();
                while (psit.hasNext()) {
                    ((PreparedStatement)psit.next()).close();
                }
            }
        } catch (SQLException e) {
            throw new RDFRDBException("Problem flushing PS cache", e);
        } finally {
            m_preparedStatements = CollectionFactory.createHashedMap();
			m_cachedStmtInUse = CollectionFactory.createHashedMap();
        }
    }
    /**
     * Return the associated jdbc connection.
     */
    public Connection getConnection() throws SQLException {
        return m_connection.getConnection();
    }

    /**
     * Set the associated jdbc connection.
     */
    public void setConnection(IDBConnection connection) {
        m_connection = connection;
    }

    /**
     * Return the raw SQL statement corresponding to the named operation.
     */
    public String getSQLStatement(String opname) throws SQLException {
        return getSQLStatement(opname, (String[]) null);
    }

    /**
     * Return the raw SQL statement corresponding to the named operation.
     * Substitute the ${a} attribute macro for the current attribute number.
     */
	public String getSQLStatement(String opname, String[] attr) throws SQLException {
		String cmd = m_sql.getProperty(opname);
		if (cmd == null) {
			if ( opname.startsWith("*") ) {
				cmd = genSQLStatement(opname);
				m_sql.setProperty(opname, cmd);
			} else {
				logger.error("Unable to find SQL for operation: " + opname);
				throw new SQLException("Unable to find SQL for operation: " + opname);
			}
		}
		int attrCnt = (attr == null) ? 0 : attr.length;
		if ( attrCnt > 0 ) cmd = substitute(cmd, "${a}", attr[0]);
		if ( attrCnt > 1 ) cmd = substitute(cmd, "${b}", attr[1]);
		if ( attrCnt > 2 ) cmd = substitute(cmd, "${c}", attr[2]);
		if ( attrCnt > 3 ) throw new JenaException("Too many arguments");

		return cmd;
	}

    
    
    public String getSQLStatement(String opname, String attr) throws SQLException {
		String[] param = {attr};
		return getSQLStatement(opname,param);
    }

	/**
	 * Return the raw SQL statement corresponding to the named operation.
	 * Attribute version - substitute the ${a} attribute macro for
	 * the current attribute number.
	 */
	public String getSQLStatement(String opname, String attrA, String attrB) throws SQLException {
		String[] param = {attrA,attrB};
		return getSQLStatement(opname,param);
	}

    /**
     * Return a set of raw SQL statements corresponding to the named operation.
     * This is used for compound operations where more than one SQL command is needed to
     * implement the operation (e.g. database formating and clean up). The
     * individual statements should be separated by double-semicolons at the end of the line.
     * <p>Needs refactoring to clarify what operations are and are not compound but for now
     * it is assumed the caller knows which is correct. Compound statements are not called
     * repeatedly so don't currently cache the parsed statement set.
     */
    public Collection getSQLStatementGroup(String opname) throws SQLException {
        String statementSrc = m_sql.getProperty(opname);
        if (statementSrc == null) {
            throw new SQLException("Unable to find SQL for operation: " + opname);
        }
        int start = 0;
        int split = 0;
        List statements = new LinkedList();
        while (split != -1) {
            split = statementSrc.indexOf(";;\n", start);
            String statement = null;
            if (split == -1) {
                statement = statementSrc.substring(start);
            } else {
                statement = statementSrc.substring(start, split);
                start = split +2;
            }
            if (!statement.trim().equals(""))
                statements.add(statement);
        }
        return statements;
    }

    /**
     * Return a prepared SQL statement corresponding to the named operation.
     * The statement should either be closed after use or returned to the
     * prepared statement pool using {@link #returnPreparedSQLStatement returnPreparedSQLStatement}
     * 
     * <p>Only works for single statements, not compound statements.
     * @param con the jdbc connection to use for preparing statements
     * @param opname the name of the sql operation to locate
     * @return a prepared SQL statement appropriate for the JDBC connection
     * used when this SQLCache was constructed or null if there is no such
     * operation or no such connection
     * 
     * 
     */
    
	public synchronized PreparedStatement getPreparedSQLStatement(String opname, String [] attr) throws SQLException {
		/* TODO extended calling format or statement format to support different
		 * result sets and conconcurrency modes.
		 */
		PreparedStatement ps=null;
		if (m_connection == null || opname == null) return null;
		int attrCnt = (attr == null) ? 0 : attr.length;
		String aop = opname;
		if ( attrCnt > 0 ) aop = concatOpName(aop, attr[0]);
		if ( attrCnt > 1 ) aop = concatOpName(aop, attr[1]);
		if ( attrCnt > 2 ) aop = concatOpName(aop, attr[2]);
		if ( attrCnt > 3 ) throw new JenaException("Too many arguments");
        
		List psl = (List) m_preparedStatements.get(aop);
		// OVERRIDE: added proper PreparedStatement removal.
		if (psl!=null && !psl.isEmpty()) {
			ps = (PreparedStatement) psl.remove(0);
			try{
    			ps.clearParameters();
    		}catch(SQLException e) {
    			ps.close();
    		}
		}
		if (ps == null) {
			String sql = getSQLStatement(opname, attr);
			if (sql == null) {
				throw new SQLException("No SQL defined for operation: " + opname);
			}
			if (psl == null && CACHE_PREPARED_STATEMENTS) {
				psl = new LinkedList();
				m_preparedStatements.put(aop, psl);
			} 
			ps = doPrepareSQLStatement(sql);
		}
		if ( CACHE_PREPARED_STATEMENTS ) m_cachedStmtInUse.put(ps,psl);
		return ps;
	}
	
	/**
	 * Prepare a SQL statement for the given statement string.
	 *  
	 * <p>Only works for single statements, not compound statements.
	 * @param stmt the sql statement to prepare.
	 * @return a prepared SQL statement appropriate for the JDBC connection
	 * used when this SQLCache was constructed or null if there is no such
	 * connection.
	 */

	private synchronized PreparedStatement doPrepareSQLStatement(String sql) throws SQLException {
		if (m_connection == null) return null;
		return getConnection().prepareStatement(sql);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -