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

📄 oraclelobhandler.java

📁 spring的源代码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 2002-2005 the original author or authors.
 * 
 * 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.springframework.jdbc.support.lob;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

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

import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
import org.springframework.util.FileCopyUtils;

/**
 * LobHandler implementation for Oracle databases. Uses proprietary API to
 * create <code>oracle.sql.BLOB</code> and <code>oracle.sql.CLOB</code>
 * instances, as necessary when working with Oracle's JDBC driver.
 * Note that this LobHandler requires Oracle JDBC driver 9i or higher!
 *
 * <p>While most databases are able to work with DefaultLobHandler, Oracle just
 * accepts Blob/Clob instances created via its own proprietary BLOB/CLOB API,
 * and additionally doesn't accept large streams for PreparedStatement's
 * corresponding setter methods. Therefore, you need to use a strategy like
 * this LobHandler implementation.
 *
 * <p>Needs to work on a native JDBC Connection, to be able to cast it to
 * <code>oracle.jdbc.OracleConnection</code>. If you pass in Connections from
 * a connection pool (the usual case in a J2EE environment), you need to set
 * an appropriate NativeJdbcExtractor to allow for automatical retrieval of
 * the underlying native JDBC Connection. LobHandler and NativeJdbcExtractor
 * are separate concerns, therefore they are represented by separate strategy
 * interfaces.
 *
 * <p>Coded via reflection to avoid dependencies on Oracle classes.
 * Even reads in Oracle constants via reflection because of different Oracle
 * drivers (classes12, ojdbc14) having different constant values! As this
 * LobHandler initializes Oracle classes on instantiation, do not define this
 * as eager-initializing singleton if you do not want to depend on the Oracle
 * JAR being in the class path: use "lazy-init=true" to avoid this issue.
 *
 * @author Juergen Hoeller
 * @since 04.12.2003
 * @see #setNativeJdbcExtractor
 * @see oracle.sql.BLOB
 * @see oracle.sql.CLOB
 */
public class OracleLobHandler extends AbstractLobHandler {

	private static final String BLOB_CLASS_NAME = "oracle.sql.BLOB";

	private static final String CLOB_CLASS_NAME = "oracle.sql.CLOB";

	private static final String DURATION_SESSION_FIELD_NAME = "DURATION_SESSION";

	private static final String MODE_READWRITE_FIELD_NAME = "MODE_READWRITE";


	protected final Log logger = LogFactory.getLog(getClass());

	private NativeJdbcExtractor nativeJdbcExtractor;

	private Boolean cache = Boolean.TRUE;

	private Class blobClass;

	private Class clobClass;

	private final Map durationSessionConstants = new HashMap(2);

	private final Map modeReadWriteConstants = new HashMap(2);


	/**
	 * Set an appropriate NativeJdbcExtractor to be able to retrieve the underlying
	 * native <code>oracle.jdbc.OracleConnection</code>. This is necessary for
	 * DataSource-based connection pools, as those need to return wrapped JDBC
	 * Connection handles that cannot be cast to a native Connection implementation.
	 * <p>Effectively, this LobHandler just invokes a single NativeJdbcExtractor
	 * method, namely <code>getNativeConnectionFromStatement</code> with a
	 * PreparedStatement argument (falling back to a
	 * <code>PreparedStatement.getConnection()</code> call if no extractor is set).
	 * <p>A common choice is SimpleNativeJdbcExtractor, whose Connection unwrapping
	 * (which is what OracleLobHandler needs) will work with many connection pools.
	 * See SimpleNativeJdbcExtractor's javadoc for details.
	 * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor#getNativeConnectionFromStatement
	 * @see org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor
	 * @see oracle.jdbc.OracleConnection
	 */
	public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
		this.nativeJdbcExtractor = nativeJdbcExtractor;
	}

	/**
	 * Set whether to cache the temporary LOB in the buffer cache.
	 * This value will be passed into BLOB/CLOB.createTemporary. Default is "true".
	 * @see oracle.sql.BLOB#createTemporary
	 * @see oracle.sql.CLOB#createTemporary
	 */
	public void setCache(boolean cache) {
		this.cache = new Boolean(cache);
	}


	/**
	 * Retrieve the <code>oracle.sql.BLOB</code> and <code>oracle.sql.CLOB</code>
	 * classes via reflection, and initialize the values for the
	 * DURATION_SESSION and MODE_READWRITE constants defined there.
	 * @param con the Oracle Connection, for using the exact same class loader
	 * that the Oracle driver was loaded with
	 * @see oracle.sql.BLOB#DURATION_SESSION
	 * @see oracle.sql.BLOB#MODE_READWRITE
	 * @see oracle.sql.CLOB#DURATION_SESSION
	 * @see oracle.sql.CLOB#MODE_READWRITE
	 */
	protected synchronized void initOracleDriverClasses(Connection con) {
		if (this.blobClass == null) {
			try {
				// Initialize oracle.sql.BLOB class
				this.blobClass = con.getClass().getClassLoader().loadClass(BLOB_CLASS_NAME);
				this.durationSessionConstants.put(
						this.blobClass, new Integer(this.blobClass.getField(DURATION_SESSION_FIELD_NAME).getInt(null)));
				this.modeReadWriteConstants.put(
						this.blobClass, new Integer(this.blobClass.getField(MODE_READWRITE_FIELD_NAME).getInt(null)));

				// Initialize oracle.sql.CLOB class
				this.clobClass = con.getClass().getClassLoader().loadClass(CLOB_CLASS_NAME);
				this.durationSessionConstants.put(
						this.clobClass, new Integer(this.clobClass.getField(DURATION_SESSION_FIELD_NAME).getInt(null)));
				this.modeReadWriteConstants.put(
						this.clobClass, new Integer(this.clobClass.getField(MODE_READWRITE_FIELD_NAME).getInt(null)));
			}
			catch (Exception ex) {
				throw new InvalidDataAccessApiUsageException(
						"Couldn't initialize OracleLobHandler because Oracle driver classes are not available. " +
						"Note that OracleLobHandler requires Oracle JDBC driver 9i or higher!", ex);
			}
		}
	}


	public byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException {
		logger.debug("Returning Oracle BLOB as bytes");
		Blob blob = rs.getBlob(columnIndex);
		return (blob != null ? blob.getBytes(1, (int) blob.length()) : null);
	}

	public InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException {
		logger.debug("Returning Oracle BLOB as binary stream");
		Blob blob = rs.getBlob(columnIndex);
		return (blob != null ? blob.getBinaryStream() : null);
	}

	public String getClobAsString(ResultSet rs, int columnIndex) throws SQLException {
		logger.debug("Returning Oracle CLOB as string");
		Clob clob = rs.getClob(columnIndex);
		return (clob != null ? clob.getSubString(1, (int) clob.length()) : null);
	}

	public InputStream getClobAsAsciiStream(ResultSet rs, int columnIndex) throws SQLException {
		logger.debug("Returning Oracle CLOB as ASCII stream");
		Clob clob = rs.getClob(columnIndex);
		return (clob != null ? clob.getAsciiStream() : null);
	}

	public Reader getClobAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException {
		logger.debug("Returning Oracle CLOB as character stream");
		Clob clob = rs.getClob(columnIndex);
		return (clob != null ? clob.getCharacterStream() : null);
	}

	public LobCreator getLobCreator() {
		return new OracleLobCreator();
	}


	/**
	 * LobCreator implementation for Oracle databases.
	 * Creates Oracle-style temporary BLOBs and CLOBs that it frees on close.
	 * @see #close
	 */
	protected class OracleLobCreator implements LobCreator {

		private final List createdLobs = new LinkedList();

		public void setBlobAsBytes(PreparedStatement ps, int paramIndex, final byte[] content)
				throws SQLException {

			if (content != null) {
				Blob blob = (Blob) createLob(ps, false, new LobCallback() {

⌨️ 快捷键说明

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