• 关于Java中集成mysql(springboot)处理数据创建时间和最后更新时间的总结


    关于Java中集成mysql(springboot)处理数据创建时间和最后更新时间的总结

    ​ 在服务端开发中,经常会遇到需要记录数据库记录的创建时间与更新时间,往常的时候只是把别人的代码粘贴过来用了,也没有实际整理过;近几天通过网上搜索及实际测试整理出一套结论

    网上目前主要流传有4种解决方案,但是有一些方案确实并不合适,以下是自己整理的以下实测结果及最终推荐方案,请参考指正

    1 在数据库表设计上直接解决

      `createTime` datetime DEFAULT CURRENT_TIMESTAMP,
      `updateTime` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
      
      --datetime(3):括号内的数字表示保留的毫秒位数。
    

    实测结果:

    在数据库中创建一测试表,并按上述脚本建立创建时间和最后更新时间
    
    因不推荐此方案,所以就不摆操作截图了,直说结果总结:
    1.该方案在entity对象中如果不设置createTime和updateTime属性是可以的,数据库可以自动更新两个时间
    2.但是在实际业务中我们很有可能会需要查询出两个时间,用于了解数据的创建和更新情况,或者用于排序;但是问题就在这里了,如果在entity对象中增加了这两个参数,并且不设置值的话,就会导致数据库中这两个字段的值为空
    

    2 有人提出用@DynamicUpdate和@DynamicInsert

    先说一下@DynamicUpdate和@DynamicInsert是干什么的,什么作用?

    @DynamicInsert属性:设置为true,设置为true,表示insert对象的时候,生成动态的insert语句,如果这个字段的值是null就不会加入到insert语句当中.默认false。
    比如希望数据库插入日期或时间戳字段时,在对象字段为空的情况下,表字段能自动填写当前的sysdate。

    @DynamicUpdate属性:设置为true,设置为true,表示update对象的时候,生成动态的update语句,如果这个字段的值是null就不会被加入到update语句中,默认false。
    比如只想更新某个属性,但是却把整个对象的属性都更新了,这并不是我们希望的结果,我们希望的结果是:我更改了哪些字段,只要更新我修改的字段就够了。

    举例说明
    看下面打印的sql语句就会立刻明白,使用这两个注解的效果

    @DynamicInsert注解下Hibernate日志打印SQL

    Hibernate: insert into Cat (cat_name, id) values (?, ?)  
    

    反之

    Hibernate: insert into Cat (create_time, update_time, cat_name, id) values (?, ?, ?, ?)  
    

    @DynamicUpdate注解下Hibernate日志打印SQL:

    说明:如果字段有更新,Hibernate才会对该字段进行更新

    Hibernate: update Cat set update_time=? where id=?
    

    反之Cat实体类去掉@DynamicUpdate

    说明:不管字段有没有更新,Hibernate都会对该字段进行更新

    Hibernate: update Cat set update_time=?, cat_name=? where id=?  
    

    @MappedSuperclass 这个注解表示在父类上面的,用来标识父类。

    基于代码复用和模型分离的思想,在项目开发中使用JPA的@MappedSuperclass注解将实体类的多个属性分别封装到不同的非实体类中。例如,数据库表中都需要id来表示编号,id是这些映射实体类的通用的属性,交给jpa统一生成主键id编号,那么使用一个父类来封装这些通用属性,并用@MappedSuperclas标识。

    注意:

    1.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。

    2.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。

    @MappedSuperclass 
    public abstract class BaseEntity{ 
        @Id 
        @GeneratedValue 
        @Column(length=20)   
        public Integer getId() { 
            return this.id; 
        } 
        public void setId(Integer id) { 
            this.id = id; 
        } 
    } 
    

    以上解释参考原文链接:https://blog.csdn.net/Janson_Lin/article/details/95059297

    实验结论:

    ​ 用@DynamicUpdate和@DynamicInsert实现最后更新时间其实是用了一种讨巧的方案,并且更新的时候也会存在问题;这里就不多做描述了,在此学习一下这两个注解也是很不错的

    3 Spring Data JPA 的时间注解:@CreatedDate 和 @LastModifiedDate

    选择 Spring Data JPA 框架开发时,常用在实体和字段上的注解有@Entity@Id@Column等。在表设计规范中,通常建议保留的有两个字段,一个是更新时间,一个是创建时间。Spring Data JPA 提供了相应的时间注解,只需要两步配置,就可以帮助开发者快速实现这方面的功能。

    1. 在实体类上加上注解 @EntityListeners(AuditingEntityListener.class),在相应的字段上添加对应的时间注解 @LastModifiedDate@CreatedDate

    注意:日期类型可以用 Date 也可以是 Long

    @Entity
    @EntityListeners(AuditingEntityListener.class)
    public class User {
    
         /**
         * 自增主键
         */
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Integer id;
    
         /**
         * 更新时间
         */
        @LastModifiedDate
        @Column(nullable = false)
        private Long updateTime;
    
         /**
         * 创建时间
         */
        @CreatedDate
        @Column(updatable = false, nullable = false)
        private Date createTime;
    
        // 省略getter和setter
    

    2.在Application启动类中添加注解 @EnableJpaAuditing

    @EnableJpaAuditing
    @SpringBootApplication
    public class TestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TestApplication.class, args);
        }
        
    }
    

    测试总结:该方案确实有效,但是配置相对繁琐;还需要在启动类上加注解

    4 Hibernate 注解(最终推荐)

    Hibernate 也提供了类似上述时间注解的功能实现,这种方法只需要一步配置,更改为注解 @UpdateTimestamp@CreationTimestamp 即可(参考如下):

    请注意:在执行更新的时候需要给UpdateTime进行一次赋值;(其实我的目标是想不赋值自动更新的,如果大家有好的解决方案请指点)
    User aa=userRepository.findByUserName("a");
    aa.setUpdateTime(new Date());
    userRepository.save(aa);

    @Entity
    @Table(name = "java2mysql")
    @Data
    public class Java2Mysql implements Serializable {
    
        private static final long serialVersionUID = -1L;
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
    
        @Column(name = "name")
        private String name;
    
        @Column(name = "update_time")
        @Temporal(TemporalType.TIMESTAMP)
        @UpdateTimestamp
        private Date updateTime;
    
        @Column(name = "create_time",updatable = false)
        @Temporal(TemporalType.TIMESTAMP)
        @CreationTimestamp
        private Date createTime;
    
    

    在此补充两个注解的解释

    @Column

    #  @Column注解
    用来标识实体类中属性与数据表中字段的对应关系
    
    #  属性详解:
    name
    定义了被标注字段在数据库表中所对应字段的名称;
    unique
    表示该字段是否为唯一标识,默认为false。如果表中有一个字段需要唯一标识,则既可以使用该标记,也可以使用@Table标记中的@UniqueConstraint。
    nullable
    表示该字段是否可以为null值,默认为true。
    insertable
    表示在使用“INSERT”脚本插入数据时,是否需要插入该字段的值。
    updatable
    表示在使用“UPDATE”脚本插入数据时,是否需要更新该字段的值。insertable和updatable属性一般多用于只读的属性,例如主键和外键等。这些字段的值通常是自动生成的。
    columnDefinition(大多数情况,几乎不用)
    表示创建表时,该字段创建的SQL语句,一般用于通过Entity生成表定义时使用。(也就是说,如果DB中表已经建好,该属性没有必要使用。)
    table
    表示当映射多个表时,指定表的表中的字段。默认值为主表的表名。
    length
    表示字段的长度,当字段的类型为varchar时,该属性才有效,默认为255个字符。
    precision和scale
    precision属性和scale属性表示精度,当字段类型为double时,precision表示数值的总长度,scale表示小数点所占的位数。
    
    #  @Column可以标注在属性前或getter方法前
    
    @Column标注在属性前(建议使用这一种方式)
    
    

    @Temporal

    数据库的字段类型有date、time、datetime
    而Temporal注解的作用就是帮Java的Date类型进行格式化,一共有三种注解值:
    
      第一种:@Temporal(TemporalType.DATE)——>实体类会封装成日期“yyyy-MM-dd”的 Date类型。
      第二种:@Temporal(TemporalType.TIME)——>实体类会封装成时间“hh-MM-ss”的 Date类型。
      第三种:@Temporal(TemporalType.TIMESTAMP)——>实体类会封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型。
    注解方式有两种:
      写在字段上:
        @Temporal(TemporalType.TIMESTAMP)
        private Date birthday;
      
      写在 getXxx方法上:
        @Temporal(TemporalType.DATE)
        @Column(name = "birthday", length = 10)
        public Date getBirthday() {
            return this.birthday;
        }
    
  • 相关阅读:
    [转]C++中cin、cin.get()、cin.getline()、getline()函数的简单总结
    Assert 的用法
    [转]C/C++作用域详解
    C++ 的getline问题
    字符数组的定义与赋值
    [转] 字符数组的赋值
    [转]标准C++中的string类的用法总结
    [转]memmove、memcpy和memccpy
    关于变长数组的一点小想法-C语言定义数组但是数组长度不确定怎么办
    Java动态代理演变之路
  • 原文地址:https://www.cnblogs.com/linuxtop/p/12697130.html
Copyright © 2020-2023  润新知