重要提示——最后在编辑#2 中取得了突破,所以请务必阅读。
我在 clojure 中,试图使用 JDBC 连接到我们公司的 PostgreSQL 服务器。服务器正在使用 pgBouncer。
这是我的项目依赖项:
:dependencies [[org.clojure/clojure "1.6.0"]
[org.clojure/java.jdbc "0.3.6"]
[org.postgresql/postgresql "9.4-1200-jdbc41"]]
这是我的代码:
(ns pg-test.core
(:require [clojure.java.jdbc :as jdbc]))
(def db
{:subprotocol "postgresql"
:subname "//the-server-name:the-port/db-name"
:sslmode "require"
:user "my-username"
:password "super-secret-password"})
(jdbc/query db ["SELECT 5"])
当我运行此代码时,我得到以下三个结果之一:
- org.postgresql.util.PSQLException:连接尝试失败。
- org.postgresql.util.PSQLException:错误:错误的数据包头:'70'
- 非常罕见(现在三次,在数百次尝试中),它实际上会起作用!它返回
({:?column? 5})
到底是怎么回事?为什么这有时有效,但几乎从不?
我的设置
- OS X Yosemite(但我也无法在我的 Ubuntu 虚拟机上运行它。)
lein repl :headless :port 2358
其次是cider-connect
在emacs中。- 服务器是 postgres 9.1.12
编辑#2
刚刚了解了这个:loglevel 2
选项。这将其设置为“调试”级别的输出,并且我收集了一些更有趣的数据。这是输出:
21:45:34.921 (31) PostgreSQL 9.4 JDBC4.1 (build 1200)
21:45:34.927 (31) Trying to establish a protocol version 3 connection to the-server-name:the-port
21:45:35.020 (31) FE=> SSLRequest
21:45:35.120 (31) <=BE SSLOk
21:45:35.120 (31) converting regular socket connection to ssl
21:45:35.324 (31) Receive Buffer Size is 131072
21:45:35.324 (31) Send Buffer Size is 131136
21:45:35.324 (31) FE=> StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2)
21:45:35.435 (31) <=BE AuthenticationReqMD5(salt=f244b442)
21:45:35.436 (31) FE=> Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1)
21:45:35.520 (31) <=BE ErrorMessage(ERROR: bad packet header: '70')
然后它给出以下堆栈跟踪:
org.postgresql.util.PSQLException: ERROR: bad packet header: '70'
at org.postgresql.core.v3.ConnectionFactoryImpl.doAuthentication(ConnectionFactoryImpl.java:420)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:195)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
at org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:127)
at org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:29)
at org.postgresql.jdbc3g.AbstractJdbc3gConnection.<init>(AbstractJdbc3gConnection.java:21)
at org.postgresql.jdbc4.AbstractJdbc4Connection.<init>(AbstractJdbc4Connection.java:41)
at org.postgresql.jdbc4.Jdbc4Connection.<init>(Jdbc4Connection.java:24)
at org.postgresql.Driver.makeConnection(Driver.java:414)
at org.postgresql.Driver.connect(Driver.java:282)
at java.sql.DriverManager.getConnection(DriverManager.java:571)
at java.sql.DriverManager.getConnection(DriverManager.java:187)
at clojure.java.jdbc$get_connection.invoke(jdbc.clj:255)
at clojure.java.jdbc$db_query_with_resultset.invoke(jdbc.clj:798)
at clojure.java.jdbc$query.doInvoke(jdbc.clj:832)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at pg_test.core$eval4536.invoke(core.clj:14)
at clojure.lang.Compiler.eval(Compiler.java:6703)
at clojure.lang.Compiler.load(Compiler.java:7130)
at pg_test.core$eval4524.invoke(form-init6588155330850041472.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6703)
at clojure.lang.Compiler.eval(Compiler.java:6666)
at clojure.core$eval.invoke(core.clj:2927)
at clojure.main$repl$read_eval_print__6625$fn__6628.invoke(main.clj:239)
at clojure.main$repl$read_eval_print__6625.invoke(main.clj:239)
at clojure.main$repl$fn__6634.invoke(main.clj:257)
at clojure.main$repl.doInvoke(main.clj:257)
at clojure.lang.RestFn.invoke(RestFn.java:1523)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__592.invoke(interruptible_eval.clj:67)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:51)
at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__634$fn__637.invoke(interruptible_eval.clj:183)
at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__627.invoke(interruptible_eval.clj:152)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
但随后它给出了这个错误代码!
SQLException: SQLState(08P01)
根据本网站,这意味着“违反协议”。
我在 google 上搜索了 08P01 协议违规,并在 GitHub 上找到了一个完全不相关的项目的错误报告,标题为“'08P01 PROTOCOL VIOLATION',当尝试将编码的 unicode 字符写入字符串字段时”。
那么让我们看看我们发送的内容:
StartupPacket(user=my-username, database=db-name, client_encoding=UTF8, DateStyle=ISO, TimeZone=America/Denver, extra_float_digits=2)
. 请注意,我们的编码是 UTF8。- 然后,我们发送
Password(md5digest=md52e3d9f29d44d48ab19ef3469d54d50d1)
,立即得到“bad packet header '70'”异常。
UTF8 又要毁了我的生活吗?我以为我们早就把这些糟糕的日子抛在脑后了。
所以现在我想知道是否有办法改变客户端编码。或者可能更改正在使用的身份验证方法。