निर्माण टाइमस्टैम्प और अंतिम अद्यतन टाइमस्टैम्प हाइबरनेट और MySQL के साथ


244

एक निश्चित हाइबरनेट इकाई के लिए हमें इसके निर्माण समय को संग्रहीत करने की आवश्यकता है और पिछली बार इसे अपडेट किया गया था। आप इसे कैसे डिजाइन करेंगे?

  • डेटाबेस में आप किस प्रकार के डेटा का उपयोग करेंगे (MySQL मानते हुए, संभवत: एक अलग टाइमज़ोन में कि JVM)? क्या डेटा के प्रकार टाइमजोन-जागरूक होंगे?

  • क्या डेटा प्रकार आप जावा में प्रयोग करेंगे ( Date, Calendar, long, ...)?

  • आप टाइमस्टैम्प-डेटाबेस, ओआरएम फ्रेमवर्क (हाइबरनेट), या एप्लिकेशन प्रोग्रामर को स्थापित करने के लिए किसे जिम्मेदार ठहराएंगे?

  • मैपिंग के लिए आप किस एनोटेशन का उपयोग करेंगे (जैसे @Temporal)?

मैं न केवल एक कार्यशील समाधान की तलाश कर रहा हूं, बल्कि एक सुरक्षित और अच्छी तरह से तैयार समाधान के लिए।

जवाबों:


266

यदि आप JPA एनोटेशन का उपयोग कर रहे हैं, तो आप हुक का उपयोग कर सकते हैं @PrePersistऔर इसे कर सकते हैं @PreUpdate:

@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();
  }
}

या आप @EntityListenerवर्ग पर एनोटेशन का उपयोग कर सकते हैं और ईवेंट कोड को बाहरी कक्षा में रख सकते हैं ।


7
J2SE में किसी भी समस्या के बिना काम करता है, क्योंकि @PrePersist और @PerUpdate जेपीए एनोटेशन हैं।
केडूवलर

2
@ कुमार - यदि आप सादे हाइबरनेट सत्र (JPA के बजाय) का उपयोग कर रहे हैं, तो आप हाइबरनेट इवेंट श्रोताओं को आज़मा सकते हैं, हालाँकि यह बहुत ही सुरुचिपूर्ण और कॉम्पैक्ट JPA एनोटेशन नहीं है।
शैलेंद्र

43
जेपीए के साथ वर्तमान हाइबरनेट में "@ क्रिएटटीमस्टैम्प" और "@ यूपीडेटिमस्टैम्प" का उपयोग कर सकते हैं
फ्लोरियन लोच

@FlorianLoch क्या टाइमस्टैम्प के बजाय डेट के बराबर है? या मुझे अपना बनाना होगा?
माइक

151

आप बस का उपयोग कर सकते हैं @CreationTimestampऔर @UpdateTimestamp:

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

@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "modify_date")
private Date modifyDate;

3
धन्यवाद भाई इस तरह की एक छोटी सी चीज को टाइमस्टैम्प को अपडेट करने की आवश्यकता है। मुझे नहीं पता था। आपने मेरा दिन बचाया।
वीरेंद्र सागर

नहीं है TemporalType.DATEकि पहले मामले में और TemporalType.TIMESTAMPदूसरा एक में।
v.ladynev

क्या आप यह कह रहे हैं कि यह स्वचालित रूप से मान सेट करता है? वह मेरा अनुभव नहीं है; यह और भी साथ लगता है @CreationTimestampऔर @UpdateTimestampएक या तो कुछ की जरूरत है @Column(..., columnDefinition = "timestamp default current_timestamp"), या उपयोग @PrePersistऔर @PreUpdate(बाद भी अच्छी तरह से यह सुनिश्चित करने के लिए ग्राहकों के लिए एक अलग मूल्य निर्धारित नहीं कर सकते)।
अर्जन

2
जब मैं ऑब्जेक्ट को अपडेट करता हूं और इसे जारी रखता हूं, तो bd ने create_date खो दिया है ... क्यों?
ब्रेनो लील

1
Im मेरे मामले को हटाने nullable=falseसे @Column(name = "create_date" , nullable=false)काम किया
शांताराम तुपे

113

विभिन्न स्रोतों से बाएँ और दाएँ जानकारी के साथ इस पोस्ट में संसाधनों को लेते हुए, मैं इस सुरुचिपूर्ण समाधान के साथ आया, निम्नलिखित अमूर्त वर्ग बनाएं

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();
    }
}

और उदाहरण के लिए आपकी सभी इकाइयाँ इसका विस्तार करती हैं:

@Entity
@Table(name = "campaign")
public class Campaign extends AbstractTimestampEntity implements Serializable {
...
}

5
यह तब तक अच्छा है जब तक आप अपनी संस्थाओं में विभिन्न विशिष्ट व्यवहार जोड़ना चाहते हैं (और आप एक से अधिक बेस क्लास का विस्तार नहीं कर सकते)। आधार वर्ग के बिना एक ही प्रभाव प्राप्त करने का एकमात्र तरीका है, हालांकि एसपीजे इट या ईवेंट श्रोता @kieren dixon उत्तर देखें
gpilotino

3
मैं एक MySQL ट्रिगर का उपयोग कर ऐसा करूंगा ताकि भले ही पूर्ण इकाई को बचाया न जाए या किसी बाहरी एप्लिकेशन या मैन्युअल क्वेरी द्वारा संशोधित न किया गया हो, फिर भी यह इन फ़ील्ड्स को अपडेट करेगा।
वेबनेट

3
क्या आप मुझे कोई काम करने का उदाहरण दे सकते हैं क्योंकि मैं अपवाद का अनुभव कर रहा हूंnot-null property references a null or transient value: package.path.ClassName.created
सुमित रामटेके

@ ऋषिअगर, नहीं, मैंने नहीं। लेकिन अभी के लिए मैंने डिफॉल्ट कंस्ट्रक्टर से अपनी प्रॉपर्टी को डेट असाइन किया है। एक बार मिल गया तो आपको बता दूंगा।
सुमित रामटेके

1
@Column(name = "updated", nullable = false, insertable = false)इसे काम करने के लिए बदलें । दिलचस्प है कि इस जवाब को इतने सारे
अपवित्र मिले

20

1. आपको किस डेटाबेस कॉलम का उपयोग करना चाहिए

आपका पहला सवाल था:

डेटाबेस में आप किस प्रकार के डेटा का उपयोग करेंगे (MySQL मानते हुए, संभवत: एक अलग टाइमज़ोन कि JVM में)? क्या डेटा के प्रकार टाइमजोन-जागरूक होंगे?

MySQL में, TIMESTAMPकॉलम प्रकार JDBC ड्राइवर स्थानीय समय क्षेत्र से डेटाबेस टाइमज़ोन पर शिफ्टिंग करता है, लेकिन यह केवल टाइमस्टैम्प को स्टोर कर सकता है '2038-01-19 03:14:07.999999, इसलिए यह भविष्य के लिए सबसे अच्छा विकल्प नहीं है।

इसलिए, DATETIMEइसके बजाय बेहतर उपयोग , जिसमें यह ऊपरी सीमा सीमा नहीं है। हालांकि, DATETIMEटाइमजोन जागरूक नहीं है। तो, इस कारण से, डेटाबेस की ओर से यूटीसी का उपयोग करना और hibernate.jdbc.time_zoneहाइबरनेट संपत्ति का उपयोग करना सबसे अच्छा है ।

hibernate.jdbc.time_zoneसेटिंग के बारे में अधिक जानकारी के लिए , इस लेख को देखें

2. आपको किस इकाई की संपत्ति का उपयोग करना चाहिए

आपका दूसरा प्रश्न था:

आप जावा (दिनांक, कैलेंडर, दीर्घ, ...) में किस प्रकार के डेटा का उपयोग करेंगे?

जावा पक्ष पर, आप जावा 8 का उपयोग कर सकते हैं LocalDateTime। आप विरासत का उपयोग भी कर सकते हैं Date, लेकिन जावा 8 दिनांक / समय प्रकार बेहतर हैं क्योंकि वे अपरिवर्तनीय हैं, और उन्हें लॉग करते समय स्थानीय समय क्षेत्र में शिफ्ट करने के लिए टाइमज़ोन नहीं करते हैं।

हाइबरनेट द्वारा समर्थित जावा 8 दिनांक / समय प्रकार के बारे में अधिक जानकारी के लिए, इस लेख को देखें

अब, हम इस प्रश्न का उत्तर भी दे सकते हैं:

मैपिंग के लिए आप किस एनोटेशन का उपयोग करेंगे (जैसे @Temporal)?

यदि आप टाइमस्टैम्प इकाई संपत्ति का उपयोग कर रहे हैं LocalDateTimeया java.sql.Timestampमैप करने के लिए उपयोग कर रहे हैं, तो आपको उपयोग करने की आवश्यकता नहीं है @Temporalक्योंकि HIbernate को पहले से ही पता है कि इस संपत्ति को JDBC टाइमस्टैम्प के रूप में सहेजा जाना है।

केवल यदि आप उपयोग कर रहे हैं java.util.Date, तो आपको @Temporalएनोटेशन निर्दिष्ट करने की आवश्यकता है , जैसे:

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

लेकिन, अगर आप इसे इस तरह से मैप करते हैं तो यह बहुत बेहतर है:

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

ऑडिट कॉलम मान कैसे उत्पन्न करें

आपका तीसरा प्रश्न था:

आप टाइमस्टैम्प-डेटाबेस, ओआरएम फ्रेमवर्क (हाइबरनेट), या एप्लिकेशन प्रोग्रामर को स्थापित करने के लिए किसे जिम्मेदार ठहराएंगे?

मैपिंग के लिए आप किस एनोटेशन का उपयोग करेंगे (उदाहरण @Temporal)?

इस लक्ष्य को प्राप्त करने के कई तरीके हैं। आप डेटाबेस को ऐसा करने की अनुमति दे सकते हैं।

के लिए create_onस्तंभ, आप एक इस्तेमाल कर सकते हैं DEFAULTजैसे DDL बाधा,:

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

के लिए updated_onस्तंभ, आप एक डीबी ट्रिगर का उपयोग स्तंभ मान के साथ स्थापित करने के लिए कर सकता है CURRENT_TIMESTAMP()हर बार किसी पंक्ति संशोधित किया गया है।

या, उन्हें सेट करने के लिए JPA या हाइबरनेट का उपयोग करें।

मान लें कि आपके पास निम्नलिखित डेटाबेस टेबल हैं:

ऑडिट कॉलम के साथ डेटाबेस टेबल

और, प्रत्येक तालिका में कॉलम हैं:

  • created_by
  • created_on
  • updated_by
  • updated_on

हाइबरनेट @CreationTimestampऔर @UpdateTimestampएनोटेशन का उपयोग करना

सीतनिद्रा में होना @CreationTimestampऔर @UpdateTimestampएनोटेशन प्रदान करता है जिसका उपयोग कॉलम created_onऔर updated_onकॉलम को मैप करने के लिए किया जा सकता है ।

आप @MappedSuperclassएक आधार वर्ग को परिभाषित करने के लिए उपयोग कर सकते हैं जो सभी संस्थाओं द्वारा बढ़ाया जाएगा:

@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
}

और, सभी निकाय BaseEntityइस तरह का विस्तार करेंगे :

@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
}

उपयोग करने के बारे में अधिक जानकारी के लिए @MappedSuperclass, इस लेख को देखें

हालाँकि, भले ही createdOnऔर updateOnसंपत्तियों को हाइबरनेट-विशिष्ट @CreationTimestampऔर @UpdateTimestampएनोटेशन द्वारा निर्धारित किया गया हो , createdByऔर updatedByनिम्नलिखित जेपीए समाधान द्वारा सचित्र के रूप में, एप्लिकेशन कॉलबैक को पंजीकृत करने की आवश्यकता होती है।

जेपीए का उपयोग करना @EntityListeners

आप ऑडिट गुणों को एक एंबेडेबल में इनकैप्सुलेट कर सकते हैं:

@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
}

और, AuditListenerऑडिट गुण सेट करने के लिए एक बनाएँ :

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());
    }
}

रजिस्टर करने के लिए AuditListener, आप @EntityListenersJPA एनोटेशन का उपयोग कर सकते हैं :

@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
}

जेपीए के साथ ऑडिट गुणों को लागू करने के बारे में अधिक जानकारी के लिए @EntityListener, इस लेख को देखें


बहुत अच्छी तरह से जवाब, धन्यवाद। मैं पसंद करने datetimeको लेकर असहमत हूं timestamp। आप अपने डेटाबेस को अपने टाइमस्टैम्प के समय क्षेत्र को जानना चाहते हैं। यह समय क्षेत्र रूपांतरण त्रुटियों को रोकता है।
ओले वीवी

timestsmpप्रकार समय-क्षेत्र की जानकारी की दुकान नहीं है। यह सिर्फ app TZ से DB TZ की बातचीत करता है। वास्तव में, आप क्लाइंट को अलग से स्टोर करना चाहते हैं और UI को रेंडर करने से पहले एप्लिकेशन में वार्तालाप करें।
व्लाद मिहालसी

सही बात। MySQL timestampहमेशा UTC में होती है। MySQL धर्मान्तरितTIMESTAMP स्टोरेज के लिए वर्तमान समय क्षेत्र से UTC तक मानों को , और पुनर्प्राप्ति के लिए UTC से वर्तमान समय क्षेत्र में वापस आ जाता है। MySQL दस्तावेज़ीकरण: DATE, DATETIME और TIMESTAMP प्रकार
OLE VV

17

मान सेट करने के लिए आप इंटरसेप्टर का भी उपयोग कर सकते हैं

एक इंटरफ़ेस बनाएँ जिसे टाइमस्टैम्प कहा जाता है जिसे आपकी संस्थाएँ कार्यान्वित करती हैं

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

इंटरसेप्टर को परिभाषित करें

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

और सत्र कारखाने के साथ इसे पंजीकृत करें


1
काम करता है, धन्यवाद। अतिरिक्त जानकारी docs.jboss.org/hibernate/core/4.0/manual/en-US/html_single/...
एंड्री Nemchenko

यह एक समाधान है, यदि आप EntityManager के बजाय SessionFactory के साथ काम करते हैं!
ओलिवमीर

बस उन लोगों के लिए, जो इस संदर्भ में एक समान समस्या से पीड़ित हैं: यदि आपकी संस्था खुद इन अतिरिक्त क्षेत्रों को परिभाषित नहीं करती है (createAt, ...) लेकिन इसे मूल वर्ग से विरासत में मिला है, तो इस मूल वर्ग को एनोटेट करना होगा @MappedSuperclass के साथ - अन्यथा हाइबरनेट को ये फ़ील्ड नहीं मिलते हैं।
ओलिवमीर

17

ओलिवियर के समाधान के साथ, अपडेट स्टेटमेंट के दौरान आप इसमें भाग ले सकते हैं:

com.mysql.jdbc.exception.jdbc4.MySQLIntegrityConstraintViolationException: स्तंभ 'बनाया' शून्य नहीं हो सकता

इसे हल करने के लिए, "बनाए गए" विशेषता के @ मूल कॉलम में अपग्रेड करने योग्य = गलत जोड़ें:

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

1
हम उपयोग कर रहे हैं @Version। जब एक इकाई सेट की जाती है तो दो कॉल किए जाते हैं एक को सहेजना और दूसरा अपडेट करना। मैं इसी मुद्दे का सामना कर रहा था। एक बार मैंने @Column(updatable = false)इसे जोड़ा तो मेरी समस्या हल हो गई।
गणेश सतपुते

12

सभी की मदद करने के लिए धन्यवाद। खुद कुछ शोध करने के बाद (मैं सवाल पूछने वाला लड़का हूं), यहाँ मुझे सबसे ज्यादा समझ में आता है:

  • डेटाबेस कॉलम का प्रकार: 1970 से मिलीसेकंड के टाइमजोन-अज्ञेय संख्या का प्रतिनिधित्व किया decimal(20)क्योंकि 2 ^ 64 में 20 अंक हैं और डिस्क स्थान सस्ता है; चलो सीधा हो। इसके अलावा, मैं न तो उपयोग करेंगेDEFAULT CURRENT_TIMESTAMP , न ही ट्रिगर। मुझे डीबी में कोई जादू नहीं चाहिए।

  • जावा फ़ील्ड प्रकार: long :। यूनिक्स टाइमस्टैम्प विभिन्न कार्यों में अच्छी तरह से समर्थित है, longइसमें कोई वाई 2038 समस्याएं नहीं हैं, टाइमस्टैम्प अंकगणित तेज और आसान है (मुख्य रूप से ऑपरेटर <और ऑपरेटर +, यह मानते हुए कि कोई दिन / महीने / वर्ष गणना में शामिल हैं)। और, सबसे महत्वपूर्ण बात यह है कि, दोनों आदिम longएस और java.lang.Longएस अपरिवर्तनीय हैं - प्रभावी रूप से मूल्य से गुजरते हैं - java.util.Dateएस के विपरीत ; मैं वास्तव में foo.getLastUpdate().setTime(System.currentTimeMillis())किसी और के कोड को डीबग करते समय कुछ खोजने के लिए नाराज हो जाता हूं।

  • डेटा स्वचालित रूप से भरने के लिए ओआरएम फ्रेमवर्क जिम्मेदार होना चाहिए।

  • मैंने अभी तक इसका परीक्षण नहीं किया है, लेकिन केवल डॉक्स को देखकर मुझे लगता है कि @Temporalयह काम करेगा; @Versionइस बारे में निश्चित नहीं हूं कि क्या मैं इस उद्देश्य के लिए उपयोग कर सकता हूं । @PrePersistतथा@PreUpdate मैन्युअल रूप से नियंत्रित करने के लिए अच्छे विकल्प हैं। सभी संस्थाओं के लिए लेयर सुपरपाइप (सामान्य आधार वर्ग) में जोड़ना एक प्यारा विचार है, बशर्ते कि आप वास्तव में अपनी सभी संस्थाओं के लिए टाइमस्टैम्पिंग चाहते हों ।


जबकि लोंग और लोंग्स अपरिवर्तनीय हो सकते हैं, यह आपके द्वारा वर्णित स्थिति में मदद नहीं करेगा। वे अभी भी foo.setLastUpdate (नई लंबी (System.currentTimeMillis ()) कह सकते हैं;
इयान मैकलेरड

2
कोई बात नहीं। हाइबरनेट को वैसे भी सेटर की आवश्यकता होती है (या यह प्रतिबिंब के माध्यम से सीधे क्षेत्र तक पहुंचने की कोशिश करेगा)। मैं कठिनाई का पीछा करने के बारे में बात कर रहा था जो हमारे आवेदन कोड से टाइमस्टैम्प को संशोधित कर रहा है। यह मुश्किल है जब आप एक गटर का उपयोग कर सकते हैं।
ngn

मैं आपके दावे से सहमत हूं कि ओआरएम फ्रेमवर्क स्वचालित रूप से तारीख को भरने के लिए जिम्मेदार होना चाहिए, लेकिन मैं एक कदम आगे बढ़ूंगा और कहूंगा कि क्लाइंट के बजाय डेटाबेस सर्वर की घड़ी से तारीख निर्धारित की जानी चाहिए। मैं स्पष्ट नहीं हूँ कि क्या यह इस लक्ष्य को पूरा करता है। Sql में, मैं sysdate फ़ंक्शन का उपयोग करके ऐसा कर सकता हूं, लेकिन मुझे नहीं पता कि हाइबरनेट या किसी JPA कार्यान्वयन में यह कैसे करना है।
मिगेलमुनोज

मुझे डीबी में कोई जादू नहीं चाहिए। मैं देख रहा हूं कि आपका क्या मतलब है, लेकिन मैं इस तथ्य पर विचार करना पसंद करता हूं कि डेटाबेस को खराब / नए / क्लूलेस डेवलपर्स से खुद को बचाना चाहिए। एक बड़ी कंपनी में डेटा अखंडता बहुत महत्वपूर्ण है, आप अच्छा डेटा डालने के लिए दूसरों पर भरोसा नहीं कर सकते। बाधाओं, चूक, और FK को प्राप्त करने में मदद मिलेगी।
आइसग्रास

6

यदि आप सत्र API का उपयोग कर रहे हैं, तो PrePersist और PreUpdate कॉलबैक इस उत्तर के अनुसार काम नहीं करेंगे

मैं अपने कोड में Hibernate Session के persist () विधि का उपयोग कर रहा हूं, इसलिए इस काम को करने का एकमात्र तरीका नीचे दिए गए कोड के साथ था और इस ब्लॉग पोस्ट ( उत्तर में पोस्ट किया गया ) का भी अनुसरण कर रहा था ।

@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;
    }
}

क्लोन किए गए ऑब्जेक्ट को वापस करना चाहिए जैसे कि updated.clone()अन्य घटक आंतरिक स्थिति (दिनांक) में हेरफेर कर सकते हैं
1ambda


3

निम्नलिखित कोड ने मेरे लिए काम किया।

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

नमस्ते, हमें सामान्य protected Integer id;रूप protectedमें माता-पिता वर्ग की आवश्यकता क्यों होगी , क्योंकि मैं इसे अपने परीक्षण मामलों में उपयोग नहीं कर सकता था.getId()
शास्त्री

2

एक अच्छा तरीका यह है कि आपकी सभी संस्थाओं के लिए एक सामान्य आधार वर्ग हो। इस बेस क्लास में, आपके पास आपकी आईडी प्रॉपर्टी हो सकती है अगर इसे आमतौर पर आपकी सभी संस्थाओं (एक सामान्य डिजाइन), आपके निर्माण और अंतिम अंतिम तिथि के गुणों में नाम दिया जाता है।

निर्माण तिथि के लिए, आप बस एक java.util.Date संपत्ति रखें। सुनिश्चित करें, हमेशा इसे नई तिथि के साथ आरंभ करें ()

अंतिम अपडेट फ़ील्ड के लिए, आप टाइमस्टैम्प संपत्ति का उपयोग कर सकते हैं, आपको इसे @Version के साथ मैप करना होगा। इस एनोटेशन के साथ संपत्ति हाइबरनेट द्वारा स्वचालित रूप से अपडेट हो जाएगी। सावधान रहें कि हाइबरनेट भी आशावादी लॉकिंग लागू करेगा (यह अच्छी बात है)।


2
आशावादी लॉकिंग के लिए टाइमस्टैम्प कॉलम का उपयोग करना एक बुरा विचार है। हमेशा एक पूर्णांक संस्करण कॉलम का उपयोग करें। कारण, 2 JVM अलग-अलग समय पर हो सकते हैं और उनमें मिलीसेकंड सटीकता नहीं हो सकती है। यदि आप इसके बजाय डीबी टाइमस्टैम्प का उपयोग हाइबरनेट करते हैं, तो इसका मतलब होगा कि डीबी से अतिरिक्त चयन। इसके बजाय बस संस्करण संख्या का उपयोग करें।
सेतु

2

बस सुदृढ़ करने के लिए: java.util.Calenderटाइमस्टैम्प के लिए नहीं हैjava.util.Dateसमय में एक पल के लिए है, टाइमजोन जैसी क्षेत्रीय चीजों का अज्ञेय। अधिकांश डेटाबेस इस तरह से चीजों को स्टोर करते हैं (भले ही वे दिखाई न दें; यह आमतौर पर क्लाइंट सॉफ़्टवेयर में एक टाइमज़ोन सेटिंग है; डेटा केवल अच्छा है)


1

जेएवीए में डेटा प्रकार के रूप में मैं java.util.Date का उपयोग करने की दृढ़ता से सलाह देता हूं। मैं कैलेंडर का उपयोग करते समय बहुत बुरा समयक्षेत्र समस्याओं में भाग गया। इस थ्रेड को देखें

टाइमस्टैम्प की स्थापना के लिए, मैं या तो एओपी दृष्टिकोण का उपयोग करने की सलाह दूंगा या आप बस मेज पर ट्रिगर का उपयोग कर सकते हैं (वास्तव में यह केवल एक चीज है जो मुझे कभी भी ट्रिगर्स का उपयोग स्वीकार्य लगता है)।


1

आप समय को दिनांक समय और UTC में संग्रहीत करने पर विचार कर सकते हैं। मैं आमतौर पर टाइमस्टैम्प के बजाय डेटटाइम का उपयोग करता हूं क्योंकि इस तथ्य के कारण कि MySql डेटा को संग्रहीत और पुनर्प्राप्त करते समय स्थानीय समय और वापस UTC में दिनांक परिवर्तित करता है। मैं एक जगह (बिजनेस लेयर) में उस तरह के किसी भी तर्क को रखना चाहूंगा। मुझे यकीन है कि ऐसी अन्य परिस्थितियां हैं जहां टाइमस्टैम्प का उपयोग करना बेहतर है, हालांकि।


1

हमारी भी ऐसी ही स्थिति थी। हम मैसूर 5.7 का उपयोग कर रहे थे।

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

यह हमारे लिए काम किया।


यह उस स्थिति में भी काम करता है जब डेटा को डेटाबेस में सीधे SQL क्वेरी द्वारा संशोधित किया जाता है। @PrePersistऔर @PrePersistऐसे मामले को कवर न करें।
पिदब्रो

1

अगर हम @Transactional का उपयोग कर रहे हैं हमारे तरीकों में, @CreationTimestamp और @UpdateTimestamp डीबी में मूल्य की बचत होगी लेकिन बचाने उपयोग करने के बाद रिक्त वापस आ जाएगी (...)।

इस स्थिति में, saveAndFlush (...) का उपयोग करके चाल चली गई


0

मुझे लगता है कि यह जावा कोड में ऐसा नहीं कर रहा है, आप बस MySql तालिका परिभाषा में कॉलम डिफ़ॉल्ट मान सेट कर सकते हैं। यहां छवि विवरण दर्ज करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.