使用jOOQ跳过行的“搜索”分页

时间:2019-12-19 11:06:59

标签: mysql jooq

我正在尝试使用jOOQ(3.11.12)+ MySQL(5.7.24)实现“搜索”分页。

我有一个产品表,其中包含以下行:

ID                    | Name      | Created At
----------------------  ---------   -------------------
XjpPXlZxT5i3tTjO7lZQ6Q  Product A   2019-10-25 03:23:05
SmytEB9lTW-UiVFhg_gViQ  Product B   2019-10-09 05:43:44
glpNYcsBTJqAzQERbgGh5g  Product C   2019-10-02 14:53:48
HDZ1K7g_Rj-2vdQaEj79Ow  Product D   2019-09-07 14:52:56
aTcWWxdJSReZBGzkLXuNIQ  Product E   2019-09-06 08:21:24
HPOD380mTR-g2Ut4Da0k4Q  Product F   2019-09-06 08:19:57
jXzfHBDAQ6We4CjXLem_WA  Product G   2019-09-06 08:16:06
duxiQ3InRXaFy_JVDkkewQ  Product H   2019-09-06 08:15:02
QF-3ECfLQD2vdVGE_5X-rQ  Product I   2019-09-04 12:35:00
zRnp0tLZRjSsQHN0wV7N_w  Product J   2019-09-04 12:34:28
6Y3E3KkITYWbOs5aOQCHOw  Product K   2019-09-04 10:33:38
ZOoG06ThRTiDDhteIW_6tA  Product L   2019-09-04 10:19:14
6UW4MUClSLSuQI3pkA0qJA  Product M   2019-09-04 10:18:40

假设我的应用程序一次显示5个产品的页面,从最新到最旧的顺序。

因此,我按创建日期降序排序,也按ID排序,以便消除可能在同一时间创建的产品之间的歧义。

我正在尝试获取结果,该内容将是第二页。代码(已替换相关的运行时值)如下所示:

selectFromWhere // <-- assume this to be a SelectConditionStep built with various filter criteria
    .orderBy(TBL_PRODUCT.CREATED_AT.desc(), TBL_PRODUCT.ID.asc())
    .seek(2019-09-06T08:21:24Z, "aTcWWxdJSReZBGzkLXuNIQ") // <-- runtime values
    .limit(limit)
    .fetchInto(Product::class.java)

这将生成以下SQL(为简洁起见,省略了标准引用和过滤条件):

select distinct 
  id, created_at
from tbl_product
where (
    (
    created_at < {ts '2019-09-06 08:21:24.0'}
    or (
      created_at = {ts '2019-09-06 08:21:24.0'}
      and id > 'aTcWWxdJSReZBGzkLXuNIQ'
    )
  )
)
order by 
  created_at desc, 
  id asc
limit 5

如果我从SQL会话中手动复制/粘贴并运行生成的查询,则会得到预期的结果:

  • 产品F
  • 产品G
  • 产品H
  • 产品I
  • 产品J

...但是,执行结果保存到局部变量中,当我调试程序以检查其内容时,我看到它包含:

  • 产品I
  • 产品J
  • 产品K
  • 产品L
  • 产品M

两个问题:

  1. 对于在同一数据库上手动运行的同一查询,jOOQ为什么会返回不同的结果?
  2. 我的方法出问题了吗?

任何建议将不胜感激!

1 个答案:

答案 0 :(得分:2)

假设TBL_PRODUCT.CREATED_AT的数据库列类型为DATETIME,并且相应的Java类型为java.sql.Timestamp(在jOOQ 3.11中为默认值),则在时区时可能会出现这种情况MySQL服务器的版本与Java客户端的版本不同,因为JDBC驱动程序将为您转换时间戳(有关详细信息,请参见https://stackoverflow.com/a/14070771/1732086)。

也可以使用各种JDBC连接URL参数来控制此行为(请参见https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-configuration-properties.html)。一种选择是使用serverTimezone JDBC URL属性将客户端的时区指定为要使用的会话时区(例如serverTimezone=Europe/Zurich)。

时区总会带来令人讨厌的惊喜,尤其是在JDBC的情况下:-(