使用Hibernate在CQRS读取模型中进行快速开发

在这篇文章中,我将分享一些在CQRS读取模型中使用Hibernate工具进行快速开发的技巧。

为什么要休眠?

休眠非常流行。 从外观上看,它也很容易,而从内部看,它却相当复杂。 它可以很容易地开始使用,而无需进行深入了解,滥用和发现问题,如果为时已晚。 由于所有这些原因,这几天真是臭名昭著。

但是,它仍然是一项坚实而成熟的技术。 经过实战测试,功能强大,文档完善,并且可以解决许多常见问题。 它可以使您*非常*高效。 如果包括工具和库,则更多。 最后,只要您知道自己在做什么,它就是安全的。

自动模式生成

使SQL模式与Java类定义保持同步相当麻烦。 在最佳情况下,这是非常繁琐且耗时的活动。 错误的机会很多。

Hibernate带有模式生成器(hbm2ddl),但其“本机”形式在生产中使用有限。 创建SessionFactory时,它只能验证架构,尝试更新或导出架构。 幸运的是,该实用程序可用于自定义编程用途。

我们进一步走了一步,并将其与CQRS预测集成在一起。 运作方式如下:

  • 当投影过程线程启动时,请验证数据库模式是否与Java类定义匹配。
  • 如果不是,请删除该架构并重新导出(使用hbm2ddl)。 重新启动投影,从一开始就重新处理事件存储。 使投影从一开始就开始。
  • 如果匹配,则继续从当前状态更新模型。

由于这个原因,在很多时候,您几乎不必手动输入带有表定义的SQL。 它使开发速度大大加快。 这类似于使用hbm2ddl.auto = create-drop 。 但是, 在视图模型中使用它意味着它实际上不会丢失数据 (这在事件存储中是安全的)。 而且,它足够聪明,仅在实际更改架构时才重新创建架构-与创建-放置策略不同。

保留数据并避免不必要的重新启动不仅会缩短开发周期。 它还可能使其在生产中可用。 至少在某些条件下,请参见下文。

有一个警告:并非所有架构更改都会使Hibernate验证失败。 一个示例是更改字段长度–只要是varchar或文本,验证就可以通过而不受限制。 另一个未发现的变化是可空性。

这些问题可以通过手动重新启动投影来解决(请参见下文)。 另一种可能性是拥有一个不存储数据的伪实体,但对其进行了修改以触发自动重启。 它可能只有一个名为schemaVersion字段,每次架构更改时, @Column(name = "v_4") schemaVersion @Column(name = "v_4")批注(由开发人员)都会更新。

实作

实施方法如下:

public class HibernateSchemaExporter {private final EntityManager entityManager;public HibernateSchemaExporter(EntityManager entityManager) {this.entityManager = entityManager;}public void validateAndExportIfNeeded(List<Class> entityClasses) {Configuration config = getConfiguration(entityClasses);if (!isSchemaValid(config)) {export(config);}}private Configuration getConfiguration(List<Class> entityClasses) {SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) getSessionFactory();Configuration cfg = new Configuration();cfg.setProperty("hibernate.dialect", sessionFactory.getDialect().toString());// Do this when using a custom naming strategy, e.g. with Spring Boot:Object namingStrategy = sessionFactory.getProperties().get("hibernate.ejb.naming_strategy");if (namingStrategy instanceof NamingStrategy) {cfg.setNamingStrategy((NamingStrategy) namingStrategy);} else if (namingStrategy instanceof String) {try {log.debug("Instantiating naming strategy: " + namingStrategy);cfg.setNamingStrategy((NamingStrategy) Class.forName((String) namingStrategy).newInstance());} catch (ReflectiveOperationException ex) {log.warn("Problem setting naming strategy", ex);}} else {log.warn("Using default naming strategy");}entityClasses.forEach(cfg::addAnnotatedClass);return cfg;}private boolean isSchemaValid(Configuration cfg) {try {new SchemaValidator(getServiceRegistry(), cfg).validate();return true;} catch (HibernateException e) {// Yay, exception-driven flow!return false;}}private void export(Configuration cfg) {new SchemaExport(getServiceRegistry(), cfg).create(false, true);clearCaches(cfg);}private ServiceRegistry getServiceRegistry() {return getSessionFactory().getSessionFactoryOptions().getServiceRegistry();}private void clearCaches(Configuration cfg) {SessionFactory sf = entityManager.unwrap(Session.class).getSessionFactory();Cache cache = sf.getCache();stream(cfg.getClassMappings()).forEach(pc -> {if (pc instanceof RootClass) {cache.evictEntityRegion(((RootClass) pc).getCacheRegionName());}});stream(cfg.getCollectionMappings()).forEach(coll -> {cache.evictCollectionRegion(((Collection) coll).getCacheRegionName());});}private SessionFactory getSessionFactory() {return entityManager.unwrap(Session.class).getSessionFactory();}
}

该API看起来过时且繁琐。 似乎没有办法从现有的SessionFactory提取Configuration 。 这只是用来创建工厂并扔掉的东西。 我们必须从头开始重新创建它。 以上是我们需要的所有内容,以使其与Spring Boot和L2缓存一起正常工作。

重新开始投影

我们还实现了一种手动执行此类重新初始化的方法,在管理控制台中以按钮形式显示。 当有关投影的某些内容发生更改但不涉及修改架构时,它会派上用场。 例如,如果值的计算/格式不同,但仍是文本字段,则可以使用此机制来手动重新处理历史记录。 另一个用例是修复错误。

生产用途?

cqrs_hibernate

在开发过程中,我们一直在成功使用这种机制。 它使我们可以通过仅更改Java类而不用担心表定义来自由地修改模式。 由于与CQRS结合使用,我们甚至可以维护长期运行的演示或试点客户实例。 数据始终在事件存储区中是安全的。 我们可以逐步开发读取模型架构,并将更改自动部署到正在运行的实例中,而不会丢失数据或手动编写SQL迁移脚本。

显然,这种方法有其局限性。 仅在很小的情况下或事件可以足够快速地处理时,才可以在随机的时间点重新处理整个事件存储。

否则,可以使用SQL迁移脚本解决迁移问题,但是它有其局限性。 这通常是冒险且困难的。 可能会很慢。 最重要的是,如果更改较大并且涉及以前未包含在读取模型中(但事件中可用)的数据,则根本不选择使用SQL脚本。

更好的解决方案是将投影(带有新代码)指向新数据库。 让它重新处理事件日志。 当它赶上来时,请测试视图模型,重定向流量并丢弃旧实例。 提出的解决方案也与此方法完美配合。

翻译自: https://www.javacodegeeks.com/2015/10/rapid-development-with-hibernate-in-cqrs-read-models.html

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

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

相关文章

美国东北大学khoury计算机学院,2021年美国东北大学计算机研究生专业有哪些?入学要求高吗?...

在“唯才是用”的时代&#xff0c;高新科技行业人才成为了社会的主流&#xff0c;各行各业也都急需计算机相关人才&#xff0c;美国可谓是计算机领域的鼻祖&#xff0c;拥有着非常先进的互联网技术&#xff0c;除此之外&#xff0c;几乎每所大学都开设了计算机专业&#xff0c;…

c++进制转换代码_轻松实现C/C++各种常见进制相互转换,你还不会你就落后了

这篇文章主要介绍了轻松实现C/C各种常见进制相互转换&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面随着小编来一起学习学习吧其它进制转为十进制在实现这个需求之前&#xff0c;先简单介绍一…

我的博客是怎么自定义的

第一步&#xff0c;打开设置&#xff0c;一切都在设置里进行&#xff0c;让我们从头到尾&#xff0c;从左到右一步步讲。 1.头像 此头像不是账号头像&#xff0c;是标题那里放图片当头像 <img src"你头像的地址" alt"" /> 步骤&#xff1a;将你喜欢…

2017年计算机三级网络技术试题,2017年计算机三级网络技术考前试题及答案(8)

三、应用题(共20分)请根据下图所示网络结构回答问题。1&#xff0e;填写路由器RG的路由表项(每空2分&#xff0c;共l0分)。2&#xff0e;如果该网络内服务器群的IP地址为58&#xff0e;45&#xff0e;57&#xff0e;11-58&#xff0e;45&#xff0e;57&#xff0e;25&#xff0…

byte数组转为string_String类

API ----StringBufferjava.lang.Object 继承者 java.lang.Stringpublic final class String extends Object implements Serializable, Comparable<String>, CharSequenceYuSLi&#xff1a;String类速查速记​zhuanlan.zhihu.comYuSLi&#xff1a;补充&#xff1a;String…

HBuilder完成webApp入门(3) 关于webview (转)

个人认为WebView是 html5 API的一个非常重要的部分。 WebView 的帮助文档http://www.html5plus.org/doc/zh_cn/webview.html 为什么对WebView的掌握很重要&#xff1f;因为它是一个HTML5 APP的基础。刚刚学习HBuilder的同学一般会将重点放在 mui 组件上。mui 提供了很多默认的方…

佛山市南海技师学校计算机类,佛山南海信息技术学校2021年有哪些专业

即将面临毕业的时候&#xff0c;同学们都要选择学校&#xff0c;都要选择专业就读&#xff0c;至于选择什么&#xff0c;就是一大难题了。学习是重要的事情&#xff0c;选择更是件大事。小编整理了学校的招生专业详情&#xff0c;仅供参考。佛山南海信息技术学校专业名单&#…

创建 floating IP - 每天5分钟玩转 OpenStack(106)

先复习一下前面我们讨论的知识。 当租户网络连接到 Neutron router&#xff0c;通常将 router 作为默认网关。当 router 接收到 instance 的数据包&#xff0c;并将其转发到外网时: 1. router 会修改包的源地址为自己的外网地址&#xff0c;这样确保数据包转发到外网&#xff…

把ipa文件上传到服务器,windows电脑上传ipa到appstore的详细流程

在使用H5混合开发的app打包后&#xff0c;需要将ipa文件上传到appstore进行发布&#xff0c;就需要去苹果开发者中心进行发布。但是在苹果开发者中心无法直接上传ipa文件&#xff0c;它要求我们使用xcode或transport等工具上传ipa文件&#xff0c;但是xcode和transport不能安装…

Java的5个古怪问题

我们有机会尝试了一些最奇怪的Java难题 即使是最有经验的Java开发人员&#xff0c;也会在这篇文章中发现令人困惑的问题。 或至少是有趣的&#xff08;绝对不公平&#xff09;。 在经历了Java Deathmatch冒险之后&#xff0c;我们决定这次发布一系列不同的问题&#xff0c;着重…

js 取得数组下标_数组的介绍及使用

JavaScript 中的数组常用于在单个变量中存储多个值。数组就是一组数据的集合&#xff0c;在内存中表现为一段连续的内存地址(保存在堆内存)。创建数组的目的就是为了保存更多的数据。数组概念和语法概念&#xff1a;数组是一个特殊变量&#xff0c;一次可以容纳多个值。特点&am…

bigdecimal取小数部分_小数精度丢失问题分析和解决

无论在什么业务中&#xff0c;钱?是非常重要的东西&#xff0c;对账的时候一定要对的上&#xff0c;不能这边少一分钱那边多一分钱。对于数值的计算&#xff0c;尤其是小数&#xff0c;floate和double都是禁止使用的。阿里强制要求存放小数时使用 decimal&#xff0c;禁止使用…

使用LinkedList模拟一个堆栈或者队列数据结构

使用LinkedList模拟一个堆栈或者队列数据结构。 堆栈&#xff1a;先进后出 如同一个杯子。 队列&#xff1a;先进先出 如同一个水管。 import java.util.LinkedList;public class DuiLie {private LinkedList link;public DuiLie() {link new LinkedList();}public void m…

k40游戏增强版服务器维护中,Redmi K40 游戏增强版发布,第四台 K40 出现了

原标题&#xff1a;Redmi K40 游戏增强版发布&#xff0c;第四台 K40 出现了今晚 Redmi 发布了旗下的新款游戏手机 —— Redmi K40 游戏增强版&#xff0c;这也是K40、K40 Pro、K40 Pro 之后的又一款 K40 产品&#xff0c;主打的是专游戏功能和轻薄设计。Redmi K40 游戏增强版使…

mpvue微信小程序动画_入门微信小程序

为何现在的微信小程序还是高温不退&#xff1f;主要原因如下&#xff1a;无需安装、不占内存、易传播。废话不多说&#xff0c;开始进入开发&#xff01;-----------小程序环境搭建-----------------------------------账号注册百度搜索 "微信公众平台"官网地址&…

瀑布流式布局

今天终于搞懂了瀑布流式布局&#xff0c;哈哈&#xff0c;总结下 瀑布流式布局分为两种类型&#xff1a;1、每一列都限定宽度不限定高度的布局&#xff08;使用浮动&#xff09;2、宽度不是写死的&#xff0c;是根据页面的放大缩小变化的&#xff08;定位布局&#xff09; 瀑布…

物理服务器备份系统,物理备份和逻辑备份区别

物理备份和逻辑备份区别 内容精选换一换可能这份面试题还不足以包含所有Java问题&#xff0c;但有了它&#xff0c;我相信你一定不会“败”的很惨&#xff0c;有了它&#xff0c;足以应对目前市面上绝大部分的Java面试了&#xff0c;因为这些问题不论是从深度还是广度上来讲&am…

dd命令iso linux_BootISO:从 ISO 文件中创建一个可启动的 USB 设备

今天&#xff0c;我们将讨论名为 BootISO 的实用程序类似工具。它是一个简单的 bash 脚本&#xff0c;允许用户来从 ISO 文件中创建一个可启动的 USB 设备。-- Prakash Subramanian(作者)为了安装操作系统&#xff0c;我们中的大多数人(包括我)经常从 ISO 文件中创建一个可启动…

java基础-接口

转载于:https://www.cnblogs.com/ceshi2016/p/6025027.html

gwt入门和进阶_GWT入门

gwt入门和进阶GWT是Google Web Development Kit的缩写&#xff0c;可让程序员使用Java开发Ajax Web应用程序。 GWT编译器将Java代码转换为JavaScript和html代码。 GWT应用程序称为模块&#xff0c;并且使用xml文件描述模块&#xff0c;假设该模块名称为xml文件的“ mymodule”名…