1

重要提示——最后在编辑#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"])

当我运行此代码时,我得到以下三个结果之一:

  1. org.postgresql.util.PSQLException:连接尝试失败。
  2. org.postgresql.util.PSQLException:错误:错误的数据包头:'70'
  3. 非常罕见(现在三次,在数百次尝试中),它实际上会起作用!它返回({:?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 又要毁了我的生活吗?我以为我们早就把这些糟糕的日子抛在脑后了。

所以现在我想知道是否有办法改变客户端编码。或者可能更改正在使用的身份验证方法。

4

4 回答 4

1

根据 PgJDBC 驱动程序,“PgJDBC 对某些功能的其他库具有可选依赖项。如果您希望使用这些功能,这些库也必须在您的类路径中;如果不是,您将在运行时收到 PSQLException尝试使用缺少库的功能。”

可能缺少某些依赖项或本机编译的 SSL 库。不过,我不知道为什么它有时会在蓝月亮中起作用。

https://github.com/pgjdbc/pgjdbc/blob/f96f6b3c0fdcb9c393b870b834adb1248f955cee/README.md#dependencies

于 2015-02-11T23:21:01.190 回答
0

这个指向Heroku postgres 连接示例的链接提到了另外两个键值对,

:ssl true

:sslfactory (when-not (:production environ/env)  
             "org.postgresql.ssl.NonValidatingFactory")
于 2015-02-11T23:26:49.027 回答
0

没有 SSL 可以工作吗?如果是这样,你能确保你的 JVM 没有运行加密残缺的版本吗?我猜 Oracles JVM 需要出口限制更强的加密 JCE。

强加密JCE可以从http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html下载

于 2015-02-11T23:11:39.980 回答
0

添加额外参数 ignore_startup_parameters=extra_float_digits 应该可以解决问题。

http://www.postgresql.org/message-id/20080625170634.DC16A17AE6FB@pgfoundry.org

于 2015-06-03T00:13:34.930 回答