【问题标题】:Spring Boot JPA Hibernate - Storing Date with millisecond precisionSpring Boot JPA Hibernate - 以毫秒精度存储日期
【发布时间】:2021-01-23 11:42:18
【问题描述】:

Spring Boot 版本“2.3.4.RELEASE”
Java 11
org.springframework.boot:spring-boot-starter-jdbc
org.springframework.boot:spring-boot-starter-data-jpa
spring-data-jpa-2.3.4.RELEASE
运行时(mysql:mysql-connector-java)

服务器数据库 MariaDB(版本 10.5.5-MariaDB)
Java MariaDB 连接器 J:2.6.0[稳定]

我正在尝试以毫秒精度在 Hibernate 中持久化 java.sql.Timestamp 对象。我需要以毫秒为单位将日期保存到数据库。例如:2020-10-08 03:23:38.454。

我的域名:

import java.sql.Timestamp;
@Entity
@Data
@Table(name = "date_test")
public class DateTestDomain {
    @Id
    @Column(nullable = false, name = "date", columnDefinition = "TIMESTAMP(3)")
    @Temporal(TIMESTAMP)
    private Calendar dateTest;
}

我的仓库:

@Repository
public interface DateTestRepo extends JpaRepository<DateTestDomain, Timestamp> {
}

保存日期到数据库:

private final JdbcTemplate db;
...
        long testTime = 1602120218454L;
        Timestamp dateTimeStamp = new Timestamp(testTime);
        db.update("INSERT INTO date_test" + " (date) VALUES( \"" + dateTimeStamp + "\")");

UPD: sql 的结果符合我的需要!!!这种方法工作完美: 2020-10-08 03:23:38.454

但是使用休眠/JPA 结果为 FALSE。
调试跟踪:
2020-10-09 22:26:53.120 休眠:插入 date_test(日期)值(?)
2020-10-09 22:26:53.122 TRACE 95038 --- [restartedMain] ohtype.descriptor.sql.BasicBinder:绑定参数 [1] 作为 [TIMESTAMP] - [2020-10-09 22:26:53.044]

        Calendar calendar = Calendar.getInstance();
        Date date = new Date();
        calendar.setTimeInMillis(date.getTime());
        dateTestDomain.setDateTest(calendar);

        dateTestRepo.save(dateTestDomain);

sql 的结果:小数秒总是设置为 .000 与休眠 sql 插入:

2020-10-09 22:26:53.000

请帮忙。我需要以毫秒精度保存到数据库时间抛出 JPA。

更新:

我试试sql方言:
org.hibernate.dialect.MySQL5InnoDBDialect 比 org.hibernate.dialect.MySQL55InnoDBDialect 比 org.hibernate.dialect.MariaDB103Dialect 比 org.hibernate.dialect.MariaDB105Dialect
没有成功。
UPD 1:
休眠: INSERT INTO date_test (timestamp, local_date_time, local_date_timea) VALUES (NOW(3), ?, ?)
2020-10-10 15:33:29.099 TRACE 44072 --- [restartedMain] ohtype.descriptor.sql.BasicBinder:绑定参数 [1] 作为 [TIMESTAMP] - [2020-10-10 15:33:29.051] 2020-10-10 15:33:29.100 TRACE 44072 --- [restartedMain] ohtype.descriptor.sql.BasicBinder:绑定参数 [2] 作为 [TIMESTAMP] - [java.util.GregorianCalendar[time=1602336809051,areFieldsSet=真的……

结果 SQL:
2020-10-10 15:33:29.101、2020-10-10 13:33:29.000、2020-10-10 15:33:29.000。

还有一个问题:
数据库日期:
2020-10-10 16:19:42.578
2020-10-10 16:20:47.000
2020-10-10 16:20:47.888
2020-10-10 16:20:47.892
2020-10-10 16:20:47.896
2020-10-10 16:20:47.900
休眠:从 date_test datetestdo0_ 中选择 datetestdo0_.timestamp 作为 timestam1_0_ where datetestdo0_.timestamp>?
绑定参数 [1] 作为 [TIMESTAMP] - [2020-10-10 16:20:47.893]
2020-10-10 16:20:47.888
2020-10-10 16:20:47.892
2020-10-10 16:20:47.896
2020-10-10 16:20:47.9

jdbcsql:
从 date_test 中选择时间戳,其中时间戳>“2020-10-10 16:20:47.893”
2020-10-10 16:20:47.896
2020-10-10 16:20:47.900

jpa/hibernate 无法使用毫秒...

【问题讨论】:

  • 您可以将格式化的时间字符串附加到 sql 中,精度为毫秒。 stackoverflow.com/questions/1459656/…
  • 格式化字符串?我有时间戳 - 格式为毫秒的时间戳。
  • 将 .append(dateTimeStamp) 替换为 .append(YourFormattedString)。您可以在链接中找到如何获取表示日期和时间的格式化字符串
  • @Dario 在这个地方 - 这不是我的问题。 jdbctemplate 工作正常,但在最后 3 行:我的问题 hibernate dateTestRepo.save(dateTestDomain) 始终设置为 .000 时间戳。这是我的问题。我,不需要将时间戳格式化为字符串或更改 sql 查询,我需要 jpa 将我的时间戳保存到数据库,毫秒与 jdbctemplate 相同。
  • 对于初学者,您应该比较相同的事物。您正在做的是将带有 Timestamp.toString 结果的静态 SQL 传递到查询中。您应该做的是db.update("INSERT INTO date_test (date) VALUES(?);", timestamps);,因为这将使用 JPA/hibernate 也在使用的正确 sql 转换。最后在你的字段定义中添加一个@Temporal(TIMESTAMP)

标签: java hibernate spring-data-jpa mariadb


【解决方案1】:

我建议您使用 Instant 来模拟时间线上的单个瞬时点。

import java.time.Instant;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        Instant now = Instant.now();
        System.out.println(now);

        // Instant to milliseconds
        System.out.println(now.toEpochMilli());

        // Milliseconds to Instant
        Instant moment = Instant.ofEpochMilli(1602120218454L);
        // Print the default representation i.e. Instant#toString
        System.out.println(moment);
        // Which is same as the following output
        String strTimestampDefaultFormat = moment.toString();
        System.out.println(strTimestampDefaultFormat);

        // Custom representation with milliseconds precision
        String strTimestamp = moment.atOffset(ZoneOffset.UTC)
                .format(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS"));
        System.out.println(strTimestamp);
    }
}

样本运行的输出:

2020-10-08T13:44:46.765240Z
1602164686765
2020-10-08T01:23:38.454Z
2020-10-08T01:23:38.454Z
2020-10-08 01:23:38.454

使用strTimestamp(如上获得),您可以替换

sql.append(" (date) VALUES( \"").append(dateTimeStamp).append("\")");

sql.append(" (date) VALUES( \"").append(strTimestamp).append("\")");

【讨论】:

  • 如何帮助我使用 JPA 休眠?
  • @Alex - 我建议您使用 Instant(它是 Java 的 modern date-time API 的一部分)而不是使用旧版 java.sql.Timestamp
  • 那么在您的情况下,我必须将数据库字段 Timestamp 更改为 Varchar?比我如何比较字符串和日期时间?或者在您的情况下将字符串传输到数据库中的 unixtime 以进行比较并返回字符串...我不明白。
  • 亲爱的@Arvind Kumar Avinash - 我不需要使用 jdbctemplate 保存到数据库并更改了 sql。它工作得很好。但我需要 jpa/hibernate。这是我的问题。
【解决方案2】:

从 JPA 2.2 开始支持 java8 日期和时间 API。我没有尝试过它是否能解决你的问题,但你可以尝试使用 java8 的 LocalDateTime 而不是 Calendar 类型。

替换:

@Id
@Column(nullable = false, name = "date", columnDefinition = "TIMESTAMP")
@Temporal(TIMESTAMP)
private LocalDateTime localDateTime;

【讨论】:

  • 谢谢,但 @Temporal 只能在 java.util.Date 或 java.util.Calendar 属性上设置。 docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/…
  • 正如我提到的,它们从 2.2 版本开始也支持其他类型。 baeldung.com/jpa-java-time检查这个
  • 带注释 Temporal 只能在 java.util.Date 或 java.util.Calendar 属性上设置。没有 - 是的,都支持其他类型。请再看你的链接。在第 5 点中,没有关于注释 Temporal 的内容。但这对于新的 hibernate 并不重要,这里更改为新的注释 org.hibernate.annotations.Type( type = "calendar" ) 。但还是不行。
  • 在这种情况下,您可以尝试不使用@Temporal 吗?
  • 我正在尽一切可能......它不起作用。并从 db 中选择,但不能正常工作。
【解决方案3】:
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(calendar.getTimeInMillis());

试试这个,而不是使用 new Date()

【讨论】:

  • 谢谢。如果您看到调试跟踪 sql 查询,那它的值没有问题。以毫秒为单位发送值。休眠后获取时间截断毫秒并保存。
猜你喜欢
  • 2023-02-10
  • 2015-09-23
  • 2017-06-13
  • 2020-01-30
  • 2017-08-31
  • 2017-06-23
  • 2013-02-03
  • 1970-01-01
  • 2020-09-27
相关资源
最近更新 更多