开发者问题收集

Jooq/PostgreSQL INSERT 子句中的反斜杠

2014-12-26
818

我正在尝试使用 Jooq 对 PostgreSQL 数据库执行 INSERT 操作。如果字符串包含反斜杠字符,查询将失败,SQL 状态代码为:42601,表示语法错误。

  • Jooq:3.4.4
  • postgresql 驱动程序:8.4-702.jdbc4
  • PostgreSQL:“PostgreSQL 8.4.20 on x86_64-redhat-linux-gnu,由 GCC gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4) 编译,64 位”
  • JDK 1.8.0_25
  • Spring Tool Suite 3.6.0.RELEASE

数据库:

CREATE TABLE datahub.test (
    body TEXT NOT NULL
);

使用生成的 Jooq 代码maven:

  • jooq-codegen-maven 版本 3.4.4
  • generator.name: org.jooq.util.DefaultGenerator
  • generator.database.name: org.jooq.util.postgres.PostgresDatabase

单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"/spring-config.xml"})
public class BatchExceptionJooqTest {
    private static Logger log = LogManager.getLogger(BatchExceptionJooqTest.class);
    @Autowired
    private DSLContext db;
    @Test
    public void runBasicJooqTest(){
        try{
            final List<InsertQuery<TestRecord>> batchUpdate = Lists.newLinkedList();
            InsertQuery<TestRecord> insertQuery = db.insertQuery(TEST);
            insertQuery.addValue(TEST.BODY, "It's a bit more complicated than just doing copy and paste... :\\");
            batchUpdate.add(insertQuery);
            db.batch(batchUpdate).execute();
        }catch(Exception e){
            log.error(e);
        }
    }
}

问题

测试失败并出现异常:

2014-12-26 17:11:16,490 [main] ERROR BatchExceptionJooqTest:36 :runBasicJooqTest - org.jooq.exception.DataAccessException: SQL [null];批量条目 0 插入“datahub”。“test”(“body”)值(‘这比复制粘贴要复杂一些……:\’)被中止。调用 getNextException 查看原因。

如果不是字符串: “这比复制粘贴要复杂一些……:\\” ,而是字符串: “这比复制粘贴要复杂一些……:\\\\” ,则测试通过。与操作期间单引号发生的情况相比,这似乎有点不一致。它被正确地加倍,以便通过 SQL 解析器。反斜杠则不是这样。

我读到过,用另一个反斜杠转义反斜杠不是 SQL 标准的一部分,Postgre 最近更改了其默认行为。但是我不清楚 手册第 4.1.2.2 页 的含义 - 它似乎表明双反斜杠应该有效,而 jooq 没有理由不这样做。

所以.. 有人可以解释一下 Jooq 中描述的情况吗:

  1. 这是所需的行为,除了将我的应用程序正在处理的所有传入反斜杠加倍之外没有其他解决方法吗?
  2. 这是所需的行为,但我可以进行配置更改,使 Jooq 以类似于单引号的方式处理反斜杠?
  3. 这是一个错误吗?
  4. 我做错了什么?

谢谢

2个回答

您使用的是 PostgreSQL 8.x。在该版本中,系统默认接受反斜杠转义的字符串文字,即使没有前面的 E

为避免这种情况,您应将服务器配置变量 standard_conforming_strings 设置为 ON

当然,强烈建议您迁移到高于 8.x 的 PostgreSQL 版本,因为 8.x 版本已达到使用寿命上限并且不再受支持。

RealSkeptic
2014-12-26

jOOQ 3.5 引入了 org.jooq.conf.Settings.backslashEscaping ( https://github.com/jOOQ/jOOQ/issues/3000 )。该设置主要针对 MySQL 而引入,目前 MySQL 仍默认使用反斜杠进行不符合标准的字符串文字转义。

请注意,此设置仅影响内联绑定值,因此在将值绑定到 PreparedStatement 时不会转义反斜杠。

我同意 RealSkeptic 的回答 ,它建议您更改数据库行为或升级到较新的 PostgreSQL 版本。

Lukas Eder
2014-12-27