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任务。


	org.apache.maven.plugins
	maven-antrun-plugin
	
		
			generate-test-sql-scripts
			generate-test-resources
			
				run
			
			
				
					
					
						
					
					
					
					
					
						
						
						
						
					
				
			
		
	
	
		
			org.hibernate
			hibernate-entitymanager
			${hibernate.version}
			
				
					org.slf4j
					slf4j-api
				
			
		
		
			org.hibernate
			hibernate-tools
			${hibernate.tools.version}
			
				
					org.hibernate
					hibernate-commons-annotations
				
			
		
		
			org.slf4j
			slf4j-api
			${slf4j.version}
		
		
			org.slf4j
			slf4j-simple
			${slf4j.version}
		
	

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


	org.codehaus.mojo
	sql-maven-plugin
	
		
			org.hsqldb
			hsqldb
			${hsqldb.version}
		
	
	
		org.hsqldb.jdbc.JDBCDriver
		jdbc:hsqldb:file:${project.build.directory}/hsqldb/db;shutdown=true
		sa
		
		true
		hsql-db-test
	
	
		
			create-test-compile-data
			process-test-resources
			true
			
				execute
			
			
				ascending
				
					${project.build.directory}/test-classes/hsqldb/
					
						create_db.sql
					
				
				true
			
		
	

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


	org.jooq
	jooq-codegen-maven
	
		
			process-test-classes
			
				generate
			
		
	
	
		
			org.hsqldb
			hsqldb
			${hsqldb.version}
		
	
	
		
			org.hsqldb.jdbc.JDBCDriver
			jdbc:hsqldb:file:${project.build.directory}/hsqldb/db
			sa
			
		
		
			org.jooq.util.JavaGenerator
			
				org.jooq.util.hsqldb.HSQLDBDatabase
				.*
				
				PUBLIC
			
			
			
				vladmihalcea.jooq.schema
				target/generated-sources/jooq
			
		
	

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

JPA元模型如下所示:

@StaticMetamodel(Image.class)
public abstract class Image_ {

	public static volatile SingularAttribute product;
	public static volatile SingularAttribute id;
	public static volatile SetAttribute versions;
	public static volatile SingularAttribute index;
	public static volatile SingularAttribute 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 {

	private static final long serialVersionUID = 1596930978;

	/**
	 * The singleton instance of PUBLIC.IMAGE
	 */
	public static final vladmihalcea.jooq.schema.tables.Image IMAGE = new vladmihalcea.jooq.schema.tables.Image();

	/**
	 * The class holding records for this type
	 */
	@Override
	public java.lang.Class getRecordType() {
		return vladmihalcea.jooq.schema.tables.records.ImageRecord.class;
	}

	/**
	 * The column PUBLIC.IMAGE.ID. 
	 */
	public final org.jooq.TableField ID = createField("ID", org.jooq.impl.SQLDataType.BIGINT.nullable(false), this);

	/**
	 * The column PUBLIC.IMAGE.INDEX. 
	 */
	public final org.jooq.TableField INDEX = createField("INDEX", org.jooq.impl.SQLDataType.INTEGER, this);

	/**
	 * The column PUBLIC.IMAGE.NAME. 
	 */
	public final org.jooq.TableField NAME = createField("NAME", org.jooq.impl.SQLDataType.VARCHAR.length(255), this);

	/**
	 * The column PUBLIC.IMAGE.PRODUCT_ID. 
	 */
	public final org.jooq.TableField PRODUCT_ID = createField("PRODUCT_ID", org.jooq.impl.SQLDataType.BIGINT, this);

	/**
	 * Create a PUBLIC.IMAGE table reference
	 */
	public Image() {
		super("IMAGE", vladmihalcea.jooq.schema.Public.PUBLIC);
	}

	/**
	 * Create an aliased PUBLIC.IMAGE table reference
	 */
	public Image(java.lang.String alias) {
		super(alias, vladmihalcea.jooq.schema.Public.PUBLIC, vladmihalcea.jooq.schema.tables.Image.IMAGE);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public org.jooq.Identity getIdentity() {
		return vladmihalcea.jooq.schema.Keys.IDENTITY_IMAGE;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public org.jooq.UniqueKey getPrimaryKey() {
		return vladmihalcea.jooq.schema.Keys.SYS_PK_10059;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public java.util.List> getKeys() {
		return java.util.Arrays.>asList(vladmihalcea.jooq.schema.Keys.SYS_PK_10059, vladmihalcea.jooq.schema.Keys.UK_OQBG3YIU5I1E17SL0FEAWT8PE);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public java.util.List> getReferences() {
		return java.util.Arrays.>asList(vladmihalcea.jooq.schema.Keys.FK_9W522RC4D0KFDKQ390IHV92GB);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public vladmihalcea.jooq.schema.tables.Image as(java.lang.String alias) {
		return new vladmihalcea.jooq.schema.tables.Image(alias);
	}
}

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


  org.codehaus.mojo
  build-helper-maven-plugin
  
    
      add-source
      process-test-sources
      
        add-test-source
      
      
        
          ${project.build.directory}/generated-sources/java
        
      
    
  

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


    
    

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

private List getImageProductDTOs_JOOQ() {
    return transactionTemplate.execute(new TransactionCallback>() {
        @Override
        public List 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

你可能感兴趣的:(数据库,java,hibernate,maven,spring,boot)