美文网首页
记一个数据库时间问题

记一个数据库时间问题

作者: 诺之林 | 来源:发表于2020-11-09 14:32 被阅读0次

本文的示例代码参考jpa-issue

目录

问题复现

  • MySQL
docker run --name jpa-issue -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7.17

docker exec -i jpa-issue mysql -uroot -p123456  < ./db.sql
CREATE DATABASE IF NOT EXISTS d_demo DEFAULT CHARSET utf8 COLLATE utf8_general_ci;

USE d_demo;
CREATE TABLE `t_demo` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `title` varchar(255) DEFAULT '''',
  `keywords` varchar(255) DEFAULT '''',
  `description` mediumtext,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  • JPA
spring init --list | grep 'jpa\|mysql'

spring init -b=2.2.10.RELEASE -j=1.8 -l=java -d=web,data-jpa,mysql --build=gradle jpa-issue && cd jpa-issue
vim src/main/resources/application.properties
spring.datasource.url = jdbc:mysql://localhost:3306/d_demo?useSSL=true&characterEncoding=UTF-8
spring.datasource.username = root
spring.datasource.password = 123456
vim src/main/java/com/example/jpaissue/Demo.java
package com.example.jpaissue;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = "t_demo")
public class Demo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @CreationTimestamp
    public Date createdAt;

    @UpdateTimestamp
    public Date updatedAt;

    public String title;

    public String keywords;

    @Column(columnDefinition = "MEDIUMTEXT")
    public String description;
}
vim src/main/java/com/example/jpaissue/DemoRepo.java
package com.example.jpaissue;

import org.springframework.data.jpa.repository.JpaRepository;

public interface DemoRepo extends JpaRepository<Demo, Long> {
}
vim src/main/java/com/example/jpaissue/DemoController.java
package com.example.jpaissue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
    @Autowired
    private DemoRepo demoRepo;

    @GetMapping("/demo")
    public Demo demo() {
        Demo demo = new Demo();
        demo.title = "title";
        demo.keywords = "keywords";
        demo.description = "description";
        return demoRepo.save(demo);
    }
}
./gradlew bootrun

curl localhost:8080/demo
  • 多次接口请求复现该问题
{"id":1,"createdAt":"2020-11-06T08:07:04.631+0000","updatedAt":"2020-11-06T08:07:04.631+0000","title":"title","keywords":"keywords","description":"description"}

id  created_at  updated_at  title   keywords    description
1   2020-11-06 08:07:05 2020-11-06 08:07:05 title   keywords    description
  • 两个时间的秒数并不相等

问题原因

  • MySQL datetime对于毫秒会有四舍五入
INSERT INTO `d_demo`.`t_demo` ( `id`, `created_at`, `updated_at`, `title`, `keywords`, `description` )
VALUES
    ( 4, '2020-11-09 13:12:36.123', '2020-11-09 13:12:36.789', 'title', 'keywords', 'description' );
id  created_at  updated_at  title   keywords    description
4   2020-11-09 13:12:36 2020-11-09 13:12:37 title   keywords    description

问题解决

vim src/main/java/com/example/jpaissue/Demo.java
package com.example.jpaissue;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@Entity
@Table(name = "t_demo")
public class Demo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    public Date createdAt;

    @NotNull
    @Temporal(TemporalType.TIMESTAMP)
    public Date updatedAt;

    public String title;

    public String keywords;

    @Column(columnDefinition = "MEDIUMTEXT")
    public String description;

    @PrePersist
    public void prePersist() throws ParseException {
        Date currentDate = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        currentDate = sdf.parse(sdf.format(currentDate));
        createdAt = currentDate;
        updatedAt = currentDate;
    }

    @PreUpdate
    public void preUpdate() throws ParseException {
        Date currentDate = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        currentDate = sdf.parse(sdf.format(currentDate));
        updatedAt = currentDate;
    }
}
./gradlew bootrun

curl localhost:8080/demo
{"id":22,"createdAt":"2020-11-09T06:30:43.000+0000","updatedAt":"2020-11-09T06:30:43.000+0000","title":"title","keywords":"keywords","description":"description"}

参考

相关文章

网友评论

      本文标题:记一个数据库时间问题

      本文链接:https://www.haomeiwen.com/subject/mwimvktx.html