我正在尝试将人们的电话号码和地址存储在数据库表中。我想支持多个电话号码和地址,并希望不同国家/地区的格式不同。我决定使用hstore来实现这种灵活性,并允许特定字段进行有效查询。目前我可以从数据库接收值,但无法找到从Java插入它们的方法。表(简化)看起来像这样:
CREATE TABLE IF NOT EXISTS contacts ( "
+ "id uuid NOT NULL, "
+ "title character varying NOT NULL DEFAULT '', "
+ "first_name character varying NOT NULL, "
+ "last_name character varying NOT NULL, "
+ "phones hstore[] NOT NULL DEFAULT '{}', "
+ "addresses hstore[] NOT NULL DEFAULT '{}')"
我已经创建了一个自定义JDBI Binder来绑定值,但是我尝试无法获取要执行的语句。目前Binder代码段如下所示:
@Override
public void bind(SQLStatement<?> q, BindContactBean bind, ContactBean bean) {
q.bind("phones",
getHstoreArray(q, PhoneDetailMapper.toMapArray(bean.phones.get())));
q.bind("addresses",
getHstoreArray(q, AddressDetailMapper.toMapArray(bean.addresses.get())));
getHstoreArray函数是一个帮助程序,它将java Array转换为SQL数组,如下所示:
private Array getHstoreArray(SQLStatement<?> q, Map<String, String>[] map) {
try {
return q.getContext().getConnection().createArrayOf("hstore", map);
} catch (SQLException e) {
throw new IllegalArgumentException(e);
}
}
我认为问题出在数据编码上。例如,对于数据(为简单起见,以JSON表示法)
{
"firstName": "Maximum",
"lastName": "Details",
"status": "active",
"phones": [{
"type": "mobile",
"number": "0777 66 55 44"
}]
}
查询扩展为:
INSERT INTO contacts (
id, first_name, last_name, status, phones )
VALUES ( '9be1a040-b408-11e3-bb43-00231832fa86', 'Maximum', 'Details', 4,
'{"{type=mobile, extracted_number=extracted, number=07777 66 55 44}"}'
)
如果我尝试从PGAdmin的SQL编辑器运行它,则返回的错误是:
ERROR: Syntax error near 'm' at position 6
LINE 5: '{"{type=mobile, extracted_number=extracted, number=07777 66...
^
********** Error **********
ERROR: Syntax error near 'm' at position 6
SQL state: XX000
Character: 179
我考虑过使用JSON而不是hstore [],但是这会使得特定字段的查询速度变慢,准确性降低(本质上是文本搜索),我宁愿避免使用它。 我在hstore之前尝试的另一个选项是UDT数组,但是如果没有为PGobject编写解析器,它甚至无法从数据库中读取它看起来像一个简单的任务。
修改
我查看了数据库中的数据以及以下列方式进行转义:
'{"\"type\"=>\"mobile\", \"number\"=>\"07777 66 55 44\", \"extracted_number\"=>\"777665544\""}'
我可以从SQL编辑器手动运行查询,但在Java中仍然没有运气。
答案 0 :(得分:1)
我找到了一个解决方案,Postgres驱动程序中有一个名为HStoreConverter的类可以将Map转换为String文字。不确定这是最好的方法,但似乎有效,修改了下面的辅助函数。
private Array getHstoreArray(SQLStatement<?> q, Map<String, String>[] maps) {
try {
String[] hstores = new String[maps.length];
for (int i = 0; i < maps.length; i++)
hstores[i] = HStoreConverter.toString(maps[i]);
return q.getContext().getConnection().createArrayOf("hstore", hstores);
} catch (SQLException e) {
throw new IllegalArgumentException(e);
}
}