PostgreSQL JDBC Null String взят в качестве байты - PullRequest
12 голосов
/ 21 ноября 2011

Если entity.getHistory () равен нулю, следующий фрагмент кода:

(getEntityManager () возвращает вставленный в пружину EntityManager, тип истории поля базы данных: text или varchar2 (2000)

Query query = getEntityManager().createNativeQuery("insert into table_name(..., history, ....) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
[...]
.setParameter(6, entity.getHistory())
[...]

query.executeUpdate();

Дает странное исключение:

17/11/11 06:26:09:009 [pool-2-thread-1]  WARN util.JDBCExceptionReporter:100 - SQL Error: 0, SQLState: 42804
17/11/11 06:26:09:009 [pool-2-thread-1] ERROR util.JDBCExceptionReporter:101 - ERROR: **column "history" is of type text but expression is of type bytea**

Подсказка: вам нужно будет переписать или привести выражение.

Проблема возникла только в этой конфигурации:
ОС: CentOS выпуск 5.6 (финал)
Java: 1.6.0_26
БД: PostgreSQL 8.1
Драйвер JDBC: postgresql-9.1-901.jdbc4
Сервер приложений: apache-tomcat-6.0.28

Все отлично работает на нескольких других конфигурациях или когда история пустая строка. То же утверждение, выполненное из pgAdmin, работает нормально.

Полагаю, проблема в драйвере JDBC PostgreSQL. Есть ли какая-то разумная причина рассматривать нулевую строку как значение в байтах? Может быть, какие-то странные изменения между Postgres 8 и 9?

Ответы [ 6 ]

5 голосов
/ 22 ноября 2011

Есть простое решение: когда вы строите строку запроса, если параметр будет иметь значение null - используйте «null» вместо «?».

Как говорит @araqnid, Hibernate неправильно переводит нулевые значения в тип bytea, потому что не знает ничего лучше.

4 голосов
/ 21 ноября 2011

Поскольку вы вызываете setParameter(int,Object) с нулевым значением, по-видимому, менеджер сущностей не знает, какой тип персистентности использовать для привязки параметра. Istr Hibernate имеет склонность к использованию SerializableType, что приравнивается к байте.

Можете ли вы использовать метод setParameter, который вместо этого принимает объект Parameter, чтобы вы могли указать тип? Я действительно не использовал JPA, поэтому не могу дать подробный указатель.

(ИМХО, это просто ваши десерты за то, что вы злоупотребляли интерфейсом запросов EntityManager native-sql для выполнения вставок, вместо того, чтобы фактически отображать сущность, или просто переходили в JDBC)

2 голосов
/ 06 мая 2014

Использование специфичного для Hibernate Session API работает в качестве обходного пути:

String sql = "INSERT INTO person (id, name) VALUES (:id, :name)";
Session session = em.unwrap(Session.class);
SQLQuery insert = session.createSQLQuery(sql);
sql.setInteger("id", 123);
sql.setString("name", null);
insert.executeUpdate();

Я также подал HHH-9165 , чтобы сообщить об этой проблеме, если это действительно ошибка.

1 голос
/ 21 ноября 2011

Если вы хотите использовать класс PreparedStatement вместо запроса:

if (entity.getHistory() == null)
    stmt.setNull(6, Types.VARCHAR);
else
    stmt.setString(6, entity.getHistory());

(Возможно, что использование ?::text в строке запроса также сработает, но я никогда сам этого не делал).

0 голосов
/ 07 мая 2019

Большинство из приведенных выше ответов имеют смысл и помогли мне сузить проблему.

Я исправил проблему с пустыми значениями следующим образом:

setParameter(8, getDate(), TemporalType.DATE);
0 голосов
/ 18 августа 2012

JDBC setNull с параметром типа sql является запасным вариантом для устаревших драйверов JDBC, которые не проходят JDBC Driver Test Suite.

Защитить от нулевых ошибок в запросе можно следующим образом:

ВЫБЕРИТЕ ОТ АВТОРА, ГДЕ: lastName НУЛЬ ИЛИ НИЖЕ (a.lastName) =: lastName

Это должно работать в Postgresql после исправления этой проблемы .

...