0

在我将字节数组保存到数据库之前,如果我打印它的输出new String(data)会返回一个可读的字符串,例如“foobar”,但是在我将它从数据库中拉出之后,new String(data)会读起来像一堆乱码,例如“9238929384739427349327 ...”。这里有很多部分,我将尝试将它们全部列出。我正在使用 eclipselink 并且我的数据列已定义:

@Lob
@Column(name = "data")
private byte[] data;

如果我运行此代码:

public static void main(String[] args) {
    System.out.println(Charset.defaultCharset());
}

它输出windows-1250.

我的数据库定义为:

CREATE DATABASE project_trunk
  WITH OWNER = project
       ENCODING = 'UTF8'
       TABLESPACE = pg_default
       LC_COLLATE = 'English_United States.1252'
       LC_CTYPE = 'English_United States.1252'
       CONNECTION LIMIT = -1;

我也在这样定义的数据库上试过这个:

CREATE DATABASE project_trunk
  WITH OWNER = project
       ENCODING = 'UTF8'
       TABLESPACE = pg_default
       LC_COLLATE = 'en_US.UTF-8'
       LC_CTYPE = 'en_US.UTF-8'
       CONNECTION LIMIT = -1;

并且问题仍然存在。

我认为发生的事情是我的数据库与我的应用服务器的编码不同。当我将内容放入数据库并再次将其取出时,它以错误的方式对其进行解码,因此看起来像乱码。我有什么事情吗?

现在,当谈到解决这个问题时,我有点困惑。我认为我应该做的是将我的应用服务器的文件编码更改为与数据库相同。我正在使用 Glassfish 2.1.1。当我application server -> advanced -> domain attributes将语言环境设置为“UTF8”或“UTF-8”时,它告诉我需要重新启动。重新启动 glassfish 后,该字段仍为空白,并且仍然出现错误。我想也许它没有节省财产。我会手动将它放在配置文件中,但我不知道该放在哪里或放什么。

或者,我尝试使用 ENCODING = 'WIN1250' 创建我的数据库,但是当我这样做时,它说我的 LC_CTYPE 需要是“WIN1252”。当我将 LC_CTYPE 设置为“WIN1252”时,它说编码不存在。


我在这方面花了很多时间,我想知道我是否在这里做一些事情。我的“appserver 和 db 之间的编码不同步”的理论听起来是正确的,还是我在追逐红鲱鱼?如果有人可以帮助我弄清楚如何更改 glassfish 2.1.1 的此设置,那也将非常有帮助。谢谢

编辑:人们问我为什么将字符串存储为原始字节。这不完全是我正在做的事情,有时原始字节代表图像或pdf或二进制文件,有时是文本。我的测试是插入一个纯文本字符串并将其拉回以确保它被正确保存。这个测试通过了我们在 linux 上的 CI 服务器。

EDIT2:我被要求显示原始二进制输入与原始二进制输出。

预期:[116、104、105、115、32、105、115、32、109、121、32、97、116、116、97、99、104、109、101、110、116、32、97、115 , 32, 97, 32, 83, 116, 114, 105, 110, 103]

实际:[60, 54, 56, 54, 57, 55, 51, 50, 48, 54, 57, 55, 51, 50, 48, 54, 100, 55, 57, 50, 48, 54, 49, 55 , 52, 55, 52, 54, 49, 54, 51, 54, 56, 54, 100, 54, 53, 54, 101, 55, 52, 50, 48, 54, 49, 55, 51, 50, 48 , 54, 49, 50, 48, 53, 51, 55, 52, 55, 50, 54, 57, 54, 101, 54, 55]

我给了我在 Mac 上的同事检查字节的相同测试,并且它通过了他。

4

2 回答 2

2

有时原始字节代表图像或pdf或二进制文件,有时是文本

好的,那么您不应该将它们存储为文本。

不管当前出了什么问题,即使你可以让它适用于实际上是文本的数据,你以后也会遇到问题。

如果您必须将任意二进制数据存储为文本,则应使用 base64 对其进行编码 - 这样您就可以毫无问题地返回原始二进制数据。(您只需要能够传输 ASCII 字符串,这通常相当容易。) Base64 有很多第三方库。我喜欢这个独立的公共领域之一

或者,将数据作为二进制数据存储在数据库中,例如使用bytea数据类型的字段。这样你就不需要做任何转换工作:你应该能够把它作为一个字节数组放入数据库,然后把它作为一个字节数组取出。

编辑:好的,看起来你正在取回二进制数据的十六进制表示,但在 ASCII 中。这显然很奇怪。

于 2013-02-12T19:34:17.860 回答
0

事实证明,这是由于 PostgreSQL 在版本 9 和版本 8 中的工作方式造成的。我的大多数同事都使用版本 8,但我最近有了一台新计算机,所以我使用了最新的 PostgreSQL。

您需要将 output_bytea 设置为“escape”。

使用 jpa 从 postgres 读取 byte[] 时长度几乎增加一倍

虽然我没有找到足够的答案,但我在邮件列表中找到了这个并解决了我的问题: http ://www.postgresql.org/message-id/AANLkTikkE-jQ9srZ9VL1JuJ5h=UCutx8ZLim+OfQ1T4z@mail.gmail .com

亲爱的名单,

最近在 9.0 中将 bytea_output 格式从 escape 更改为 hex 显然破坏了流行的持久会话处理 perl 模块,例如 Apache::Session::Postgres,它将腌制数据结构存储在 db 表的 bytea 列中。很难从所述模块抛出的异常中猜测根本原因。该问题通过在 postgresql.conf 中添加 bytea_output='escape' 并发出 pg_ctl 重新加载来解决。

例如,在 RT 应用程序中,错误是:错误:RT 无法存储您的会话。这可能意味着目录 /blah/blah/foo/bar 不可写或数据库表丢失或损坏

Regds Rajesh Kumar Mallah。

于 2013-02-13T00:24:36.840 回答