簡體   English   中英

如何使用Spring JdbcTemplate更新Postgresql數組列?

[英]How to update a postgresql array column with spring JdbcTemplate?

我使用的是Spring JdbcTemplate,並且卡在查詢中會更新實際上是int數組的列。 該數據庫是postgres 8.3.7。 這是我正在使用的代碼:

public int setUsersArray(int idUser, int idDevice, Collection<Integer> ids) {

    int update = -666;

    int[] tipi = new int[3];
    tipi[0] = java.sql.Types.INTEGER;
    tipi[1] = java.sql.Types.INTEGER;
    tipi[2] = java.sql.Types.ARRAY;

    try {
        update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
                ids, idUser, idDevice }, tipi);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return update;
}

查詢是“更新table_name設置array_column =?,其中id_user =?和id_device =?”。 我得到這個例外:

org.springframework.dao.DataIntegrityViolationException:PreparedStatementCallback; SQL [更新acotel_msp.users_mau設置否認_sub_client =嗎? 其中id_users =? 和id_mau =?]; 列索引超出范圍:4,列數:3; 嵌套的異常是org.postgresql.util.PSQLException:列索引超出范圍:4,列數:3。

原因:org.postgresql.util.PSQLException:列索引超出范圍:4,列數:3。

我已經研究過Spring JDBC模板文檔,但是我找不到任何幫助,我會一直尋找,無論如何有人會指出我正確的方向嗎? 謝謝!

編輯:

顯然訂單錯了,我的錯...

我嘗試了兩種解決方案,第一種情況是:

org.springframework.jdbc.BadSqlGrammarException:PreparedStatementCallback; 錯誤的SQL語法[更新用戶設置為deny_sub_client =? 其中id_users =? 和id_device =?]; 嵌套的異常是org.postgresql.util.PSQLException:無法將java.util.ArrayList的實例強制轉換為Types.ARRAY。

嘗試第二個解決方案,我有這個:

org.springframework.jdbc.BadSqlGrammarException:PreparedStatementCallback; 錯誤的SQL語法[更新用戶設置為deny_sub_client =? 其中id_users =? 和id_device =?]; 嵌套的異常是org.postgresql.util.PSQLException:無法轉換[Ljava.lang.Object; 鍵入Types.ARRAY

我想我需要一個java.sql.Array實例,但是如何使用JdbcTemplate創建它呢?

private static final String ARRAY_DATATYPE = "int4";
private static final String SQL_UPDATE = "UPDATE foo SET arr = ? WHERE d = ?";
final Integer[] existing = ...;
final DateTime dt = ...;

getJdbcTemplate().update(new PreparedStatementCreator() {
    @Override
    public PreparedStatement createPreparedStatement(final Connection con) throws SQLException {
        final PreparedStatement ret = con.prepareStatement(SQL_UPDATE);
        ret.setArray(1, con.createArrayOf(ARRAY_DATATYPE, existing));
        ret.setDate(2, new java.sql.Date(dt.getMillis()));
        return ret;
    }
});

經過許多嘗試之后,我們決定使用一個小助手ArraySqlValue為Java Array Types創建Spring SqlValue對象。

用法是這樣的

jdbcTemplate.update(
                "UPDATE sometable SET arraycolumn = ?",
                ArraySqlValue.create(arrayValue))

ArraySqlValue也可以在MapSqlParameterSource中使用,與NamedParameterJdbcTemplate一起使用。

import static com.google.common.base.Preconditions.checkNotNull;

import java.sql.Array;
import java.sql.JDBCType;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Locale;

import org.springframework.jdbc.core.StatementCreatorUtils;
import org.springframework.jdbc.support.SqlValue;

public class ArraySqlValue implements SqlValue {
    private final Object[] arr;
    private final String   dbTypeName;

    public static ArraySqlValue create(final Object[] arr) {
        return new ArraySqlValue(arr, determineDbTypeName(arr));
    }

    public static ArraySqlValue create(final Object[] arr, final String dbTypeName) {
        return new ArraySqlValue(arr, dbTypeName);
    }

    private ArraySqlValue(final Object[] arr, final String dbTypeName) {
        this.arr = checkNotNull(arr);
        this.dbTypeName = checkNotNull(dbTypeName);
    }

    @Override
    public void setValue(final PreparedStatement ps, final int paramIndex) throws SQLException {
        final Array arrayValue = ps.getConnection().createArrayOf(dbTypeName, arr);
        ps.setArray(paramIndex, arrayValue);
    }

    @Override
    public void cleanup() {}

    private static String determineDbTypeName(final Object[] arr) {
        // use Spring Utils similar to normal JdbcTemplate inner workings
        final int sqlParameterType =
            StatementCreatorUtils.javaTypeToSqlParameterType(arr.getClass().getComponentType());
        final JDBCType jdbcTypeToUse = JDBCType.valueOf(sqlParameterType);
        // lowercasing typename for Postgres
        final String typeNameToUse = jdbcTypeToUse.getName().toLowerCase(Locale.US);
        return typeNameToUse;
    }
}

此代碼在公共領域中提供

參數類型和參數不匹配。

嘗試更改參數類型順序

int[] tipi = new int[3];
tipi[0] = java.sql.Types.ARRAY;
tipi[1] = java.sql.Types.INTEGER;
tipi[2] = java.sql.Types.INTEGER;

或使用

update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
                                ids.toArray(), idUser, idDevice })

看看是否可行

http://valgogtech.blogspot.com/2009/02/passing-arrays-to-postgresql-database.html解釋了如何創建java.sql.Array postgresql,基本上Array.getBaseTypeName應該返回int,Array.toString應該返回數組“ {1,2,3}”格式的內容

創建數組后,可以使用PreparedStatementCreator中的preparestatement.setArray (...)進行設置,例如

jdbcTemplate.update(
    new PreparedStatementCreator() {
        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {

祝好運 ..

這個解決方案是使用postgreSQL內置函數的一種解決方法,它肯定對我有用。

參考博客

1)將字符串數組轉換為逗號分隔的字符串

如果您使用的是Java8,則非常簡單。 其他選項在這里

String commaSeparatedString = String.join(",",stringArray); // Java8 feature

2)PostgreSQL內置函數string_to_array()

你可以在這里找到其他的postgreSQL數組函數

// tableName ( name text, string_array_column_name text[] )

String query = "insert into tableName(name,string_array_column_name ) values(?, string_to_array(?,',') )";


int[] types = new int[] { Types.VARCHAR, Types.VARCHAR};

Object[] psParams = new Object[] {"Dhruvil Thaker",commaSeparatedString };

jdbcTemplate.batchUpdate(query, psParams ,types); // assuming you have jdbctemplate instance

到目前為止,我發現的最干凈的方法是先將Collection轉換為Integer[] ,然后使用Connection將其轉換為Array

Integer[] idArray = ids.toArray(new Integer[0]);

Array idSqlArray = jdbcTemplate.execute(
        (Connection c) -> c.createArrayOf(JDBCType.INTEGER.getName(), idArray)
);

update = this.jdbcTemplate.update(setUsersArrayQuery, new Object[] {
                            idSqlArray, idUser, idDevice })

這基於文檔中的信息: https : //jdbc.postgresql.org/documentation/head/arrays.html

java.sql.Array intArray = connection.createArrayOf("int", existing);
List<Object> values= new ArrayList<Object>();
values.add(intArray);
values.add(dt);
getJdbcTemplate().update(SQL_UPDATE,values);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM