#java #oracle #hibernate #jpa
#java #Oracle #переход в спящий режим #jpa
Вопрос:
Я был бы признателен за некоторую помощь в этом исключении.
Я провел некоторое исследование этой ошибки, но не смог найти решение. Я использую JPA с гибернацией и получаю эту ошибку при выполнении запроса.
Очевидно, есть что-то, чего я не понимаю в Java LocalDate и oracle Date. 🙁
Это объект:
@Entity
@Table(name = "MY_TABLE")
public class MyObject implements Serializable {
private static final long serialVersionUID = 1731972128723930612L;
@Id
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "OTHER_ID", nullable = false)
private OtherObject otherObject;
@Column(name = "MY_DATE", columnDefinition="DATE", nullable = false)
// @Convert(converter = LocalDateSQLDateConverter.class)
// @Convert(converter = LocalDateConverter.class)
private LocalDate date;
Как вы можете видеть, я пытался использовать конвертеры, которые преобразуют LocalDate в java.util.Date или java.sql.Date и наоборот — оба, к сожалению, не помогли.
Это запрос:
public class MyDao extends BaseDao {
public void save(MyObject object) {
entityManager.persist(object);
}
public MyObject findByDate(LocalDate date) {
TypedQuery<MyObject> query = entityManager.createQuery("SELECT w from MyObject w"
" where w.date = :date", MyOBject.class)
.setParameter("date", date);
return query.getResultList().stream().findFirst().orElse(null);
}
Это исключение:
java.sql.SQLSyntaxErrorException: ORA-00932: несогласованные типы данных: ожидаемая ДАТА получена ДВОИЧНОЙ
oracle.jdbc.driver.Ошибка T4CTTIoer.Processor(T4CTTIoer.java:445) oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396) oracle.jdbc.driver.Ошибка T4C8Oall.Processor(T4C8Oall.java:879) oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450) oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531) oracle.jdbc.driver.T4CPreparedStatement.doOall8(t4cpreparredstatement.java:207) oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:884) oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1167) oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1289) oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584) oracle.jdbc.driver.OraclePreparedStatement.ExecuteQuery(OraclePreparedStatement.java:3628) oracle.jdbc.driver.OraclePreparedStatementWrapper.ExecuteQuery(OraclePreparedStatementWrapper.java:1493) org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.ExecuteQuery(WrappedPreparedStatement.java:462) org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79) org.hibernate.loader.Loader.getResultSet(Loader.java:2090) org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1887) org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1866) org.hibernate.loader.Loader.doQuery(Loader.java:905) org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:347) org.hibernate.loader.Загрузчик.Список(Loader.java:2578) org.hibernate.loader.Загрузчик.Список(Loader.java:2564) org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2394) org.hibernate.loader.Loader.list(Loader.java:2389) org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:495) org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:357) org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:198) org.hibernate.internal.SessionImpl.list(SessionImpl.java:1230) org.hibernate.internal.Запрос IMPL.list(запрос IMPL.java:101) org.hibernate.ejb.Запрос IMPL.getResultList(запрос IMPL.java:268) my.company.path.MyDao.findByDate(MyDaoDao.java:21)
Заранее большое спасибо за любые подсказки!
Комментарии:
1. Какая версия вашего драйвера Oracle JDBC? попробуйте более свежую!
2. К сожалению, я не смогу изменить ее, как указано в изображении jboss docker.
3. Я обнаружил, что не использовал новейшую версию JPA и изменил ее. К сожалению, проблема осталась. Я заменил LocalDate amp; LocalDateTime в своем приложении на java.util. Дата, и это работает. Но я бы действительно предпочел использовать LocalDate amp; LocalDateTime.
4. Попробуйте что-то вроде этого: thoughts-on-java.org/persist-localdate-localdatetime-jpa
5. Я тоже это обнаружил и попробовал, к сожалению, безуспешно.
Ответ №1:
Хотя это кажется нелогичным, вы должны передать строковое представление, например, так:
SELECT * FROM xxx where date_of_birth = '1990-08-21';
где date_of_birth
имеет тип DATE
( MySQL
, не Oracle
, но не должно иметь значения) и сопоставляется с LocalDate
в Spring
/ Hibernate
Комментарии:
1. В Oracle вы можете захотеть использовать
TO_CHAR()
/TO_DATE()
, поскольку он плохо сочетается со стандартами…
Ответ №2:
Hibernate 4 вышел до java.time.LocalDate был добавлен, и он этого не понимает. Поэтому он отправляет данные в виде двоичного файла в Oracle.
Лучшее решение — перейти на спящий режим 5.
Комментарии:
1. Ммм, на самом деле я использую hibernate-core-5.4.1.Final.jar .
2. Ваш ответ заставил меня узнать, что я не использовал JPA 2.2, который теоретически поддерживает LocalDate amp; LocalDateTime. К сожалению, проблема не была решена этим изменением.
Ответ №3:
Я узнал, что наш образ docker использует JBoss 6.4, который, согласно https://access.redhat.com/articles/112673 — использует гибернацию JPA 2.0.
Итак, это не может сработать. Нам нужен JPA 2.2 для поддержки LocalDate amp; LocalDateTime.
Я изменил все вхождения LocalDate и LocalDateTime в DAOS на Date, в то время как остальная часть моего приложения продолжает использовать LocalDate и LocalDateTime — с помощью небольшого конвертера:
public class LocalDateConverter {
public static Date convertToDate(LocalDate date) {
return date != null ? Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()) : null;
}
public static LocalDate convertToLocalDate(Date date) {
return date != null ? LocalDate.from(date.toInstant().atZone(ZoneId.systemDefault())) : null;
}
public static Date convertToDate(LocalDateTime dateTime) {
return dateTime != null ? Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()) : null;
}
}
Теоретически, отсутствует один метод, который преобразует дату в LocalDateTime, но в моем случае мне это не нужно, потому что я использую LocalDateTime только для creationDates, которые никогда не читаются.
Ответ №4:
Проблема заключается не в отображении выходных данных, а в отображении параметра.
В то время как hibernate управляет компонентами, он знает, что должен преобразовать LocalDate в Date.
Я не знаю почему, но EntityManager не делает то же самое для ввода параметров. Я предполагаю, что EntityManager имеет более короткий список известных классов с преобразователями, а другие преобразуются с помощью toString().
Вы должны преобразовать свой входной параметр в Date:
TypedQuery<MyObject> query = entityManager.createQuery("SELECT w from MyObject w" " where w.date = :date", MyOBject.class) .setParameter("date",Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
Если вы используете Spring, вы также можете org.springframework.data.jpa.repository.Запрос
@Query("SELECT w from MyObject w where w.date = :date") public MyObject findByDate(LocalDate date);
Он автоматически преобразует ваш входной параметр.