001/* 002 * Copyright 2002-2013 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.jdbc.support.lob; 018 019import java.io.InputStream; 020import java.io.Reader; 021import java.sql.ResultSet; 022import java.sql.SQLException; 023 024/** 025 * Abstraction for handling large binary fields and large text fields in 026 * specific databases, no matter if represented as simple types or Large OBjects. 027 * Its main purpose is to isolate Oracle 9i's peculiar handling of LOBs in 028 * {@link OracleLobHandler}; most other databases should be able to work 029 * with the provided {@link DefaultLobHandler}. 030 * 031 * <p>Provides accessor methods for BLOBs and CLOBs, and acts as factory for 032 * LobCreator instances, to be used as sessions for creating BLOBs or CLOBs. 033 * LobCreators are typically instantiated for each statement execution or for 034 * each transaction; they are not thread-safe because they might track 035 * allocated database resources in order to free them after execution. 036 * 037 * <p>Most databases/drivers should be able to work with {@link DefaultLobHandler}, 038 * which by default delegates to JDBC's direct accessor methods, avoiding the 039 * {@code java.sql.Blob} and {@code java.sql.Clob} API completely. 040 * {@link DefaultLobHandler} can also be configured to access LOBs using 041 * {@code PreparedStatement.setBlob/setClob} (e.g. for PostgreSQL), through 042 * setting the {@link DefaultLobHandler#setWrapAsLob "wrapAsLob"} property. 043 * 044 * <p>Unfortunately, Oracle 9i just accepts Blob/Clob instances created via its own 045 * proprietary BLOB/CLOB API, and additionally doesn't accept large streams for 046 * PreparedStatement's corresponding setter methods. Therefore, you need to use 047 * {@link OracleLobHandler} there, which uses Oracle's BLOB/CLOB API for both types 048 * of access. The Oracle 10g+ JDBC driver will work with {@link DefaultLobHandler} 049 * as well, with some limitations in terms of LOB sizes depending on DBMS setup; 050 * as of Oracle 11g (or actually, using the 11g driver even against older databases), 051 * there should be no need to use {@link OracleLobHandler} at all anymore. 052 * 053 * <p>Of course, you need to declare different field types for each database. 054 * In Oracle, any binary content needs to go into a BLOB, and all character content 055 * beyond 4000 bytes needs to go into a CLOB. In MySQL, there is no notion of a 056 * CLOB type but rather a LONGTEXT type that behaves like a VARCHAR. For complete 057 * portability, use a LobHandler for fields that might typically require LOBs on 058 * some database because of the field size (take Oracle's numbers as a guideline). 059 * 060 * <p><b>Summarizing the recommended options (for actual LOB fields):</b> 061 * <ul> 062 * <li><b>JDBC 4.0 driver (including Oracle 11g driver):</b> Use {@link DefaultLobHandler}, 063 * potentially with {@code streamAsLob=true} if your database driver requires that 064 * hint when populating a LOB field. Fall back to {@code createTemporaryLob=true} 065 * if you happen to run into LOB size limitations with your (Oracle) database setup. 066 * <li><b>Oracle 10g driver:</b> Use {@link DefaultLobHandler} with standard setup. 067 * On Oracle 10.1, set the "SetBigStringTryClob" connection property; as of Oracle 10.2, 068 * DefaultLobHandler should work with standard setup out of the box. Alternatively, 069 * consider using the proprietary {@link OracleLobHandler} (see below). 070 * <li><b>Oracle 9i driver:</b> Use {@link OracleLobHandler} with a connection-pool-specific 071 * {@link OracleLobHandler#setNativeJdbcExtractor NativeJdbcExtractor}. 072 * <li><b>PostgreSQL:</b> Configure {@link DefaultLobHandler} with {@code wrapAsLob=true}, 073 * and use that LobHandler to access OID columns (but not BYTEA) in your database tables. 074 * <li>For all other database drivers (and for non-LOB fields that might potentially 075 * turn into LOBs on some databases): Simply use a plain {@link DefaultLobHandler}. 076 * </ul> 077 * 078 * @author Juergen Hoeller 079 * @since 23.12.2003 080 * @see DefaultLobHandler 081 * @see OracleLobHandler 082 * @see java.sql.ResultSet#getBlob 083 * @see java.sql.ResultSet#getClob 084 * @see java.sql.ResultSet#getBytes 085 * @see java.sql.ResultSet#getBinaryStream 086 * @see java.sql.ResultSet#getString 087 * @see java.sql.ResultSet#getAsciiStream 088 * @see java.sql.ResultSet#getCharacterStream 089 */ 090public interface LobHandler { 091 092 /** 093 * Retrieve the given column as bytes from the given ResultSet. 094 * Might simply invoke {@code ResultSet.getBytes} or work with 095 * {@code ResultSet.getBlob}, depending on the database and driver. 096 * @param rs the ResultSet to retrieve the content from 097 * @param columnName the column name to use 098 * @return the content as byte array, or {@code null} in case of SQL NULL 099 * @throws SQLException if thrown by JDBC methods 100 * @see java.sql.ResultSet#getBytes 101 */ 102 byte[] getBlobAsBytes(ResultSet rs, String columnName) throws SQLException; 103 104 /** 105 * Retrieve the given column as bytes from the given ResultSet. 106 * Might simply invoke {@code ResultSet.getBytes} or work with 107 * {@code ResultSet.getBlob}, depending on the database and driver. 108 * @param rs the ResultSet to retrieve the content from 109 * @param columnIndex the column index to use 110 * @return the content as byte array, or {@code null} in case of SQL NULL 111 * @throws SQLException if thrown by JDBC methods 112 * @see java.sql.ResultSet#getBytes 113 */ 114 byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException; 115 116 /** 117 * Retrieve the given column as binary stream from the given ResultSet. 118 * Might simply invoke {@code ResultSet.getBinaryStream} or work with 119 * {@code ResultSet.getBlob}, depending on the database and driver. 120 * @param rs the ResultSet to retrieve the content from 121 * @param columnName the column name to use 122 * @return the content as binary stream, or {@code null} in case of SQL NULL 123 * @throws SQLException if thrown by JDBC methods 124 * @see java.sql.ResultSet#getBinaryStream 125 */ 126 InputStream getBlobAsBinaryStream(ResultSet rs, String columnName) throws SQLException; 127 128 /** 129 * Retrieve the given column as binary stream from the given ResultSet. 130 * Might simply invoke {@code ResultSet.getBinaryStream} or work with 131 * {@code ResultSet.getBlob}, depending on the database and driver. 132 * @param rs the ResultSet to retrieve the content from 133 * @param columnIndex the column index to use 134 * @return the content as binary stream, or {@code null} in case of SQL NULL 135 * @throws SQLException if thrown by JDBC methods 136 * @see java.sql.ResultSet#getBinaryStream 137 */ 138 InputStream getBlobAsBinaryStream(ResultSet rs, int columnIndex) throws SQLException; 139 140 /** 141 * Retrieve the given column as String from the given ResultSet. 142 * Might simply invoke {@code ResultSet.getString} or work with 143 * {@code ResultSet.getClob}, depending on the database and driver. 144 * @param rs the ResultSet to retrieve the content from 145 * @param columnName the column name to use 146 * @return the content as String, or {@code null} in case of SQL NULL 147 * @throws SQLException if thrown by JDBC methods 148 * @see java.sql.ResultSet#getString 149 */ 150 String getClobAsString(ResultSet rs, String columnName) throws SQLException; 151 152 /** 153 * Retrieve the given column as String from the given ResultSet. 154 * Might simply invoke {@code ResultSet.getString} or work with 155 * {@code ResultSet.getClob}, depending on the database and driver. 156 * @param rs the ResultSet to retrieve the content from 157 * @param columnIndex the column index to use 158 * @return the content as String, or {@code null} in case of SQL NULL 159 * @throws SQLException if thrown by JDBC methods 160 * @see java.sql.ResultSet#getString 161 */ 162 String getClobAsString(ResultSet rs, int columnIndex) throws SQLException; 163 164 /** 165 * Retrieve the given column as ASCII stream from the given ResultSet. 166 * Might simply invoke {@code ResultSet.getAsciiStream} or work with 167 * {@code ResultSet.getClob}, depending on the database and driver. 168 * @param rs the ResultSet to retrieve the content from 169 * @param columnName the column name to use 170 * @return the content as ASCII stream, or {@code null} in case of SQL NULL 171 * @throws SQLException if thrown by JDBC methods 172 * @see java.sql.ResultSet#getAsciiStream 173 */ 174 InputStream getClobAsAsciiStream(ResultSet rs, String columnName) throws SQLException; 175 176 /** 177 * Retrieve the given column as ASCII stream from the given ResultSet. 178 * Might simply invoke {@code ResultSet.getAsciiStream} or work with 179 * {@code ResultSet.getClob}, depending on the database and driver. 180 * @param rs the ResultSet to retrieve the content from 181 * @param columnIndex the column index to use 182 * @return the content as ASCII stream, or {@code null} in case of SQL NULL 183 * @throws SQLException if thrown by JDBC methods 184 * @see java.sql.ResultSet#getAsciiStream 185 */ 186 InputStream getClobAsAsciiStream(ResultSet rs, int columnIndex) throws SQLException; 187 188 /** 189 * Retrieve the given column as character stream from the given ResultSet. 190 * Might simply invoke {@code ResultSet.getCharacterStream} or work with 191 * {@code ResultSet.getClob}, depending on the database and driver. 192 * @param rs the ResultSet to retrieve the content from 193 * @param columnName the column name to use 194 * @return the content as character stream 195 * @throws SQLException if thrown by JDBC methods 196 * @see java.sql.ResultSet#getCharacterStream 197 */ 198 Reader getClobAsCharacterStream(ResultSet rs, String columnName) throws SQLException; 199 200 /** 201 * Retrieve the given column as character stream from the given ResultSet. 202 * Might simply invoke {@code ResultSet.getCharacterStream} or work with 203 * {@code ResultSet.getClob}, depending on the database and driver. 204 * @param rs the ResultSet to retrieve the content from 205 * @param columnIndex the column index to use 206 * @return the content as character stream 207 * @throws SQLException if thrown by JDBC methods 208 * @see java.sql.ResultSet#getCharacterStream 209 */ 210 Reader getClobAsCharacterStream(ResultSet rs, int columnIndex) throws SQLException; 211 212 /** 213 * Create a new {@link LobCreator} instance, i.e. a session for creating BLOBs 214 * and CLOBs. Needs to be closed after the created LOBs are not needed anymore - 215 * typically after statement execution or transaction completion. 216 * @return the new LobCreator instance 217 * @see LobCreator#close() 218 */ 219 LobCreator getLobCreator(); 220 221}