本文档介绍了如何使用提交时间戳功能来跟踪对数据库记录进行更改的日期和时间。如果您的大型数据库的许多事务都会更改记录,并且您需要捕获对数据集所做的更改,您可以使用提交时间戳功能简化此任务。
通过一系列代码示例,本文档介绍了如何重写现有数据操纵语言 (DML),以创建更改日志。本文档使用 Java 和 JDBC 演示相关方法,扩展了使用 Cloud Spanner 提交时间戳来通过 Go 创建更改日志的内容。逻辑使用 SQL(而不是以 Spanner 客户端对象形式)表示。
表的工作原理
假设您有一个名为 msgs
的事实表和一个名为 msg_history
的记录表。每次修改事实表时,您都希望在 msg_history
表中并发保存一条记录。您可以稍后将记录表的内容用于其他用途,例如用于审核或用作事件来源。
msgs
表包含由事务 ID (id
) 和消息 (msg
) 表示的事实。您用于创建该表的数据定义语言 (DDL) 语句如下所示:
CREATE TABLE msgs (
id INT64,
msg STRING(MAX),
) PRIMARY KEY (id)
msg_history
表包含事务记录。以下 DDL 用于创建记录表。ts
列存储着提交时间戳。
CREATE TABLE msgs_history (
id INT64,
ts TIMESTAMP OPTIONS (allow_commit_timestamp=true),
previous_msg STRING(MAX)
) PRIMARY KEY (ts, id)
示例
向事实表写入内容时,您还必须在同一事务中向记录表写入同样的内容。Spanner 的 JDBC 驱动程序支持声明事务的开始和结束,这是一个标准 JDBC 操作。
第 1 步:重写 insert 操作
第一步是按如下形式重写 insert
操作:
insert into msgs (id, msg) values (1, 'a real msg')
更改插入内容,使其如下所示:
insert into msgs_history (id, previous_msg, ts) values (1, Null, PENDING_COMMIT_TIMESTAMP()); insert into msgs (id, msg) values (1, 'a real msg');
以下是 Java 代码:
// insert into history stmt.executeUpdate( "insert into msgs_history (id, previous_msg, ts)" + " values (1, Null, PENDING_COMMIT_TIMESTAMP())"); // insert into real table stmt.executeUpdate("insert into msgs (id, msg)" + " values (1, 'a real msg')"); conn.commit();
第 2 步:重写 update 操作
接下来,您可以按如下形式重写 update
操作:
update msgs set msg = 'new message' where id = 1
更改更新内容,使其如下所示:
insert msgs_history (id, previous_msg, ts) values ((select id from msgs where id =1 ), (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP()); update msgs set msg = 'new message' where id = 1;
以下是 Java 代码:
// insert into historystmt.executeUpdate( "insert msgs_history (id, previous_msg, ts)" + " values ((select id from msgs where id =1)," + " (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP())"); // update into fact table stmt.executeUpdate("update msgs set msg = 'new message' where id = 1"); conn.commit();
第 3 步:重写 delete 操作
最后,您可以按如下形式重写 delete
操作:
delete from msgs where id = 1
更改删除内容,使其如下所示:
insert msgs_history (id, previous_msg, ts) values ((select id from msgs where id =1 ), (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP()); delete from msgs where id = 1;
以下是 Java 代码:
// insert into history stmt.executeUpdate( "insert msgs_history (id, previous_msg, ts)" + " values ((select id from msgs where id =1)," + " (select msg from msgs where id = 1), PENDING_COMMIT_TIMESTAMP()) "); // delete from real table stmt.executeUpdate("delete from msgs where id = 1"); conn.commit();
使用记录表
使用如下命令访问更改历史记录:
select id,msg,current_timestamp() as ts from msgs where id = 1 union all select id,previous_msg, ts as msg from msgs_history where id = 1 order by ts desc
结果类似于以下内容:
id msg ts 1 new message 2020-02-07T07:44:10.24833726Z 1 a real msg 2020-01-14T10:07:20.137935Z 1 2020-01-14T10:07:20.070374Z
后续步骤
- 详细了解 Spanner 提交时间戳功能。
- 详细了解 Spanner 变更数据流。
- 探索有关 Google Cloud 的参考架构、图表和最佳实践。查看我们的 Cloud Architecture Center。