博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一张表有且只有一条记录(续) - 支持插入,并且查询、更新、删除只作用在最后一条记录上...
阅读量:7226 次
发布时间:2019-06-29

本文共 6673 字,大约阅读时间需要 22 分钟。

标签

PostgreSQL , 有且只有一条记录


背景

之前写过一篇文档,介绍如何控制某张表有且只有一条记录。

接下来这个需求与之类似,一张表好像有且只有一条记录,要求这样:

1、支持插入、更新、删除、查询操作,

2、有一个时间字段用来区分这条记录是什么时候插入、更新的。

3、更新只作用在最后一条记录(时间最大的那条)上,

4、查询只返回时间最大的一条记录。所以看起来就只有一条记录一样。(实际上如果插入了很多,那么就是很多条)

5、删除时,删除所有记录。

实现方法

建立2张表,一张视图,面向用户的是视图(所有的增删改查都基于视图,所以用户可以忘记基表和影子表)。

1、基表

create table base_tbl (    id serial8 primary key,  -- 必须有一个PK    info text,    --  用户自身需求的内容    c1 int,       --  用户自身需求的内容    c2 int,       --  用户自身需求的内容    ts timestamp  --  时间(更新、插入时务必更新这个时间)  );    create index idx_base_tbl on base_tbl (ts);

2、影子表(用于触发器),如果没有影子表,直接对基表建立触发器,会有锁错误。

create table shadow_base_tbl ();

3、基表的limit 1视图

create view tbl as select * from base_tbl order by ts desc limit 1;

创建规则和触发器,实现前面提到的需求。

1、视图insert, update, delete规则

create rule r1 AS ON INSERT TO tbl DO INSTEAD INSERT INTO base_tbl (info, c1, c2, ts) VALUES (new.info, new.c1, new.c2, clock_timestamp());  create rule r2 AS ON UPDATE TO tbl DO INSTEAD UPDATE base_tbl SET info = new.info, c1=new.c1, c2=new.c2, ts=clock_timestamp() WHERE base_tbl.id=old.id;  create rule r3 AS ON DELETE TO tbl DO INSTEAD DELETE FROM shadow_base_tbl;

2、影子表delete触发器

create or replace function tg_truncate_v() returns trigger as $$  declare  begin    truncate base_tbl;    return null;  end;  $$ language plpgsql strict;    create trigger tg before delete on shadow_base_tbl for each statement execute procedure tg_truncate_v();

结构定义如下

postgres=# \d+ tbl                                         View "public.tbl"   Column |            Type             | Collation | Nullable | Default | Storage  | Description   --------+-----------------------------+-----------+----------+---------+----------+-------------   id     | bigint                      |           |          |         | plain    |    info   | text                        |           |          |         | extended |    c1     | integer                     |           |          |         | plain    |    c2     | integer                     |           |          |         | plain    |    ts     | timestamp without time zone |           |          |         | plain    |   View definition:   SELECT base_tbl.id,      base_tbl.info,      base_tbl.c1,      base_tbl.c2,      base_tbl.ts     FROM base_tbl    ORDER BY base_tbl.ts DESC   LIMIT 1;  Rules:   r1 AS      ON INSERT TO tbl DO INSTEAD  INSERT INTO base_tbl (id, info, c1, c2, ts)    VALUES (new.id, new.info, new.c1, new.c2, clock_timestamp())   r2 AS      ON UPDATE TO tbl DO INSTEAD  UPDATE base_tbl SET info = new.info, c1 = new.c1, c2 = new.c2, ts = clock_timestamp()    WHERE base_tbl.id = old.id   r3 AS      ON DELETE TO tbl DO INSTEAD  DELETE FROM shadow_base_tbl    postgres=# \d+ base_tbl                                                            Table "public.base_tbl"   Column |            Type             | Collation | Nullable |               Default                | Storage  | Stats target | Description   --------+-----------------------------+-----------+----------+--------------------------------------+----------+--------------+-------------   id     | bigint                      |           | not null | nextval('base_tbl_id_seq'::regclass) | plain    |              |    info   | text                        |           |          |                                      | extended |              |    c1     | integer                     |           |          |                                      | plain    |              |    c2     | integer                     |           |          |                                      | plain    |              |    ts     | timestamp without time zone |           |          |                                      | plain    |              |   Indexes:      "base_tbl_pkey" PRIMARY KEY, btree (id)      "idx_base_tbl" btree (ts)    postgres=# \d+ shadow_base_tbl                               Table "public.shadow_base_tbl"   Column | Type | Collation | Nullable | Default | Storage | Stats target | Description   --------+------+-----------+----------+---------+---------+--------------+-------------  Triggers:      tg BEFORE DELETE ON shadow_base_tbl FOR EACH STATEMENT EXECUTE PROCEDURE tg_truncate_v()

测试tbl视图的dml如下

1、插入多次

postgres=# insert into tbl(info,c1,c2,ts) values ('test',1,2,now());  INSERT 0 1  postgres=# insert into tbl(info,c1,c2,ts) values ('test12',2,222,now());  INSERT 0 1  postgres=# insert into tbl(info,c1,c2,ts) values ('test12',2,222,now());  INSERT 0 1  postgres=# insert into tbl(info,c1,c2,ts) values ('test12',2,222,now());  INSERT 0 1    只显示最后一条记录的目的达到  postgres=# select * from tbl;   id |  info  | c1 | c2  |            ts               ----+--------+----+-----+---------------------------    4 | test12 |  2 | 222 | 2017-07-11 20:39:56.75285  (1 row)    查看基表,所有记录都在  postgres=# select * from base_tbl;   id |  info  | c1 | c2  |             ts               ----+--------+----+-----+----------------------------    1 | test   |  1 |   2 | 2017-07-11 20:39:49.933267    2 | test12 |  2 | 222 | 2017-07-11 20:39:54.939552    3 | test12 |  2 | 222 | 2017-07-11 20:39:56.406619    4 | test12 |  2 | 222 | 2017-07-11 20:39:56.75285  (4 rows)

2、查询

postgres=# select * from tbl;   id |  info  | c1 | c2  |            ts               ----+--------+----+-----+---------------------------    4 | test12 |  2 | 222 | 2017-07-11 20:39:56.75285  (1 row)

3、更新

只会更新最后一条     postgres=# update tbl set info='abcde';  UPDATE 1  postgres=# select * from base_tbl;   id |  info  | c1 | c2  |             ts               ----+--------+----+-----+----------------------------    1 | test   |  1 |   2 | 2017-07-11 20:39:49.933267    2 | test12 |  2 | 222 | 2017-07-11 20:39:54.939552    3 | test12 |  2 | 222 | 2017-07-11 20:39:56.406619    4 | abcde  |  2 | 222 | 2017-07-11 20:42:08.230306  (4 rows)    postgres=# select * from tbl;   id | info  | c1 | c2  |             ts               ----+-------+----+-----+----------------------------    4 | abcde |  2 | 222 | 2017-07-11 20:42:08.230306  (1 row)

4、删除

删除,触发truncate基表的动作    postgres=# delete from tbl;  DELETE 0  postgres=# select * from tbl;   id | info | c1 | c2 | ts   ----+------+----+----+----  (0 rows)    postgres=# select * from base_tbl;   id | info | c1 | c2 | ts   ----+------+----+----+----  (0 rows)

5、维护

实际上如果用户一直不调用delete,那么随着插入,基表会越来越大。

建议要经常维护基表(例如 锁住基表,把最后一条查出来,TRUNCATE 基表,然后把最后一条插进去)。

例子

begin;set lock_timeout ='1s';create LOCAL temp table tmp1 (like tbl) ;lock table base_tbl in ACCESS EXCLUSIVE mode;insert into tmp1 select * from tbl;truncate base_tbl;insert into tbl select * from tmp1;drop table tmp1;end;

注意

注意到,插入是不管你原来有没有记录的,并不是insert on conflict do update的做法。

所以插入的并发可以做到很高。

而更新,可能并发还是会较低,因为锁的是最后一条记录。记录成为锁热点并发就上不来。

转载地址:http://tfufm.baihongyu.com/

你可能感兴趣的文章
Xcode调试断点不停止解决方案!
查看>>
CentOS6.6+Puppet3.7.4分布式部署Nagios监控系统
查看>>
SQL Server 2008 存储结构之DCM、BCM
查看>>
asp.net2005里给控件重命名,提示“目录名无效”怎么解决
查看>>
Redis源码解析--Replication
查看>>
Java的多进程运行模式分析
查看>>
百度面试题:求绝对值最小的数
查看>>
敏捷个人手机应用:如何使用时中法目标
查看>>
Android 解决ListView 和 ScrollView 共存冲突的问题
查看>>
利用Power Designer反向数据库结构
查看>>
在ISA 2006企业版环境下配置存储服务器(CSS)
查看>>
使用Seam-gen生成基础项目骨架
查看>>
RHCE学习<13>RHCS集群(RHCS+GFS2+ISCSI)
查看>>
Java线程:线程私有变量
查看>>
[Web开发] Web 2.0 网站估价工具
查看>>
IE8 默认以Web Standards模式显示网页 全面遵循Web标准
查看>>
网站Web项目树形菜单的实现过程(ExtJS+SpringMVC+Spring+Hibernate+MySQL)
查看>>
深入浅出Attribute(中)——Attribute本质论
查看>>
Lync 小技巧-52-Lync 2013-不加域-客户端-2-导入-证书-信任链
查看>>
Drawable、Bitmap、Canvas和Paint的关系以及部分使用方法
查看>>