使用 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) 获得的也是一个字符串。

类别: Database. 标签: . 阅读(31). 订阅评论. TrackBack.

Leave a Reply

avatar