【问题标题】:Spring Boot Data JPA query doesn't work with LocalDateTime.MAXSpring Boot Data JPA 查询不适用于 LocalDateTime.MAX
【发布时间】:2020-03-27 10:48:07
【问题描述】:

我有方法:

@Query(value = "SELECT bs FROM BookedSlot bs WHERE bs.timeFrom >= :timeFrom AND bs.timeFrom < :timeTo")
Set<BookedSlot> test(@Param("timeFrom") LocalDateTime fromTime, @Param("timeTo") LocalDateTime timeTo);

还有两个测试

    @Sql(scripts = "/test-data.sql")
    @Test
    public void test1() {
        final Set<BookedSlot> res = unit.test(LocalDateTime.now(), LocalDateTime.MAX);
        assertNotNull(res);
        assertEquals(1, res.size());//fails
    }

    @Sql(scripts = "/test-data.sql")
    @Test
    public void test2() {
        final Set<BookedSlot> res = unit.test(LocalDateTime.now(), LocalDateTime.of(2050,1,1,1,1));
        assertNotNull(res);
        assertEquals(1, res.size());//ok
    }

还有test-data.sql

INSERT INTO booked_slots (id, created_at, updated_at, time_from, time_to, user_id, service_box_id)
VALUES (1, NOW(), NOW(), '2040-01-01 08:30:00.0', '2040-01-01 10:00:00.0', 1, 1);

test1 - 失败

test2 - 好的

BookedSlots.java

@Entity
@Table(name = "booked_slots")
public class BookedSlot extends DbEntity implements Comparable<BookedSlot> {

    @Column(name = "time_from")
    private LocalDateTime timeFrom;
    @Column(name = "time_to")
    private LocalDateTime timeTo;
}

数据库 h2(在 MySQL 5.7 上也是如此,我只是使用 H2 进行集成测试)

test.properties

spring.datasource.url=jdbc:h2:mem:myDb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;MODE=MySQL
spring.datasource.username=sa
spring.datasource.password=sa
spring.datasource.initialization-mode=always
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect

对此有什么想法吗?

【问题讨论】:

    标签: java mysql spring spring-data-jpa


    【解决方案1】:

    支持的最大LocalDateTime999999999-12-31T23:59:59.999999999。数据库不支持那么远的未来日期。

    MySQL range for DATETIME 的值是 1000-01-01 00:00:00.0000009999-12-31 23:59:59.999999


    hibernate-core: LiteralType::objectToSQLString 将值转换为字符串 表示,适合嵌入到 SQL 语句中作为 字面意思。

    这里可以看到LocalDateTimeType::objectToSQLString方法

    public class LocalDateTimeType
            extends AbstractSingleColumnStandardBasicType<LocalDateTime>
            implements VersionType<LocalDateTime>, LiteralType<LocalDateTime> {
    
        public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern( "yyyy-MM-dd HH:mm:ss.S", Locale.ENGLISH );
    
        //...
    
        @Override
        public String objectToSQLString(LocalDateTime value, Dialect dialect) throws Exception {
            return "{ts '" + FORMATTER.format( value ) + "'}";
        }
    
        //..
    }
    

    对于LocalDateTime.MAX,它返回{ts '+999999999-12-31 23:59:59.9'}

    【讨论】:

    • 谢谢,但是......它没有解释为什么 Java 的 999999999 没有转换为 MySQL 的 9999 :)
    • 无法转换以防止数据丢失 (999999999 != 9999)。我提供了额外的解释
    猜你喜欢
    • 2016-12-03
    • 2023-03-06
    • 1970-01-01
    • 2018-10-20
    • 2018-08-06
    • 2021-03-01
    • 2018-12-16
    • 1970-01-01
    • 2022-01-26
    相关资源
    最近更新 更多