使用 clojure.java.jdbc/db-do-prepared 检查 uuid 是否存在于 PostgreSQL table 中失败
Checking if uuid exists in PostgreSQL table using clojure.java.jdbc/db-do-prepared fails
我正在连接到 PostgreSQL 数据库,我想知道某个 table 中的 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"]
来自 do-prepared
的文档:
Return a seq of update counts (one count for each param-group)
UPDATE
和 DELETE
是 return 更新计数的唯一 SQL CRUD 操作。所以 do-prepared
应该只与那些一起使用。但是,还有更直接的抽象:对于 UPDATE
使用 update!
,对于 DELETE
使用 delete!
.
INSERT
s return 生成的键,并且可以使用 do-prepared
returning 插入计数。但是,这种方式无法获取生成的主键的值。使用 do-prepared-return-keys
或更好的直接抽象 insert!
SELECT
s return 结果集,不是更新计数,不适用于 do-prepared
。
如果您确实想将批处理 SELECT
s 与准备好的语句一起使用,请通过以下方式进行:
- 使用
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"])))
我正在连接到 PostgreSQL 数据库,我想知道某个 table 中的 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"]
来自 do-prepared
的文档:
Return a seq of update counts (one count for each param-group)
UPDATE
和 DELETE
是 return 更新计数的唯一 SQL CRUD 操作。所以 do-prepared
应该只与那些一起使用。但是,还有更直接的抽象:对于 UPDATE
使用 update!
,对于 DELETE
使用 delete!
.
INSERT
s return 生成的键,并且可以使用 do-prepared
returning 插入计数。但是,这种方式无法获取生成的主键的值。使用 do-prepared-return-keys
或更好的直接抽象 insert!
SELECT
s return 结果集,不是更新计数,不适用于 do-prepared
。
如果您确实想将批处理 SELECT
s 与准备好的语句一起使用,请通过以下方式进行:
- 使用
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"])))