0、写在前面
要理解【分布式事务】,首先确认【分布式事务】相关问题,通过解决问题的角度,分析各种【分布式事务】模式,以及每个模式的优缺点和使用场景:
- 事务的作用是什么?
- 分布式事务的来源
- 常用的分布式事务模式有哪些?适用场景是哪些?各有什么优缺点?
- 开源的分布式事务处理中间件
1、事务的作用
数据库事务的ACID(原子性,一致性,隔离性,持久性),就是保住对数据的更新操作能完整和一致,保住数据修改的正确性。
2、什么是【分布式事务】?
来自维基百科的定义:en.wikipedia.org/wiki/Distri…
A distributed transaction is a database transaction in which two or more network hosts are involved.
分布式事务就是【涉及】【两个及以上】的网络主机的【数据库事务】。
本质上还是【数据库事务】。
3、【分布式事务】中的角色
来自维基百科的定义:
Usually, hosts provide transactional resources, while the transaction manager is responsible for creating and managing a global transaction that encompasses all operations against such resources.
通常,涉及的主机提供了【事务资源(transactional resources)】,而【事务管理器(transaction manager)】则负责创建和管理一个全局事务,涵盖了针对这些资源的所有操作。
分布式事务就是跨越(Span)多个数据库的事务处理。
按这个定义,参考下图,在分布式事务中存在两个角色:
- 一是【事务管理器(Transaction Manager)】,负责【创建】事务,【管理】参与事务处理的所有资源;
- 另外就是【事务资源(Transaction Resources)】,资源是参与事务的数据库和数据;
4、【分布式事务】的挑战
【分布式事务】如同其他事务一样,都需要保证【ACID】这四个特性,而ACID的特性只能在一个数据库实例上得到保证。
【分布式事务】中涉及的参与者都在不同网络中,【分布式的一致性】需要通过【网络通信】保证,但是【网络通信】不可避免出现 失败、超时 等情况,因此【分布式事务】实现比本地事务面临更多困难。
一个叫【X/Open】的组织,就提出了【X/OPEN XA】的【分布式事务处理】标准。参考维基百科:en.wikipedia.org/wiki/X/Open…,而【XA标准】是基于两阶段提交(tow-phase commit)协议来保证事务的提交和回滚。
5、分布式一致性的算法和协议
- 两阶段提交
- 三阶段提交
- Paxos算法
- Raft算法
- 针对Zookeeper的ZAB协议
具体可以参考:分布式一致性算法和协议总结
6、【分布式事务】的场景
分布式事务主要有以下三种常见:
- 【跨数据库】分布式事务;
- 【跨服务】分布式事务;
- 【混合】分布式事务;
7、解决分布式事务的主要模式
- XA Specification;
- TCC模式;
- SAGA模式;
- 本地消息事务;
- 基于【事务消息】的方案;
- 最大努力通知;
8、XA Specification
来自维基百科的定义:en.wikipedia.org/wiki/X/Open…
In computing, the X/Open XA standard (short for "eXtended Architecture") is a specification released in 1991[1] by X/Open (which later merged with The Open Group) for distributed transaction processing (DTP).
XA规范是由X/Open这个组织在 在1991年发布的 【分布式事务处理(DTP】标准。
为了保证分布式全局事务的ACID,采用【两阶段协议】这种方式保证所有事务的变更,要么全部提交(Commit),要么全部回滚(rollback)。
8-1、XA规范中的角色
- Resource Managers (RM): 资源管理器,提供数据资源操作、管理接口,保证数据的一致性和完整性,如 数据库管理系统、文件系统 或 MQ;
- Transaction Managers(TM):事务管理器,全局事务的协调者,负责协调跨事务管理的所有RM行为;
- Application Program (AP) :应用程序,按照业务规则调用 RM 接口完成对业务模型数据变更,当数据的变更涉及多个RM且要保证事务时,AP就会通过TM定义事务边界,TM负责协调【参与事务的RM】一同完成一个全局事务。
XA规范中,分布式事务时构建在RM本地事务(此时本地事务被看作事务分支)的基础上,TM负责协调这些分支【提交】或者【回滚】。
关于XA的分布式事务处理(Distributed Transaction Processing)
在XA规范中,【分布式事务处理】必须满足以下几点:
- 系统必须具有一种【引用事务】的方式,该事务包含了系统中任何地方完成的所有工作;
- 提交或回滚事务的决定必须考虑代表事务在任何地方完成的工作的状态,该决定必须在整个DTP系统中具有统一的效果。
8-2、XA规范-两阶段提交协议
XA规范把【分布式事务处理】分为两阶段,是一种【两阶段提交协议(Two-phase Commit)】:
1、阶段一:准备阶段(Prepare)
这个阶段的操作分为以下步骤:
- TM记录事务开始日志,并询问各个RM是否可以执行提交准备操作;
- RM收到指令后,评估自己的状态,尝试执行本地事务的预备操作,如:预留资源,为资源加锁、执行操作等,但是并不提交事务;(以MySQL为例,这个阶段会完成资源加锁,以及 redo log 和 undo log 的写入);
- RM将准备操作的结果反馈给TM,如果操作成功,则反馈给TM事务可以处理,如果失败,则告知TM本阶段失败,然后不再参与本次事务;
- TM收集RM的响应,记录【事务准备完成】日志;
2、阶段二:提交(Commit) / 回滚(Rollback)阶段
这个阶段根据【Prepare】返回的结果发起提交或回滚操作,又分为两种情况:
2-1、事务提交(Commit)
Prepare阶段所有RM都返回执行成功,则按以下步骤进行操作:
- TM记录Commit日志,并向所有RM发起【事务提交命令】;
- RM收到命令后,提交事务,释放资源,并向TM响应【提交完成】;
- TM收到所有RM响应,记录【事务结束日志】;
2-2、事务回滚(Rollback)
如果有RM在【Prepare阶段】返回执行失败或者超时没有应答,则TM按照执行失败处理,进行回滚操作:
- TM记录abort日志,向所有RM发送事务回滚指令;
- RM收到指令后,回滚事务,释放资源,并向TM响应回滚完成;
- TM收到所有RM响应,记录事务结束日志;
8-3、XA规范的优化
XA规范还定义一些优化措施:
- 如果TM发现整个事务只涉及到一个RM,那么就将整个过程改为一阶段提交;
- 如果RM收到AP的数据操作为【只读】,在【Prepare阶段】完成事务,并告知TM不在参与【二阶段】过程,会有【脏读】风险;
- 如果RM在【Prepare阶段】完成后,长时间等不到TM发出的【提交/回滚指令】,则【自动提交或者回滚】本地事务,这被称作 Heuristic Completion。这种场景会破坏【事务的一致性】;
8-4、XA规范流程
XA规范中详细定义各个核心组件之间的交互接口,以TM和RM交互接口为例,一次完整的全局事务,TM 和 RM 之间的交互比较麻烦,如下图所示:
8-5、XA规范中的异常处理
事务执行过程中,可能发生宕机和网络超时,针对这些异常,不同XA规范的实现,对异常处理可能不同,参考如下:
1、在【Prepare阶段】的异常处理
- TM在询问RM【前】宕机,恢复后无需做任何操作;
- TM在询问RM【后】宕机,可能只有部分RM收到【Prepare请求】,因此需要向RM发起回滚请求;
- TM在询问RM,并收到响应,在准备完成日志时宕机,因为不知道宕机前的事务协商结果,因此恢复后,需要向RM发起回滚请求;
- TM在完成事务日志后宕机,还没有给RM发送提交/回滚指令,恢复后根据日志发起提交/回滚;
- 当RM响应超时,TM按失败处理,向所有RM发送回滚指令;
2、在【提交/回滚阶段】的异常处理
- TM在记录【commit/abort】日志【前】宕机,恢复后根据日志发起 提交或回滚 指令;
- TM在记录【事务结束】日志【前】宕机,恢复后根据日志发起 提交或回滚 指令;
- TM在记录【事务结束】日志【后】宕机,无需做任何操作;
- RM发生超时,TM需要对超时的RM持续重复发送指令。
8-6、XA规范实现ACID分析
- 原子性:在【Prepare】和【Commit】阶段保证事务原子性;
- 一致性:XA协议实现的【强一致性】;
- 隔离性:XA事务在完成之前一致持有资源的锁,可以做到【写隔离】;
- 持久性:基于本地事务实现;
8-7、XA规范的应用
- 主流的数据库如 Oracle、MySQL、SQLServer等都支持XA规范;
- J2EE中的JTA规范参考XA规范编写;
8-8、XA规范的优缺点
1、优点
对业务的侵入较低;
2、缺点
- 如果出现同步阻塞时间长:因为在全局事务执行过程中,RM一直持有资源锁,如果参与的RM过多,网络通信次数和时间会增加,阻塞时间变长,系统吞吐量变差,性能降低,事务出现死锁的概率增高,并不适合【微服务架构】场景中【跨服务的分布式事务】模式。
- TM单点故障:因为TM是单点,存在单点故障风险,如果在【Prepare阶段】TM宕机,会导致参与的RM收不到指令,从而长期持有资源的锁,导致系统吞吐量降低。
- 过于繁琐:参考上面的AP、TM、RM交互,完成一次事务需要TM到RM之间多达8次的交互;
- 脑裂:在【阶段二】时,TM通知RM提交事务,当出现 提交部分 TM宕机,或者部分RM宕机,或者TM发出提交,但是因为网络原因,部分RM没收到请求,会导致 部分RM提交事务,而部分RM没有收到请求;
3、三阶段提交
针对XA两阶段提交,又提出了一个【三阶段提交】方案,主要是为了解决【单点故障】问题,并且在RM侧引入【超时机制】,避免资源长时间锁定,但是仍然无法解决【脑裂】问题。
9、TCC模式
TCC(Try-Confirm-Cancel)是一种【补偿型】事务,该模式要求参与分布式事务的每个应用都要提供 try、confirm、cancel 三个接口,它的核心思想是:
通过对资源的预留(提供中间态),尽早释放对资源的加锁,如事务可以提交,则完成对预留资源的确认,如果事务要回滚,则释放预留的资源;
TCC也是一种【两阶段提交】协议。
9-1、TCC事务的两阶段
1、阶段一
完成业务检查(一致性)、预留业务资源(准隔离性),即【Try】操作;
2、阶段二
如果【阶段一】中所有业务资源都预留成功,则执行【Confirm】操作,否则执行【Cancel】操作:
- Confirm:不做任何业务检查,仅适用预留的资源执行业务操作,如果失败会一直重试;
- Cancel:取消执行业务操作,释放预留的资源,如果失败会一直重试;
9-2、TCC实现细节
TCC模式中,事务的【发起者】和【参与者】都需要记录事务日志:
- 事务的发起者,需要记录全局事务和各个分支事务的状态和信息;
- 事务的参与者,需要记录分支事务的状态;
这样做,可以保证事务的一致性。在TCC事务执行过程中,可能发生 宕机、重启、网络中断 等异常情况,此时事务处于【非原子】状态和【非最终一致】状态,需要根据【事务发起者的日志】和【参与者的日志】,去完成剩余的提交或者回滚,使整个【分布式事务】内所有参与者达到【最终一致】的状态,实现事务的原子性。
9-3、TCC对于ACID的支持
- 原子性:事务发起方协调各个分支事务全部提交或者全部回滚;
- 一致性:TCC提供【最终一致性】;
- 隔离性:通过【Try】预分配资源的方式,来实现数据的隔离;
- 持久性:由各个分支事务实现;
9-4、TCC的异常策略
针对网络通信失败和超时等异常情况,TCC要求业务方在实现时遵循以下策略:
- 允许空回滚:当异常在【阶段一】发生时,【参与方】没有收到【Try】请求但要执行【Cancel】操作,当【Try失败】或者【没有执行Try操作】的参与方,收到【Cancel请求】,需要进行空回滚操作;
- 保持幂等性:在【阶段二】网络出现超时,事务【发起方】会重复调用【参与方】的 Confirm/Cancel 方法,因此这两个方法实现上必须保证幂等性;
- 防止资源悬挂:网络异常,导致两个阶段无法保证【严格顺序执行】,出现【Try请求】比【Cancel请求】更晚到达的情况,【Cancel】会执行空回滚而确保事务正确性,此时【Try方法】不能再被执行;
9-5、TCC的优缺点
1、优点
- 保证一致性,通过在【事务发起方】和【事务参与方】记录事务日志,保证事务的一致性(最终一致性),不会出现脑裂;
- 提高吞吐量,因为TCC事务将分布式事务从资源层提到业务层来实现,可以让业务灵活选择资源的锁定粒度,全局事务处理【不会一直持有锁】;
2、缺点
对业务侵入较大,因为参与方要实现 Try、Confirm、Cancel三个接口;
开发成本高,将功能实现由一个接口变为三个;
10、Saga模式--最适合微服务架构的分布式模式
Saga 和 TCC 一样,也是一种【补偿】事务,但是没有Try阶段,而是把【分布式事务】看作一组本地事务构成的【事务链】。
事务链中的每一个正向事务操作,都对应一个可逆的事务操作。Saga事务协调器负责按照【顺序执行】事务链中的【分支事务】,【分支事务】执行完毕,即释放资源。如果某个分支事务失败了,则按照【反方向】执行事务补偿操作。
假如一个Saga的【分布式事务链】有n个分支事务构成,[T1, T2, ..., Tn],那么该分布式事务的执行有三种情况:
- T1, T2, ..., Tn : n个事务全部执行成功;
- T1, T2, ..., Ti, Ci..., C2, C1 : 执行到 第i ( i <= n) 个事务时失败了,则按照 【i -> 1】的顺序依次调用补偿操作。如果补偿操作失败,就一直操作。这个类似于回滚,这些操作如果没有依赖,可以优化为并行执行;
- T1, T2, ..., Ti(失败), Ti(重试), Ti(重试), ..., Tn:适用于【事务必须成功】的场景,如果发生失败就一直重试,不会执行补偿操作。
10-1、适用场景
Saga一般使用于【流程比较长】的业务场景,包括 旅行的机票或酒店预订,或者 金融借贷场景;
例如:
旅游订票或订酒店,比如 按顺序去 A, B, C 三个地方,并且要在当地住宿,则需要预订 :
起点 --> A,A --> B,B --> C 的车票或机票,以及在 A,B,C三个地方的酒店,先预订
【A --> B --> C】的机票,在预订【A --> B --> C】的酒店,当预订C地的酒店时失败,可以按照【C --> B --> A】的顺序回滚;
10-2、Saga对ACID的支持
Saga可以保证事务的 原子性、一致性 和 持久性,但是【不保证隔离性】 ,因为本地事务提交后,对其他事务就可见了;
原子性:Saga协调器可以协调【事务链】中的本地事务,要么全部成功,要么全部回滚;
一致性:Saga事务可以实现【最终一致性】;
持久性:基于本地事务;
10-3、Saga的异常处理策略
- 允许空补偿:网络异常导致事务的参与方只收到【补偿操作指令】,因为没有执行过正常操作,因此要进行空补偿;
- 保持幂等性:事务的【正向操作】和【补偿操作】都可能被重复触发,因此要保证操作的幂等性;
- 防止资源悬挂:网络异常导致事务的【正向操作指令】晚于【补偿操作指令】到达,则要丢弃本次正常操作,否则会出现【资源悬挂】问题;
10-4、Saga与TCC比较
虽然Saga与TCC都是【补偿事务】,但是由于提交阶段不同,两者也是有不同的:
- Saga是不完美补偿,补偿操作会留下之前原始事务操作的痕迹,需要考虑对业务上的影响;
- TCC是完美补偿,补偿操作会彻底清理之前的原始事务操作,用户是感知不到事务取消之前的状态信息;
- TCC事务可以更好的支持异步化,但是Saga模式一般在补偿阶段比较适合异步化;
10-5、Saga的优缺点
1、优点
- 适合业务流程长的场景;
- 实现上对业务侵入低;
- 系统性能和吞吐量高,Saga采用【一阶段提交】模式,不会对资源长时间加锁;
基于以上三个优点,再比较TCC或者XA模式,TCC模式对业务侵入较高,而XA模式的同步阻塞(持有锁和资源)的时间较长,不适合当下微服务框架,所以Saga模式是_非常适合【微服务架构】的场景;_
10-6、支持Saga开源的框架
- 阿里巴巴的Seata项目
- 华为的ServiceComb项目
11、【基于消息】的分布式事务
【基于消息】的分布式事务模式,核心思想是:通过消息系统来通知其他事务参与方处理事务的执行状态。
消息系统的引入更有效将事务参与方【解耦】,各个参与方可以【异步执行】。
该模式的难点在于解决本地事务执行和消息发送的一致性:两者要同时执行成功或者同时取消执行。
实现上主要有两种方式:
- 基于【事务消息】的方案;
- 基于【本地消息】的方案;
11-1、基于【事务消息】的分布式事务
普通消息无法解决【本地事务执行】和【消息发送】的一致性问题。因为消息发送是一个网络通信过程,发送消息的过程就有可能出现【发送失败】或【超时】的情况。【超时】有可能发送成功,有可能发送失败,消息的发送方 无法确定,此时消息发送方无论是提交事务,还是回滚事务,都有可能出现不一致性。
解决这个问题,需要引入【事务消息】,【事务消息】和【普通消息】的区别在于【事务消息】发送成功后,处于prepare状态,不能被订阅者消费,等到事务消息的状态改为可消费状态后,下游订阅者才能监听到消息。
【本地事务】和【事务消息】的发送处理流程如下:
-
事务发起者预先发送一个【事务消息】;
-
MQ系统受到【事务消息】后,将消息持久化,消息的状态是【待发送】,并给发送者一个ACK消息;
-
事务发起者如果没有收到ACK消息,则取消本地事务执行;如果收到了ACK消息,则执行【本地事务】,并给MQ系统再发送一个消息,通知【本地事务】执行情况;
-
MQ系统收到消息通知后,根据【本地事务】的执行情况更改【事务消息】的状态,如果事务成功执行,则将消息改为【可消费】并下发给订阅者;如果事务执行失败,则删除该【事务消息】;
-
如果【事务消息】的状态是”可发送“,则MQ系统向下游参与者推送消息,推送失败会不停重试;
-
下游参与者收到消息后,执行【本地事务】,【本地事务】如果执行成功,则给MQ系统发生ACK消息;如果执行失败,则不发送ACK消息,MQ系统会持续推;
11-2、基于【事务消息】的异常处理
【本地事务】执行完毕后,发给MQ的通知消息可能丢失,所以支持【事务消息】的MQ系统会有一个【定时扫描】逻辑,扫描出状态仍然是【待发送】的消息,并向消息的发送方发起询问,询问这条【事务消息】的最终状态,并根据结果更新【事务消息】的状态。因此,事务的发起方需要给MQ系统提供一个【事务消息】状态查询接口;
11-3、基于【本地消息】的分布式事务
基于【事务消息】的模式对MQ系统要求较高,并不是所有MQ系统都支持【事务消息】,RocketMQ是目前为数不多的支持【事务消息】的MQ系统。
如果依赖的MQ系统【不支持事务消息】,可以采用【本地消息】的分布式模式。
这种模式的核心思想是:
- 事务的发起方维护一个【本地消息表】,业务执行和【本地消息表】的执行处在同一个【本地事务】中。
- 业务执行成功,则同时记录一条【待发送】状态的消息到【本地消息表】;
- 系统启动一个【定时任务】定时扫描【本地消息表】中状态为【待发送】的记录,并将其发送到MQ系统,如果发送失败或者超时,则一直发送,直到发送成功,从本地消息表删除该记录 OR 更新消息发送状态为【已发送】。
- 后续的消费订阅流程,则与事务消息的模式雷同。
11-4、基于【消息】分布式事务对ACID的支持
- 原子性:最终可以实现分支事务都执行或者都不执行;
- 一致性:提供最终一致性;
- 隔离性:不保障隔离性;
- 持久性:由本地事务来保证;
11-5、基于【消息】分布式事务的优缺点
1、优点
分布式系统之间【解耦】,各个事务参与方之间不再是同步调用;
2、缺点
- 对MQ系统要求较高;
- 对业务实现也有一定侵入性,要么提供【事务消息】状态查询,要么需要维护【本地消息表】;
- 原则上只接受下游分支事务的成功,不接受事务的回滚,如果失败就一直重试;
11-6、基于【消息】分布式事务的适用场景
对【最终一致性】敏感度较低的业务场景,例如跨企业的系统间调用;
12、【最大努力通知】的分布式事务
【最大努力通知】的分布式事务解决方案,也是基于MQ系统,但是不要求MQ消息可靠;
【最大努力通知】方案,本质上是通过引入【定期校验机制】,来对【最终一致性】做兜底;
优点:
- 对业务侵入较低;
- 对MQ系统要求较低;
- 实现简单;
适用场景:
适合对【最终一致性】敏感度比较低、【业务链路较短】的场景,如跨平台、跨企业的系统间业务交互;
13、分布式事务中间件--Seata
Seata : Simple Extensible Autonomous Transaction Architecture;
Seata支持TCC模式、Saga模式。但是Seata对TCC模式的支持提供一种对业务侵入为0的解决方案,这种方案叫做AT(Automatic Transaction)模式。
13-1、AT模式的运行机制
- 全局事务依然是基于各个分支事务来完成。Seata Server 协调各个分支事务要么一起提交,要么一起回滚;
- 各个【分支事务】在运行时,Seata Client 通过对 SQL执行的代理和拦截,通过解析SQL定位到行记录,记录下SQL执行前后的行数据快照【 beforeImage 和 afterImage】共同构成回滚日志,回滚日志记录在独立的表中。回滚日志的写入和业务数据的更改在【同一个本地事务】中提交;
- 【分支事务】完成后,立即是否对【本地资源】的锁,然后给Seata协调器【上报】事务执行结果;
- Seata协调器汇总各个分支事务的完成情况,生成事务提交或者回滚决议,将决议下发给 Seata Client;
- 如果决议是【提交事务】,则 Seata Client 异步清理回滚日志;如果决议是【回滚事务】,则 Seata Client 根据回滚日志进行补偿操作,补偿前会对比当前数据快照和afterImage是否一致,如果不一致则回滚失败,需要人工介入。
13-2、Seata的AT模式分析
- AT模式只支持基于ACID事务的关系型数据库;因为分支事务还是由各个【本地事务】自己完成;
- AT模式是通过对SQL解析完成,对SQL语法支持有限,使用复杂SQL时需要考虑兼容性;分析:需要额外的SQL解析操作;
- 不支持复合主键,业务表在设计时添加自增主键;
- 全局事务默认的隔离级别是【读未提交】;
- 通过 SELECT ... FOR UPDATE 实现【读已提交】的隔离级别;
- 通过全局排他写锁,可以做到隔离级别介于【读未提交】和【读已提交】之间。
14、总结
【分布式事务】因为有【跨数据库】、【跨服务数据】等场景,很难完全保证事务的ACID特性,并且如今的分布式系统,都要满足【高可用】和【高性能】这两个特性,因此【分布式事务】都采用【最终一致性】的解决方案。
一般把提供【强一致性】的事务称为【刚性事务】;把提供【最终一致性】的事务称为【柔性事务】。【刚性事务】完全满足ACID四个特性,【柔性事务】对事务的ACID支持情况如下:
- 原子性:完全支持;
- 一致性:提供【最终一致性】支持;
- 隔离性:不完全保证,通常为了系统吞吐和性能,会一定程度放弃对隔离性的要求;
- 持久性:完全支持;
【最终一致性】是一种特殊的一致性:系统能够保证在【没有其他更新操作】的情况下,数据最终一定能够达到一致的状态,所有客户端对系统的数据访问都能够获取到最新的值。在没有发生故障的前提下,数据达到一致状态的时间延迟,取决于网络延迟、系统负载和数据复制方案设计等因素。
【Base理论】是面向【大型高可用可扩展的分布式系统】,和传统事务的ACID特性相反,不同于ACID的【强一致性】,而是提出通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。
【最终一致性】不只是大型分布式系统才有的特性,传统的关系型数据库也采用最终一致性模式。在关系型数据库中,大多采用【同步和异步方式】来实现主备数据复制技术。
-
在同步方式中,数据的复制过程通常是更新事务的一部分,因此在事务完成后,主备数据库的数据就会达到一致;
-
在异步方式中,备库的更新往往存在延时,这取决于事务日志在主备数据库之间传输的时间长短,如果传输时间过长或者甚至在传输过程中出现异常,导致无法及时将事务更新到备库,在备库读取的数据将是旧的,就出现了数据不一致的情况。通过多次重试或者人为数据订正,关系型数据库还是能保证最终数据达到一致。
在系统选择分布式事务方案时,可根据对【一致性】的要求进行选择;
若业务上游有【强一致性】要求的场景时,优先考虑XA规范的两阶段提交;
业务上只需要【最终一致性】的场景时,可以根据具体场景选择【柔性事务】方案;