SpringBoot使用Hibernate攔截器實現(xiàn)時間自動注入的操作代碼
最近項目有個改動:另一個系統(tǒng)根據(jù)更新時間戳來拉取本系統(tǒng)數(shù)據(jù)。這就要求基本上所有的數(shù)據(jù)表都要及時更新時間戳。以前的方式是在新增數(shù)據(jù)或者修改數(shù)據(jù)時手動調(diào)用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不能從回調(diào)中調(diào)用(回調(diào)也不能導致集合或代理被延遲初始化)。與其直接實現(xiàn)此接口,不如繼承EmptyInterceptor并僅覆蓋感興趣的回調(diào)方法。
/** 在刷新期間檢測到對象臟時調(diào)用。攔截器可能會修改檢測到的currentState ,這將被傳播到數(shù)據(jù)庫和持久對象。 請注意,并非所有刷新都以與數(shù)據(jù)庫的實際同步結(jié)束,在這種情況下,新的currentState將傳播到對象,但不一定(立即)傳播到數(shù)據(jù)庫。 強烈建議攔截器不要修改previousState 。 */ onFlushDirty(): /** 在保存對象之前調(diào)用。攔截器可能會修改狀態(tài),該狀態(tài)將用于 SQL INSERT并傳播到持久對象。 */ onSave():
那我們?nèi)mptyInterceptor看一下。
- EmptyInterceptor類:
一個什么都不做的攔截器。可用作應用程序定義的自定義攔截器的基類 。
參看上面接口的方法描述,我們只需要繼承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攔截器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java調(diào)用WebService服務的四種方法總結(jié)
WebService是一種跨編程語言、跨操作系統(tǒng)平臺的遠程調(diào)用技術,已存在很多年了,很多接口也都是通過WebService方式來發(fā)布的,下面這篇文章主要給大家介紹了關于java調(diào)用WebService服務的四種方法,需要的朋友可以參考下2021-11-11LoggingEventAsyncDisruptorAppender類執(zhí)行流程源碼解讀
這篇文章主要介紹了LoggingEventAsyncDisruptorAppender類執(zhí)行流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12使用純Java實現(xiàn)一個WebSSH項目的示例代碼
這篇文章主要介紹了使用純Java實現(xiàn)一個WebSSH項目,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03javax.management.InvalidApplicationException的問題解決
javax.management.InvalidApplicationException是與Java Management Extensions (JMX) API相關的一個常見異常,本文主要介紹了javax.management.InvalidApplicationException的問題解決,感興趣的可以了解一下2024-08-08使用多個servlet時Spring security需要指明路由匹配策略問題
這篇文章主要介紹了使用多個servlet時Spring security需要指明路由匹配策略問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-08-08