Cap waktu pembuatan dan cap waktu pembaruan terakhir dengan Hibernate dan MySQL

244

Untuk entitas Hibernate tertentu, kami memiliki persyaratan untuk menyimpan waktu pembuatannya dan terakhir kali diperbarui. Bagaimana Anda mendesain ini?

  • Tipe data apa yang akan Anda gunakan dalam database (dengan asumsi MySQL, mungkin dalam zona waktu yang berbeda dari JVM)? Apakah tipe data akan sadar zona waktu?

  • Data apa jenis yang akan Anda gunakan di Jawa ( Date, Calendar, long, ...)?

  • Dengan siapa Anda bertanggung jawab untuk mengatur stempel waktu — basis data, kerangka kerja ORM (Hibernate), atau pemrogram aplikasi?

  • Anotasi apa yang akan Anda gunakan untuk pemetaan (misalnya @Temporal)?

Saya tidak hanya mencari solusi yang berfungsi, tetapi untuk solusi yang aman dan dirancang dengan baik.

ngn
sumber

Jawaban:

266

Jika Anda menggunakan anotasi JPA, Anda dapat menggunakan @PrePersistdan @PreUpdatekait acara melakukan ini:

@Entity
@Table(name = "entities")    
public class Entity {
  ...

  private Date created;
  private Date updated;

  @PrePersist
  protected void onCreate() {
    created = new Date();
  }

  @PreUpdate
  protected void onUpdate() {
    updated = new Date();
  }
}

atau Anda dapat menggunakan @EntityListeneranotasi di kelas dan menempatkan kode acara di kelas eksternal.

Guðmundur Bjarni
sumber
7
Berfungsi tanpa masalah di J2SE, karena @PrePersist dan @PerUpdate adalah anotasi JPA.
Kdeveloper
2
@Kumar - Jika Anda menggunakan sesi Hibernate biasa (bukan JPA), Anda dapat mencoba pendengar acara hibernasi, meskipun itu tidak terlalu elegan dan ringkas vs anotasi JPA.
Shailendra
43
Dalam Hibernate saat ini dengan JPA kita dapat menggunakan "@CreationTimestamp" dan "@UpdateTimestamp"
Florian Loch
@FlorianLoch apakah ada yang setara untuk Date daripada Timestamp? Atau haruskah saya membuat sendiri?
mike
151

Anda bisa menggunakan @CreationTimestampdan @UpdateTimestamp:

@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "create_date")
private Date createDate;

@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "modify_date")
private Date modifyDate;
idmitriev
sumber
3
terima kasih bro hal kecil seperti itu perlu memperbarui cap waktu. Saya tidak tahu. kamu menyelamatkan hariku.
Virendra Sagar
Ada TemporalType.DATEdalam kasus pertama dan TemporalType.TIMESTAMPyang kedua.
v.ladynev
Apakah Anda mengatakan ini juga secara otomatis menetapkan nilai? Itu bukan pengalaman saya; tampaknya bahkan dengan @CreationTimestampdan @UpdateTimestampsatu membutuhkan beberapa @Column(..., columnDefinition = "timestamp default current_timestamp"), atau menggunakan @PrePersistdan @PreUpdate(yang terakhir juga memastikan klien tidak dapat menetapkan nilai yang berbeda).
Arjan
2
Ketika saya memperbarui objek dan bertahan, bd kehilangan create_date ... mengapa?
Brenno Leal
1
Saya kasus saya dihapus nullable=falsedari @Column(name = "create_date" , nullable=false)bekerja
Shantaram Tupe
113

Mengambil sumber daya dalam posting ini bersama dengan informasi yang diambil kiri dan kanan dari berbagai sumber, saya datang dengan solusi elegan ini, membuat kelas abstrak berikut

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@MappedSuperclass
public abstract class AbstractTimestampEntity {

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created", nullable = false)
    private Date created;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "updated", nullable = false)
    private Date updated;

    @PrePersist
    protected void onCreate() {
    updated = created = new Date();
    }

    @PreUpdate
    protected void onUpdate() {
    updated = new Date();
    }
}

dan minta semua entitas Anda memperluasnya, misalnya:

@Entity
@Table(name = "campaign")
public class Campaign extends AbstractTimestampEntity implements Serializable {
...
}
Olivier Refalo
sumber
5
ini bagus sampai Anda ingin menambahkan perilaku eksklusif yang berbeda ke entitas Anda (dan Anda tidak dapat memperpanjang lebih dari satu kelas dasar). afaik satu-satunya cara untuk mendapatkan efek yang sama tanpa kelas dasar adalah melalui aspekj itd atau acara pendengar lihat @kieren dixon answer
gpilotino
3
Saya akan melakukan ini menggunakan pemicu MySQL sehingga bahkan jika entitas penuh tidak disimpan atau dimodifikasi oleh aplikasi eksternal atau permintaan manual, masih akan memperbarui bidang ini.
Webnet
3
dapatkah Anda memberi saya contoh kerja karena saya sedang mengalami pengecualiannot-null property references a null or transient value: package.path.ClassName.created
Sumit Ramteke
@ RishiAgar, Tidak, aku belum. Tetapi untuk sekarang saya telah menetapkan tanggal ke properti saya dari konstruktor default. Akan memberitahu Anda setelah saya temukan.
Sumit Ramteke
1
Ubah @Column(name = "updated", nullable = false, insertable = false)untuk membuatnya berfungsi. Menarik bahwa jawaban ini mendapat begitu banyak upvotes ..
displayname
20

1. Jenis kolom basis data apa yang harus Anda gunakan

Pertanyaan pertama Anda adalah:

Tipe data apa yang akan Anda gunakan dalam database (dengan asumsi MySQL, mungkin dalam zona waktu yang berbeda dari JVM)? Apakah tipe data akan sadar zona waktu?

Di MySQL, TIMESTAMPtipe kolom bergeser dari zona waktu lokal driver JDBC ke zona waktu database, tetapi hanya dapat menyimpan cap waktu hingga '2038-01-19 03:14:07.999999, jadi itu bukan pilihan terbaik untuk masa depan.

Jadi, lebih baik gunakan DATETIME, yang tidak memiliki batasan batas atas ini. Namun, DATETIMEtidak sadar zona waktu. Jadi, untuk alasan ini, lebih baik menggunakan UTC di sisi basis data dan menggunakan hibernate.jdbc.time_zoneproperti Hibernate.

Untuk detail lebih lanjut tentang hibernate.jdbc.time_zonepengaturan, periksa artikel ini .

2. Jenis properti entitas apa yang harus Anda gunakan

Pertanyaan kedua Anda adalah:

Jenis data apa yang akan Anda gunakan di Jawa (Tanggal, Kalender, panjang, ...)?

Di sisi Java, Anda dapat menggunakan Java 8 LocalDateTime. Anda juga dapat menggunakan warisan Date, tetapi tipe Tanggal / Waktu Java 8 lebih baik karena tidak dapat diubah, dan jangan melakukan zona waktu bergeser ke zona waktu lokal saat mencatatnya.

Untuk detail lebih lanjut tentang tipe Tanggal / Waktu Java 8 yang didukung oleh Hibernate, lihat artikel ini .

Sekarang, kita juga dapat menjawab pertanyaan ini:

Anotasi apa yang akan Anda gunakan untuk pemetaan (misalnya @Temporal)?

Jika Anda menggunakan LocalDateTimeatau java.sql.Timestampuntuk memetakan properti entitas timestamp, maka Anda tidak perlu menggunakan @Temporalkarena HIbernate sudah tahu bahwa properti ini harus disimpan sebagai JDBC Timestamp.

Hanya jika Anda menggunakan java.util.Date, Anda perlu menentukan @Temporalanotasi, seperti ini:

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created_on")
private Date createdOn;

Tapi, jauh lebih baik jika Anda memetakannya seperti ini:

@Column(name = "created_on")
private LocalDateTime createdOn;

Cara menghasilkan nilai kolom audit

Pertanyaan ketiga Anda adalah:

Dengan siapa Anda bertanggung jawab untuk mengatur stempel waktu — basis data, kerangka kerja ORM (Hibernate), atau pemrogram aplikasi?

Anotasi apa yang akan Anda gunakan untuk pemetaan (misalnya @ temporal)?

Ada banyak cara untuk mencapai tujuan ini. Anda dapat mengizinkan database untuk melakukan itu ..

Untuk create_onkolom, Anda bisa menggunakan DEFAULTbatasan DDL, seperti:

ALTER TABLE post 
ADD CONSTRAINT created_on_default 
DEFAULT CURRENT_TIMESTAMP() FOR created_on;

Untuk updated_onkolom, Anda bisa menggunakan pemicu DB untuk mengatur nilai kolom dengan CURRENT_TIMESTAMP()setiap kali baris yang diberikan dimodifikasi.

Atau, gunakan JPA atau Hibernate untuk mengaturnya.

Mari kita asumsikan Anda memiliki tabel database berikut:

Tabel database dengan kolom audit

Dan, setiap tabel memiliki kolom seperti:

  • created_by
  • created_on
  • updated_by
  • updated_on

Menggunakan Hibernate @CreationTimestampdan @UpdateTimestampanotasi

Hibernate menawarkan @CreationTimestampdan @UpdateTimestampanotasi yang dapat digunakan untuk memetakan created_ondan updated_onkolom.

Anda bisa menggunakan @MappedSuperclassuntuk mendefinisikan kelas dasar yang akan diperluas oleh semua entitas:

@MappedSuperclass
public class BaseEntity {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "created_on")
    @CreationTimestamp
    private LocalDateTime createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @Column(name = "updated_on")
    @UpdateTimestamp
    private LocalDateTime updatedOn;

    @Column(name = "updated_by")
    private String updatedBy;

    //Getters and setters omitted for brevity
}

Dan, semua entitas akan memperpanjang BaseEntity, seperti ini:

@Entity(name = "Post")
@Table(name = "post")
public class Post extend BaseEntity {

    private String title;

    @OneToMany(
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();

    @OneToOne(
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.LAZY
    )
    private PostDetails details;

    @ManyToMany
    @JoinTable(
        name = "post_tag",
        joinColumns = @JoinColumn(
            name = "post_id"
        ),
        inverseJoinColumns = @JoinColumn(
            name = "tag_id"
        )
    )
    private List<Tag> tags = new ArrayList<>();

    //Getters and setters omitted for brevity
}

Untuk detail lebih lanjut tentang penggunaan @MappedSuperclass, lihat artikel ini .

Namun, bahkan jika createdOndan updateOnproperti diatur oleh khusus Hibernate @CreationTimestampdan @UpdateTimestampanotasi, createdBydan updatedBymengharuskan mendaftarkan panggilan balik aplikasi, seperti yang diilustrasikan oleh solusi JPA berikut.

Menggunakan JPA @EntityListeners

Anda dapat merangkum properti audit dalam Embeddable:

@Embeddable
public class Audit {

    @Column(name = "created_on")
    private LocalDateTime createdOn;

    @Column(name = "created_by")
    private String createdBy;

    @Column(name = "updated_on")
    private LocalDateTime updatedOn;

    @Column(name = "updated_by")
    private String updatedBy;

    //Getters and setters omitted for brevity
}

Dan, buat AuditListeneruntuk mengatur properti audit:

public class AuditListener {

    @PrePersist
    public void setCreatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();

        if(audit == null) {
            audit = new Audit();
            auditable.setAudit(audit);
        }

        audit.setCreatedOn(LocalDateTime.now());
        audit.setCreatedBy(LoggedUser.get());
    }

    @PreUpdate
    public void setUpdatedOn(Auditable auditable) {
        Audit audit = auditable.getAudit();

        audit.setUpdatedOn(LocalDateTime.now());
        audit.setUpdatedBy(LoggedUser.get());
    }
}

Untuk mendaftar AuditListener, Anda dapat menggunakan @EntityListenersanotasi JPA:

@Entity(name = "Post")
@Table(name = "post")
@EntityListeners(AuditListener.class)
public class Post implements Auditable {

    @Id
    private Long id;

    @Embedded
    private Audit audit;

    private String title;

    @OneToMany(
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true
    )
    private List<PostComment> comments = new ArrayList<>();

    @OneToOne(
        mappedBy = "post",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.LAZY
    )
    private PostDetails details;

    @ManyToMany
    @JoinTable(
        name = "post_tag",
        joinColumns = @JoinColumn(
            name = "post_id"
        ),
        inverseJoinColumns = @JoinColumn(
            name = "tag_id"
        )
    )
    private List<Tag> tags = new ArrayList<>();

    //Getters and setters omitted for brevity
}

Untuk detail lebih lanjut tentang menerapkan properti audit dengan JPA @EntityListener, lihat artikel ini .

Vlad Mihalcea
sumber
Jawaban yang sangat teliti, terima kasih. Saya tidak setuju tentang memilih datetimelebih timestamp. Anda ingin database Anda mengetahui zona waktu cap waktu Anda. Ini mencegah kesalahan konversi zona waktu.
Ole VV
The timestsmptipe tidak menyimpan informasi zona waktu. Itu hanya melakukan percakapan dari aplikasi TZ ke DB TZ. Pada kenyataannya, Anda ingin menyimpan TZ klien secara terpisah dan melakukan percakapan dalam aplikasi sebelum merender UI.
Vlad Mihalcea
Benar. MySQL timestampselalu dalam UTC. MySQL mengonversi TIMESTAMPnilai dari zona waktu saat ini ke UTC untuk penyimpanan, dan kembali dari UTC ke zona waktu saat ini untuk pengambilan. Dokumentasi MySQL: Tipe DATE, DATETIME, dan TIMESTAMP
Ole VV
17

Anda juga dapat menggunakan interseptor untuk mengatur nilai

Buat antarmuka yang disebut TimeStamped yang diterapkan entitas Anda

public interface TimeStamped {
    public Date getCreatedDate();
    public void setCreatedDate(Date createdDate);
    public Date getLastUpdated();
    public void setLastUpdated(Date lastUpdatedDate);
}

Tentukan pencegat

public class TimeStampInterceptor extends EmptyInterceptor {

    public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, 
            Object[] previousState, String[] propertyNames, Type[] types) {
        if (entity instanceof TimeStamped) {
            int indexOf = ArrayUtils.indexOf(propertyNames, "lastUpdated");
            currentState[indexOf] = new Date();
            return true;
        }
        return false;
    }

    public boolean onSave(Object entity, Serializable id, Object[] state, 
            String[] propertyNames, Type[] types) {
            if (entity instanceof TimeStamped) {
                int indexOf = ArrayUtils.indexOf(propertyNames, "createdDate");
                state[indexOf] = new Date();
                return true;
            }
            return false;
    }
}

Dan daftarkan ke pabrik sesi

Kieren Dixon
sumber
1
Bekerja, terima kasih. Informasi tambahan docs.jboss.org/hibernate/core/4.0/manual/en-US/html_single/…
Andrii Nemchenko
Ini adalah salah satu solusi, jika Anda bekerja dengan SessionFactory alih-alih EntityManager!
olivmir
Hanya untuk mereka, yang menderita dengan masalah yang sama seperti yang saya lakukan dalam konteks ini: jika entitas Anda sendiri tidak mendefinisikan bidang tambahan ini (CreatedAt, ...) tetapi mewarisinya dari kelas induk, maka kelas induk ini harus dijelaskan dengan @MappedSuperclass - jika tidak, Hibernate tidak menemukan bidang ini.
olivmir
17

Dengan solusi Olivier, selama laporan pembaruan Anda dapat mengalami:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Kolom 'dibuat' tidak boleh nol

Untuk mengatasi ini, tambahkan updatable = false ke penjelasan @Column atribut "dibuat":

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created", nullable = false, updatable=false)
private Date created;
endriju
sumber
1
Kami menggunakan @Version. Ketika suatu entitas diatur dua panggilan dilakukan satu untuk menyimpan dan satu lagi untuk memperbarui. Saya menghadapi masalah yang sama karena ini. Setelah saya menambahkannya @Column(updatable = false)memecahkan masalah saya.
Ganesh Satpute
12

Terima kasih semuanya yang telah membantu. Setelah melakukan riset sendiri (saya orang yang mengajukan pertanyaan), inilah yang menurut saya paling masuk akal:

  • Jenis kolom basis data: jumlah zona waktu-agnostik milidetik sejak tahun 1970 direpresentasikan decimal(20)karena 2 ^ 64 memiliki 20 digit dan ruang disk murah; mari kita berterus terang. Juga, saya tidak akan menggunakan DEFAULT CURRENT_TIMESTAMP, atau memicu. Saya tidak menginginkan keajaiban dalam DB.

  • Java tipe field: long. longCap waktu Unix didukung dengan baik di berbagai lib , tidak memiliki masalah Y2038, aritmatika stempel waktu cepat dan mudah (terutama operator <dan operator +, dengan asumsi tidak ada hari / bulan / tahun yang terlibat dalam perhitungan). Dan, yang paling penting, baik primitif longmaupun java.lang.Longs tidak dapat diubah - secara efektif diteruskan oleh nilai - tidak seperti java.util.Dates; Saya akan sangat kesal untuk menemukan sesuatu seperti foo.getLastUpdate().setTime(System.currentTimeMillis())ketika men-debug kode orang lain.

  • Kerangka kerja ORM harus bertanggung jawab untuk mengisi data secara otomatis.

  • Saya belum menguji ini, tetapi hanya melihat dokumen saya berasumsi bahwa @Temporalakan melakukan pekerjaan; tidak yakin apakah saya akan menggunakan @Versionuntuk tujuan ini. @PrePersistdan @PreUpdatemerupakan alternatif yang baik untuk mengendalikannya secara manual. Menambahkan itu ke supertype layer (kelas dasar umum) untuk semua entitas, adalah ide yang lucu asalkan Anda benar-benar ingin timestamping untuk semua entitas Anda.

ngn
sumber
Sementara rindu dan rindu mungkin tidak berubah, itu tidak akan membantu Anda dalam situasi yang Anda gambarkan. Mereka masih bisa mengatakan foo.setLastUpdate (new Long (System.currentTimeMillis ());
Ian McLaird
2
Tidak apa-apa. Hibernate tetap memerlukan setter (atau ia akan mencoba mengakses bidang secara langsung melalui refleksi). Saya sedang berbicara tentang kesulitan mengejar siapa yang memodifikasi stempel waktu dari kode aplikasi kami. Sangat sulit ketika Anda bisa melakukannya dengan menggunakan rajin
ngn
Saya setuju dengan klaim Anda bahwa kerangka kerja ORM harus bertanggung jawab untuk mengisi tanggal secara otomatis, tetapi saya akan melangkah lebih jauh dan mengatakan bahwa tanggal tersebut harus ditetapkan dari jam server database, daripada klien. Saya tidak jelas apakah ini mencapai tujuan ini. Dalam sql, saya bisa melakukan ini dengan menggunakan fungsi sysdate, tapi saya tidak tahu bagaimana melakukan ini di Hibernate atau implementasi JPA.
MiguelMunoz
Saya tidak menginginkan keajaiban dalam DB. Saya mengerti maksud Anda, tetapi saya ingin mempertimbangkan fakta bahwa database harus melindungi dirinya dari pengembang yang buruk / baru / tidak mengerti. Integritas data sangat penting di perusahaan besar, Anda tidak bisa mengandalkan orang lain untuk memasukkan data yang baik. Kendala, standar, dan FK akan membantu mencapainya.
Icegras
6

Jika Anda menggunakan Session API, panggilan balik PrePersist dan PreUpdate tidak akan berfungsi sesuai dengan jawaban ini .

Saya menggunakan metode persisten () Hibernate Session dalam kode saya sehingga satu-satunya cara saya bisa membuatnya bekerja adalah dengan kode di bawah ini dan mengikuti posting blog ini (juga diposting dalam jawabannya ).

@MappedSuperclass
public abstract class AbstractTimestampEntity {

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created")
    private Date created=new Date();

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "updated")
    @Version
    private Date updated;

    public Date getCreated() {
        return created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    public Date getUpdated() {
        return updated;
    }

    public void setUpdated(Date updated) {
        this.updated = updated;
    }
}
vicch
sumber
Seharusnya mengembalikan objek yang dikloning seperti updated.clone()komponen lain dapat memanipulasi keadaan internal (tanggal)
1ambda
3

Kode berikut berhasil untuk saya.

package com.my.backend.models;

import java.util.Date;

import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

import com.fasterxml.jackson.annotation.JsonIgnore;

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

import lombok.Getter;
import lombok.Setter;

@MappedSuperclass
@Getter @Setter
public class BaseEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Integer id;

    @CreationTimestamp
    @ColumnDefault("CURRENT_TIMESTAMP")
    protected Date createdAt;

    @UpdateTimestamp
    @ColumnDefault("CURRENT_TIMESTAMP")
    protected Date updatedAt;
}
praray
sumber
Hai, mengapa kita perlu protected Integer id;seperti protecteddi kelas induk pada umumnya, karena saya tidak bisa menggunakannya dalam kasus pengujian saya sebagai.getId()
shareef
2

Pendekatan yang baik adalah memiliki kelas dasar yang sama untuk semua entitas Anda. Di kelas dasar ini, Anda dapat memiliki properti id Anda jika itu umumnya dinamai di semua entitas Anda (desain umum), kreasi Anda dan properti tanggal pembaruan terakhir.

Untuk tanggal pembuatan, Anda cukup menyimpan properti java.util.Date . Pastikan, untuk selalu menginisialisasi dengan Date baru () .

Untuk bidang pembaruan terakhir, Anda dapat menggunakan properti Timestamp, Anda perlu memetakannya dengan @Version. Dengan Anotasi ini, properti akan diperbarui secara otomatis oleh Hibernate. Berhati-hatilah bahwa Hibernate juga akan menerapkan penguncian optimis (itu adalah hal yang baik).

bernardn
sumber
2
menggunakan kolom cap waktu untuk penguncian yang optimis adalah ide yang buruk. Selalu gunakan kolom versi integer. Alasannya, 2 JVM mungkin berada di waktu yang berbeda dan mungkin tidak memiliki akurasi milidetik. Jika Anda sebaliknya membuat hibernate menggunakan stempel waktu DB, itu berarti pemilihan tambahan dari DB. Alih-alih hanya menggunakan nomor versi.
sethu
2

Hanya untuk memperkuat: java.util.Calenderbukan untuk Stempel Waktu . java.util.Dateuntuk sesaat, agnostik hal-hal regional seperti zona waktu. Sebagian besar database menyimpan hal-hal dengan cara ini (bahkan jika mereka tampaknya tidak melakukannya; ini biasanya merupakan pengaturan zona waktu dalam perangkat lunak klien; datanya baik)

davetron5000
sumber
1

Sebagai tipe data di JAWA saya sangat merekomendasikan untuk menggunakan java.util.Date. Saya mengalami masalah zona waktu yang cukup buruk saat menggunakan Kalender. Lihat Utas ini .

Untuk mengatur cap waktu saya akan merekomendasikan menggunakan pendekatan AOP atau Anda bisa menggunakan Pemicu di atas meja (sebenarnya ini adalah satu-satunya hal yang saya temukan penggunaan pemicu dapat diterima).

huo73
sumber
1

Anda mungkin mempertimbangkan menyimpan waktu sebagai DateTime, dan dalam UTC. Saya biasanya menggunakan DateTime alih-alih Timestamp karena fakta bahwa MySql mengubah tanggal menjadi UTC dan kembali ke waktu lokal ketika menyimpan dan mengambil data. Saya lebih suka menyimpan logika semacam itu di satu tempat (lapisan Bisnis). Saya yakin ada situasi lain di mana menggunakan Timestamp lebih disukai.

mmacaulay
sumber
1

Kami memiliki situasi yang serupa. Kami menggunakan Mysql 5.7.

CREATE TABLE my_table (
        ...
      updated_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    );

Ini berhasil untuk kita.

amdg
sumber
Ini juga berfungsi dalam kasus ketika data diubah oleh query SQL langsung di database. @PrePersistdan @PrePersistjangan menutupi kasus seperti itu.
pidabrow
1

Jika kita menggunakan @Transaksional dalam metode kami, @CreationTimestamp dan @UpdateTimestamp akan menyimpan nilai dalam DB tetapi akan mengembalikan nol setelah menggunakan save (...).

Dalam situasi ini, menggunakan saveAndFlush (...) berhasil

chomp
sumber
0

Saya pikir lebih baik tidak melakukan ini dalam kode Java, Anda cukup mengatur nilai default kolom dalam definisi tabel MySql. masukkan deskripsi gambar di sini

Wayne Wei
sumber