美文网首页
8.事务浅析

8.事务浅析

作者: 善良的良 | 来源:发表于2019-05-28 21:19 被阅读0次

    事务

    事务的正确执行使得数据库从一种状态转换为另一种状态

    事务的特性(ACID)

    A atomicity : 要么成功要么失败--undo,mvcc
    C consistency : 状态一致,数据完整性约束--对开发者的要求
    I isolation : 事务间相互隔离,不能影响--lock,undo,mvcc
    D durability : 事务正确提交,必须永久保留--redo,wal

    并发事务下的问题

    脏读:读未提交,数据不一样(update)
    不可重复读*:同一个事务读取到不同数据
    幻读:记录不一样(delete/insert)

    事务隔离级别

    隔离级别 脏读 不可重复读 幻读
    read uncommit
    read commit--pg默认
    repeatable read
    serialiable

    ----pg实现了三种,READ UNCOMMITTED和READ COMMITTED 一样

    pg中的事务控制

    • begin :开启一个事务
    • commit : 提交
    • rollback :回滚
    • psql : 缺省autocommit-- \set AUTOCOMMIT off 关闭
    • 默认autocommit

    MVCC

    Multi-Version Concurrency Control:多版本并发控制
    pg的实现方法:update/delete保留原有行,重新insert一条记录,旧的数据由vacuum做清理

    事务号TXID

    • 每当事务开启时,事务管理器都会分配一个唯一的标识符,称为事务ID(TXID)
    • txid 32位无符号整数,最大2^32
    • 事务启动会执行内置txid_current(),返回当前txid
    • txid_current() 获取当前事务ID,当前无事务,分配一个
    • txid_current_if_assigned() 同上,当前无事务,返回null

    事务的相关信息

    存在于tuple head

    • xmin :插入该行版本的事务ID
    • xmax:删除此行的事务ID(delete/update),查询出来>0,说明未commit or rollback
    • cmin:insert,该事务中dml的序列,从0开始
    • cmax:update/delete,该事务中dml的序列,从0开始
    • ctid:行版本在其表中物理位置,类似于oracle rowid(),update和vacuum full会被改变

    事务实现

    每行有xmin和xmax两个字段

    • insert:xmin为当前事务ID,xmax为0
    • update:实际上insert一个新行,同上。同时,旧行的xmax置为当前事务ID
    • delete:将当前行的xmax设置为当前事务ID
      读到一行时,查询xmin和xmax对应的事务状态:committed、aborted、in progress,判断次行对当前行是否可见

    事务ID的增长

    • 1.不会无限增长,最大2^32
    • 2.txid到最大值,又会从最小值3开始
      • 0:InvalidXID,无效事务ID
      • 1:BootstrapXID,表示系统表初始化时的事务ID,比任何普通的事务ID都旧
      • 2:FrozenXID,冻结的事务ID,比任何普通事务ID都旧
    • 3.同一个数据库中,存在的最旧和最新两个事务之间的年龄允许最大为2^31
    • pg的事务号最多只占2^32 序号中的一半
    • pg定期清理数据文件中过老的事务ID,使他们比所有普通事务ID都旧

    事务可见性判定

    • 1.普通事务的比较方法
      ((int32)(id1 - id2)) < 0
      表达式为真,则id1比id2旧,为假则id1比id2新
    最大事务ID为2^32 ,最小事务id为2^31 +1
    2^32 - (2^31+2) = 2147483646
    二进制
    111 1111 1111 1111 1111 1111 1111 1110 > 0
    
    最大事务ID为2^32,此时再来一个新事务,回卷之后为3
    2^32 - 3 = 4294967293
    二进制
    1111   1111  1111  1111  1111  1111  1111 1101 < 0
    
    • 2.BootstrapXID比所有其他事务都旧,包括FrozenXID
    • 3.FrozenXID比普通事务旧
    • 4.数据中的每个sql都会有自己的事务号,这个事务号会记入SnapshotData,通过快照中的txid和tuple中的xmin和xmax对比,判断出当前行对当前事务是否可见.

    事务快照相关函数

    txid_current_snapshot() 获取当前快照
    txid_snapshot_xip(txid_snapshot) 获取在快照中进行中的事务ID
    txid_snapshot_xmax(txid_snapshot) 获取快照的 xmax
    txid_snapshot_xmin(txid_snapshot) 获取快照的xmin
    txid_visible_in_snapshot(bigint,txid_current_snapshot) 在快照中事务ID是否可见(不使用子事务ID)
    txid_status(bigint) 获取当前事务的状态,committed、aborted、in progress 或者如果事务ID太老,则是null

    获取当前快照

    txid_current_snapshot()
    格式xmin:xmax:xip_list

    • xmin:最早仍活跃的事务ID(以下简称XID),早于此XID的事务要么被提交并可见,要么回滚要么丢弃。
    • xmax:最后已完结事务(COMMITTED/ABORTED)的事务ID + 1。
    • xip_list:在”拍摄”快照时仍进行中的事务ID。该列表包含xmin和xmax之间的活动事务ID。

    总结一下,简单来说,对于给定的XID:
    XID ∈ [1,xmin),过去的事务,对此快照均可见;
    XID ∈ [xmin,xmax),不考虑子事务的情况,仍处于IN_PROGRESS状态的,不可见;COMMITED状态,可见;ABORTED状态,不可见;
    XID ∈ [xmax,∞),未来的事务,对此快照均不可见;

    --session 1
    testdb=# begin;
    BEGIN
    testdb=# select txid_current();
     txid_current
    --------------
             1303
    testdb=# select txid_current_snapshot();
     txid_current_snapshot
    -----------------------
     1303:1303:
    
    --session 2
    testdb=# begin;
    BEGIN
    testdb=# select txid_current();
     txid_current
    --------------
             1304
    
    --session 3
    testdb=# begin;
    BEGIN
    testdb=# select txid_current();
     txid_current
    --------------
             1305
             
    --session 4
    testdb=# begin;
    BEGIN
    testdb=# select txid_current();
     txid_current
    --------------
             1306
    
    --session 1
    testdb=# select txid_current_snapshot();
     txid_current_snapshot
    -----------------------
     1303:1303:
     
    --session 4
    testdb=# rollback;
    ROLLBACK
    
    --session 1
    testdb=# select txid_current_snapshot();
     txid_current_snapshot
    -----------------------
     1303:1307:1304,1305
    
    --session 3
    testdb=# rollback;
    ROLLBACK
    
    --session 1
    testdb=# select txid_current_snapshot();
     txid_current_snapshot
    -----------------------
     1303:1307:1304
    

    相关文章

      网友评论

          本文标题:8.事务浅析

          本文链接:https://www.haomeiwen.com/subject/oqlnzqtx.html