如何自定义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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/361881.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

读vue【深入响应式系统】后整理

一直以来对vue的依赖自动追踪的原理很感兴趣&#xff0c;像魔法一样。对于交给vue的对象返回后&#xff0c;在哪里使用了这个返回的对象vue会自动追踪&#xff0c;等这个对象改变时vue会自动通知到之前使用改变量的方法&#xff0c;整个过程和react很不一样&#xff0c;react的…

萌新自我介绍

第一次用博客&#xff0c;多有不会&#xff0c;可能向各位大佬请教&#xff0c;谢谢&#xff01;&#xff01;&#xff01;&#xff01;转载于:https://www.cnblogs.com/fakerOrz/p/11194872.html

使用select一个表更新另一个表(批量更新)

update a set a2b.b2, a3b.b3, ... from b where a.a1b.b1 转载于:https://www.cnblogs.com/haver/articles/2244740.html

用js来实现那些数据结构06(队列)

其实队列跟栈有很多相似的地方&#xff0c;包括其中的一些方法和使用方式&#xff0c;只是队列使用了与栈完全不同的原则&#xff0c;栈是后进先出原则&#xff0c;而队列是先进先出&#xff08;First In First Out&#xff09;。 一、队列 队列是一种特殊的线性表&#xff0c…

探索SwitchYard 2.0.0.Alpha2快速入门

在我的最后一篇文章中&#xff0c;我解释了如何在WildFly 8.1上使用SwitchYard。 同时&#xff0c;该项目很忙&#xff0c;并发布了另一个Alpha2。 这是一个很好的机会&#xff0c;在这里浏览快速入门并刷新您的记忆。 除了版本更改之外&#xff0c;您仍然可以使用较早的博客来…

MySQL之触发器

二&#xff1a;触发器 1. 什么是触发器 触发器&#xff0c;是一段与某个表相关的sql语句&#xff0c;会在某个时间点&#xff0c;满足某个条件后自动触发执行 其中两个关键因素&#xff1a; 时间点 * 事件发生前&#xff0c;before|事件发生后 after事件 * update delete inser…

PowerDesigner使用技巧

PowerDesigner使用MySQL的auto_increment   ◇问题描述&#xff1a;   PD怎样能使主键id使用MySQL的auto_increment呢&#xff1f; ◇解决方法&#xff1a;    打开table properties窗口 → columns → 选中id列 → 打开columns properties窗口 → 勾选identity即可   …

走进webpack(1)--环境拆分及模块化

初级的文章和demo已经基本完成了&#xff0c;代码也已经上传到了我的github上&#xff0c;如果你对webpack的使用并不是十分了解&#xff0c;那么建议你回头看下走近系列&#xff0c;里面包括了当前项目中使用频繁的插件&#xff0c;loader的讲解。以及基本的webpack配置&#…

适用于微服务架构的Apache Camel

在知道微服务架构被称为之前&#xff0c;我一直在使用它们。 我曾经使用过由隔离模块组成的管道应用程序&#xff0c;这些模块通过队列相互交互。 从那时起&#xff0c;许多&#xff08;前&#xff09;ThoughtWorks专家讨论了微服务。 首先是 Fred George&#xff0c; 然后是 J…

题解 P3811 【【模板】乘法逆元】

P3811 【模板】乘法逆元 一个刚学数论的萌新&#xff0c;总结了一下这题的大部分做法 //一、费马小定理快速幂 O(nlogn) 64分 #include<cstdio> using namespace std; typedef long long ll; int a,b; inline ll pow(ll x,ll p) {ll ans1;x%b;while(p) {if (p&1) an…

QueryString加密

有些人不想由URL暴露一些訊息&#xff0c;除了可以使用URL Rewrite之外&#xff0c;其實簡便一點的方法還有使用編碼or加密來達到偽裝的目的。使用Base64的原因是因為他的編碼不會有難以接受的特殊字元(註1)&#xff0c;你也可以用其他的編碼or加密算法替代(註2)。其實這邊已經…

即时大数据流处理=即时风暴

在Ubuntu背后的公司Canonical&#xff0c;每6个月进行一次技术工作&#xff0c;以第一手测试我们的工具并向其他人展示新想法。 这次&#xff0c;我创建了一个即时大数据解决方案&#xff0c;更具体地讲是“即时风暴”。 Storm现在是Apache基金会的一部分&#xff0c;但以前St…

webstorm中vue项目--运行配制

## npm搭建的项目&#xff0c;需要运行npm run dev来启动 webstorm作为一款优秀的编辑器&#xff0c;通过配置运行设置&#xff0c;达到一键运行 1.添加node.js配置 2.configuration->node interpreter : 路径/node.exe 3.configuration->working directory&#xff1a; …

VS2010 自动化整理代码(1)--- VS正则表达替换 PK Vim

自从开始在VS2010的IDE中开始用正则表达式修改 最近为了给Fortran找个好一点的编辑器&#xff0c;又开始使用Vim了。Vim是久负盛名的编辑器之神&#xff0c;可我们习惯了Visual Studio的智能提示等方便的操作&#xff0c;就总在琢磨要是VS 1. VS正则表达替换 PK Vim 这是善用…

Java基础(多态的理解与应用)

1.多态概述 多态是继封装、继承之后&#xff0c;面向对象的第三大特性。 多态现实意义理解&#xff1a; 现实事物经常会体现出多种形态&#xff0c;如学生&#xff0c;学生是人的一种&#xff0c;则一个具体的同学张三既是学生也是人&#xff0c;即出现两种形态。 …

Java并发教程–锁定:内在锁

在以前的文章中&#xff0c;我们回顾了在不同线程之间共享数据的一些主要风险&#xff08;例如原子性和可见性 &#xff09;以及如何设计类以安全地共享&#xff08; 线程安全的设计 &#xff09;。 但是&#xff0c;在许多情况下&#xff0c;我们将需要共享可变数据&#xff0…

小程序在wxml页面中取整

小程序无法像html中&#xff0c;在页面中直接parseInt() index.wxml {{price | Int}} 小程序还有另一种处理方法 wxs 是一种类似于js脚本的东西 filters.wxs var filters {toFix: function (value) {return parseFloat(value)} } module.exports {toFix: filters.toFix } …

2019.7.16考试总结

对于这个狗屎成绩我不想说什么&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c;前两次考炸也就算了&#xff0c;主要因为不会&#xff0c;这次考成这狗屎&#xff0c;是因为手残眼瘸大脑间歇性抽搐 T1&#xff1a;我是菜鸡&#xff0c;我是蒟蒻&#xff0c;我好菜…

PrimeFaces Extensions中的全新JSF组件

PrimeFaces扩展团队很高兴宣布即将推出的3.0.0主要版本的几个新组件。 我们的新提交人Francesco Strazzullo为该项目提供了“ Turbo Boost”&#xff0c;并带来了至少6个已成功集成的 JSF组件&#xff01; 当前的开发状态是OpenShift上的deployet – 请查看展示柜。以下是有关添…

Application Verifier

老徐 says Application Verifier can help to check the memory leak issue of the notepad app.转载于:https://www.cnblogs.com/backpacker/archive/2011/11/16/2250648.html