Added "createTemporaryLob" flag to DefaultLobHandler, using JDBC 4.0's createBlob/Clob mechanism
Issue: SPR-10339
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -32,18 +32,20 @@ import org.apache.commons.logging.Log;
|
|||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of the {@link LobHandler} interface. Invokes
|
* Default implementation of the {@link LobHandler} interface.
|
||||||
* the direct accessor methods that {@code java.sql.ResultSet}
|
* Invokes the direct accessor methods that {@code java.sql.ResultSet}
|
||||||
* and {@code java.sql.PreparedStatement} offer.
|
* and {@code java.sql.PreparedStatement} offer.
|
||||||
*
|
*
|
||||||
* <p>This LobHandler should work for any JDBC driver that is JDBC compliant
|
* <p>This LobHandler should work for any JDBC driver that is JDBC compliant
|
||||||
* in terms of the spec's suggestions regarding simple BLOB and CLOB handling.
|
* in terms of the spec's suggestions regarding simple BLOB and CLOB handling.
|
||||||
* This does not apply to Oracle 9i, and only to a limited degree to Oracle 10g!
|
* This does not apply to Oracle 9i's drivers at all; as of Oracle 10g,
|
||||||
* As a consequence, use {@link OracleLobHandler} for accessing Oracle BLOBs/CLOBs.
|
* it does work but may still come with LOB size limitations. Consider using
|
||||||
|
* recent Oracle drivers even when working against an older database server.
|
||||||
|
* See the {@link LobHandler} javadoc for the full set of recommendations.
|
||||||
*
|
*
|
||||||
* <p>Some JDBC drivers require values with a BLOB/CLOB target column to be
|
* <p>Some JDBC drivers require values with a BLOB/CLOB target column to be
|
||||||
* explicitly set through the JDBC {@code setBlob} / {@code setClob}
|
* explicitly set through the JDBC {@code setBlob} / {@code setClob} API:
|
||||||
* API: for example, PostgreSQL's driver. Switch the {@link #setWrapAsLob "wrapAsLob"}
|
* for example, PostgreSQL's driver. Switch the {@link #setWrapAsLob "wrapAsLob"}
|
||||||
* property to "true" when operating against such a driver.
|
* property to "true" when operating against such a driver.
|
||||||
*
|
*
|
||||||
* <p>On JDBC 4.0, this LobHandler also supports streaming the BLOB/CLOB content
|
* <p>On JDBC 4.0, this LobHandler also supports streaming the BLOB/CLOB content
|
||||||
@@ -51,11 +53,15 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
* argument directly. Consider switching the {@link #setStreamAsLob "streamAsLob"}
|
* argument directly. Consider switching the {@link #setStreamAsLob "streamAsLob"}
|
||||||
* property to "true" when operating against a fully compliant JDBC 4.0 driver.
|
* property to "true" when operating against a fully compliant JDBC 4.0 driver.
|
||||||
*
|
*
|
||||||
* <p>See the {@link LobHandler} javadoc for a summary of recommendations.
|
* <p>Finally, primarily as a direct equivalent to {@link OracleLobHandler},
|
||||||
|
* this LobHandler also supports the creation of temporary BLOB/CLOB objects.
|
||||||
|
* Consider switching the {@link #setCreateTemporaryLob "createTemporaryLob"}
|
||||||
|
* property to "true" when "streamAsLob" happens to run into LOB size limitations.
|
||||||
|
*
|
||||||
|
* <p>See the {@link LobHandler} interface javadoc for a summary of recommendations.
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 04.12.2003
|
* @since 04.12.2003
|
||||||
* @see #setStreamAsLob
|
|
||||||
* @see java.sql.ResultSet#getBytes
|
* @see java.sql.ResultSet#getBytes
|
||||||
* @see java.sql.ResultSet#getBinaryStream
|
* @see java.sql.ResultSet#getBinaryStream
|
||||||
* @see java.sql.ResultSet#getString
|
* @see java.sql.ResultSet#getString
|
||||||
@@ -75,15 +81,18 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
|
|
||||||
private boolean streamAsLob = false;
|
private boolean streamAsLob = false;
|
||||||
|
|
||||||
|
private boolean createTemporaryLob = false;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify whether to submit a byte array / String to the JDBC driver
|
* Specify whether to submit a byte array / String to the JDBC driver
|
||||||
* wrapped in a JDBC Blob / Clob object, using the JDBC {@code setBlob} /
|
* wrapped in a JDBC Blob / Clob object, using the JDBC {@code setBlob} /
|
||||||
* {@code setClob} method with a Blob / Clob argument.
|
* {@code setClob} method with a Blob / Clob argument.
|
||||||
* <p>Default is "false", using the common JDBC 2.0 {@code setBinaryStream}
|
* <p>Default is "false", using the common JDBC 2.0 {@code setBinaryStream}
|
||||||
* / {@code setCharacterStream} method for setting the content.
|
* / {@code setCharacterStream} method for setting the content. Switch this
|
||||||
* Switch this to "true" for explicit Blob / Clob wrapping against
|
* to "true" for explicit Blob / Clob wrapping against JDBC drivers that
|
||||||
* JDBC drivers that are known to require such wrapping (e.g. PostgreSQL's).
|
* are known to require such wrapping (e.g. PostgreSQL's for access to OID
|
||||||
|
* columns, whereas BYTEA columns need to be accessed the standard way).
|
||||||
* <p>This setting affects byte array / String arguments as well as stream
|
* <p>This setting affects byte array / String arguments as well as stream
|
||||||
* arguments, unless {@link #setStreamAsLob "streamAsLob"} overrides this
|
* arguments, unless {@link #setStreamAsLob "streamAsLob"} overrides this
|
||||||
* handling to use JDBC 4.0's new explicit streaming support (if available).
|
* handling to use JDBC 4.0's new explicit streaming support (if available).
|
||||||
@@ -100,7 +109,7 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
* {@code setClob} method with a stream argument.
|
* {@code setClob} method with a stream argument.
|
||||||
* <p>Default is "false", using the common JDBC 2.0 {@code setBinaryStream}
|
* <p>Default is "false", using the common JDBC 2.0 {@code setBinaryStream}
|
||||||
* / {@code setCharacterStream} method for setting the content.
|
* / {@code setCharacterStream} method for setting the content.
|
||||||
* Switch this to "true" for explicit JDBC 4.0 usage, provided that your
|
* Switch this to "true" for explicit JDBC 4.0 streaming, provided that your
|
||||||
* JDBC driver actually supports those JDBC 4.0 operations (e.g. Derby's).
|
* JDBC driver actually supports those JDBC 4.0 operations (e.g. Derby's).
|
||||||
* <p>This setting affects stream arguments as well as byte array / String
|
* <p>This setting affects stream arguments as well as byte array / String
|
||||||
* arguments, requiring JDBC 4.0 support. For supporting LOB content against
|
* arguments, requiring JDBC 4.0 support. For supporting LOB content against
|
||||||
@@ -112,6 +121,23 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
this.streamAsLob = streamAsLob;
|
this.streamAsLob = streamAsLob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether to copy a byte array / String into a temporary JDBC
|
||||||
|
* Blob / Clob object created through the JDBC 4.0 {@code createBlob} /
|
||||||
|
* {@code createClob} methods.
|
||||||
|
* <p>Default is "false", using the common JDBC 2.0 {@code setBinaryStream}
|
||||||
|
* / {@code setCharacterStream} method for setting the content. Switch this
|
||||||
|
* to "true" for explicit Blob / Clob creation using JDBC 4.0.
|
||||||
|
* <p>This setting affects stream arguments as well as byte array / String
|
||||||
|
* arguments, requiring JDBC 4.0 support. For supporting LOB content against
|
||||||
|
* JDBC 3.0, check out the {@link #setWrapAsLob "wrapAsLob"} setting.
|
||||||
|
* @see java.sql.Connection#createBlob()
|
||||||
|
* @see java.sql.Connection#createClob()
|
||||||
|
*/
|
||||||
|
public void setCreateTemporaryLob(boolean createTemporaryLob) {
|
||||||
|
this.createTemporaryLob = createTemporaryLob;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException {
|
public byte[] getBlobAsBytes(ResultSet rs, int columnIndex) throws SQLException {
|
||||||
logger.debug("Returning BLOB as bytes");
|
logger.debug("Returning BLOB as bytes");
|
||||||
@@ -169,12 +195,12 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public LobCreator getLobCreator() {
|
public LobCreator getLobCreator() {
|
||||||
return new DefaultLobCreator();
|
return (this.createTemporaryLob ? new TemporaryLobCreator() : new DefaultLobCreator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default LobCreator implementation as inner class.
|
* Default LobCreator implementation as an inner class.
|
||||||
* Can be subclassed in DefaultLobHandler extensions.
|
* Can be subclassed in DefaultLobHandler extensions.
|
||||||
*/
|
*/
|
||||||
protected class DefaultLobCreator implements LobCreator {
|
protected class DefaultLobCreator implements LobCreator {
|
||||||
@@ -268,15 +294,10 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
PreparedStatement ps, int paramIndex, InputStream asciiStream, int contentLength)
|
PreparedStatement ps, int paramIndex, InputStream asciiStream, int contentLength)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
|
|
||||||
if (streamAsLob || wrapAsLob) {
|
if (streamAsLob) {
|
||||||
if (asciiStream != null) {
|
if (asciiStream != null) {
|
||||||
try {
|
try {
|
||||||
if (streamAsLob) {
|
ps.setClob(paramIndex, new InputStreamReader(asciiStream, "US-ASCII"), contentLength);
|
||||||
ps.setClob(paramIndex, new InputStreamReader(asciiStream, "US-ASCII"), contentLength);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ps.setClob(paramIndex, new PassThroughClob(asciiStream, contentLength));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (UnsupportedEncodingException ex) {
|
catch (UnsupportedEncodingException ex) {
|
||||||
throw new SQLException("US-ASCII encoding not supported: " + ex);
|
throw new SQLException("US-ASCII encoding not supported: " + ex);
|
||||||
@@ -286,6 +307,14 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
ps.setClob(paramIndex, (Clob) null);
|
ps.setClob(paramIndex, (Clob) null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (wrapAsLob) {
|
||||||
|
if (asciiStream != null) {
|
||||||
|
ps.setClob(paramIndex, new PassThroughClob(asciiStream, contentLength));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ps.setClob(paramIndex, (Clob) null);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
ps.setAsciiStream(paramIndex, asciiStream, contentLength);
|
ps.setAsciiStream(paramIndex, asciiStream, contentLength);
|
||||||
}
|
}
|
||||||
@@ -325,7 +354,7 @@ public class DefaultLobHandler extends AbstractLobHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
// nothing to do here
|
// nothing to do when not creating temporary LOBs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2012 the original author or authors.
|
* Copyright 2002-2013 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -24,7 +24,7 @@ import java.sql.SQLException;
|
|||||||
/**
|
/**
|
||||||
* Abstraction for handling large binary fields and large text fields in
|
* Abstraction for handling large binary fields and large text fields in
|
||||||
* specific databases, no matter if represented as simple types or Large OBjects.
|
* specific databases, no matter if represented as simple types or Large OBjects.
|
||||||
* Its main purpose is to isolate Oracle's peculiar handling of LOBs in
|
* Its main purpose is to isolate Oracle 9i's peculiar handling of LOBs in
|
||||||
* {@link OracleLobHandler}; most other databases should be able to work
|
* {@link OracleLobHandler}; most other databases should be able to work
|
||||||
* with the provided {@link DefaultLobHandler}.
|
* with the provided {@link DefaultLobHandler}.
|
||||||
*
|
*
|
||||||
@@ -45,8 +45,10 @@ import java.sql.SQLException;
|
|||||||
* proprietary BLOB/CLOB API, and additionally doesn't accept large streams for
|
* proprietary BLOB/CLOB API, and additionally doesn't accept large streams for
|
||||||
* PreparedStatement's corresponding setter methods. Therefore, you need to use
|
* PreparedStatement's corresponding setter methods. Therefore, you need to use
|
||||||
* {@link OracleLobHandler} there, which uses Oracle's BLOB/CLOB API for both types
|
* {@link OracleLobHandler} there, which uses Oracle's BLOB/CLOB API for both types
|
||||||
* of access. The Oracle 10g JDBC driver should basically work with
|
* of access. The Oracle 10g+ JDBC driver will work with {@link DefaultLobHandler}
|
||||||
* {@link DefaultLobHandler} as well, with some limitations in terms of LOB sizes.
|
* as well, with some limitations in terms of LOB sizes depending on DBMS setup;
|
||||||
|
* as of Oracle 11g (or actually, using the 11g driver even against older databases),
|
||||||
|
* there should be no need to use {@link OracleLobHandler} at all anymore.
|
||||||
*
|
*
|
||||||
* <p>Of course, you need to declare different field types for each database.
|
* <p>Of course, you need to declare different field types for each database.
|
||||||
* In Oracle, any binary content needs to go into a BLOB, and all character content
|
* In Oracle, any binary content needs to go into a BLOB, and all character content
|
||||||
@@ -57,12 +59,20 @@ import java.sql.SQLException;
|
|||||||
*
|
*
|
||||||
* <p><b>Summarizing the recommended options (for actual LOB fields):</b>
|
* <p><b>Summarizing the recommended options (for actual LOB fields):</b>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><b>JDBC 4.0 driver:</b> {@link DefaultLobHandler} with {@code streamAsLob=true}.
|
* <li><b>JDBC 4.0 driver (including Oracle 11g driver):</b> Use {@link DefaultLobHandler},
|
||||||
* <li><b>PostgreSQL:</b> {@link DefaultLobHandler} with {@code wrapAsLob=true}.
|
* potentially with {@code streamAsLob=true} if your database driver requires that
|
||||||
* <li><b>Oracle 9i/10g:</b> {@link OracleLobHandler} with a connection-pool-specific
|
* hint when populating a LOB field. Fall back to {@code createTemporaryLob=true}
|
||||||
|
* if you happen to run into LOB size limitations with your (Oracle) database setup.
|
||||||
|
* <li><b>Oracle 10g driver:</b> Use {@link DefaultLobHandler} with standard setup.
|
||||||
|
* On Oracle 10.1, set the "SetBigStringTryClob" connection property; as of Oracle 10.2,
|
||||||
|
* DefaultLobHandler should work with standard setup out of the box. Alternatively,
|
||||||
|
* consider using the proprietary {@link OracleLobHandler} (see below).
|
||||||
|
* <li><b>Oracle 9i driver:</b> Use {@link OracleLobHandler} with a connection-pool-specific
|
||||||
* {@link OracleLobHandler#setNativeJdbcExtractor NativeJdbcExtractor}.
|
* {@link OracleLobHandler#setNativeJdbcExtractor NativeJdbcExtractor}.
|
||||||
|
* <li><b>PostgreSQL:</b> Configure {@link DefaultLobHandler} with {@code wrapAsLob=true},
|
||||||
|
* and use that LobHandler to access OID columns (but not BYTEA) in your database tables.
|
||||||
* <li>For all other database drivers (and for non-LOB fields that might potentially
|
* <li>For all other database drivers (and for non-LOB fields that might potentially
|
||||||
* turn into LOBs on some databases): a plain {@link DefaultLobHandler}.
|
* turn into LOBs on some databases): Simply use a plain {@link DefaultLobHandler}.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
|||||||
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2013 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.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.sql.Blob;
|
||||||
|
import java.sql.Clob;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.dao.DataAccessResourceFailureException;
|
||||||
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link LobCreator} implementation based on temporary LOBs,
|
||||||
|
* using JDBC 4.0's {@link java.sql.Connection#createBlob()} /
|
||||||
|
* {@link java.sql.Connection#createClob()} mechanism.
|
||||||
|
*
|
||||||
|
* <p>Used by DefaultLobHandler's {@link DefaultLobHandler#setCreateTemporaryLob} mode.
|
||||||
|
* Can also be used directly to reuse the tracking and freeing of temporary LOBs.
|
||||||
|
*
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.2.2
|
||||||
|
* @see DefaultLobHandler#setCreateTemporaryLob
|
||||||
|
* @see java.sql.Connection#createBlob()
|
||||||
|
* @see java.sql.Connection#createClob()
|
||||||
|
*/
|
||||||
|
public class TemporaryLobCreator implements LobCreator {
|
||||||
|
|
||||||
|
protected static final Log logger = LogFactory.getLog(TemporaryLobCreator.class);
|
||||||
|
|
||||||
|
private final Set<Blob> temporaryBlobs = new LinkedHashSet<Blob>(1);
|
||||||
|
|
||||||
|
private final Set<Clob> temporaryClobs = new LinkedHashSet<Clob>(1);
|
||||||
|
|
||||||
|
|
||||||
|
public void setBlobAsBytes(PreparedStatement ps, int paramIndex, byte[] content)
|
||||||
|
throws SQLException {
|
||||||
|
|
||||||
|
Blob blob = ps.getConnection().createBlob();
|
||||||
|
blob.setBytes(1, content);
|
||||||
|
|
||||||
|
this.temporaryBlobs.add(blob);
|
||||||
|
ps.setBlob(paramIndex, blob);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(content != null ? "Copied bytes into temporary BLOB with length " + content.length :
|
||||||
|
"Set BLOB to null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlobAsBinaryStream(
|
||||||
|
PreparedStatement ps, int paramIndex, InputStream binaryStream, int contentLength)
|
||||||
|
throws SQLException {
|
||||||
|
|
||||||
|
Blob blob = ps.getConnection().createBlob();
|
||||||
|
try {
|
||||||
|
FileCopyUtils.copy(binaryStream, blob.setBinaryStream(1));
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.temporaryBlobs.add(blob);
|
||||||
|
ps.setBlob(paramIndex, blob);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(binaryStream != null ?
|
||||||
|
"Copied binary stream into temporary BLOB with length " + contentLength :
|
||||||
|
"Set BLOB to null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClobAsString(PreparedStatement ps, int paramIndex, String content)
|
||||||
|
throws SQLException {
|
||||||
|
|
||||||
|
Clob clob = ps.getConnection().createClob();
|
||||||
|
clob.setString(1, content);
|
||||||
|
|
||||||
|
this.temporaryClobs.add(clob);
|
||||||
|
ps.setClob(paramIndex, clob);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(content != null ? "Copied string into temporary CLOB with length " + content.length() :
|
||||||
|
"Set CLOB to null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClobAsAsciiStream(
|
||||||
|
PreparedStatement ps, int paramIndex, InputStream asciiStream, int contentLength)
|
||||||
|
throws SQLException {
|
||||||
|
|
||||||
|
Clob clob = ps.getConnection().createClob();
|
||||||
|
try {
|
||||||
|
FileCopyUtils.copy(asciiStream, clob.setAsciiStream(1));
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.temporaryClobs.add(clob);
|
||||||
|
ps.setClob(paramIndex, clob);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(asciiStream != null ?
|
||||||
|
"Copied ASCII stream into temporary CLOB with length " + contentLength :
|
||||||
|
"Set CLOB to null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClobAsCharacterStream(
|
||||||
|
PreparedStatement ps, int paramIndex, Reader characterStream, int contentLength)
|
||||||
|
throws SQLException {
|
||||||
|
|
||||||
|
Clob clob = ps.getConnection().createClob();
|
||||||
|
try {
|
||||||
|
FileCopyUtils.copy(characterStream, clob.setCharacterStream(1));
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.temporaryClobs.add(clob);
|
||||||
|
ps.setClob(paramIndex, clob);
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(characterStream != null ?
|
||||||
|
"Copied character stream into temporary CLOB with length " + contentLength :
|
||||||
|
"Set CLOB to null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
for (Blob blob : this.temporaryBlobs) {
|
||||||
|
blob.free();
|
||||||
|
}
|
||||||
|
for (Clob clob : this.temporaryClobs) {
|
||||||
|
clob.free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException ex) {
|
||||||
|
logger.error("Could not free LOB", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user