Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/357.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么我的H2数据库/Spring启动应用程序会出现JdbcSQLException(非十六进制字符)?_Java_Hibernate_Spring Boot_Spring Data Jpa_H2 - Fatal编程技术网

Java 为什么我的H2数据库/Spring启动应用程序会出现JdbcSQLException(非十六进制字符)?

Java 为什么我的H2数据库/Spring启动应用程序会出现JdbcSQLException(非十六进制字符)?,java,hibernate,spring-boot,spring-data-jpa,h2,Java,Hibernate,Spring Boot,Spring Data Jpa,H2,因此,简短的版本,我猜我有某种字符编码问题,或者DB以Hibernate/Spring jpa不喜欢的格式存储/返回日期 但如果我能找出哪里出了问题,我会很兴奋的 使用Hibernate5在实体道具中使用J8LocalDate 正在创建数据库,数据插入正常(您将在下面的日志片段中看到我返回了日期值) 日志片段: 2016-10-26 13:25:19.885 ERROR 1028 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet

因此,简短的版本,我猜我有某种字符编码问题,或者DB以Hibernate/Spring jpa不喜欢的格式存储/返回日期

但如果我能找出哪里出了问题,我会很兴奋的

使用Hibernate5在实体道具中使用J8LocalDate

正在创建数据库,数据插入正常(您将在下面的日志片段中看到我返回了日期值)

日志片段:

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>
实体:

@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');
属性(问题发生在我添加下面的编码属性之前和之后):

编辑: 在进一步挖掘之后,我发现“validate”是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]

您没有在hibernate中为
last\u grading\u date
指定列的类型。 您可以使用:

@Column(name = "last_grading_date", nullable = true)
@Type(type="date")
private LocalDate lastGradingDate;

如果不起作用,请将
LocalDate
类更改为
java.sql.Date

我通过在pom中添加此依赖项使其起作用:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-java8</artifactId>
    <version>${hibernate.version}</version>
</dependency>
应用程序属性

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
PersonRepository

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


在上添加了一个工作示例。该演示基于
Spring boot
java8
hibernate5
maven
Java.time.LocalDate
如果要在
DATE
列中存储
LocalDate
属性,或在
TIMESTAMP
列中存储
LocalDateTime
,则需要自己定义到
java.sql.DATE
java.sql.TIMESTAMP
的映射

属性转换器是JPA2.1规范的一部分,因此可以与任何JPA2.1实现一起使用,例如Hibernate或EclipseLink。我在下面的示例中使用了Wildfly 8.2和Hibernate 4.3

转换本地日期

正如您在下面的代码片段中所看到的,为LocalDate创建属性转换器不需要做很多事情

@转换器(autoApply=true)
公共类LocalDateAttributeConverter实现AttributeConverter{
@凌驾
public Date convertToDatabaseColumn(LocalDate locDate){
返回(locDate==null?null:Date.valueOf(locDate));
}
@凌驾
公共LocalDate convertToEntityAttribute(日期sqlDate){
返回(sqlDate==null?null:sqlDate.toLocalDate());
}
}
您需要使用两种方法实现
AttributeConverter
接口
convertToDatabaseColumn
convertToEntityAttribute
。正如您在方法名称上看到的,其中一个定义了从实体属性类型(
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();
示例实体

@实体
公共类MyEntity{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
@列(name=“id”,updateable=false,nullable=false)
私人长id;
@纵队
私有本地日期;
@纵队
私有LocalDateTime日期时间;
...
}
在我的例子(Spring Boot 1.5.10)中,我需要做的就是将以下内容添加到pom.xml属性部分

<hibernate.version>5.2.12.Final</hibernate.version>
5.2.12.Final

默认情况下,这个版本的Spring Boot使用Hibernate 5.0.12.Final

Add
org.Hibernate:Hibernate-java8
作为依赖项,否则它将不知道如何从java8日期时间对象转换为java8日期时间对象。感谢您的建议。这会导致一个不同的错误,不管是否提到hibernate-java8依赖项:无法设置java.time.LocalDate字段。。。对于java.sql.Date,我的意思是,您应该使用private
private Date lastGradingDateDate
作为
java.sql.Date
而不是
LocalDate
时,问题在于如何使用Java8日期类。这在HIbernate 5中应该是可能的。哦,是的,我应该仔细阅读。另一个答案似乎解决了这个问题,通过添加一个具有正确转换器的依赖项(在本例中,它似乎不需要@Type),我使用的是CrudePO而不是JpaRepo,更改为JpaRepo没有帮助。我还将@type注释再次更改为java.time.LocalDate,仍然是相同的错误(十六进制字符串包含非十六进制字符:“2016-03-23”)。@DaFoot是否在应用程序中添加了依赖项?我想你需要这个图书馆,但我不能让它工作。如果没有,我将添加pom.xml,您可以尝试使用maven。是的,尝试添加依赖项。“我想这里可能还有别的东西值得支付。”DaFoot我在上面添加了我的工作项目。克隆它,并尝试它是否适合您。但它是建立在maven的基础上的。希望没问题。哇,谢谢你。已签出,似乎按预期工作。令人沮丧的!我正在尝试将Hibernate5与Java8W结合使用
@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());
    }
}
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();
@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());
    }
}
<hibernate.version>5.2.12.Final</hibernate.version>