开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群(共1100人左右 1 + 2 + 3)新人会进入3群
关于Prepare 提交事务的方式问题,有两个阵营,如爱之人,爱如子嗣拥入怀中,不爱之人,如弃置水中随波逐流。那么到底prepare事务的提交方式,到底应该不应该用,怎么用是一个开发应该知晓的问题,同时由于开发使用了prepare 提交事务,造成的问题,DBA 也应该知道如何处理。
先说第一个阵营,使用perpare的开发组,perpare 本身是一个预处理的事务的语句,将执行的语句的执行计划等内容进行固化到系统内
prepared transaction是独立于会话、抗崩溃、状态维护的事务。事务的状态存储在磁盘上,这使得数据库服务器即使在从崩溃中重新启动后也可以恢复事务。在对prepared transaction执行回滚或提交操作之前,将一直维护该事务,这个是官方的解释,也就是prepare 操作后,事务已经和数据库服务绑定。
在用户调用prepare transaction语句的情况下,会触发一个两阶段提交的工作,PG调用PrepareTransactionBlock函数,在这个函数中将perpare声明的事务状态进行TBLOCK_PREPARE ,相关的函数会开始在共享内存建立一个全局事务,同时会将事务的资源信息写入磁盘,这个事务和当前的backend接触绑定,无论当前推出会话,还是重启PG,Prepare 事务会一直存在,不会释放。
使用prepare transaction的优点是,在事务commit 前,数据库已经接受了事务。同时相关执行命令的方式也有所不同,在提交的情况下,采用SQL接口中,包含了
prepare transaction 'gid'
commit prepared 'gid'
rollback prepared 'gid'
上图为在进行事务工作中,产生的问题,prepare transaction 无法进行工作,主要在于默认POSTGRESQL 是关闭prepare transaction的功能。
提到这里,根据官方的文档,针对prepare transaction 信息有这样一段话。
让事务长时间处于准备状态是不明智的。这将干扰VACUUM回收存储的能力,并且在极端情况下可能导致数据库关闭以防止事务ID封装(参见第25.1.5节)。还要记住,事务将继续持有它所持有的锁。该特性的预期用途是,一旦外部事务管理器验证了其他数据库也准备好了提交,通常就会提交或回滚准备好的事务。
如果您没有设置外部事务管理器来跟踪准备好的事务并确保它们及时关闭,那么最好通过将max_prepared_transactions设置为零来禁用准备好的事务特性。这将防止意外创建准备好的事务,这些事务可能会被遗忘并最终导致问题。
实际中prepare transaction本身并不是为应用服务处理所工作的,他工作的目标是真对多个POSTGRESQL在共同完成一个事务的基础上而形成的,类似与MYSQL XA 事务。
那么如果我们使用了prepare transaction会产生那些风险的问题
1 客户端销售,掌握prepare的客户端不在掌握这个功能的情况下,事务会持续HOLD在数据库服务器上,处于失控的状态,我们称之为孤儿事务。
而持续情况下,VACUUM 将对相关的事务掌握的表失去控制,导致数据库事务号无法回收,数据表死元组无法回收等问题。所以我们应该持续,在开启了prepare 事务的数据库中,检索当前是否有长期没有commit 的 prepared 事务。
select * from pg_prepared_xacts;
而在处理丢失了控制的情况下,DB 需要对于这些已经失去管理的事务,进行commit 或rollback.
更多针对两阶段事务的讨论可以参见
https://cn.greenplum.org/greenplum_distributed_transaction/