Spring Boot JPA Hibernate - 以毫秒精度存储日期
Posted
技术标签:
【中文标题】Spring Boot JPA Hibernate - 以毫秒精度存储日期【英文标题】:Spring Boot JPA Hibernate - Storing Date with millisecond precision 【发布时间】: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 中,精度为毫秒。 ***.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)
。
【参考方案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 查询,那它的值没有问题。以毫秒为单位发送值。休眠后获取时间截断毫秒并保存。以上是关于Spring Boot JPA Hibernate - 以毫秒精度存储日期的主要内容,如果未能解决你的问题,请参考以下文章
制作多个 EntityManager(Spring-Boot-JPA、Hibernate、MSSQL)
Spring Boot / JPA / Hibernate,如何根据 Spring 配置文件切换数据库供应商?
Spring boot之 JPA/Hibernate/Spring Data
Spring Boot JPA Hibernate - 以毫秒精度存储日期
当加载 spring-boot 和 spring-data-jpa 时,Hibernate 无法加载 JPA 2.1 Converter