![](/img/trans.png)
[英]H2 user-defined-function org.h2.jdbc.JdbcSQLException non-hex character error
[英]Why am I getting JdbcSQLException (non-hex characters) with my H2 database / Spring boot application?
所以簡短的版本,我猜我有某種字符編碼問題,或者數據庫出於某種原因以Hibernate / Spring-jpa不喜歡的格式存儲/返回日期。
但是,如果我能解決問題的話,我會感到不安!
使用Hibernate 5在實體道具中使用J8 LocalDate東西。
正在創建數據庫並正確插入了數據(您將在下面的日志代碼段中看到返回的日期值)。
日志片段:
2016-10-26 13:25:19.885 ERROR 1028 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.orm.jpa.JpaSystemException:
Could not read entity state from ResultSet : EntityKey[uk.co.deditech.entity.Person#2];
nested exception is org.hibernate.exception.GenericJDBCException: Could not read entity state from ResultSet :
EntityKey[uk.co.deditech.entity.Person#2]] with root cause org.h2.jdbc.JdbcSQLException: Hexadecimal string contains non-hex character: "2016-03-23" [90004-192]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.192.jar:1.4.192]
at org.h2.message.DbException.get(DbException.java:179) ~[h2-1.4.192.jar:1.4.192]
at org.h2.message.DbException.get(DbException.java:155) ~[h2-1.4.192.jar:1.4.192]
at org.h2.util.StringUtils.convertHexToBytes(StringUtils.java:986) ~[h2-1.4.192.jar:1.4.192]
at org.h2.value.Value.convertTo(Value.java:973) ~[h2-1.4.192.jar:1.4.192]
at org.h2.value.Value.getBytes(Value.java:422) ~[h2-1.4.192.jar:1.4.192]
at org.h2.jdbc.JdbcResultSet.getBytes(JdbcResultSet.java:1077) ~[h2-1.4.192.jar:1.4.192]
<snip>
搖籃:
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-freemarker")
compile group: 'com.h2database', name: 'h2', version:'1.4.192'
實體:
@Entity
@Table(name = "person")
public @Data class Person {
...
@Column(name = "last_grading_date", nullable = true)
private LocalDate lastGradingDate;
}
Spring Boot自動數據庫創建腳本片段:
schema.sql
create table PERSON
(
id int not null,
last_grading_date date
)
data.sql
insert into person (id, last_grading_date)
values (1, '2015-02-20');
屬性(問題發生在添加以下編碼屬性之前和之后):
spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.sql-script-encoding=UTF-8
編輯:經過更多的挖掘后,我發現“驗證”是spring.jpa.hibernate.ddl-auto屬性的設置。 所以我嘗試了。
我現在在啟動過程中遇到以下錯誤...
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException: Schema-validation: wrong column type encountered in column [last_grading_date] in table [person]; found [date (Types#DATE)], but expecting [binary(255) (Types#VARBINARY)]
at org.hibernate.tool.schema.internal.SchemaValidatorImpl.validateColumnType(SchemaValidatorImpl.java:105) ~[hibernate-core-5.0.11.Final.jar:5.0.11.Final]
我通過在pom中添加此依賴項來使其工作:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>${hibernate.version}</version>
</dependency>
我不知道為什么它不能開箱即用,但是有了這種依賴性,它解決了這個問題。
我還在屬性下面添加了此屬性: <hibernate.version>5.0.5.Final</hibernate.version>
我的用於復制的示例代碼:
Data.sql:
insert into person (id, last_grading_date)
values (1, '2015-02-20');
application.properties
spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;
spring.datasource.driverClassName=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.sql-script-encoding=UTF-8
人員資料庫
public interface PersonRepository extends JpaRepository<Person, Integer>{
}
人
@Entity
@Table(name = "person")
public class Person {
@Id
@Column
private int id;
@Column(name = "last_grading_date", nullable = true)
@Type(type = "java.time.LocalDate")
private LocalDate lastGradingDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public LocalDate getLastGradingDate() {
return lastGradingDate;
}
public void setLastGradingDate(LocalDate lastGradingDate) {
this.lastGradingDate = lastGradingDate;
}
}
應用方式
@SpringBootApplication
public class TestApplication implements CommandLineRunner{
@Autowired
PersonRepository repo;
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@Override
public void run(String... arg0) throws Exception {
Person p = repo.findOne(1);
System.out.println(p.getLastGradingDate());
}
}
結果: 2015-02-20
在GitHub上添加了一個工作示例。 該演示基於Spring-boot
, Java 8
, Hibernate 5
, maven
和java.time.LocalDate
。
JPA 2.1在Java 8之前發布,而Date and Time API當時根本不存在。 因此,@ Temporal批注只能應用於類型為java.util.Date和java.util.Calendar的屬性。
如果要將LocalDate
屬性存儲在DATE
列中,或者將LocalDateTime
在TIMESTAMP
列中,則需要自己定義到java.sql.Date
或java.sql.Timestamp
的映射。
屬性轉換器是JPA 2.1規范的一部分,因此可以與任何JPA 2.1實現一起使用,例如Hibernate或EclipseLink。 我為以下示例使用了Wildfly 8.2和Hibernate 4.3。
轉換LocalDate
如下面的代碼片段所示,為LocalDate創建屬性轉換器不需要做很多事情。
@Converter(autoApply = true)
public class LocalDateAttributeConverter implements AttributeConverter<LocalDate, Date> {
@Override
public Date convertToDatabaseColumn(LocalDate locDate) {
return (locDate == null ? null : Date.valueOf(locDate));
}
@Override
public LocalDate convertToEntityAttribute(Date sqlDate) {
return (sqlDate == null ? null : sqlDate.toLocalDate());
}
}
您需要使用其兩個方法convertToDatabaseColumn
和convertToEntityAttribute
實現AttributeConverter<LocalDate, Date>
接口。 在方法名稱上可以看到,其中一個定義了從實體屬性( LocalDate
)的類型到數據庫列類型( Date
)的轉換,另一個定義了逆向轉換。 轉換本身非常簡單,因為java.sql.Date
已經提供了與LocalDate
之間進行轉換的方法。
另外,屬性轉換器需要使用@Converter
注釋進行注釋。 由於可選的autoApply = true屬性,該轉換器將應用於LocalDate類型的所有屬性。 如果要為每個屬性分別定義轉換器的用法,請看這里。
屬性的轉換對開發人員是透明的, LocalDate
屬性可以用作任何其他實體屬性。 例如,您可以將其用作查詢參數。
LocalDate date = LocalDate.of(2015, 8, 11);
TypedQuery<MyEntity> query = this.em.createQuery("SELECT e FROM MyEntity e WHERE date BETWEEN :start AND :end", MyEntity.class);
query.setParameter("start", date.minusDays(2));
query.setParameter("end", date.plusDays(7));
MyEntity e = query.getSingleResult();
轉換LocalDateTime
LocalDateTime
的屬性轉換器基本相同。 您需要實現AttributeConverter<LocalDateTime, Timestamp>
接口,並且轉換器需要使用@Converter批注進行批注。 與LocalDateConverter
相似, LocalDateTime
和java.sql.Timestamp
之間的轉換是通過Timestamp
的轉換方法完成的。
@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
@Override
public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
}
@Override
public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
}
}
實體實例
@Entity
public class MyEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Long id;
@Column
private LocalDate date;
@Column
private LocalDateTime dateTime;
...
}
就我而言(Spring Boot 1.5.10),我要做的就是將以下內容添加到pom.xml屬性部分
<hibernate.version>5.2.12.Final</hibernate.version>
默認情況下,此版本的Spring Boot看起來使用的是Hibernate 5.0.12.Final
您沒有在休眠狀態中為last_grading_date
指定列的類型。 您可以使用:
@Column(name = "last_grading_date", nullable = true)
@Type(type="date")
private LocalDate lastGradingDate;
如果不起作用,請將LocalDate
類更改為java.sql.Date
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.