原文翻译
JOOQ是一个简洁的框架,它解决了我在使用高级动态过滤查询时遇到的一个长期问题。虽然Hibernate和JPA附带了一个有用的Criteria API(我已经使用了很长一段时间),但是您可以使用这些API进行操作有一些可以理解的限制。例如,您不能超出简单的SQL操作(例如,JOINS,NESTED SLECTS,AGGREGATION),并且要做类似的事情:窗口函数,用户定义的函数或简单的排序等。
JOOQ不想和Hibernate竞争,但是我觉得它可以完成它。我一直在将Hibernate用于数据层的WRITE部分,因此使用它的名称或JPA中的“ Persisting”部分。对于简单到中等复杂的查询,Hibernate会尽力而为,但是我不必全部依靠它进行所有查询,是吗?查询属性还有一个缺点,这是因为有时为了仅针对少数用例进行查询,有时必须向域模型添加关联。
因此,由于我不怕编写本机查询,因此可以以DSL方式和独立于供应商的方式来执行此操作。
尽管可以使用基于字符串的列命名,但JOOQ通过使用类型安全的元数据提供了一种更好的方法,因此,我们要做的第一件事是为数据库架构生成表映射。
由于我已经有了JPA模型,因此可以从中生成数据库模式DDL,为此,我们可以使用hibernatetool ant任务。
<插件> <groupId> org.apache.maven.plugins </ groupId> <artifactId> maven-antrun-plugin </ artifactId> <执行> <执行> <id> generate-test-sql-scripts </ id> <phase>生成测试资源</ phase> <目标> <goal>运行</ goal> </ goals> <配置> <任务> <属性名称=“ maven_test_classpath” refid =“ maven.test.classpath” /> <path id =“ hibernate_tools_path”> <pathelement path =“ $ {maven_test_classpath}” /> </ path> <属性名称=“ 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 =“;” 格式=“ true” /> <hbm2ddl drop =“ true” create =“ false” export =“ false” outputfilename =“ drop_db.sql” delimiter =“;” 格式=“ true” /> </ hibernatetool> </ tasks> </ configuration> </ execution> </ executions> <依赖项> <依赖性> <groupId> org.hibernate </ groupId> <artifactId>休眠实体经理</ artifactId> <version> $ {hibernate.version} </ version> <排除> <排除> <groupId> org.slf4j </ groupId> <artifactId> slf4j-api </ artifactId> </ exclusion> </ exclusions> </ dependency> <依赖性> <groupId> org.hibernate </ groupId> <artifactId>休眠工具</ artifactId> <version> $ {hibernate.tools.version} </ version> <排除> <排除> <groupId> org.hibernate </ groupId> <artifactId> hibernate-commons-批注</ artifactId> </ exclusion> </ exclusions> </ dependency> <依赖性> <groupId> org.slf4j </ groupId> <artifactId> slf4j-api </ artifactId> <version> $ {slf4j.version} </ version> </ 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,但不幸的是它没有保存插件执行之间的状态。
<插件> <groupId> org.codehaus.mojo </ groupId> <artifactId> sql-maven-plugin </ artifactId> <依赖项> <依赖性> <groupId> org.hsqldb </ groupId> <artifactId> hsqldb </ artifactId> <version> $ {hsqldb.version} </ version> </ dependency> </ dependencies> <配置> <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> <执行> <执行> <id>创建测试编译数据</ id> <phase>过程测试资源</ phase> <inherited> true </ inherited> <目标> <goal>执行</ goal> </ goals> <配置> <orderFile>升序</ orderFile> <文件集> <basedir> $ {project.build.directory} / test-classes / hsqldb / </ basedir> <包括> <include> create_db.sql </ include> </ includes> </ fileset> <autocommit> true </ autocommit> </ configuration> </ execution> </ executions> </ plugin>
因此,HSQLDB现在已由我们的JPA生成的架构填充,并且我们终于可以调用JOOQ代码生成来构建表映射。
<插件> <groupId> org.jooq </ groupId> <artifactId> jooq-codegen-maven </ artifactId> <执行> <执行> <phase>过程测试类</ phase> <目标> <goal>生成</ goal> </ goals> </ execution> </ executions> <依赖项> <依赖性> <groupId> org.hsqldb </ groupId> <artifactId> hsqldb </ artifactId> <version> $ {hsqldb.version} </ version> </ dependency> </ dependencies> <配置> <jdbc> <driver> org.hsqldb.jdbc.JDBCDriver </ driver> <url> jdbc:hsqldb:file:$ {project.build.directory} / hsqldb / db </ url> <user> sa </ user> <password> </ password> </ jdbc> <发电机> <name> org.jooq.util.JavaGenerator </ name> <数据库> <name> org.jooq.util.hsqldb.HSQLDBDatabase </ name> <includes>。* </ includes> <excludes> </ excludes> <inputSchema> PUBLIC </ inputSchema> </数据库> <generate> </ generate> <目标> <packageName> vladmihalcea.jooq.schema </ packageName> <directory> target / generated-sources / jooq </ directory> </ target> </ generator> </ configuration> </ plugin>
通过maven运行,我们生成了表映射,因此让我们将Image类的JPA元模型与关联的JOOQ表映射进行比较:
JPA元模型如下所示:
@StaticMetamodel(Image.class) 公共抽象类Image_ { 公共静态挥发性SingularAttribute <Image,Product>产品; 公共静态挥发物SingularAttribute <Image,Long> id; 公共静态volatile SetAttribute <Image,Version>版本; 公共静态挥发性SingularAttribute <Image,Integer>索引; 公共静态volatile SingularAttribute <图像,字符串>名称; }
和JOOQ表映射
@ javax.annotation.Generated(value = {“ http://www.jooq.org”,“ 3.2.0”}, comments =“此类是由jOOQ生成的”) @ java.lang.SuppressWarnings({“ all”,“ unchecked”,“ rawtypes”}) 公共类Image扩展了org.jooq.impl.TableImpl <vladmihalcea.jooq.schema.tables.records.ImageRecord> { 私有静态最终长serialVersionUID = 1596930978; / ** * <code> PUBLIC.IMAGE </ code>的单例实例 * / 公共静态最终vladmihalcea.jooq.schema.tables.Image图片=新的vladmihalcea.jooq.schema.tables.Image(); / ** *持有该类型的记录的班级 * / @Override 公共java.lang.Class <vladmihalcea.jooq.schema.tables.records.ImageRecord> getRecordType(){ 返回vladmihalcea.jooq.schema.tables.records.ImageRecord.class; } / ** *列<code> PUBLIC.IMAGE.ID </ code>。 * / 公共最终org.jooq.TableField <vladmihalcea.jooq.schema.tables.records.ImageRecord,java.lang.Long> ID = createField(“ ID”,org.jooq.impl.SQLDataType.BIGINT.nullable(false),此); / ** *列<code> PUBLIC.IMAGE.INDEX </ code>。 * / 公共最终org.jooq.TableField <vladmihalcea.jooq.schema.tables.records.ImageRecord,java.lang.Integer> INDEX = createField(“ INDEX”,org.jooq.impl.SQLDataType.INTEGER,this); / ** *列<code> PUBLIC.IMAGE.NAME </ code>。 * / 公共最终org.jooq.TableField <vladmihalcea.jooq.schema.tables.records.ImageRecord,java.lang.String> NAME = createField(“ NAME”,org.jooq.impl.SQLDataType.VARCHAR.length(255),这个); / ** *列<code> PUBLIC.IMAGE.PRODUCT_ID </ code>。 * / 公共最终org.jooq.TableField <vladmihalcea.jooq.schema.tables.records.ImageRecord,java.lang.Long> PRODUCT_ID = createField(“ PRODUCT_ID”,org.jooq.impl.SQLDataType.BIGINT,this); / ** *创建<code> PUBLIC.IMAGE </ code>表引用 * / 公众形象() { super(“ IMAGE”,vladmihalcea.jooq.schema.Public.PUBLIC); } / ** *创建别名<code> PUBLIC.IMAGE </ code>表引用 * / 公共图片(java.lang.String别名){ 超级(别名,vladmihalcea.jooq.schema.Public.PUBLIC,vladmihalcea.jooq.schema.tables.Image.IMAGE); } / ** * {@inheritDoc} * / @Override 公共org.jooq.Identity <vladmihalcea.jooq.schema.tables.records.ImageRecord,java.lang.Long> getIdentity(){ 返回vladmihalcea.jooq.schema.Keys.IDENTITY_IMAGE; } / ** * {@inheritDoc} * / @Override 公共org.jooq.UniqueKey <vladmihalcea.jooq.schema.tables.records.ImageRecord> getPrimaryKey(){ 返回vladmihalcea.jooq.schema.Keys.SYS_PK_10059; } / ** * {@inheritDoc} * / @Override 公共java.util.List <org.jooq.UniqueKey <vladmihalcea.jooq.schema.tables.records.ImageRecord >> getKeys(){ 返回java.util.Arrays。 } / ** * {@inheritDoc} * / @Override 公共java.util.List <org.jooq.ForeignKey <vladmihalcea.jooq.schema.tables.records.ImageRecord,?>> getReferences(){ 返回java.util.Arrays。<org.jooq.ForeignKey <vladmihalcea.jooq.schema.tables.records.ImageRecord,?>> asList(vladmihalcea.jooq.schema.Keys.FK_9W522RC4D0KFDKQ390IHV92GB); } / ** * {@inheritDoc} * / @Override 公共vladmihalcea.jooq.schema.tables.Image as(java.lang.String别名){ 返回新的vladmihalcea.jooq.schema.tables.Image(alias); } }
现在,我们还需要使Maven意识到我们新生成的JOOQ元数据类,以便它可以在下一个测试编译阶段对其进行编译。
<插件> <groupId> org.codehaus.mojo </ groupId> <artifactId> build-helper-maven-plugin </ artifactId> <执行> <执行> <id>添加源</ id> <phase>过程测试源</ phase> <目标> <goal>添加测试源</ goal> </ goals> <配置> <来源> <source> $ {project.build.directory} / generate-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
我们将编写一个测试来检查一切是否正常:
私人列表<ImageProductDTO> getImageProductDTOs_JOOQ(){ return transactionTemplate.execute(new TransactionCallback <List <ImageProductDTO >>(){ @Override 公共列表<ImageProductDTO> doInTransaction(TransactionStatus transactionStatus){ 返回jooqContext 。选择(IMAGE.NAME,PRODUCT.NAME) 。从图片中) .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
选择“ PUBLIC”。“ image”。“ name”, “ PUBLIC”。“产品”。“名称” 来自“公共”。“图像” 加入“公共”。“产品” ON“ PUBLIC”。“图像”。“ product_id” =“ PUBLIC”。“产品”。“ id” 在哪儿(较低(“ PUBLIC”。“产品”。“名称”)喜欢较低(‘%tv%‘) AND“ PUBLIC”。“ image”。“ index”> 0) 按“ PUBLIC”。“图像”。“名称” ASC排序
这是我第一次使用JOOQ,花了我太多时间浏览文档并在Hibernate Facts编码示例中进行了所有设置。JOOQ查询的构建感觉很自然,就像编写本机SQL代码一样,因此我不必真正学习API就能知道如何使用它。我将很自豪地将其添加到我的Java Data Toolbox中。
这个编码示例将JOOQ映射生成到test-classes文件夹中,因此您不能在main / java源文件中使用它们。这可以解决,但是需要通过将模型类移动到单独的Maven模块中来重构现有解决方案。您可以在此单独的模块中生成JOOQ模式,在打包之前,您可以在其中将模式类从测试类移至classes文件夹。然后,您将必须包括这个新模块,通常在其中使用JOOQ模式。
jooq映射原理_JOOQ事实:从JPA批注到JOOQ表映射
原文:https://www.cnblogs.com/ScarecrowAnBird/p/14052332.html