springboot 2.1.7 + mysql5.6 弃用 Calendar类型字段

Java框架

浏览数:118

2019-8-24

原因:在使用Calendar做为字段类型时,每进行一次findById()操作返回的数据的值都比实际值要大一点。更新后再调用查询,还会再大一点。也就是说:如果我们用Calendar做为字段类型,那么该字段会在程序运行时会静悄悄的增大。

代码准备

示例代码很简单:我们只需要准备两个类,一个实体,一个数据访问对象。

Student.java

package com.example.demo;

import org.hibernate.annotations.CreationTimestamp;

import javax.persistence.*;
import java.sql.Timestamp;
import java.util.Calendar;

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    
    @CreationTimestamp
    private Calendar applyTime;
    
    @CreationTimestamp
    private Timestamp applyTimestamp;

    // 省略构造函数及setter/getter
}

为了测试代码更简单,我们为applyTimeapplyTime加入CreationTimestamp注解。让其自动生成。

删除自动时间戳并不会影响测试结果

package com.example.demo;

import org.springframework.data.repository.CrudRepository;

public interface StudentRepository extends CrudRepository<Student, Long> {
}

测试代码

package com.example.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class StudentRepositoryTest {
    private static final Logger logger = LoggerFactory.getLogger(StudentRepositoryTest.class);
    @Autowired StudentRepository studentRepository;

    @Test
    public void test() {
        Student student = new Student();
        studentRepository.save(student);

        Student student1 = studentRepository.findById(student.getId()).get();
        System.out.println(student1.getApplyTime().getTimeInMillis());
        System.out.println(student1.getApplyTimestamp().getTime());
   }
}

结果如下:

1566119784000
1566090984000

可见,使用Calendar类型获取值较Timestamp类型的自动增加了。如果此时保存实体,则此增加的值将被自动写入数据表。

github: https://github.com/mengyunzhi…
stackoverflow: https://stackoverflow.com/que…

结论

Calendar类型在spring-boot 2.1.7版本中应该暂时弃用,转而使用TimestampLocalDateTime

老项目升级

如果你也是在版本的基础上升的级,那么需要处理一样时区的问题。因为同样的数据CalendarTimestamp最终存到数据库中的值是不一致的。其中Calendar存的是加入了时区以后的值,Timestamp存的是原始值:

幸运的是:两个类型映射到mysql中的类型均是datetime,这为我们降低了升级的难度。

变更实体映射类型

    @CreationTimestamp
    private Timestamp applyTime;

老数据-8时处理

update student set apply_time = SUBTIME(apply_time, '8:00');

作者:myskies