spring – JdbcTemplate – 使用SQL MERGE插入或更新Oracle BLOB

使用JdbcTemplate我想调用MERGE SQL语句,该语句将向表中插入新记录,或者如果已存在具有特定键的行,则更新.关键部分是其中一列是Oracle BLOB类型.

这是我到现在为止所尝试的:

试试1.

Sql语句:

    String sql = ""
            + "MERGE INTO file_thumbnails "
            + "     USING (SELECT ? as file_c_id, ? as thumbnail_type, ? as thumbnail_image FROM DUAL) tmp "
            + "        ON (file_thumbnails.file_c_id = tmp.file_c_id AND "
            + "            file_thumbnails.thumbnail_type = tmp.thumbnail_type) "
            + "      WHEN MATCHED THEN "
            + "        UPDATE "
            + "           SET thumbnail_image = tmp.thumbnail_image "
            + "              ,thumbnail_date = SYSDATE "
            + "      WHEN NOT MATCHED THEN "
            + "        INSERT (c_id, file_c_id, thumbnail_type, thumbnail_image, thumbnail_date) "
            + "        VALUES (cedar_c_id_seq.nextval, tmp.file_c_id, tmp.thumbnail_type, tmp.thumbnail_image, SYSDATE)";

数据库通话:

List<Object[]> x = fileList.stream().map(file -> {
    byte[] thumbnail = file.getThumbnail();
    SqlLobValue sqlLobValue = new SqlLobValue(new ByteArrayInputStream(thumbnail), thumbnail.length, new DefaultLobHandler());
    return new Object[] { file.getFileCId(), file.getType().toString(), sqlLobValue};
}).collect(Collectors.toList());
jdbcTemplate.batchUpdate(sql, x, new int[] { OracleTypes.NUMBER, OracleTypes.VARCHAR, OracleTypes.BLOB});

例外:

Caused by: org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [MERGE INTO file_thumbnails      USING (SELECT ? as file_c_id, ? as thumbnail_type, ? as thumbnail_image FROM DUAL) tmp         ON (file_thumbnails.file_c_id = tmp.file_c_id AND             file_thumbnails.thumbnail_type = tmp.thumbnail_type)       WHEN MATCHED THEN         UPDATE            SET thumbnail_image = tmp.thumbnail_image               ,thumbnail_date = SYSDATE       WHEN NOT MATCHED THEN         INSERT (c_id, file_c_id, thumbnail_type, thumbnail_image, thumbnail_date)         VALUES (cedar_c_id_seq.nextval, tmp.file_c_id, tmp.thumbnail_type, tmp.thumbnail_image, SYSDATE)]; SQL state [72000]; error code [1461]; ORA-01461: can bind a LONG value only for insert into a LONG column
; nested exception is java.sql.BatchUpdateException: ORA-01461: can bind a LONG value only for insert into a LONG column

    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:662) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:950) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.BatchUpdateUtils.executeBatchUpdate(BatchUpdateUtils.java:32) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:1000) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at cern.edms.thumbnails.generator.repository.EdmsFileRepository.saveThumbnails(EdmsFileRepository.java:61) ~[classes/:na]
    at cern.edms.thumbnails.generator.repository.EdmsFileRepository$$FastClassBySpringCGLIB$$e3d79386.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at cern.edms.thumbnails.generator.repository.EdmsFileRepository$$EnhancerBySpringCGLIB$$70f43ba5.saveThumbnails(<generated>) ~[classes/:na]
    at cern.edms.thumbnails.generator.Application.run(Application.java:58) [classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) [spring-boot-1.5.2.RELEASE.jar:1.5.2.RELEASE]
    ... 6 common frames omitted
Caused by: java.sql.BatchUpdateException: ORA-01461: can bind a LONG value only for insert into a LONG column

    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10401) ~[ojdbc6-11.2.0.3.0.jar:11.2.0.3.0]
    at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:230) ~[ojdbc6-11.2.0.3.0.jar:11.2.0.3.0]
    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:966) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:950) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    ... 21 common frames omitted

试试2.

Sql statement:
        String sql = ""
                + "MERGE INTO file_thumbnails "
                + "     USING (SELECT ? as file_c_id, ? as thumbnail_type FROM DUAL) tmp "
                + "        ON (file_thumbnails.file_c_id = tmp.file_c_id AND "
                + "            file_thumbnails.thumbnail_type = tmp.thumbnail_type) "
                + "      WHEN MATCHED THEN "
                + "        UPDATE "
                + "           SET thumbnail_image = ? "
                + "              ,thumbnail_date = SYSDATE "
                + "      WHEN NOT MATCHED THEN "
                + "        INSERT (c_id, file_c_id, thumbnail_type, thumbnail_image, thumbnail_date) "
                + "        VALUES (cedar_c_id_seq.nextval, tmp.file_c_id, tmp.thumbnail_type, ?, SYSDATE)";

数据库通话:

List<Object[]> x = fileList.stream().map(file -> {
    byte[] thumbnail = file.getThumbnail();
    SqlLobValue sqlLobValue = new SqlLobValue(new ByteArrayInputStream(thumbnail), thumbnail.length, new DefaultLobHandler());
    SqlLobValue sqlLobValue2 = new SqlLobValue(new ByteArrayInputStream(thumbnail), thumbnail.length, new DefaultLobHandler());
    return new Object[] { file.getFileCId(), file.getType().toString(), sqlLobValue, sqlLobValue2 };
}).collect(Collectors.toList());
jdbcTemplate.batchUpdate(sql, x, new int[] { OracleTypes.NUMBER, OracleTypes.VARCHAR, OracleTypes.BLOB, OracleTypes.BLOB });

例外:

Caused by: org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [MERGE INTO file_thumbnails      USING (SELECT ? as file_c_id, ? as thumbnail_type FROM DUAL) tmp         ON (file_thumbnails.file_c_id = tmp.file_c_id AND             file_thumbnails.thumbnail_type = tmp.thumbnail_type)       WHEN MATCHED THEN         UPDATE            SET thumbnail_image = ?               ,thumbnail_date = SYSDATE       WHEN NOT MATCHED THEN         INSERT (c_id, file_c_id, thumbnail_type, thumbnail_image, thumbnail_date)         VALUES (cedar_c_id_seq.nextval, tmp.file_c_id, tmp.thumbnail_type, ?, SYSDATE)]; SQL state [63000]; error code [3106]; ORA-03106: fatal two-task communication protocol error
; nested exception is java.sql.BatchUpdateException: ORA-03106: fatal two-task communication protocol error

    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:84) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:81) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:649) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:662) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:950) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.BatchUpdateUtils.executeBatchUpdate(BatchUpdateUtils.java:32) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:1000) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at cern.edms.thumbnails.generator.repository.EdmsFileRepository.saveThumbnails(EdmsFileRepository.java:62) ~[classes/:na]
    at cern.edms.thumbnails.generator.repository.EdmsFileRepository$$FastClassBySpringCGLIB$$e3d79386.invoke(<generated>) ~[classes/:na]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) ~[spring-tx-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656) ~[spring-aop-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at cern.edms.thumbnails.generator.repository.EdmsFileRepository$$EnhancerBySpringCGLIB$$587b6598.saveThumbnails(<generated>) ~[classes/:na]
    at cern.edms.thumbnails.generator.Application.run(Application.java:58) [classes/:na]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:776) [spring-boot-1.5.2.RELEASE.jar:1.5.2.RELEASE]
    ... 6 common frames omitted
Caused by: java.sql.BatchUpdateException: ORA-03106: fatal two-task communication protocol error

    at oracle.jdbc.driver.OraclePreparedStatement.executeBatch(OraclePreparedStatement.java:10401) ~[ojdbc6-11.2.0.3.0.jar:11.2.0.3.0]
    at oracle.jdbc.driver.OracleStatementWrapper.executeBatch(OracleStatementWrapper.java:230) ~[ojdbc6-11.2.0.3.0.jar:11.2.0.3.0]
    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:966) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:950) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:633) ~[spring-jdbc-4.3.7.RELEASE.jar:4.3.7.RELEASE]
    ... 21 common frames omitted

补充说明.

>在数据库调用的第二次尝试中,我不能使用两次相同的SqlLobValue对象,因为我收到一个异常:

引起:java.sql.SQLException:重复的流参数:4
>如果我将进行第二次尝试,但只将BLOB输入参数放入一次(例如仅在MERGE语句的INSERT部分中),它可以正常工作.但当然它并没有解决我的问题.

能否请你帮忙?

解决方法:

由于@gvenzi的答案,我解决了这个问题,但我决定发布自己的答案,因为我还有一些额外的评论.

所以,是的,OracleLobHandler解决了这个问题.但实际上我们并没有*使用弃用的类.在OracleLobHandler documentation我找到了

Deprecated. in favor of DefaultLobHandler for the Oracle 10g driver
and higher. Consider using the 10g/11g driver even against an Oracle
9i database! DefaultLobHandler.setCreateTemporaryLob(boolean) is the
direct equivalent of this OracleLobHandler’s implementation strategy,
just using standard JDBC 4.0 API. That said, in most cases, regular
DefaultLobHandler setup will work fine as well.

我测试了它,它的工作原理.

但是我在PreparedStatementSetter中使用SqlLobValue和OracleTypes.BLOB时遇到了另一个问题(这里描述的是ClassCastException: SqlLobValue cannot be cast to oracle.sql.BLOB using PreparedStatementSetter)

我的最终工作代码如下:

public void saveThumbnails(List<Thumbnail> fileList) throws SQLException, IOException {

    BatchPreparedStatementSetter b = new BatchPreparedStatementSetter() {
        @Override
        public void setValues(PreparedStatement ps, int i) throws SQLException {
            Thumbnail thumbnail = fileList.get(i);
            byte[] thumbnailBytes = thumbnail.getThumbnail();
            ps.setObject(1, thumbnail.getFileCId(), OracleTypes.NUMBER);
            ps.setObject(2, thumbnail.getType().toString(), OracleTypes.VARCHAR);
            DefaultLobHandler lobHandler = new DefaultLobHandler();
            lobHandler.setCreateTemporaryLob(true);
            lobHandler.getLobCreator().setBlobAsBytes(ps, 3, thumbnailBytes);
        }

        @Override
        public int getBatchSize() {
            return fileList.size();
        }
    };
    jdbcTemplate.batchUpdate(getSaveThumbnailSql(), b);
}

private String getSaveThumbnailSql() {
    // @formatter:off
    String sql = ""
            + "MERGE INTO file_thumbnails "
            + "     USING (SELECT ? as file_c_id, ? as thumbnail_type, ? AS thumbnail_image FROM DUAL) tmp "
            + "        ON (file_thumbnails.file_c_id = tmp.file_c_id AND "
            + "            file_thumbnails.thumbnail_type = tmp.thumbnail_type) "
            + "      WHEN MATCHED THEN "
            + "        UPDATE "
            + "           SET thumbnail_image = tmp.thumbnail_image"
            + "              ,thumbnail_date = SYSDATE "
            + "      WHEN NOT MATCHED THEN "
            + "        INSERT (c_id, file_c_id, thumbnail_type, thumbnail_image, thumbnail_date) "
            + "        VALUES (cedar_c_id_seq.nextval, tmp.file_c_id, tmp.thumbnail_type, tmp.thumbnail_image , SYSDATE)";
    //@formatter:on
    return sql;
}
上一篇:mockjs安装与配置


下一篇:java – SQL state [null];错误代码[0]; ORA-00900:带有jdbcTemplate的无效SQL语句