Java SpringJDBC-将blob数组传递给SQL函数
我试图传入一个Java SpringJDBC-将blob数组传递给SQL函数,java,sql,spring,oracle,jdbc,Java,Sql,Spring,Oracle,Jdbc,我试图传入一个数组的BLOBs,但我得到了错误 uploadFiles = new SimpleJdbcCall(dataSource).withCatalogName("FILES_PKG") .withFunctionName("insertFiles").withReturnValue() .declareParameters(new SqlParameter("p_userId", Types.NUMERIC
数组的BLOB
s,但我得到了错误
uploadFiles = new SimpleJdbcCall(dataSource).withCatalogName("FILES_PKG")
.withFunctionName("insertFiles").withReturnValue()
.declareParameters(new SqlParameter("p_userId", Types.NUMERIC),
new SqlParameter("p_data", Types.ARRAY, "BLOB_ARRAY"),
new SqlOutParameter("v_groupId", Types.NUMERIC));
uploadFiles.compile();
List<Blob> fileBlobs = new ArrayList<>();
for(int x = 0; x < byteFiles.size(); x++){
fileBlobs.add(new javax.sql.rowset.serial.SerialBlob(byteFiles.get(x)));
}
final Blob[] data = fileBlobs.toArray(new Blob[fileBlobs.size()]);
SqlParameterSource in = new MapSqlParameterSource()
.addValue("p_files", new SqlArrayValue<Blob>(data, "BLOB_ARRAY"))
.addValue("p_userId", userId);
Map<String, Object> results = uploadFiles.execute(in);
功能规格
FUNCTION insertFiles(p_userId IN NUMBER,
p_files IN BLOB_ARRAY)
RETURN NUMBER;
功能体
FUNCTION insertFiles (p_userId IN NUMBER,
p_files IN BLOB_ARRAY)
RETURN NUMBER
AS
v_groupId NUMBER := FILE_GROUP_ID_SEQ.NEXTVAL;
v_fileId NUMBER;
BEGIN
FOR i IN 1..p_files.COUNT
LOOP
v_fileId := FILE_ID_SEQ.NEXTVAL;
BEGIN
INSERT INTO FILES
(FILE_ID,
FILE_GROUP_ID,
FILE_DATA,
UPDT_USER_ID)
SELECT
v_fileId,
v_groupId,
p_files(i),
USER_ID
FROM USERS
WHERE USER_ID = p_userId;
EXCEPTION WHEN OTHERS THEN
v_groupId := -1;
END;
END LOOP;
RETURN v_groupId;
END insertFiles;
我不知道如何正确地将blob数组传递给SQL函数
错误:
java.sql.SQLException:无法转换为内部表示形式:
javax.sql.rowset.serial。SerialBlob@87829c90在
oracle.jdbc.oracore.OracleTypeBLOB.toDatum(OracleTypeBLOB.java:69)
~[ojdbc7.jar:12.1.0.1.0]at
oracle.jdbc.oracore.OracleType.toDatumArray(OracleType.java:176)
~[ojdbc7.jar:12.1.0.1.0]at
toOracleArray(ArrayDescriptor.java:1321)
~[ojdbc7.jar:12.1.0.1.0]位于oracle.sql.ARRAY.(ARRAY.java:140)
~[ojdbc7.jar:12.1.0.1.0]at
更新
在尝试了Luke的建议后,我发现以下错误:
SQL[{?=call FILES_PKG.INSERTFILES(?)的未分类SQLException?,
?)}]; SQL状态[99999];错误代码[22922];ORA-22922:不存在
LOB值;嵌套异常为java.sql.SQLException:ORA-22922:
不存在具有根本原因的LOB值]
java.sql.SQLException:ORA-22922:不存在LOB值
出现的错误消息表明Oracle JDBC驱动程序不知道如何处理传递给它的javax.sql.rowset.serial.SerialBlob对象
尝试使用创建Blob
对象。换句话说,尝试替换以下内容
环路
我已经使用您现在在问题中包含的存储函数对此进行了测试,它能够调用此函数并将BLOB
s插入数据库
我将让您对变量result
执行您认为合适的操作,并添加任何必要的清理或事务控制
然而,尽管这种方法有效,但感觉并不正确。它不适合春天的做事方式。它至少证明了您所要求的是可能的,因为JDBC驱动程序中没有一些限制,这意味着您不能使用BLOB
数组。我觉得应该有办法使用SpringJDBC调用函数
我花了一些时间研究ORA-22922错误,并得出结论,根本问题在于Blob
对象是使用与执行语句所用的连接不同的来创建的。接下来的问题是如何获得Spring使用的连接
在深入挖掘了各种Spring类的源代码之后,我意识到一种更像Spring的方法是将SqlArrayValue
类替换为一个专门用于BLOB
数组的类。这就是我的结局:
import java.sql.Array;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import oracle.jdbc.OracleConnection;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;
public class SqlBlobArrayValue extends AbstractSqlTypeValue {
private List<byte[]> values;
private String defaultTypeName;
public SqlBlobArrayValue(List<byte[]> values) {
this.values = values;
}
public SqlBlobArrayValue(List<byte[]> values, String defaultTypeName) {
this.values = values;
this.defaultTypeName = defaultTypeName;
}
protected Object createTypeValue(Connection conn, int sqlType, String typeName)
throws SQLException {
if (typeName == null && defaultTypeName == null) {
throw new InvalidDataAccessApiUsageException(
"The typeName is null in this context. Consider setting the defaultTypeName.");
}
Blob[] blobs = new Blob[values.size()];
for (int i = 0; i < blobs.length; ++i) {
Blob blob = conn.createBlob();
blob.setBytes(1, values.get(i));
blobs[i] = blob;
}
Array array = conn.unwrap(OracleConnection.class).createOracleArray(typeName != null ? typeName : defaultTypeName, blobs);
return array;
}
}
出现的错误消息表明Oracle JDBC驱动程序不知道如何处理传递给它的javax.sql.rowset.serial.SerialBlob对象
尝试使用创建Blob
对象。换句话说,尝试替换以下内容
环路
我已经使用您现在在问题中包含的存储函数对此进行了测试,它能够调用此函数并将BLOB
s插入数据库
我将让您对变量result
执行您认为合适的操作,并添加任何必要的清理或事务控制
然而,尽管这种方法有效,但感觉并不正确。它不适合春天的做事方式。它至少证明了您所要求的是可能的,因为JDBC驱动程序中没有一些限制,这意味着您不能使用BLOB
数组。我觉得应该有办法使用SpringJDBC调用函数
我花了一些时间研究ORA-22922错误,并得出结论,根本问题在于Blob
对象是使用与执行语句所用的连接不同的来创建的。接下来的问题是如何获得Spring使用的连接
在深入挖掘了各种Spring类的源代码之后,我意识到一种更像Spring的方法是将SqlArrayValue
类替换为一个专门用于BLOB
数组的类。这就是我的结局:
import java.sql.Array;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import oracle.jdbc.OracleConnection;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;
public class SqlBlobArrayValue extends AbstractSqlTypeValue {
private List<byte[]> values;
private String defaultTypeName;
public SqlBlobArrayValue(List<byte[]> values) {
this.values = values;
}
public SqlBlobArrayValue(List<byte[]> values, String defaultTypeName) {
this.values = values;
this.defaultTypeName = defaultTypeName;
}
protected Object createTypeValue(Connection conn, int sqlType, String typeName)
throws SQLException {
if (typeName == null && defaultTypeName == null) {
throw new InvalidDataAccessApiUsageException(
"The typeName is null in this context. Consider setting the defaultTypeName.");
}
Blob[] blobs = new Blob[values.size()];
for (int i = 0; i < blobs.length; ++i) {
Blob blob = conn.createBlob();
blob.setBytes(1, values.get(i));
blobs[i] = blob;
}
Array array = conn.unwrap(OracleConnection.class).createOracleArray(typeName != null ? typeName : defaultTypeName, blobs);
return array;
}
}
谢谢你的回复,我更新了我的问题。在使用连接创建BLOB
时,我似乎遇到了另一个错误。我还使参数名保持一致。@Alan:很抱歉您的代码仍然返回错误。这可能是我的错,因为我没有费心编写一个适当的存储函数来进行测试!我已经编辑了我的答案,添加了一个“普通”的JDBC方法,这对我来说很有效,因为我可以使用它来调用您的函数。谢谢!几天来,我一直在为这个问题绞尽脑汁,并一直试图用“Spring”的方式来解决这个问题,但似乎效果很好。@Alan:如果您感兴趣,我已经设法想出了一种更像Spring的方法来调用您的函数。我编辑了我的答案,把它包括进去。太棒了!谢谢您的更新。:)我可能会用“弹性方式”结束谢谢你的回答,我更新了我的问题。在使用连接创建BLOB
时,我似乎遇到了另一个错误。我还使参数名保持一致。@Alan:很抱歉您的代码仍然返回错误。这可能是我的错,因为我没有费心编写一个适当的存储函数来进行测试!我已经编辑了我的答案,添加了一个“普通”的JDBC方法,这对我来说很有效,因为我可以使用它来调用您的函数。谢谢!几天来,我一直在为这个问题绞尽脑汁,并一直试图用“春天”的方式来解决它,而这似乎效果很好。@Alan:如果你有兴趣,我已经设法想出了一个更像春天的ap
Connection conn = dataSource.getConnection();
for(int x = 0; x < byteFiles.size(); x++){
Blob blob = conn.createBlob();
blob.setBytes(1, byteFiles.get(x));
fileBlobs.add(blob);
}
import oracle.jdbc.OracleConnection;
// ...
OracleConnection conn = dataSource.getConnection().unwrap(OracleConnection.class);
List<Blob> fileBlobs = new ArrayList<>();
for(int x = 0; x < byteFiles.size(); x++){
Blob blob = conn.createBlob();
blob.setBytes(1, byteFiles.get(x));
fileBlobs.add(blob);
}
Array array = conn.createOracleArray("BLOB_ARRAY",
fileBlobs.toArray(new Blob[fileBlobs.size()]));
CallableStatement cstmt = conn.prepareCall("{? = call insertFiles(?, ?)}");
cstmt.registerOutParameter(1, Types.NUMERIC);
cstmt.setInt(2, userId);
cstmt.setArray(3, array);
cstmt.execute();
int result = cstmt.getInt(1);
import java.sql.Array;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import oracle.jdbc.OracleConnection;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.support.AbstractSqlTypeValue;
public class SqlBlobArrayValue extends AbstractSqlTypeValue {
private List<byte[]> values;
private String defaultTypeName;
public SqlBlobArrayValue(List<byte[]> values) {
this.values = values;
}
public SqlBlobArrayValue(List<byte[]> values, String defaultTypeName) {
this.values = values;
this.defaultTypeName = defaultTypeName;
}
protected Object createTypeValue(Connection conn, int sqlType, String typeName)
throws SQLException {
if (typeName == null && defaultTypeName == null) {
throw new InvalidDataAccessApiUsageException(
"The typeName is null in this context. Consider setting the defaultTypeName.");
}
Blob[] blobs = new Blob[values.size()];
for (int i = 0; i < blobs.length; ++i) {
Blob blob = conn.createBlob();
blob.setBytes(1, values.get(i));
blobs[i] = blob;
}
Array array = conn.unwrap(OracleConnection.class).createOracleArray(typeName != null ? typeName : defaultTypeName, blobs);
return array;
}
}
SqlParameterSource in = new MapSqlParameterSource()
.addValue("p_files", new SqlBlobArrayValue(byteFiles, "BLOB_ARRAY"))
.addValue("p_userId", userId);
Map<String, Object> results = uploadFiles.execute(in);