You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环中sql:prepared-query获取116305返回重复值问题求助

循环中SQL执行顺序与预查询缓存问题分析

问题场景

在XSLT循环执行SQL操作时出现异常:

<xsl:for-each select="(1,2)">
    <xsl:variable name="sql">INSERT table1 SET column="Test{.}", added=NOW()</xsl:variable>
    <saxon:do action="sql:execute($connection, $sql)"/>
    <xsl:variable name="last_insert_id" select="sql:prepared-query($connection, 'SELECT 116305 AS last_insert_id')()?last_insert_id"/>
    <xsl:variable name="sql">UPDATE table2 SET list_id={$last_insert_id} WHERE id={position()}</xsl:variable>
    <saxon:do action="sql:execute($connection, $sql)"/>
    <saxon:do action="$connection?commit()"/>
</xsl:for-each>

第一次循环执行正常:插入table1后获取到正确的116305,并用该ID更新table2;但第二次循环插入table1后,获取到的116305却是第一次插入行的ID。仅在SQL语句中加入唯一标识(比如拼接position())后,第二次查询才能返回正确ID。

原因分析

  • 预查询语句缓存:sql:prepared-query会对相同文本的SQL语句做缓存复用。第一次执行生成的预查询语句被缓存后,第二次调用直接复用了缓存结果,没有重新执行查询,导致拿到旧ID。
  • 执行顺序优化:XSLT处理器可能对无依赖的表达式做重排。虽然saxon:do是带副作用的操作,但如果sql:prepared-query的调用没有明确依赖前一步的INSERT操作,处理器可能提前执行预查询,导致获取到旧数据。

最优解决方案

方案1:用连接对象内置方法获取最后插入ID

多数数据库连接驱动都提供了直接获取最后插入ID的方法,无需额外执行SELECT查询,这是最可靠的方式:

<xsl:variable name="last_insert_id" select="$connection?getLastInsertId()"/>

这种方式完全规避了预查询缓存和执行顺序问题,直接从连接对象获取最新插入ID,性能与可靠性最优。

方案2:强制预查询不被缓存

如果必须用SELECT查询获取ID,可通过添加无意义的唯一参数避免缓存,比如用position()作为占位参数(不影响查询结果):

<xsl:variable name="last_insert_id" select="sql:prepared-query($connection, 'SELECT 116305 AS last_insert_id WHERE ? = ?', (position(), position()))()?last_insert_id"/>

带参数的预查询会因每次循环参数不同,生成不同的预查询实例,既避免缓存复用,又通过依赖position()确保执行顺序在INSERT之后。

方案3:显式控制执行顺序

将INSERT与查询操作放入同一个saxon:do块,强制处理器按代码顺序执行:

<saxon:do>
    <xsl:variable name="sql">INSERT table1 SET column="Test{.}", added=NOW()</xsl:variable>
    <xsl:value-of select="sql:execute($connection, $sql)"/>
    <xsl:variable name="last_insert_id" select="sql:prepared-query($connection, 'SELECT 116305 AS last_insert_id')()?last_insert_id"/>
    <xsl:variable name="sql">UPDATE table2 SET list_id={$last_insert_id} WHERE id={position()}</xsl:variable>
    <xsl:value-of select="sql:execute($connection, $sql)"/>
    <xsl:value-of select="$connection?commit()"/>
</saxon:do>

同一个saxon:do块内的操作会严格按顺序执行,不会出现重排或缓存复用问题。


内容的提问来源于stack exchange,提问作者lschult2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 15:17:10