本文的示例代码参考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"}
网友评论