關於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;
    }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM