hibernate自定义_如何自定义Hibernate脏检查机制
hibernate自定義
介紹
在上一篇文章中,我描述了Hibernate自動臟檢查機制。 盡管您應該始終喜歡它,但是有時您可能想添加自己的自定義污垢檢測策略。
自定義臟檢查策略
Hibernate提供以下定制機制:
- Hibernate攔截器#findDirty()
- CustomEntityDirtinessStrategy
手動檢查臟物
作為練習,我將構建一個手動的臟檢查機制,以說明自定義更改檢測策略的難易程度:
自臟檢查實體
首先,我將定義一個DirtyAware接口,所有手動臟檢查實體都必須實現:
public interface DirtyAware {Set<String> getDirtyProperties();void clearDirtyProperties(); }接下來,我將在基類中封裝當前的臟檢查邏輯:
public abstract class SelfDirtyCheckingEntity implements DirtyAware {private final Map<String, String> setterToPropertyMap = new HashMap<String, String>();@Transientprivate Set<String> dirtyProperties = new LinkedHashSet<String>();public SelfDirtyCheckingEntity() {try {BeanInfo beanInfo = Introspector.getBeanInfo(getClass());PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();for (PropertyDescriptor descriptor : descriptors) {Method setter = descriptor.getWriteMethod();if (setter != null) {setterToPropertyMap.put(setter.getName(), descriptor.getName());}}} catch (IntrospectionException e) {throw new IllegalStateException(e);}}@Overridepublic Set<String> getDirtyProperties() {return dirtyProperties;}@Overridepublic void clearDirtyProperties() {dirtyProperties.clear();}protected void markDirtyProperty() {String methodName = Thread.currentThread().getStackTrace()[2].getMethodName();dirtyProperties.add(setterToPropertyMap.get(methodName));} }所有手動的臟檢查實體都必須擴展此基類,并通過調用markDirtyProperty方法顯式標記臟屬性。
實際的自我臟檢查實體如下所示:
@Entity @Table(name = "ORDER_LINE") public class OrderLine extends SelfDirtyCheckingEntity {@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;private Long number;private String orderedBy;private Date orderedOn;public Long getId() {return id;}public Long getNumber() {return number;}public void setNumber(Long number) {this.number = number;markDirtyProperty();}public String getOrderedBy() {return orderedBy;}public void setOrderedBy(String orderedBy) {this.orderedBy = orderedBy;markDirtyProperty();}public Date getOrderedOn() {return orderedOn;}public void setOrderedOn(Date orderedOn) {this.orderedOn = orderedOn;markDirtyProperty();} }每當調用setter時,關聯的屬性就會變臟。 為簡單起見,當我們將屬性還原為其原始值時,此簡單練習不涵蓋用例。
臟檢查測試
為了測試自臟檢查機制,我將運行以下測試用例:
@Test public void testDirtyChecking() {doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {OrderLine orderLine = new OrderLine();session.persist(orderLine);session.flush();orderLine.setNumber(123L);orderLine.setOrderedBy("Vlad");orderLine.setOrderedOn(new Date());session.flush();orderLine.setOrderedBy("Alex");return null;}}); }Hibernate攔截器解決方案
Hibernate Interceptor findDirty回調使我們可以控制臟屬性發現過程。 該方法可能返回:
- null ,將臟檢查委托給Hibernate默認策略
- 一個int []數組,包含修改后的屬性索引
我們的Hibernate臟檢查攔截器如下所示:
public class DirtyCheckingInterceptor extends EmptyInterceptor {@Overridepublic int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) {if(entity instanceof DirtyAware) {DirtyAware dirtyAware = (DirtyAware) entity;Set<String> dirtyProperties = dirtyAware.getDirtyProperties();int[] dirtyPropertiesIndices = new int[dirtyProperties.size()];List<String> propertyNamesList = Arrays.asList(propertyNames);int i = 0;for(String dirtyProperty : dirtyProperties) {LOGGER.info("The {} property is dirty", dirtyProperty);dirtyPropertiesIndices[i++] = propertyNamesList.indexOf(dirtyProperty);}dirtyAware.clearDirtyProperties();return dirtyPropertiesIndices;}return super.findDirty(entity, id, currentState, previousState, propertyNames, types);}}將此攔截器傳遞到當前的SessionFactory配置時,我們將獲得以下輸出:
INFO [main]: c.v.h.m.l.f.InterceptorDirtyCheckingTest - The number property is dirty INFO [main]: c.v.h.m.l.f.InterceptorDirtyCheckingTest - The orderedBy property is dirty INFO [main]: c.v.h.m.l.f.InterceptorDirtyCheckingTest - The orderedOn property is dirty DEBUG [main]: o.h.e.i.AbstractFlushingEventListener - Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:1 Num:1 Query:{[update ORDER_LINE set number=?, orderedBy=?, orderedOn=? where id=?][123,Vlad,2014-08-20 07:35:05.649,1]} INFO [main]: c.v.h.m.l.f.InterceptorDirtyCheckingTest - The orderedBy property is dirty DEBUG [main]: o.h.e.i.AbstractFlushingEventListener - Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[update ORDER_LINE set number=?, orderedBy=?, orderedOn=? where id=?][123,Alex,2014-08-20 07:35:05.649,1]}手動臟檢查機制已檢測到傳入的更改,并將其傳播到刷新事件偵聽器。
鮮為人知的CustomEntityDirtinessStrategy
CustomEntityDirtinessStrategy是Hibernate API的新增功能,使我們能夠提供特定于應用程序的臟檢查機制。 該接口可以如下實現:
public static class EntityDirtinessStrategy implements CustomEntityDirtinessStrategy {@Overridepublic boolean canDirtyCheck(Object entity, EntityPersister persister, Session session) {return entity instanceof DirtyAware;}@Overridepublic boolean isDirty(Object entity, EntityPersister persister, Session session) {return !cast(entity).getDirtyProperties().isEmpty();}@Overridepublic void resetDirty(Object entity, EntityPersister persister, Session session) {cast(entity).clearDirtyProperties();}@Overridepublic void findDirty(Object entity, EntityPersister persister, Session session, DirtyCheckContext dirtyCheckContext) {final DirtyAware dirtyAware = cast(entity);dirtyCheckContext.doDirtyChecking(new AttributeChecker() {@Overridepublic boolean isDirty(AttributeInformation attributeInformation) {String propertyName = attributeInformation.getName();boolean dirty = dirtyAware.getDirtyProperties().contains( propertyName );if (dirty) {LOGGER.info("The {} property is dirty", propertyName);}return dirty;}});}private DirtyAware cast(Object entity) {return DirtyAware.class.cast(entity);}}要注冊CustomEntityDirtinessStrategy實現,我們必須設置以下Hibernate屬性:
properties.setProperty("hibernate.entity_dirtiness_strategy", EntityDirtinessStrategy.class.getName());運行我們的測試將產生以下輸出:
INFO [main]: c.v.h.m.l.f.CustomEntityDirtinessStrategyTest - The number property is dirty INFO [main]: c.v.h.m.l.f.CustomEntityDirtinessStrategyTest - The orderedBy property is dirty INFO [main]: c.v.h.m.l.f.CustomEntityDirtinessStrategyTest - The orderedOn property is dirty DEBUG [main]: o.h.e.i.AbstractFlushingEventListener - Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:1 Num:1 Query:{[update ORDER_LINE set number=?, orderedBy=?, orderedOn=? where id=?][123,Vlad,2014-08-20 12:51:30.068,1]} INFO [main]: c.v.h.m.l.f.CustomEntityDirtinessStrategyTest - The orderedBy property is dirty DEBUG [main]: o.h.e.i.AbstractFlushingEventListener - Flushed: 0 insertions, 1 updates, 0 deletions to 1 objects DEBUG [main]: n.t.d.l.SLF4JQueryLoggingListener - Name: Time:0 Num:1 Query:{[update ORDER_LINE set number=?, orderedBy=?, orderedOn=? where id=?][123,Alex,2014-08-20 12:51:30.068,1]}結論
盡管默認的字段級檢查或字節碼檢測替代方法足以滿足大多數應用程序的需求,但有時您還是需要對變更檢測過程進行控制。 在長期項目中,定制某些內置機制以滿足特殊的服務質量要求并不少見。 框架采用決定還應該考慮框架的可擴展性和定制支持。
- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/09/how-to-customize-hibernate-dirty-checking-mechanism.html
hibernate自定義
總結
以上是生活随笔為你收集整理的hibernate自定义_如何自定义Hibernate脏检查机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 天玥电脑系统重装(天玥电脑什么系统)
- 下一篇: 维持硒测试自动化的完美方法