简体   繁体   English

是否可以结合MyBatis和QueryDSL / jOOQ?

[英]Is it possible to combine MyBatis and QueryDSL/jOOQ?

MyBatis provides the mapping, local cache, and logging out of the box. MyBatis提供了映射,本地缓存和开箱即用的日志记录。
QueryDSL / jOOQ provide compile-time check of SQL statements and IDE auto-completion as a result. 因此,QueryDSL / jOOQ提供SQL语句的编译时检查和IDE自动完成。
Is it possible to combine them? 是否可以将它们结合起来?

In other words, I would like to create a query with either QueryDSL or jOOQ, and then execute it with some glue code/adapters with MyBatis . 换句话说, 我想用QueryDSL或jOOQ创建一个查询,然后使用MyBatis的一些粘合代码/适配器执行它

What I have already checked: 我已经检查过:

  • I considered to generate SQL query strings with QueryDSL and use them in MyBatis with its '@SelectProvider' annotation, but it seems to be a dead end: MyBatis requires "${xxx}" stuff in its SQL strings, but QueryDSL only generates queries based on the actual Java types, so it will not work even for IDs. 我考虑用QueryDSL生成SQL查询字符串,并在MyBatis中使用它们的'@SelectProvider'注释,但它似乎是一个死胡同:MyBatis在其SQL字符串中需要“$ {xxx}”,但QueryDSL只生成查询基于实际的Java类型,因此即使对于ID也不起作用。
  • MyBatis Generator as an alternative to QueryDSL/jOOQ: quite poor alternative, since it actually generates a boilerplate code which you will later have to maintain and extend MyBatis Generator作为QueryDSL / jOOQ的替代品:非常差的替代方案,因为它实际上生成了一个样板代码,您稍后将需要维护和扩展
  • MyBatis SQL Builder as an alternative to QueryDSL/jOOQ: much weaker than QueryDSL or jOOQ, eg it does not offer compile-time check of column names, it is more cumbersome, and it relies on the '@SelectProvider' which complicates the code MyBatis SQL Builder作为QueryDSL / jOOQ的替代品:比QueryDSL或jOOQ弱得多,例如它不提供列名的编译时检查,它更麻烦,并且它依赖于使代码复杂化的'@SelectProvider'

I'm going to answer from a high level - so I'm not delving into the actual differences between QueryDSL and jOOQ, which at this point of the discussion "just" both provide type safe embedded SQL in Java. 我将从高层回答 - 所以我不深入研究QueryDSL和jOOQ之间的实际差异,在讨论的这一点上,“只是”在Java中提供了类型安全的嵌入式SQL。 However, I'll give the answer from a jOOQ perspective, as I know that API much better. 但是,我会从jOOQ的角度给出答案,因为我知道API要好得多。

Disclaimer: I'm giving this answer from the perspective of someone who works for the company behind jOOQ. 免责声明:我是从为jOOQ背后的公司工作的人的角度给出这个答案的。

Yes you can: 是的你可以:

Yes you can combine jOOQ with MyBatis. 是的,您可以将jOOQ与MyBatis结合使用。 For instance, you can extract a query string from a jOOQ query like this: 例如,您可以从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();

Many people actually use this technique to then run the query with Spring JDBC instead of with jOOQ. 许多人实际上使用这种技术然后使用Spring JDBC而不是jOOQ运行查询。 The main reasaon why they do this is because they have already widely used Spring JDBC, and they don't want to have two types of query execution on their stack. 他们这样做的主要原因是因为他们已经广泛使用了Spring JDBC,并且他们不希望在他们的堆栈上有两种类型的查询执行。

But why would you: 但你为什么要这样:

Every API that you add to your stack will also add complexity and a set of rules to the way your stack behaves. 您添加到堆栈中的每个API也会增加堆栈行为的复杂性和一组规则。 On the other hand, you have a set of features that you want to have implemented from those APIs. 另一方面,您有一组要从这些API实现的功能。 Let's identify those features: 让我们来识别这些功能:

  1. Type safe embedded SQL 键入安全的嵌入式SQL
  2. Caching 高速缓存
  3. Logging 记录
  4. Mapping of denormalised SQL results to your domain 将非规范化SQL结果映射到您的域

1) type safe embedded SQL 1)类型安全的嵌入式SQL

This is a no-brainer. 这是一个明智的做法。 You probably don't want to use MyBatis for that. 你可能不想使用MyBatis。 That implementation (as you've discovered) was more of a proof of concept. 这种实现(正如您所发现的)更多地是一个概念证明。 So you came to the choice of jOOQ 所以你选择了jOOQ

2) caching 2)缓存

This is something that I personally think you jumped to conclusions for too quickly. 这是我个人认为你太快就得出结论的东西。 MyBatis has a lot of very simple implementations for things, but in the case of caching, I'm pretty sure you want to implement a much more general caching strategy, eg using the new JSR-107 caching support, like the one from Spring simply because caching is not really that tightly coupled to SQL. MyBatis有许多非常简单的实现,但在缓存的情况下,我很确定你想要实现一个更通用的缓存策略,例如使用新的JSR-107缓存支持,就像Spring中的那个一样因为缓存并不是真正与SQL紧密耦合的。

3) logging 3)记录

jOOQ for instance implements easy to hook into logging hooks , but you could also use logging on a JDBC level using a JDBC trace logging library or your JDBC drivers' capabilities 例如,jOOQ实现了很容易挂钩到日志记录挂钩 ,但您也可以使用JDBC跟踪日志库或JDBC驱动程序的功能来使用 JDBC级别的日志记录

4) mapping 4)映射

The same that I've said for caching is true here. 我说过缓存的内容在这里也是如此。 MyBatis has a simple default implementation for your mapping algorithms, which might quickly not be enough as you move on to more complex mapping scenarios. MyBatis为您的映射算法提供了一个简单的默认实现,当您转向更复杂的映射方案时,这可能很快就不够了。 The same is true for jOOQ, btw, which also implements default mapping for POJOs , which you can override any way you want . 对于jOOQ,btw也是如此,它也实现了POJO的默认映射您可以以任何方式覆盖它 But much like caching, mapping is not really something that should be solved on a SQL level. 但很像缓存,映射并不是一个应该在SQL级别上解决的问题。 You will find much better tools out there for the mapping per se - eg Model Mapper (which has built-in jOOQ support , btw). 你会发现更好的工具用于映射本身 - 例如Model Mapper内置jOOQ支持 ,顺便说一下 )。 Or if you're in a Java 8 environment, you could just use regular functional programming techniques to map stuff , eg like this: 或者如果你在Java 8环境中,你可以使用常规的函数编程技术来映射东西 ,例如:

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()

Above: jOOQ code. 上图:jOOQ代码。 Below: Java 8 mapping code 下图: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 is the example from the bottom of this article , and it shows how to query the H2 INFORMATION_SCHEMA for all tables, and map results into CREATE TABLE statements 这是本文底部的示例,它显示了如何查询所有表的H2 INFORMATION_SCHEMA ,并将结果映射到CREATE TABLE语句

Conclusion: 结论:

Many APIs tend to lure you into using them because of their non-core "features", such as caching or mapping, which are really non-core features for a SQL API. 许多API倾向于引诱您使用它们,因为它们具有非核心“功能”,例如缓存或映射,它们实际上是SQL API的非核心功能。 You will get up and running quickly with simple use cases and pet/cat/dog or author/book applications, but you'll be stuck with more complex ones. 您可以通过简单的用例和宠物/猫/狗或作者/书籍应用程序快速启动并运行,但您将遇到更复杂的问题。 In your use-case, the type safe embedded SQL feature is the reason you wanted to use something like jOOQ. 在您的用例中,类型安全的嵌入式SQL功能是您希望使用类似jOOQ的原因。 The other features you're looking for are all not very compelling reasons to use MyBatis (whose core feature is external SQL files, which is completely the opposite of jOOQ, which embeds SQL). 您正在寻找的其他功能都不是非常令人信服的使用MyBatis的原因(其核心功能是外部SQL文件,这与嵌入SQL的jOOQ完全相反)。

So, my advice to you is: Identify the best tool for each one of the features you want on your stack, and see if those tools are easy to combine. 所以,我给你的建议是:找出你想要在堆栈中使用的每个功能的最佳工具,看看这些工具是否易于组合。 We've taken extreme care when implementing jOOQ to allow for any third party application to plug in very easily into jOOQ (eg caching, logging, mapping) because those features are not jOOQ's core features. 我们在实现jOOQ时非常谨慎,以允许任何第三方应用程序非常容易地插入jOOQ(例如缓存,日志记录,映射),因为这些功能不是jOOQ的核心功能。

Just like to add a point to Lukas very complete answer. 就像给Lukas添加一个非常完整的答案。

From my benchmark MyBatis has some serious perfomance issue on the mapping, Jooq as a much nicer performance curve. 从我的基准测试来看,MyBatis在映射方面存在一些严重的性能问题,Jooq是一个更好的性能曲线。 That's with Jooq on mapper. 那是Jooq在mapper上的问题。

https://github.com/arnaudroger/SimpleFlatMapper#local-mysql https://github.com/arnaudroger/SimpleFlatMapper#local-mysql

在此输入图像描述

Also SimpleFlatMapper as an integration point with querydsl and spring data. SimpleFlatMapper也是与querydsl和spring数据的集成点。 I did not know you could integrate your own mapping with Jooq and will add that to the backlog. 我不知道你可以将自己的映射与Jooq集成,并将其添加到积压中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM