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

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

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

相关文章

php 读取文件fread,PHP: 读取文件 fgets 和 fread 的差异

程序在写时, 何时要用 fgets? 何时要用 fread? 主要的差异在哪边? 以下就用简单的范例来说明~先创建一个文件: /tmp/readfile.txt, 内容如下:abcdefg123456789写两只简单的小程序:fgets 版$handle fopen(/tmp/readfile.txt, "r");$contents ;if ($handle) {whil…

java 并发线程_Java并发教程–线程之间的可见性

java 并发线程当在不同线程之间共享对象的状态时&#xff0c;除了原子性外&#xff0c;其他问题也会发挥作用。 其中之一是可见性。 关键事实是&#xff0c;如果没有同步&#xff0c;则不能保证指令按照它们在源代码中出现的顺序执行。 这不会影响单线程程序中的结果&#xff…

php实现中间件6,说一说ThinkPHP6中五花八门的中间件_PHP开发框架教程

thinkphp配置配置多应用多配置的方法_PHP开发框架教程一般的thinkphp框架一般都是单模块开发的&#xff0c;但有时候我们可能需要进行多模块开发&#xff0c;本文就来为大家介绍一下thinkphp配置多模块、多应用的方法。在ThinkPHP6中新增中间件功能&#xff0c;而且中间件又分很…

oracle怎么格式化sql语句,Oracle sqlplus格式化数据

SQL>set colsep ;     //-域输出分隔符SQL>set newp none //设置查询出来的数据分多少页显示&#xff0c;如果需要连续的数据&#xff0c;中间不要出现空行就把newp设置为none&#xff0c;这样输出的数据行都是连续的&#xff0c;中间没有空行之类的SQL&g…

使用Java迭代器修改数据时要小心

随着本学期的结束&#xff0c;我想我会分享一个关于我对Java迭代器非常非常熟悉的小故事。 现实世界语境 就上下文而言&#xff0c;我教第二年的软件组件课程&#xff0c;这是尝试进入该专业的学生的最后障碍。 当然&#xff0c;这门课程对学生来说压力很大&#xff0c;我经常…

oracle添加表的索引,oracle批量添加指定表前缀的索引SQL语句

oracle批量添加指定表前缀的索引SQL语句需要输入用户名&#xff0c;表空间&#xff0c;索引个数&#xff0c;表名前缀&#xff0c;过滤的表名后缀##需要输入用户名&#xff0c;表空间&#xff0c;索引个数&#xff0c;表名前缀&#xff0c;过滤的表名后缀declare--用户名userNa…

javafx隐藏_JavaFX技巧14:StackPane子项-隐藏但不消失

javafx隐藏另一个简短提示&#xff1a;Swing提供了一个名为CardLayout的布局管理器&#xff0c;该管理器管理容器内的一组组件&#xff08;卡&#xff09;&#xff0c;但始终仅显示其中一个。 方法CardLayout.show&#xff08;Container &#xff0c;String&#xff09;允许在组…

oracle yyyy和yy,Oracle PL / SQL:SYSDATE与’DD-MMM-YY’的区别?

在Oracle中,DATE值 – 尽管名称 – 也包含时间部分. SYSDATE包含当前日期和当前时间(最多秒).默认情况下,Oracle工具(愚蠢地)隐藏DATE值的时间部分.如果您运行&#xff1a;select to_char(sysdate,yyyy-mm-dd hh24:mi:ss) as sysdatefrom dual;你可以看到.所以SYSDATE可能是201…

维持硒测试自动化的完美方法

毫无疑问&#xff0c; 自动浏览器测试已经改变了软件开发的工作方式。 如果不是Selenium&#xff0c;我们将无法像我们一样使用各种各样的无错误Web应用程序。 但是有时&#xff0c;甚至IT部门也误解了自动化一词。 大多数人认为计算机将为他们完成所有测试&#xff01; 他们最…

oracle42997,oracle与db2的比较

在DB2中从客户端访问服务器端的数据库时&#xff0c;不能直接用connect命令&#xff0c;而必须先建立通信node&#xff0c;再在node的基础上建立数据库连接。在命令行的具体操作如下&#xff1a;->db2 catalog tcpip node ABC remote serverName server 50000->db2 catal…

双色球霸主网络问题_霸主–统治和管理API的地方

双色球霸主网络问题今天我们生活在一个越来越分散的世界中。 如今的计算机系统不再是在随机桌子下面的某些硬件上运行单个部门项目&#xff0c;而是大规模&#xff0c;集中甚至分散地运行。 监视和管理的需求从未改变&#xff0c;但是随着时间的推移变得越来越复杂。 如果将所有…

php验证码 php中文网,ThinkPHP 使用不同风格及中文的验证码

使用其他风格验证码在上文《ThinkPHP 验证码详解及实例》中了解了 ThinkPHP 验证码的具体用法&#xff0c;本文将进一步介绍如何使用不同风格的验证码以及使用中文验证码。上文例子使用的是默认参数&#xff0c;也就是生成 4 位的数字验证码。buildImageVerify 方法生成验证码时…

Spring Boot端口从默认更改为自定义或新端口

更改Spring Boot应用程序端口的快速指南。 application.properties文件和yml文件中的server.port属性的示例。 以及从命令行参数 SpringBootApplication&#xff0c;WebServerFactoryCustomizer 1.简介 在本教程中&#xff0c;您将学习如何在Spring Boot应用程序中更改端口。 …

java 开发人员工具_Java开发人员应该知道的5种错误跟踪工具

java 开发人员工具随着Java生态系统的发展&#xff0c;可满足不断增长的请求和用户对高性能需求的Web应用程序成为了新型的现代开发工具。 具有快速新部署的快速节奏环境需要跟踪错误&#xff0c;并以传统方法无法维持的水平获得对应用程序行为的洞察力。 在本文中&#xff0c;…

oracle定时关闭job,Oracle 定时JOB

讲一下Oracle创建临时job小窍门&#xff0c;创建Oracle临时JOB是为了临时执行调用过程或者函数&#xff0c;只调用一次。1、创建Oracle临时jobdeclareVJOB number;beginsys.dbms_job.submit(VJOB,‘PKG_RULECALL.MAKE_ALL_SAMPLE_BY_MONTH_WTH(‘‘201701‘‘,NULL);‘,Sysdat…

Apache Camel 3.2 – Camel的无反射配置

在Apache Camel项目中&#xff0c;我们正在努力开发下一个即将发布的下一个Apache Camel 3.2.0版本。 我们在Camel 3中努力研究的问题之一就是使其变得更小&#xff0c;更快。 其中一个方面是配置管理。 您可以按照12要素原则以多种方式完全配置Camel&#xff0c;以使配置与应…

oracle dbwr trace文件,ORA-01157: cannot identify/lock data file 19 - see DBWR trace file问题处理...

ORA-01157: cannot identify/lock data file 19 - see DBWR trace file问题处理告警信息&#xff1a;ORA-01157: cannot identify/lock data file 19 - see DBWR trace fileORA-01110: data file 19: /app/Oracle/oradata/users02.dbfORA-27037: unable to obtain file statusS…

java jsoup解析_3使用Jsoup解析Java中HTML文件的示例

java jsoup解析HTML是Web的核心&#xff0c;无论您是通过JavaScript&#xff0c;JSP&#xff0c;PHP&#xff0c;ASP或任何其他Web技术动态生成的&#xff0c;您在Internet上看到的所有页面都是基于HTML的。 您的浏览器实际上是解析HTML并为您呈现它。 但是&#xff0c;如果需要…

linux 命令解码空格,Shell 编程:Bash空格的那点事

先了解下bash中什么时候该用空格&#xff0c;什么时候不该用。1. 等号赋值两边不能有空格2. 命令与选项之间需要空格3. 管道两边空格可有可无我们来看看常见的问题1. 赋值时等号两边或者只有左边多了空格igigentoo ~ $ var1 testbash: var1: command not foundigigentoo ~ $ e…

使用类似Lambda的语法切换为Java中的表达式

从Java 14开始&#xff0c; switch表达式具有额外的Lambda式 &#xff08; case ... -> labels &#xff09;语法&#xff0c;它不仅可以用作语句&#xff0c;还可以用作计算为单个值的表达式。 使用新的类似Lambda的语法&#xff0c;如果标签匹配&#xff0c;则仅执行箭头…