SpringBoot使用Hibernate攔截器實現(xiàn)時間自動注入的操作代碼
最近項目有個改動:另一個系統(tǒng)根據(jù)更新時間戳來拉取本系統(tǒng)數(shù)據(jù)。這就要求基本上所有的數(shù)據(jù)表都要及時更新時間戳。以前的方式是在新增數(shù)據(jù)或者修改數(shù)據(jù)時手動調用setProperty(TimeStamp),因為沒有用到這兩個字段加上每個人的編碼習慣不同,有時候沒設置createTime或者updateTime,可能存在遺漏,導致數(shù)據(jù)庫中有的時間戳默認值0。
前提:本系統(tǒng)時間戳在數(shù)據(jù)庫類型為int,長度為int默認值,存儲示例:1665295775,Java類型Integer,單位: /s
因為沒怎么使用過Hibernate框架,就想Hibernate有沒有MybatisPlus一樣的自動填充功能呢?查了一下還真有日期相關的注解:@Temporal(TemporalType.XXX),但是對應Java的類型為:java.sql.Date,java.sql.Time,java.sql.Timestamp,數(shù)據(jù)庫的類型為時間相關的類型:date,time,datetime,timestamp,在不改動歷史數(shù)據(jù)表字段類型的情況下,只能尋求其它方式。
Hibernate攔截器:
- Interceptor接口:
允許用戶代碼檢查和/或更改屬性值。檢查發(fā)生在屬性值寫入之前和從數(shù)據(jù)庫中讀取之后。 SessionFactory可能有一個Interceptor實例,或者可能為每個Session指定一個新實例。無論使用哪種方法,如果Session要可序列化,則攔截器必須是可序列化的。這意味著SessionFactory范圍的攔截器應該實現(xiàn)readResolve() 。 Session不能從回調中調用(回調也不能導致集合或代理被延遲初始化)。與其直接實現(xiàn)此接口,不如繼承EmptyInterceptor并僅覆蓋感興趣的回調方法。
/** 在刷新期間檢測到對象臟時調用。攔截器可能會修改檢測到的currentState ,這將被傳播到數(shù)據(jù)庫和持久對象。 請注意,并非所有刷新都以與數(shù)據(jù)庫的實際同步結束,在這種情況下,新的currentState將傳播到對象,但不一定(立即)傳播到數(shù)據(jù)庫。 強烈建議攔截器不要修改previousState 。 */ onFlushDirty(): /** 在保存對象之前調用。攔截器可能會修改狀態(tài),該狀態(tài)將用于 SQL INSERT并傳播到持久對象。 */ onSave():
那我們去EmptyInterceptor看一下。
- EmptyInterceptor類:
一個什么都不做的攔截器??捎米鲬贸绦蚨x的自定義攔截器的基類 。
參看上面接口的方法描述,我們只需要繼承EmptyInterceptor并重寫onSave()和onFlushDirty()兩個方法,來分別實現(xiàn)保存(SQL INSERT)和更新(SQL UPDATE)即可。Hibernate在檢測到save和update操作時先執(zhí)行自定義邏輯。
代碼實現(xiàn)
看完了攔截器相關,來實現(xiàn)一下代碼,如下:
為了控制每個DDO的行為,可以設計一個BaseEntityControl接口
/**
* 數(shù)據(jù)的頂層接口
*/
public interface BaseEntityControl{
/**
可以加入其它邏輯
/
/**
* 控制是否需要自動寫入createTime和updateTime
* @return
*/
default boolean writeTimeStamp() {
return true;
}
}import com.xx.xxx.BaseEntityControl;
import java.io.Serializable;
/**
* Interceptor for entity audits.
*/
public class AuditInterceptor extends EmptyInterceptor {
/**
* Serial version UID
*/
private static final long serialVersionUID = 6892420119984901561L;
/**
* @see org.hibernate.Interceptor#onFlushDirty(Object, Serializable, Object[], Object[], String[], Type[])
*/
@Override
public boolean onFlushDirty(final Object entity, final Serializable id, final Object[] currentState,
final Object[] previousState, final String[] propertyNames, final Type[] types) {
if (entity instanceof BaseEntityControl) {
if (!((BaseEntityControl) entity).writeTimeStamp()) {
return false;
}
for (int i = 0; i < propertyNames.length; i++) {
if ("updateTime".equals(propertyNames[i])) {
currentState[i] = (int) (System.currentTimeMillis() / 1000);
return true;
}
}
}
return false;
}
/**
* @see org.hibernate.Interceptor#onSave(Object, Serializable, Object[], String[], Type[])
*/
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
if (entity instanceof BaseEntityControl) {
if (!((BaseEntityControl) entity).writeTimeStamp()) {
return false;
}
boolean crtModify = false;
boolean uptModify = false;
int i = 0;
while (true) {
if (i >= propertyNames.length) {
if (crtModify || uptModify) {
return true;
}
break;
}
if ("createTime".equals(propertyNames[i])) {
crtModify = true;
state[i] = (int) (System.currentTimeMillis() / 1000L);
}
if ("updateTime".equals(propertyNames[i])) {
uptModify = true;
state[i] = (int) (System.currentTimeMillis() / 1000L);
}
++i;
}
}
return false;
}
}
將自定義Interceptor配置到session factory
在session factory配置類中將
public class xxxConfig {
...
public FactoryBean<SessionFactory> getSessionFactory() {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setEntityInterceptor(new AuditInterceptor());
...
}
...
}
對比測試
4.0.9:加入攔截器之前
4.3.1:加入攔截器之后
單個對象20個property情況下:

到此這篇關于SpringBoot使用Hibernate攔截器實現(xiàn)時間自動注入的操作代碼的文章就介紹到這了,更多相關SpringBoot使用Hibernate攔截器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Springmvc調用存儲過程,并返回存儲過程返還的數(shù)據(jù)方式
這篇文章主要介紹了Springmvc調用存儲過程,并返回存儲過程返還的數(shù)據(jù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
java easyUI實現(xiàn)自定義網(wǎng)格視圖實例代碼
這篇文章主要給大家介紹了關于java easyUI實現(xiàn)自定義網(wǎng)格視圖的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2018-10-10
解決Error:(5,55)java:程序包org.springframework.cloud.netflix.eure
這篇文章主要介紹了解決Error:(5,55)java:程序包org.springframework.cloud.netflix.eureka.server不存在問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
SpringBoot使用MapStruct生成映射代碼的示例詳解
MapStruct 是一個用于 Java 的代碼生成器,專門用于生成類型安全的 bean 映射代碼,它通過注解處理器在編譯時生成映射代碼,從而避免了運行時的性能開銷和潛在的錯誤,本文給大家介紹了SpringBoot使用MapStruct生成映射代碼的示例,需要的朋友可以參考下2024-11-11

