JOOQ事实:从JPA批注到JOOQ表映射

JOOQ是一个简洁的框架,它解决了我在使用高级动态过滤查询时遇到的一个长期问题。 虽然Hibernate和JPA附带了一个有用的Criteria API(我已经使用了很长一段时间),但是使用它们时所能做的却有一些可以理解的限制。 例如,您不能超出简单的SQL操作(例如,JOINS,NESTED SLECTS,AGGREGATION),并且要做类似的事情: 窗口函数 , 用户定义的函数或简单的排序等 。

JOOQ不想和Hibernate竞争,但是我觉得它可以完成它。 我一直在将Hibernate用于数据层的WRITE部分,因此使用它的名称或JPA中的“ Persisting”部分。 对于简单到中等复杂的查询,Hibernate会尽力而为,但是我不必只依靠它来进行所有查询,是吗? 查询属性也有一个缺点,这是因为有时为了仅针对少数用例进行查询,有时必须向域模型添加关联。

因此,由于我不担心编写本机查询,因此可以以DSL方式和独立于供应商的方式来执行此操作。

尽管可以使用基于字符串的列命名,但JOOQ通过使用类型安全的元数据提供了一种更好的方法,因此,我们要做的第一件事是为数据库架构生成表映射。

由于我已经有了JPA模型,因此可以从中生成数据库模式DDL,为此,我们可以使用hibernatetool ant任务。

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-antrun-plugin</artifactId><executions><execution><id>generate-test-sql-scripts</id><phase>generate-test-resources</phase><goals><goal>run</goal></goals><configuration><tasks><property name="maven_test_classpath" refid="maven.test.classpath"/><path id="hibernate_tools_path"><pathelement path="${maven_test_classpath}"/></path><property name="hibernate_tools_classpath" refid="hibernate_tools_path"/><taskdef name="hibernatetool"classname="org.hibernate.tool.ant.HibernateToolTask"/><mkdir dir="${project.build.directory}/test-classes/hsqldb"/><hibernatetool destdir="${project.build.directory}/test-classes/hsqldb"><classpath refid="hibernate_tools_path"/><jpaconfiguration persistenceunit="testPersistenceUnit"propertyfile="src/test/resources/META-INF/spring/jdbc.properties"/><hbm2ddl drop="false" create="true" export="false"outputfilename="create_db.sql"delimiter=";" format="true"/><hbm2ddl drop="true" create="false" export="false"outputfilename="drop_db.sql"delimiter=";" format="true"/></hibernatetool></tasks></configuration></execution></executions><dependencies><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>${hibernate.version}</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-tools</artifactId><version>${hibernate.tools.version}</version><exclusions><exclusion><groupId>org.hibernate</groupId><artifactId>hibernate-commons-annotations</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>${slf4j.version}</version></dependency></dependencies>
</plugin>

这将生成一个“ create_db.sql”数据库DDL脚本,我们将使用“ maven.sql.plugin”将其用于填充基于文件的临时HSQLDB。 我本来希望使用内存中的HSQLDB,但不幸的是它没有保存插件执行之间的状态。

<plugin><groupId>org.codehaus.mojo</groupId><artifactId>sql-maven-plugin</artifactId><dependencies><dependency><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId><version>${hsqldb.version}</version></dependency></dependencies><configuration><driver>org.hsqldb.jdbc.JDBCDriver</driver><url>jdbc:hsqldb:file:${project.build.directory}/hsqldb/db;shutdown=true</url><username>sa</username><password></password><autocommit>true</autocommit><settingsKey>hsql-db-test</settingsKey></configuration><executions><execution><id>create-test-compile-data</id><phase>process-test-resources</phase><inherited>true</inherited><goals><goal>execute</goal></goals><configuration><orderFile>ascending</orderFile><fileset><basedir>${project.build.directory}/test-classes/hsqldb/</basedir><includes><include>create_db.sql</include></includes></fileset><autocommit>true</autocommit></configuration></execution></executions>
</plugin>

因此,HSQLDB现在已由我们的JPA生成的架构填充,并且我们最终可以调用JOOQ代码生成来构建表映射。

<plugin><groupId>org.jooq</groupId><artifactId>jooq-codegen-maven</artifactId><executions><execution><phase>process-test-classes</phase><goals><goal>generate</goal></goals></execution></executions><dependencies><dependency><groupId>org.hsqldb</groupId><artifactId>hsqldb</artifactId><version>${hsqldb.version}</version></dependency></dependencies><configuration><jdbc><driver>org.hsqldb.jdbc.JDBCDriver</driver><url>jdbc:hsqldb:file:${project.build.directory}/hsqldb/db</url><user>sa</user><password></password></jdbc><generator><name>org.jooq.util.JavaGenerator</name><database><name>org.jooq.util.hsqldb.HSQLDBDatabase</name><includes>.*</includes><excludes></excludes><inputSchema>PUBLIC</inputSchema></database><generate></generate><target><packageName>vladmihalcea.jooq.schema</packageName><directory>target/generated-sources/jooq</directory></target></generator></configuration>
</plugin>

在maven中运行,我们将生成表映射,因此,我们将Image类的JPA元模型与关联的JOOQ表映射进行比较:

JPA元模型如下所示:

@StaticMetamodel(Image.class)
public abstract class Image_ {public static volatile SingularAttribute<Image, Product> product;public static volatile SingularAttribute<Image, Long> id;public static volatile SetAttribute<Image, Version> versions;public static volatile SingularAttribute<Image, Integer> index;public static volatile SingularAttribute<Image, String> name;}

和JOOQ表映射

@javax.annotation.Generated(value    = { "http://www.jooq.org", "3.2.0" },comments = "This class is generated by jOOQ")
@java.lang.SuppressWarnings({ "all", "unchecked", "rawtypes" })
public class Image extends org.jooq.impl.TableImpl<vladmihalcea.jooq.schema.tables.records.ImageRecord> {private static final long serialVersionUID = 1596930978;/*** The singleton instance of <code>PUBLIC.IMAGE</code>*/public static final vladmihalcea.jooq.schema.tables.Image IMAGE = new vladmihalcea.jooq.schema.tables.Image();/*** The class holding records for this type*/@Overridepublic java.lang.Class<vladmihalcea.jooq.schema.tables.records.ImageRecord> getRecordType() {return vladmihalcea.jooq.schema.tables.records.ImageRecord.class;}/*** The column <code>PUBLIC.IMAGE.ID</code>. */public final org.jooq.TableField<vladmihalcea.jooq.schema.tables.records.ImageRecord, java.lang.Long> ID = createField("ID", org.jooq.impl.SQLDataType.BIGINT.nullable(false), this);/*** The column <code>PUBLIC.IMAGE.INDEX</code>. */public final org.jooq.TableField<vladmihalcea.jooq.schema.tables.records.ImageRecord, java.lang.Integer> INDEX = createField("INDEX", org.jooq.impl.SQLDataType.INTEGER, this);/*** The column <code>PUBLIC.IMAGE.NAME</code>. */public final org.jooq.TableField<vladmihalcea.jooq.schema.tables.records.ImageRecord, java.lang.String> NAME = createField("NAME", org.jooq.impl.SQLDataType.VARCHAR.length(255), this);/*** The column <code>PUBLIC.IMAGE.PRODUCT_ID</code>. */public final org.jooq.TableField<vladmihalcea.jooq.schema.tables.records.ImageRecord, java.lang.Long> PRODUCT_ID = createField("PRODUCT_ID", org.jooq.impl.SQLDataType.BIGINT, this);/*** Create a <code>PUBLIC.IMAGE</code> table reference*/public Image() {super("IMAGE", vladmihalcea.jooq.schema.Public.PUBLIC);}/*** Create an aliased <code>PUBLIC.IMAGE</code> table reference*/public Image(java.lang.String alias) {super(alias, vladmihalcea.jooq.schema.Public.PUBLIC, vladmihalcea.jooq.schema.tables.Image.IMAGE);}/*** {@inheritDoc}*/@Overridepublic org.jooq.Identity<vladmihalcea.jooq.schema.tables.records.ImageRecord, java.lang.Long> getIdentity() {return vladmihalcea.jooq.schema.Keys.IDENTITY_IMAGE;}/*** {@inheritDoc}*/@Overridepublic org.jooq.UniqueKey<vladmihalcea.jooq.schema.tables.records.ImageRecord> getPrimaryKey() {return vladmihalcea.jooq.schema.Keys.SYS_PK_10059;}/*** {@inheritDoc}*/@Overridepublic java.util.List<org.jooq.UniqueKey<vladmihalcea.jooq.schema.tables.records.ImageRecord>> getKeys() {return java.util.Arrays.<org.jooq.UniqueKey<vladmihalcea.jooq.schema.tables.records.ImageRecord>>asList(vladmihalcea.jooq.schema.Keys.SYS_PK_10059, vladmihalcea.jooq.schema.Keys.UK_OQBG3YIU5I1E17SL0FEAWT8PE);}/*** {@inheritDoc}*/@Overridepublic java.util.List<org.jooq.ForeignKey<vladmihalcea.jooq.schema.tables.records.ImageRecord, ?>> getReferences() {return java.util.Arrays.<org.jooq.ForeignKey<vladmihalcea.jooq.schema.tables.records.ImageRecord, ?>>asList(vladmihalcea.jooq.schema.Keys.FK_9W522RC4D0KFDKQ390IHV92GB);}/*** {@inheritDoc}*/@Overridepublic vladmihalcea.jooq.schema.tables.Image as(java.lang.String alias) {return new vladmihalcea.jooq.schema.tables.Image(alias);}
}

现在,我们还需要使Maven意识到我们新生成的JOOQ元数据类,以便它可以在下一个测试编译阶段对其进行编译。

<plugin><groupId>org.codehaus.mojo</groupId><artifactId>build-helper-maven-plugin</artifactId><executions><execution><id>add-source</id><phase>process-test-sources</phase><goals><goal>add-test-source</goal></goals><configuration><sources><source>${project.build.directory}/generated-sources/java</source></sources></configuration></execution></executions>
</plugin>

现在,我可以开始玩JOOQ了。 让我们将DSLContext添加到我们的Spring应用程序上下文中:

<bean id="jooqContext" class="org.jooq.impl.DSL" factory-method="using"><constructor-arg ref="dataSource"/><constructor-arg value="#{T(org.jooq.SQLDialect).HSQLDB}"/>
</bean

我们将编写一个测试来检查一切是否正常:

private List<ImageProductDTO> getImageProductDTOs_JOOQ() {return transactionTemplate.execute(new TransactionCallback<List<ImageProductDTO>>() {@Overridepublic List<ImageProductDTO> doInTransaction(TransactionStatus transactionStatus) {return jooqContext.select(IMAGE.NAME, PRODUCT.NAME).from(IMAGE).join(PRODUCT).on(IMAGE.PRODUCT_ID.equal(PRODUCT.ID)).where(PRODUCT.NAME.likeIgnoreCase("%tv%")).and(IMAGE.INDEX.greaterThan(0)).orderBy(IMAGE.NAME.asc()).fetch().into(ImageProductDTO.class);}});
}

生成以下SQL

SELECT "PUBLIC"."image"."name","PUBLIC"."product"."name"
FROM     "PUBLIC"."image"JOIN "PUBLIC"."product"ON "PUBLIC"."image"."product_id" = "PUBLIC"."product"."id"
WHERE   ( Lower("PUBLIC"."product"."name") LIKE Lower('%tv%')AND "PUBLIC"."image"."index" > 0 )
ORDER   BY "PUBLIC"."image"."name" ASC

这是我第一次使用JOOQ,花了我太多时间浏览文档并在Hibernate Facts编码示例中进行了所有设置。 JOOQ查询的构建感觉很自然,就像编写本机SQL代码一样,因此我不必真正学习API就能知道如何使用它。 我将很自豪地将其添加到我的Java Data Toolbox中。

这个编码示例将JOOQ映射生成到test-classes文件夹中,因此您不能在main / java源文件中使用它们。 这可以解决,但需要通过将模型类移到单独的Maven模块中来重构现有解决方案。 您可以在此单独的模块中生成JOOQ模式,在打包之前,您可以在其中将模式类从测试类移至classes文件夹。 然后,您将必须包含这个新模块,通常您将在其中使用JOOQ模式。

参考: JOOQ事实:从JPA批注到我们的JCG合作伙伴 Vlad Mihalcea的Vlad Mihalcea博客博客中的JOOQ 表映射 。

翻译自: https://www.javacodegeeks.com/2013/12/jooq-facts-from-jpa-annotations-to-jooq-table-mappings.html

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

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

相关文章

解决Charles手机安装SSL证书后,获取到的接口为unknown,且乱码问题

按照正常流程将Charles安装并设置代理后&#xff0c;手机添加完代理并安装SSL证书&#xff0c;尝试抓取接口时&#xff0c;获取到的接口为unknown且返回内容乱码&#xff0c;如下图所示 解决办法&#xff1a; 在Proxy-SSL Proxying Settings-SSL Proxying下添加想要抓取的服务地…

Sum of Even Numbers After Queries

Solution: 转载于:https://www.cnblogs.com/Julietma/p/10414394.html

python的颜色有哪些_Python颜色分类及格式

Python字符串颜色使用下面方式进行修改\033[显示方式;字体色;背景色m 字符串 \033[0m显示方式包括&#xff1a;0 终端默认设置1 高亮显示4 使用下划线5 闪烁7 反白显示8 不可见字体颜色 | 背景颜色 | 颜色描述-------------------------------------------3…

我们甚至没有进行包容性的讨论

科技行业需要更加包容女性和有色人种。 这是关于拥有最大的人才库以吸取卓越的经验。 可悲的是&#xff0c;大多数讨论&#xff0c;甚至是倡导更具包容性的文化讨论&#xff0c;本身都是分裂的。 我们都是个人 我们都是个人。 我们都有自己的优点和缺点。 我们都有自己一生以…

第一次连接mysql失败_MySQL 远程连接失败

解决服务器能登陆 MySQL &#xff0c; 远程账户不能链接问题。(第一次遇见还是挺蒙的)一、 配置文件执行顺序/etc/my.cnf/etc/mysql/my.cnf/usr/etc/my.cnf~/.my.cnf二、用户密码注 &#xff1a; 服务器 tx 云 &#xff0c; OS ubuntu 18.4。1、linux ssh 端口 22 登陆账号密码…

Python学习week7-文件操作

1、文件IO常用操作 # 文件操作命令 2、打开操作open # open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) 创建并打开一个文件test&#xff0c;然后关闭&#xff1b;打开一个文件&#xff0c;返回一个文件对象&#xff08;流对…

将一个实体转换成 Url 参数的形式 ?a=ab=b

function toQueryString(obj) { var ret []; for (var key in obj) { key encodeURIComponent(key); var values obj[key]; if (values && values.constructor Array) { //数组 var queryValues []; for (var i 0, len values.length, value; i < len; i ) …

Spring Boot –现代Java应用程序的基础

Spring Boot是Spring.io中一个相对较新的项目。 其目的是简化创建新的基于Spring Framework的项目&#xff0c;并通过应用一些约定来统一其配置。 这种关于配置的方法约定已经成功地应用于大多数所谓的现代Web框架中&#xff0c;例如Ruby on Rails&#xff0c;Django或Play&…

python qt快速入门_PyQt5快速入门(一)

PyQt5快速入门(一)前言为什么选择PyQt5作为GUI框架?API与Qt一致, 学会PyQt后再使用qt很简单开发迅速, 可视化操作,使用designer快速拖拽布局进行调试可以将文件打包成exe进行发布本节课内容(假设已经掌握python语法)搭建PyQt5环境测试PyQt5环境本节课使用环境python 3.6.6IDLE…

风险定量分析工具 龙卷风图 决策树形图 蒙特卡洛模拟

龙卷风图&#xff1a;是项目管理中用于在风险识别和定性分析之后&#xff0c;进行定量风险分析的技术----敏感性分析技术中最常用的一种图表技术。 敏感性分析&#xff1a;敏感性分析有助于确定哪些风险对项目具有最大的潜在影响。它把所有其他不确定因素保持在基准值的条件下…

java 先序遍历_二叉树的前序中序后序遍历(java代码)

importjava.util.*;public classtraversal {public static voidmain(String[] args) {List listnewArrayList<>();//构造二叉树TreeNode treeNode6newTreeNode(2,null,null);TreeNode treeNode5newTreeNode(1,null,null);TreeNode treeNode4newTreeNode(7,null,null);Tre…

js正则验证方法大全

/* 用途&#xff1a;检查输入手机号码是否正确 输入&#xff1a; s&#xff1a;字符串 返回&#xff1a; 如果通过验证返回true,否则返回false */ function checkMobile(s) { var regu /^[1][3][0-9]{9}$/; var re new RegExp(regu); if (re.test(s)) { return true; } els…

使用CLI设置WildFly绑定地址并关闭

仅使用命令行参数将WildFly绑定到主机名/ IP上非常容易。 我有一个简单的GNU / Linux盒子&#xff0c;可以用它玩各种东西&#xff0c;其中之一就是WildFly。 我使用以下命令开始在特定IP上监听WildFly&#xff1a; $> cd /opt/wildfly/wildfly-8.0.0.Beta1/bin $> ./s…

JS基本数据类型

基本数据类型&#xff1a; Undefined&#xff0c;null&#xff0c;boolean&#xff0c;number&#xff0c;string symbol&#xff08;ES6&#xff09; 复杂数据类型&#xff1a; object undefined: 变量声明未初始化&#xff0c;自动为undefined typeof 操作符检测变量数据类型…

用python自制背单词程序_c++自制背单词应用

文件结构&#xff1a;背词历史.log 用来存放背过的单词&#xff0c;存放的格式是年-月-日 时&#xff1a;分&#xff1a;秒单词 词性 中文解释生词本.txt 用来存放当下要背诵的单词列表&#xff0c;格式是单词 词性 中文解释历史记录.txt 用来当做按照时间查询生词的缓存&#…

mongodb lbs java_LBS JAVA Spring mongoDB

基本介绍位置服务(LBS)解决的主要问题是当前位置周围某个范围内的人或场所.在传统的解决方案,开发人员需要根据复杂的几何运算与大量的SQL语句进行查找,这无疑加大的开发人员的开发难度.现在我们需要更为方便的解决方案,MongoDB为我们完美解决此类LBS问题.此篇文章也主要使用Sp…

让height: 100%生效

html&#xff1a; <body><div class"box"></div> </body> css&#xff1a; .box{position: fixed;// 使用fixed定位width: 100%;height: 100%;background: orange;} 补充&#xff1a; &#xff08;父元素不设高度&#xff0c;如何让子元素高…

hash

HashSet Set接口&#xff0c;元素不能重复&#xff0c;要确保重写hashCode&#xff08;&#xff09;方法和equals&#xff08;&#xff09;方法&#xff0c;这样才能比较对象的值是否相等HashMap Map接口&#xff0c;key可为null线程安全ConcurrentHashMap&#xff08;Map接口&…

推土机:将JAXB对象映射到业务/域对象

Dozer是开放源代码&#xff08; Apache 2许可 &#xff09;“ Java Bean到Java Bean映射器&#xff0c;可将数据从一个对象递归复制到另一个对象”。 正如从其主页上的描述所描述的那样&#xff0c;它用于映射两个JavaBeans实例&#xff0c;以在实例之间进行自动数据复制。 尽管…

openssl不是内部或外部命令_OpenSSL新架构蓝图

概述日前OpenSSL官网公布了未来OpenSSL的架构蓝图。作为战略性的架构目标&#xff0c;需要大量的版本迭代本文档概述了OpenSSL战略架构。它需要多个版本的迭代从目前最新的版本1.1开始直到3.0甚至是4.0最终实现。由于版本架构变动非常大&#xff0c;涉及大量的变化和迭代&#…