如何用spring JdbcTemplate更新postgresql数组列?

6tqwzwtp  于 2023-03-16  发布在  Spring
关注(0)|答案(7)|浏览(186)

我使用的是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;
}

查询为“更新表名设置数组列=?其中id用户=?和id设备=?"。我得到了以下异常:
数据完整性违规异常:准备好的语句回调;SQL [更新acotel_msp.users_mau设置拒绝子客户端=?,其中id_users =?和id_mau =?];列索引超出范围:4、列数:3.;嵌套的异常是org.postgresql.util.列索引超出范围:4、列数:3.
原因是:org.postgresql.util.列索引超出范围:4、列数:3.
我已经看过了spring jdbc模板文档,但是我找不到任何帮助,我会继续找的,不管怎样,有人能给我指一下正确的方向吗?谢谢!
编辑:
很明显命令错了,是我的错...
我尝试了你的两种解决方案,在第一种情况下,我有这样的:
org.springframework.jdbc.BadSqlGrammarException:准备好的语句回调;SQL语法错误[更新用户设置denied_sub_client =?,其中id_users =?和id_device =?];嵌套异常是org.postgresql.util.无法将java.util.ArrayList的示例强制转换为类型Types.ARRAY
尝试第二个解决方案,我有这个:
org.springframework.jdbc.BadSqlGrammarException:准备好的语句回调;SQL语法错误[更新用户设置denied_sub_client =?,其中id_users =?和id_device =?];嵌套异常是org.postgresql.util.无法强制转换[Ljava.lang.Object;类型类型.阵列
我想我需要一个java.sql.Array的示例,但是我如何使用JdbcTemplate创建它呢?

x4shl7ld

x4shl7ld1#

经过多次尝试,我们决定使用一个小助手ArraySqlValue来为Java数组类型创建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;
    }
}

此代码在公共域中提供

mpgws1up

mpgws1up2#

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;
    }
});
eqqqjvef

eqqqjvef3#

这个解决方案是一种使用PostgreSQL内置函数的变通方案,它对我来说确实有效。
reference blog

1)将字符串数组转换为逗号分隔的字符串

如果您使用Java8,这非常简单。其他选项是here

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

2)PostgreSQL内置函数字符串到数组()

您可以找到其他PostgreSQL数组函数here

// 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
p4tfgftt

p4tfgftt4#

到目前为止,我发现的最简洁的方法是首先将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/server-prepare/#arrays

z5btuh9x

z5btuh9x5#

参数类型和参数不匹配。
尝试更改参数类型顺序

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 })

看看是否有效

ddrv8njm

ddrv8njm6#

http://valgogtech.blogspot.com/2009/02/passing-arrays-to-postgresql-database.html解释了如何创建java.sql.Array postgresql基本上Array.getBaseTypeName应该返回int和Array.toString应该返回“{1,2,3}”格式的数组内容
创建数组后,您可以使用**preparedstatement.setArray(...)**从PreparedStatementCreator设置它,例如

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

祝你好运。

6uxekuva

6uxekuva7#

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);

相关问题