使用clojure.java.jdbc / db-do-prepared检查PostgreSQL表中是否存在uuid失败

时间:2015-11-08 23:08:10

标签: postgresql jdbc clojure uuid

我正在连接到PostgreSQL数据库,我想知道某个表中的UUID类型列中是否存在uuid。参数uuid在另一个函数中生成。 在clojure中我尝试

(jdbc/db-do-prepared {:datasource datasource}
             "SELECT exists (SELECT 1 FROM account WHERE guid=?::uuid)"
             [uuid])

但它引发了一个例外:

BatchUpdateException Batch entry 0 SELECT exists (SELECT 1 FROM table WHERE guid='dbe8cda5-d37c-3446-9b9c-85e0344af3b1'::uuid) was aborted.  Call getNextException to see the cause.  org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError (AbstractJdbc2Statement.java:2781)

如果我连接到数据库并粘贴生成的SQL并执行它,它可以正常工作。我也可以使用以下代码从clojure插入:

(jdbc/db-do-prepared {:datasource datasource}
                   "INSERT INTO table(guid) VALUES (?::uuid)"
                   [uuid])

来自project.clj的相关依赖项:

[org.clojure/java.jdbc "0.4.2"]
[org.postgresql/postgresql "9.4-1205-jdbc42"]
[hikari-cp "1.3.1"]

1 个答案:

答案 0 :(得分:1)

来自do-prepared的文档:

  

返回一系列更新计数(每个参数组一个计数)

UPDATEDELETE是唯一返回更新计数的SQL CRUD操作。所以do-prepared应该只与那些一起使用。但是,还有更多直接抽象:UPDATE使用update!DELETE使用delete!

INSERT返回生成的密钥,可以使用do-prepared返回插入计数。但是,这样您就无法获得生成的主键的值。使用do-prepared-return-keys或更好的直接抽象insert!

SELECT返回结果集,而不是更新计数,并且无法使用do-prepared

如果您确实希望将批处理SELECT与预准备语句一起使用,请执行以下操作:

  • 使用with-db-connection
  • 绑定单个数据库连接
  • 在该连接上创建预准备语句并将其绑定到var
  • 使用引用绑定连接和预准备语句的查询函数

像这样:

(j/with-db-connection [c datasource]
      (let [ps (j/prepare-statement (j/get-connection c)
                "SELECT count(*) from person where left(name,1)=?")]
        (doall (map #(j/query c [ps %]) ["a" "b" "c"]))))

虽然我最初认为数据库能够通过参数化来优化查询,但进一步的测试表明,这可以将查询速度提高60%。这种加速大部分都在数据库方面,因为语句准备开销可以忽略不计。该测试使用与提到的OP相同的用例,检查UUID(从1K到100K)。

使用预准备语句的通用版本可以通过以下一点宏魔法来清理:

(defmacro with-prepared-statement
  [[connection-bind datasource
    statement-bind sql & keys]
   & body]
  `(clojure.java.jdbc/with-db-connection [~connection-bind datasource]
                                         (let [~statement-bind (apply clojure.java.jdbc/prepare-statement
                                                                      (clojure.java.jdbc/get-connection datasource) ~sql ~keys)]
                                           ~@body)))

(with-prepared-statement [c datasource
                          ps "SELECT count(*) from persoon where left(voornaam,1)=?"]
                         (doall (map #(j/query c [ps %]) ["a" "b" "c"])))