使用 PostgreSQL 的 uuid 字段类型

上一篇 使用 SQL Server 的 uniqueidentifier 字段类型 了解了 SQL Server 中如何使用 uniqueidentifier 字段类型后,现在来看下 PostgreSQL 中如何使用 uuid 字段类型。在 PostgreSQL 的字段类型是 uuid 了,所以创建一个带有 uuid 字段的表是

CREATE TABLE customers (
    id uuid PRIMARY KEY,
    name VARCHAR(36)
);

我们这里设置 id 字段类型为 uuid, 并且它是一个主键。也可以应用函数指定它的默认值,下面将会讲述到。

然后用 SQL 语句来向该表插入记录

uuid 字段值必须为一个合法的 UUID 字符串, 我们可以用 Java 的 java.util.UUID.randomUUID().toString() 来生成。同样 UUID 按模式 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx 展示出来也是它的外部表现形式,它内部是以 16 位来存储的,所以改变字符的大小写也是同一个值。插入非法的 uuid 字符串不被接受,也就是该字符串不能用 java.util.UUID.fromString("your-input") 还原为 UUID 对象就是不合法的。

这儿是一个 SQL Server 的 uniqueidentifier 和 PostgreSQL 的 uuid 字段的对比: UNIVERSAL UNIQUE IDENTIFIERS POSTGRESQL SQL SERVER COMPARE

前面还落下一个问题,即如何为 uuid 字段设定默认值及调用 PostgreSQL 函数来生成 uuid 值

从搜索到的资料来看,PostgreSQL 中可以调用uuid_generate_v1() 或 uuid_generate_v4() 等函数生成 uuid,于是我们试一下

均提示函数不存在,这是因为它们依赖于一个第三方模块 uuid-ossp, 在使用它的函数之前必须用 CREATE EXTENSION 安装该模块

只有安装了 uuid-ossp 之后,上面的那两个函数 uuid_generate_v1() 和 uuid_generate_v4() 才能调用, 而且这时候才能在创建表时为 uuid 字段使用其中一个函数作为默认值

uuid-ossp 模块包含的所有函数,和 uuid_generate_v1() 与 uuid_generate_v4() 之间的区别请查看链接 https://www.postgresql.org/docs/9.4/static/uuid-ossp.html

参观一下插入记录后查询 uuid 字段是怎么显示的,如下图

最后,也来看下 JDBC 中如何操作 uuid 字段

读取 uuid 字段仍然是用 rs.getString(column)rs.getObject(column) 得到的是一个 java.util.UUID 对象。

JDBC 在应用 PreparedStatement 插入或更新 uuid 字段,只能用 PreparedStatement 的 setObject(...) 方法

以上用 pstmt.setObject(1, UUID.randomUUID()) 可以正常插入一个 uuid 值。而如果尝试把 uuid 类型字段当作一个 VARCHAR 字段类型用

pstmt.setObject(1, UUID.randomUUID().toString());
pstmt.setString(1, UUID.randomUUID().toString());

将会得到错误信息

Exception in thread "main" org.postgresql.util.PSQLException: ERROR: column "id" is of type uuid but expression is of type character varying
    Hint: You will need to rewrite or cast the expression.
    Position: 40
        at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2433)
        at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2178)
        at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:306)
        at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:441)
        at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:365)
        at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:155)
        at org.postgresql.jdbc.PgPreparedStatement.execute(PgPreparedStatement.java:144)

而从前一篇使用 SQL Server 的 uniqueidentifier 字段类型 看到的是 SQL Server 用 JDBC 操作时是可以把  uniqueidentifier 字段当作 VARCHAR 类型来对待,这与 PostgreSQL 的 uuid 字段类型是不同的。

JDBC 插入 PostgreSQL 的 uuid 字段还有一种比之 setObject(1, uuid) 更烦琐的操作

在 PostgreSQL 的 PreparedStatement 的实现类 PgPreparedStatement (该类的可见度为默认,非 public) 有一个私有方法

private void setUuid(int parameterIndex, UUID uuid) throws SQLException { ... }

该方法只被 setObject(...) 在判定字段类型为 uuid 后调用,基本确定 uuid 操作时最简单的方式还是用 setObject(...)

pstmt.setObject(index, UUID.randomUUID());
pstmt.setObject(index, UUID.fromString("<uuid-string>"));

由此想到另一个问题,查询 uuid 字段后如果 getObject(index) 得到的是什么类型了,由 setObject(index, value) 和 getObject(index) 这么一对反操作,你应该猜到了,getObject(index) 得到的是一个真真切切的 UUID 对象

这与 SQL Server 的又一个不同之处,SQL Server 的 uniqueidentifer 字段查询出来 getObject(index) 获得的也是一个字符串。

 


2019-05-16

使用 JdbcTemplate 操作 PostgreSQL 的 UUID 类型字段,需要把字符串转换回 UUID 类型

不能直接用字符串形式的 UUID, 否则 JdbcTemplate 会尝试用 setString(index, uuid) 来设置参数。

本文链接 https://yanbin.blog/use-postgresql-uuid-field-data-type/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments