PostgreSQL数据库事务实现方法分析

本文实例讲述了PostgreSQL数据库事务实现方法。分享给大家供大家参考,具体如下:

事务简介

  • 事务管理器:有限状态机

    • 日志管理器

      • CLOG:事务的执行结果
      • XLOG:undo/redo日志
    • 锁管理器:实现并发控制,读阶段采用MVCC,写阶段采用锁控制实现不同的隔离级别

事务是所有数据库系统的一个基本概念。 一次事务的要点就是它把多个步骤捆绑成了一个单一的,不成功则成仁的操作。 其它并发的事务是看不到在这些步骤之间的中间状态的,并且如果发生了一些问题, 导致该事务无法完成,那么所有这些步骤都完全不会影响数据库。PostgreSQL为每条事务创建一个postgre进程,并发执行事务。采用分层的机制执行事务,上层事务块和底层事务。上层事务块是用户眼中的事务,用于控制事务执行的状态;底层事务是事务中的每条语句,可以改变上层事务块的状态。

上层事务块

每个postgre进程只有一个事务块,上层事务块记录着本次事务执行过程中的各个状态。

typedef enum TBlockState
{
  /* not-in-transaction-block states */
  TBLOCK_DEFAULT,       /* idle */
  TBLOCK_STARTED,       /* 执行简单查询事务 */
  /* transaction block states */
  TBLOCK_BEGIN,        /* 遇见事务开始BEGIN */
  TBLOCK_INPROGRESS,     /* 事务正在执行中 */
  TBLOCK_PARALLEL_INPROGRESS, /* live transaction inside parallel worker */
  TBLOCK_END,         /* 遇见事务结束COMMIT/END的时候设置 */
  TBLOCK_ABORT,        /* 事务出错,等待ROLLBACK */
  TBLOCK_ABORT_END,      /* 事务出错,收到ROLLBACK */
  TBLOCK_ABORT_PENDING,    /* 事务处理中,接收到ROLLBACK */
  TBLOCK_PREPARE,       /* 事务处理中,收到PREPARE(分布式事务) */
  /* subtransaction states */
  TBLOCK_SUBBEGIN,      /* starting a subtransaction */
  TBLOCK_SUBINPROGRESS,    /* live subtransaction */
  TBLOCK_SUBRELEASE,     /* RELEASE received */
  TBLOCK_SUBCOMMIT,      /* COMMIT received while TBLOCK_SUBINPROGRESS */
  TBLOCK_SUBABORT,      /* failed subxact, awaiting ROLLBACK */
  TBLOCK_SUBABORT_END,    /* failed subxact, ROLLBACK received */
  TBLOCK_SUBABORT_PENDING,  /* live subxact, ROLLBACK received */
  TBLOCK_SUBRESTART,     /* live subxact, ROLLBACK TO received */
  TBLOCK_SUBABORT_RESTART   /* failed subxact, ROLLBACK TO received */
} TBlockState;

常见的事务块状态转换图

  • startTransactionCommand:事务块中每条语句执行前都会调用。
  • commitTransactionCommand:事务块中每条语句执行结束都会调用
  • abortCurrentTransaction:事务块中语句执行错误,在调用点调用
  • BeginTransactionBlock:遇见BEGIN命令调用,状态变为TBLOCK_BEGIN
  • EndTransactionBlock:遇见END调用,可能成功提交,也可能回滚
  • AbortTransactionBlock:遇见ABORT指令调用

底层事务

底层事务是需要执行的每条命令,负责处理资源和锁的获取和释放,信号的处理,日志记录等等

typedef enum TransState
{
  TRANS_DEFAULT,       /* idle */
  TRANS_START,        /* transaction starting */
  TRANS_INPROGRESS,      /* inside a valid transaction */
  TRANS_COMMIT,        /* commit in progress */
  TRANS_ABORT,        /* abort in progress */
  TRANS_PREPARE        /* prepare in progress */
} TransState;

主要有四个函数:

  • StartTransaction:由BEGIN的startTransactionCommand调用,调用结束后事务块状态为TBLOCK_STARTED
  • CommitTransaction:由END的commitTransactionCommand调用,提交事务
  • AbortTransaction和CleanupTransaction:释放资源,恢复默认状态

分布式事务

PostgreSQL提供了分布式事务中的,两阶段提交的接口

并发控制

PostgreSQL采用MVCC的方式进行并发控制,每个事务看到的是一段时间前的数据快照。同时,MVCC并不能够解决所有问题,所以也提供了行级和表级的锁。

标准的事务隔离级别有4个,而PostgreSQL只实现了读已提交和可串行化。

PostgreSQL实现了8种锁(可怕)

太多了,就记住几个吧。

  • 行共享锁:select for update/for share
  • 表共享锁:select
  • 行排他锁:insert/update/delete
  • 表排他锁:drop

加锁的对象

    • 表锁
    • 会话锁
    • 扩展锁:新增表空间
  • 页:对索引页面
  • 元组:
  • 事务:

死锁处理

  • postgresql检测出最后一个等待的杀掉,oracle是第一个等待的杀掉
  • 死锁检测算法(等待图)

MVCC

关键词:

  • 基于事务ID
  • 行级多版本
  • 无回滚段,行内存储
    • 一次UPDATE,产生记录两个版本
    • 两个版本都存在页面内部
typedef struct HeapTupleFields
{
  TransactionId t_xmin;    /* Insert,Update事务 */
  TransactionId t_xmax;    /* Delete,Update,Row Locks事务ID */
  union
  {
    CommandId  t_cid;   /* 操作ID */
    TransactionId t_xvac;  /* old-style VACUUM FULL xact ID */
  }      t_field3;
} HeapTupleFields;

cmin:插入该元组的命令在插入事务中的命令标识(从0开始累加)
cmax:删除该元组的命令在插入事务中的命令标识(从0开始累加)
ctid:相当于rowid , <数据块ID,偏移量>
XID:事务ID
Xid_snapshot:当前系统中未提交的事务
CLOG:事务状态日志(已提交的日志)

隔离级别

  1. RC:读已提交

    1. 两个事务可以并发更新同一行
    2. 一个事务更新,一个事务删除同一行,删除操作会上锁
  2. RR:读未提交,其实是snapshot isolation,(冲突状态会回滚)
  3. 可串行化:serialize snapshot isolation,比标准可串行化要高,通过加内存中的意向锁实现,不允许预加锁的数据被其他事务变更

数据可见性判断

  1. 记录的头部XID信息比当前事务更早(rr和ssi有这个要求,read commited没有这个要求,读已经提交可以读未来的事务!!)
  2. 记录头部的XID信息不在当前的XID_snapshot中,(记录上的事务状态不是未提交的事务)
  3. 记录头部的XID信息在CLOG中代表已提交。
  • MVCC需要判断该行数据在这个事务中的有效性,可见性,可更新性(需要锁的帮助才能正确执行隔离级别)
  • 判断条件:若xmin等于当前事务ID,则包含所有xmax=0(未被删除)的元组。
    若与xmin相等的事务ID对应的事务已经被提交,则包含所有xmax=0或xmax为当前事务ID的元组。
  • 实现概要
    • 对读不用加锁,对写加锁(只阻塞写),事务结束对比是否冲突

多行数据需要过期版本回收

  1. 页面级:页面访问时回收
  2. 表级/系统级: autovacuum; vacuum

日志

  1. pg_log:数据库活动日志(也就是数据库的操作日志);
  2. pg_xlog:事务日志,记录事务的执行过程,redo日志
  3. pg_clog:事务状态日志(pg_clog是pg_xlog的辅助日志),记录事务的结果。

希望本文所述对大家PostgreSQL数据库程序设计有所帮助。

(0)

相关推荐

  • Mybatis调用PostgreSQL存储过程实现数组入参传递

    前言 项目中用到了Mybatis调用PostgreSQL存储过程(自定义函数)相关操作,由于PostgreSQL自带数组类型,所以有一个自定义函数的入参就是一个int数组,形如: 复制代码 代码如下: CREATE OR REPLACE FUNCTION "public"."func_arr_update"(ids _int4)... 如上所示,参数是一个int数组,Mybatis提供了对调用存储过程的支持,那么PostgreSQL独有的数组类型作为存储过程的参数又

  • PostgreSQL中调用存储过程并返回数据集实例

    这里用一个实例来演示PostgreSQL存储过程如何返回数据集. 1.首先准备数据表 复制代码 代码如下: //member_category create table member_category(id serial, name text, discount_rate real, base_integral integer); alter table member_category add primary key(id); alter table member_category add ch

  • 初识PostgreSQL存储过程

    什么是存储过程, 百度百科是这么定义的:存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,存储在数据库中经过第一次编译后再次调用不需要再次编译,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它.存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程. Postgresql的存储过程语法结构如下: 复制代码 代码如下: CREATE OR REPLACE FUNCTION 函数名(参数1,[整

  • 15个postgresql数据库实用命令分享

    最初是想找postgresql数据库占用空间命令发现的这篇blog,发现其中提供的几 条命令很有用(但也有几条感觉是充数的=.=),于是就把它翻译过来了.另外这篇文章是09年的,所以里面的内容可能有点过时,我收集了原文中有用的评论放在了最后面. 现在有不少开源软件都在使用postgreSQL作为它们的数据库系统.但公司可能不会招一些全职的postgreSQL DBA来维护它(piglei: 在国内基本也找不到).而会让一些比如说Oracle DBA.Linux系统管理员或者程序员去 维护.在这篇

  • PostgreSQL 安装和简单使用第1/2页

    据我了解国内四大国产数据库,其中三个都是基于PostgreSQL开发的.并且,因为许可证的灵活,任何人都可以以任何目的免费使用,修改,和分发 PostgreSQL,不管是私用,商用,还是学术研究使用.本文只是简单介绍一下postgresql的安装和简单的使用,语法方面涉及的比较少,以方便新手上路为目的. 1.系统环境和安装方法 : PostgreSQL的安装方法比较灵活,可以用源码包安装,也可以用您使用的发行版所带的软件包来安装,还可以采用在线安装-- 1.1 系统环境:Ubuntu Linux

  • PostgreSQL 创建表分区

    创建表分区步骤如下: 1. 创建主表 CREATE TABLE users ( uid int not null primary key, name varchar(20)); 2. 创建分区表(必须继承上面的主表) CREATE TABLE users_0 ( check (uid >= 0 and uid< 100) ) INHERITS (users); CREATE TABLE users_1 ( check (uid >= 100)) INHERITS (users); 3.

  • PostgreSQL数据库事务出现未知状态的处理方法

    背景 数据库的事务是原子操作,要么成功,要么失败.但是实际上在客户端的视角,可能有第三种状态:unknown状态. 当客户端提交事务结束(rollback , commit , prepare xact , rollback pxact , commit pxact)的请求后,数据库收到请求,数据库可能执行失败,也可能执行成功,不管怎样都要写对于的WAL日志,还有CLOG,然后数据库要将执行结果返回给客户端ACK. 这里存在几种可能,导致客户端不知道执行到底怎么样了? 收到客户端请求后,数据库没

  • PostgreSQL存储过程用法实战详解

    本文实例讲述了postgreSQL存储过程用法.分享给大家供大家参考,具体如下: 转了N多的SQL语句,可是自己用时,却到处是坑啊,啊,啊!!!!!!!!!!!!!!! 想写一个获取表中最新ID值. 上代码 CREATE TABLE department( ID INT PRIMARY KEY NOT NULL, d_code VARCHAR(50), d_name VARCHAR(50) NOT NULL, d_parentID INT NOT NULL DEFAULT 0 ); --inse

  • PostgreSQL新手入门教程

    自从MySQL被Oracle收购以后,PostgreSQL逐渐成为开源关系型数据库的首选. 本文介绍PostgreSQL的安装和基本用法,供初次使用者上手.以下内容基于Debian操作系统,其他操作系统实在没有精力兼顾,但是大部分内容应该普遍适用. 安装 1.首先,安装PostgreSQL客户端. sudo apt-get install postgresql-client 然后,安装PostgreSQL服务器. sudo apt-get install postgresql 2.正常情况下,安

  • PostgreSQL教程(十六):系统视图详解

    一.pg_tables: 该视图提供了对有关数据库中每个表的有用信息地访问. 名字 类型 引用 描述 schemaname name pg_namespace.nspname 包含表的模式名字. tablename name pg_class.relname 表的名字. tableowner name pg_authid.rolname 表的所有者的名字. tablespace name pg_tablespace.spcname 包含表的表空间名字(如果是数据库缺省,则为 NULL). has

  • Postgresql ALTER语句常用操作小结

    postgresql版本:psql (9.3.4) 1.增加一列 复制代码 代码如下: ALTER TABLE table_name ADD column_name datatype; 2.删除一列 复制代码 代码如下: ALTER TABLE table_name DROP  column_name; 3.更改列的数据类型 复制代码 代码如下: ALTER TABLE table_name ALTER  column_name TYPE datatype; 4.表的重命名 复制代码 代码如下:

随机推荐