java - 是否可以将MyBatis和QueryDSL/jOOQ结合使用?

标签 java spring-data mybatis querydsl jooq

MyBatis提供了映射,本地缓存和开箱即用的功能。
QueryDSL/jOOQ提供了SQL语句的编译时检查和IDE自动完成的结果。
是否可以将它们组合?

换句话说,我想用QueryDSL或jOOQ创建一个查询,然后用MyBatis 用一些粘合代码/适配器执行它。

我已经检查过的内容:

  • 我考虑使用QueryDSL生成SQL查询字符串,并在MyBatis中使用其带有'@SelectProvider'批注的字符串,但这似乎是一个死胡同:MyBatis在其SQL字符串中需要“$ {xxx}”的内容,但是QueryDSL仅生成根据实际的Java类型进行查询,因此即使是ID也无法使用。
  • MyBatis Generator作为QueryDSL/jOOQ的替代品:相当差的替代品,因为它实际上会生成样板代码,您稍后必须维护和扩展
  • MyBatis SQL Builder作为QueryDSL/jOOQ的替代:比QueryDSL或jOOQ弱得多,例如它不提供列名的编译时检查,更麻烦,并且依赖于“@SelectProvider”,这会使代码
  • 变得复杂

    最佳答案

    我将从更高的角度进行回答-因此,我不会深入研究QueryDSL和jOOQ之间的实际差异,在本文的讨论中,“仅”两者都提供了Java中类型安全的嵌入式SQL。但是,我将从jOOQ的角度给出答案,因为我知道API更好。

    免责声明:我是从jOOQ背后为公司工作的人的角度给出这个答案的。

    是的你可以:

    是的,您可以将jOOQ与MyBatis结合使用。例如,您可以像这样从jOOQ查询中提取查询字符串:

    Select<?> query =
    DSL.using(configuration)
       .select(TABLE.A, TABLE.B)
       .from(TABLE)
       .where(TABLE.C.eq(1));
    
    String sql = query.getSQL();
    List<Object> bindvalues = query.getBindValues();
    

    实际上,许多人使用此技术然后通过Spring JDBC而不是jOOQ运行查询。之所以这么做,主要是因为他们已经广泛使用了Spring JDBC,并且他们不想在堆栈上执行两种查询。

    但是你为什么要:

    您添加到堆栈中的每个API都会增加堆栈行为的复杂性和一组规则。另一方面,您希望通过这些API实现一组功能。让我们确定这些功能:
  • 输入安全嵌入式SQL
  • 缓存
  • 正在记录
  • 将非规范化的SQL结果映射到您的域

  • 1)输入安全的嵌入式SQL

    这是理所当然的。您可能不想为此使用MyBatis。该实现(如您所发现的)更多是一种概念证明。所以您来到了jOOQ的选择

    2)缓存

    我个人认为这是您太快得出结论的事情。 MyBatis有很多非常简单的东西实现方法,但是在缓存的情况下,我很确定您想实现更通用的缓存策略,例如使用新的JSR-107 caching support, like the one from Spring仅仅是因为缓存与SQL并没有那么紧密地耦合。

    3)记录

    jOOQ for instance implements easy to hook into logging hooks,但您也可以在JDBC级别using a JDBC trace logging library or your JDBC drivers' capabilities上使用日志记录

    4)映射

    我说过的缓存在这里是一样的。 MyBatis为您的映射算法提供了一个简单的默认实现,当您转到更复杂的映射方案时,这可能很快就不够用。 jOOQ btw也是如此,它也实现了default mapping for POJOswhich you can override any way you want。但是,就像缓存一样,映射实际上并不是应该在SQL级别上解决的问题。您将在其中找到更好的工具来进行映射-例如Model Mapper(具有built-in jOOQ support,btw)。或者,如果您使用的是Java 8环境,则可以只使用regular functional programming techniques to map stuff,例如像这样:
    DSL.using(configuration)
       .select(
           COLUMNS.TABLE_NAME,
           COLUMNS.COLUMN_NAME,
           COLUMNS.TYPE_NAME
       )
       .from(COLUMNS)
       .orderBy(
           COLUMNS.TABLE_CATALOG,
           COLUMNS.TABLE_SCHEMA,
           COLUMNS.TABLE_NAME,
           COLUMNS.ORDINAL_POSITION
       )
       .fetch()
    

    上图:jOOQ代码。下图:Java 8映射代码
       .stream()
       .collect(groupingBy(
           r -> r.getValue(COLUMNS.TABLE_NAME),
           LinkedHashMap::new,
           mapping(
               r -> new Column(
                   r.getValue(COLUMNS.COLUMN_NAME),
                   r.getValue(COLUMNS.TYPE_NAME)
               ),
               toList()
           )
       ))
       .forEach(
           (table, columns) -> {
                System.out.println(
                    "CREATE TABLE " + table + " (");
    
                System.out.println(
                    columns.stream()
                           .map(col -> "  " + col.name +
                                        " " + col.type)
                           .collect(Collectors.joining(",\n"))
                );
    
               System.out.println(");");
           }
      );
    

    这是this article底部的示例,它显示了如何查询所有表的H2 INFORMATION_SCHEMA,以及如何将结果映射到CREATE TABLE语句中

    结论:

    由于它们的非核心“功能”(例如缓存或映射),它们实际上是SQL API的非核心功能,因此许多API往往会诱使您使用它们。使用简单的用例以及pet/cat/dog或author/book应用程序,您将快速启动并运行,但是您将被更复杂的应用程序所困扰。在您的用例中,类型安全的嵌入式SQL功能是您想使用jOOQ之类的原因。您正在寻找的其他功能并不是使用MyBatis的令人信服的理由(其核心功能是外部SQL文件,与嵌入SQL的jOOQ完全相反)。

    因此,我对您的建议是:为堆栈中想要的每个功能确定最佳工具,并查看这些工具是否易于组合。我们在实现jOOQ时要格外小心,以允许任何第三方应用程序很容易地插入jOOQ(例如,缓存,日志记录,映射),因为这些功能不是jOOQ的核心功能。

    关于java - 是否可以将MyBatis和QueryDSL/jOOQ结合使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26639057/

    相关文章:

    spring - Spring Data JPA @Query 是动态的还是命名的?

    spring-boot - 使用 Spring Data Redis 将对象映射到哈希

    java - MyBatis:如何存储查询中的多个值?

    java - 将文件数据读入 JTable

    java - 在 POI 中过滤 Excel 中的列时删除考虑空白

    java - 遍历数组并检查项目的值

    java - AutoConfigureMybatis注解是什么意思?

    java - 输入第二个数字后如何在编辑文本字段中设置固定小数?类似于显示 00.00 的 ATM 机屏幕

    spring - 使用elasticsearch.yml中的默认副本配置

    java - Mybatis在select语句中动态列