Как обновить столбец массива postgresql с помощью пружины JdbcTemplate? - PullRequest
2 голосов
/ 11 ноября 2009

Я использую 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;
}

Запрос: «обновить имя таблицы set array_column =? Где id_user =? И id_device =?». Я получаю это исключение:

org.springframework.dao.DataIntegrityViolationException: PreparedStatementCallback; SQL [обновить acotel_msp.users_mau set denied_sub_client =? где id_users =? и id_mau =?]; Индекс столбца находится вне диапазона: 4, количество столбцов: 3 .; вложенное исключение: org.postgresql.util.PSQLException: индекс столбца выходит за пределы диапазона: 4, количество столбцов: 3.

Причина: org.postgresql.util.PSQLException: индекс столбца находится вне диапазона: 4, количество столбцов: 3.

Я изучил шаблоны документов jdbc, но я не могу найти никакой помощи, я буду продолжать искать, в любом случае, кто-то может указать мне правильное направление? Спасибо!

РЕДАКТИРОВАТЬ:

Очевидно, что заказ был неправильным, моя вина ...

Я попробовал оба ваших решения, в первом случае у меня было это:

org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; плохая грамматика SQL [обновить набор пользователей где id_users =? и id_device =?]; вложенное исключение: org.postgresql.util.PSQLException: невозможно привести экземпляр java.util.ArrayList к типу Types.ARRAY

Пробуя второе решение, у меня было это:

org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; плохая грамматика SQL [обновить набор пользователей где id_users =? и id_device =?]; Вложенное исключение - org.postgresql.util.PSQLException: Невозможно привести экземпляр [Ljava.lang.Object; набрать Types.ARRAY

Полагаю, мне нужен экземпляр java.sql.Array, но как мне его создать, используя JdbcTemplate?

Ответы [ 7 ]

2 голосов
/ 11 января 2011
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;
    }
});
1 голос
/ 06 сентября 2016

Это решение является своего рода обходным решением с использованием встроенной функции 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
1 голос
/ 12 ноября 2009

http://valgogtech.blogspot.com/2009/02/passing-arrays-to-postgresql-database.html объясняет, как создать java.sql. Array postgresql в основном Array.getBaseTypeName должен возвращать int, а Array.toString должен возвращать содержимое массива в формате "{1,2,3}"

после создания массива вы можете установить его с помощью preparestatement.setArray (...) от PreparedStatementCreator, например

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

Удачи ..

1 голос
/ 11 ноября 2009

Тип аргумента и аргумент не совпадают.

Попробуйте изменить порядок типов аргументов

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

и посмотрите, работает ли он

0 голосов
/ 28 марта 2019

После многих попыток мы решили использовать небольшой вспомогательный объект ArraySqlValue для создания объектов Spring SqlValue для типов массивов Java.

использование похоже на это

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

этот код предоставляется в открытом доступе

0 голосов
/ 01 февраля 2019

Самый чистый способ, который я нашел до сих пор, - сначала преобразовать 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

0 голосов
/ 18 сентября 2015
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);
...