从事物的四个基本特性开始谈起
事物的四个基本特性包括原子性、一致性、隔离性和持久性;
原子性是指事物中的所有指令要么全部执行成功,要么全部回滚,不能存在部分执行成功部分执行失败的情况;
一致性是指事物的执行要从一个一致性状态到另一个一致性的状态;
隔离性是指事物之间是相互隔离的,两个事物的执行不能相互受到影响;
持久性是指事物一旦执行成功就会永久的保存在数据库中,不会因为数据库的崩溃等原因造成数据丢失;
原子性:
postgres通过记录事物块的执行状态、记录日志保障事物的原子性;
每个postgres进程只有一个事物块,上层事物块记录着本次执行过程的各个状态。
顶层事务
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指令调用
在正常流程中事物块的状态从TBLOCK_DEFAULT------startTransactionCommand—>TBLOCK_STARTED-----BeginTransactionBlock---->TBLOCK_BEGIN-------commitTransactionCommand------>TBLOCK_INPROGRESS--------startTransactionCommand---------->TBLOCK_INPROGRESS------------commitTransactionCommand------->TBLOCK_INPROGRESS--------startTransactionCommand-------->TBLOCK_INPROGRESS------------EndTransactionBlock------->TBLOCK_END--------startTransactionCommand-------->TBLOCK_DEFAULT;
在事物块中执行出错会调用abortCurrentTransaction将事物块的状态设置成TBLOCK_ABORT再调用startTransactionCommand函数时状态会变成TBLOCK_ABORT_END;最后将事物块回滚并设置成TBLOCK_DEFAULT;
底层事务
底层事务是需要执行的每条命令,负责处理资源和锁的获取和释放,信号的处理,日志记录等等
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提供了分布式事务中的,两阶段提交的接口;
一致性
一致性是数据库执行要从一个一致性状态到另一个一致性的状态。一致性是数据库执行的最终目的,其他三个特性都是为一致性服务的,其他三个特性的实现都是为了实现一致性;
隔离性
隔离性即保证每一个事物能够看到的数据总是一致的,就好像其他并行事物并不存在一样,用术语来讲,就是多个事物并发后的执行状态和他们串行执行后的状态是等价的,实现隔离性是通过锁机制实现的。
锁机制
原则上有两种类型的锁,一种是悲观锁。一种是乐观锁;
悲观锁
悲观锁即当前事物的所有涉及对象加锁,操作完成后释放给其他对象使用。为了尽可能的提高性能,有各种粒度的锁(数据库级/表级/行级)各种性质的锁(共享锁、排他锁、共享意向锁、排他意向锁、共享排他意向锁)
乐观锁
即不同事物可以同时看到同一对象的不同版本,如果两个对象同时修改了同一行数据,那么较晚提交的事物会检测出冲突;冲突检测也有两种一种是通过日志UNDO的方式获取数据行的历史版本,一种是在内存中保存统一数据行的多个历史版本,通过时间戳来区分。
持久性
实现持久性关键有两点:一是尽快下盘,postgres是通过wal日志记录就是万一数据库挂了或者重启要从log里做redo。为了吞吐量管理员可以设置自动下盘时间每N个时间或每N个事物进行下盘。
第二点就是备份,可以将一个数据库设置多个副本,当一个数据库挂掉之后可以用副本恢复,
- [ todo] 如何实现备份待学习。