当前位置: 首页 > news >正文

河北省建设部网站郑州网站seo哪家公司好

河北省建设部网站,郑州网站seo哪家公司好,长沙微信网站开发,永久域名怎么注册Seata 基本信息 GitHub#xff1a;https://github.com/seata/seatastars: 20.6k 最新版本#xff1a; v1.6.1 Dec 22, 2022 官方文档#xff1a;http://seata.io/zh-cn/index.html 注意 官方仅仅支持同步调用。 官方在FAQ中表示对于异步框架需要自行支持。 具体的扩展思…Seata 基本信息 GitHubhttps://github.com/seata/seatastars: 20.6k 最新版本 v1.6.1 Dec 22, 2022 官方文档http://seata.io/zh-cn/index.html 注意 官方仅仅支持同步调用。 官方在FAQ中表示对于异步框架需要自行支持。 具体的扩展思路看查阅下文中的事务传播章节。 四种事务模式 阅读前置条件 需要理解XA规范 或者2PC提交流程。XA是一个规范2PC是这个规范的具体体现理念是一样的 概念 TC TM RM Seata TCC 模式 TCC即Try-Confirm-Cancel。针对每个操作都要编排一个与其对应的确认和补偿撤销操作。 TCC模式不依赖于底层数据资源的事务支持依靠开发者自己编排的Try-Confirm-Cancel逻辑来进行全局事务数据维护Seata仅用来用来管理全局事务统筹分支事务状态并决策执行Confirm Or Cancel针对已注册到TC的分支事务。 TCC的优势在于不会对资源有任何的锁定和占用性能较高。缺点是需要自行编排逻辑需要对业务流转比较清楚与业务的耦合性较高。 Seata的TCC如果使用Fence还是会有一定的资源占用 Seata通过方法级别的注解TwoPhaseBusinessAction来指定 Try-Confirm-Cancel。 TwoPhaseBusinessAction(name “beanName”, commitMethod “commit”, rollbackMethod “rollback”, useTCCFence true) 注解所在方法即为Try, commitMethod指定Confirm rollbackMethod指定Cancel。 name用来指定beanName即这些方法所在的bean。 如果希望通过Seata解决TCC的幂等空回滚悬挂等问题就设置useTCCFence为true同时需要建表tcc_fence_log。 useTCCFence默认为false即开发者自己通过逻辑编排解决幂等空回滚悬挂这些TCC的问题。 接下来看一下useTCCFence为true时Seata是如何解决这些问题的 幂等 在 commit/cancel 阶段因为 TC 没有收到分支事务的响应需要进行重试这就要分支事务支持幂等。 分支事务提交时如果useTCCFence为true则会走到TCCFenceHandler 类中的 commitFence 逻辑首先会判断 tcc_fence_log 表中是否已经有记录如果有记录则判断事务执行状态并返回。这样如果判断到事务的状态已经是 STATUS_COMMITTED就不会再次提交保证了幂等。如果 tcc_fence_log 表中没有记录则插入一条记录供后面重试时判断。 Rollback 的逻辑跟 commit 类似逻辑在类 TCCFenceHandler 的 rollbackFence 方法。 防空回滚 对于分布式事务来说在try阶段一般我们会调用多个服务。但是在全局事务回滚时并非一定是所有的分支事务都已进行了提交。若分支事务未提交就因为全局事务失败产生了回滚就会出现空回滚的情况 即回滚了一个未提交的分支事务。 如图账户服务的分支事务执行失败导致分布式事务回滚此时账户服务的Cannel依然会被执行就发生了空回滚现象。 面对这种情况Seata的处理策略是在try阶段往tcc_fence_log表里面插入一条数据status字段是STATUS_TRIED在Rollback阶段判断是否存在如果不存在则不执行回滚操作。 防悬挂 所谓的事务悬挂就是指因为某些原因分支事务在全局事务回滚之后提交。 如图分支事务的try阶段因为某些原因如网络阻塞阻塞阻塞过程中全局事务发生了回滚。回滚结束后分支事务被收到并执行此时就发生了事务悬挂。 对于事务悬挂Seata的TCC模式的处理策略是在Rollback时首先判断tcc_fence_log 中是否存在当前分支事务xid的记录如果不存在则插入一条记录状态是STATUS_SUSPENDED并且不再执行回滚操作。而分支事务的try的第一步也是向tcc_fence_log 表插入xid的记录这样若后面分支事务产生悬挂现象也会因为tcc_fence_log 表中已有xid的记录而造成主键冲突分支事务无法执行。从而避免了事务悬挂。 另外Rollback时对tcc_fence_log 的查询是select for update。 所以也就不会说出现并发的问题。 脏读与脏写 需要注意TCC除了幂等空回滚事务悬挂问题之外。不合理的业务编排还可能导致脏写和脏读的问题因为try执行完成后数据库事务已提交此时数据对于其它事务已处于可见状态。如果在业务编排时未考虑此场景就可能出现其它事务读取只进行了try而未Confirm的数据造成脏写或脏读。 因为在业务编排时我们一定要注意非特殊情况TCC修改的数据要在confirm阶段后才应该对其它业务可见在confirm之前数据应该处于数据库可见而业务不可见的状态。 SEATA Saga 模式 Seata XA 模式 使用事务资源对XA协议的支持以 XA 协议的机制来管理分支事务的一种 事务模式。 如图所示 执行阶段 可回滚业务 SQL 操作放在 XA 分支中进行由资源对 XA 协议的支持来保证 可回滚持久化XA 分支完成后执行 XA prepare同样由资源对 XA 协议的支持来保证 持久化即之后任何意外都不会造成无法回滚的情况 完成阶段 分支提交执行 XA 分支的 commit分支回滚执行 XA 分支的 rollback Seata XA 模式需要依赖于数据源的XA模式因此数据源需要是支持XA 事务的数据库。 简单的说XA模式在数据库事务启动时注册分支事务数据库事务执行完成后并不提交而是反馈给TC结果。TC根据分支事务的执行结果再通知分支事务(也就是数据库事务)提交或者回滚之后数据库事务才算真正的结束。 可以看到XA模式在全局事务执行期间需要一直保持数据库事务为已执行未提交状态需要长期占据RM已经数据库的本地锁即连接资源并发度必然会受到影响。好处是不会出现各种事务隔离问题。 鉴于此Seata提供了AT模式。 Seata AT 模式 脱胎于XA规范。两阶段提交 一阶段业务数据和回滚日志记录在同一个本地事务中提交释放本地锁和连接资源。二阶段 提交异步化非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。 如图AT模式下每一个分支事务操作时都先将其操作的目标数据查出来。并记录到undolog表中注意这个是自建的undolog表而不是mysql的undolog日志。并对目标数据加全局锁。如果二阶段全局事务提交则解开全局锁。如果二阶段全局事务回滚则从undolog表里面查出修改前的数据再进行目标数据更新操作以进行反向补偿。 这样做的好处是在一阶段就释放事务资源的资源无需长时间占据事务资源。缺点是需要进行对事务资源进行额外的数据资源操作需要额外的负载。 写隔离 AT 模式通过全局锁来实现写隔离 一阶段本地事务提交前(注意是提交前哦而不是事务开始时)需要确保先拿到 全局锁 。拿不到 全局锁 不能提交本地事务。拿 全局锁 的尝试被限制在一定范围内超出范围将放弃并回滚本地事务释放本地锁。 也就是说AT模式在提交之前都会对影响到的目标数据加一个全局锁如果锁成功则继续提交事务如果获取锁失败则需要等待全局锁。可以理解AT模式会对目标数据加一个分布式锁以此来保证同一数据同时只能有一个事务操作从而解决了脏写问题。 如果还不理解写隔离,下面以两个全局事务 tx1 和 tx2分别对 a 表的 m 字段进行更新操作,m 的初始值 1000为例 tx1 先开始开启本地事务拿到本地锁更新操作 m 1000 - 100 900。本地事务提交前先拿到该记录的 全局锁 本地提交释放本地锁。 tx2 后开始开启本地事务拿到本地锁更新操作 m 900 - 100 800。本地事务提交前尝试拿该记录的 全局锁 tx1 全局提交前该记录的全局锁被 tx1 持有tx2 需要重试等待 全局锁 。 tx1 二阶段全局提交释放 全局锁 。tx2 拿到 全局锁 提交本地事务。 如果 tx1 的二阶段全局回滚则 tx1 需要重新获取该数据的本地锁进行反向补偿的更新操作实现分支的回滚。 此时如果 tx2 仍在等待该数据的 全局锁同时持有本地锁则 tx1 的分支回滚会失败。分支的回滚会一直重试直到 tx2 的 全局锁 等锁超时放弃 全局锁 并回滚本地事务释放本地锁tx1 的分支回滚最终成功。 因为整个过程 全局锁 在 tx1 结束前一直是被 tx1 持有的所以不会发生 脏写 的问题。 读隔离 如果数据库默认的事务隔离级别是读已提交Read Committed或以上 那么Seata默认的分布式事务隔离级别是读未提交Read Uncommitted 。是无法避免脏读的。 因为AT模式在第一阶段是真真切切的提交了数据库事务的而全局事务仅仅读是不加全局锁的因此其它事务的读自然可以读到这个全局事务未提交数据库事务已提交的数据。 若流程需要全局事务是读已提交Read Committed 则需要使用select for update。 Seata会对加了select for update的读操作加全局锁直到获取成功才执行实际的查询。如图 Seata没有使用默认的全局事务RC模式也是出于性能考虑。 脏读和脏写 可以看到上文提到的通过select for update实现读写隔离仅仅是在两个全局事务之间如果一个流程是全局事务一个流程非全局事务。Seata就无法实现全局事务的读写隔离了。毕竟AT模式的一阶段完成数据库事务实际上是已经结束了数据已经处于可见状态。 但是有的事务确实就是一个简单的事务而全局事务相较于简单的数数据库事务要重的多。如果为了实现全局的读写隔离就都加入全局事务那性能必然会受更大的影响。因此Seata推出了GlobalLock注解。 GlobalLock简化了rpc过程使其做到更高的性能。当然select for update依然还是需要的。 更多的关于Seata事务隔离的信息可以见官方文档 Seata事务隔离 脏事务 需要注意的是如果一个表存在全局事务和非全局事务混用无论是逻辑更新还是说你直接用sql更新了数据就可能导致脏事务。Seata在事务失败回滚时会确认undolog中的镜像数据是否和当前表中的一致如果不一致内部会抛出一个SQLUndoDirtyException异常(内部异常不会抛到外部)并终止回滚流程源码见io.seata.rm.datasource.DataSourceManager。此时就形成了脏事务。 脏数据需手动处理根据日志提示修正数据或者将对应undo删除可自定义实现FailureHandler做邮件通知或其他。 Seata还支持关闭回滚时undo镜像校验当然该方案是很不推荐的。 防悬挂 事务悬挂定义在上文中的TCC模式中已经提过这里不再赘述。 AT模式下产生事务悬挂的场景是分支事务a注册TC后a的本地事务提交前发生了全局事务回滚此时就会导致全局事务回滚成功而a资源被占用掉产生了资源悬挂问题。 Seata AT模式的防悬挂措施是a回滚时发现回滚undo还未插入则插入一条log_status1的undo记录a本地事务业务写操作sql和对应undo为一个本地事务提交时会因为undo表唯一索引冲突而提交失败。 使用 环境基础 需要搭建Seate节点需要注册中心支持: eurekaconsulnacosetcdzookeeper 注官方文档仅有此目录无实际内容sofa 注官方文档无此目录redis 注官方文档无此目录file (直连) 支持配置中心 nacosconsulapolloetcdzookeeper 注官方文档仅有此目录无实际内容file (读本地文件, 包含conf、properties、yml配置文件的支持) server端 配置信息 必要配置#store.modedb需要以下配置#store.moderedis 需要以下配置registry.type–注册中心类型默认filestore.db.driverClassNamestore.redis.hostconfig.type–配置中心类型默认filestore.db.urlstore.redis.portstore.mode–事务会话信息存储方式store.db.userstore.redis.databasestore.db.passwordstore.redis.password 事务信息存储模式 file 仅适用于单机模式。全局事务会话信息内存中读写并持久化本地文件root.data性能较高db: 适用于高可用集群模式。需要一个数据库实例全局事务会话信息通过db共享相应性能差些;redis: 适用于高可用集群模式。需要一个redis实例, 性能较高缺点是存在数据丢失风险无持久化的宕机 更多配置见seata参数配置 部署 下载部署包。 下载地址https://github.com/seata/seata/releases建表仅store.mode为db时需要共需要三个表。global_table、branch_table、lock_table。 分别对应全局事务会话信息的3块内容全局事务–分支事务–全局锁。官方建表语句地址 https://github.com/seata/seata/tree/master/script/server/db配置与启动 若计划使用启动包命令 修改store.mode相关配置在seata–conf–application.yml修改store.mode“db或者redis”修改数据库连接|redis属性配置。seata–conf–application.example.yml中附带额外配置将其db|redis相关配置复制至application.yml,进行修改store.db或store.redis相关属性。使用命令 seata-server.sh -h 127.0.0.1 -p 8091 -m db 启动命令参数为 若计划使用源码启动则配置 修改store.mode相关配置在根目录–seata-server–resources–application.yml修改store.mode“db或者redis”修改数据库连接|redis属性配置。根目录–seata-server–resources–application.example.yml中附带额外配置将其db|redis相关配置复制至application.yml,进行修改store.db或store.redis相关属性。执行ServerApplication.java的main方法启动 若使用Docker部署 docker部署官方文档 -h: 注册到注册中心的ip -p: Server rpc 监听端口 -m: 全局事务会话信息存储模式file、db、redis优先读取启动参数 (Seata-Server 1.3及以上版本支持redis) -n: Server node多个Server时需区分各自节点用于生成不同区间的transactionId以免冲突 -e: 多环境配置参考 http://seata.io/en-us/docs/ops/multi-configuration-isolation.html注: 官方建议堆内存分配2G堆外内存1G client端 集成 三种集成方式 分表对应不依赖于spring boot 依赖于spring boot, 依赖于spring cloud。 根据自己的项目选择一个即可。 依赖seata-all 引入依赖 dependencygroupIdio.seata/groupIdartifactIdseata-all/artifactIdversion${seata.version}/version /dependency建表AT模式或TCC模式需要AT模式官方建表语句地址https://github.com/seata/seata/tree/master/script/client/at/db如果TCC模式为true即通过Seata解决TCC的幂等空回滚悬挂问题则需要建表 tcc_fence_log注意这些表和Server端的表不一样这个表要在所有你纳入全局事务涉及的库里面都建一份。数据源代理仅AT模式和XA模式需要 自动代理需使用spring的数据源自动配置若采用AT模式。启动类上使用EnableAutoDataSourceProxy注解。若采用XA模式则注解加上参数EnableAutoDataSourceProxy(dataSourceProxyMode “XA”)手动代理 Primary Bean(dataSource) public DataSource dataSource(DataSource druidDataSource) {// 以下两个二选一//AT 代理 return new DataSourceProxy(druidDataSource);//XA 代理return new DataSourceProxyXA(druidDataSource) }初始化GlobalTransactionScanner Bean public GlobalTransactionScanner globalTransactionScanner() {String applicationName this.applicationContext.getEnvironment().getProperty(spring.application.name);String txServiceGroup this.seataProperties.getTxServiceGroup();if (StringUtils.isEmpty(txServiceGroup)) {txServiceGroup applicationName -fescar-service-group;this.seataProperties.setTxServiceGroup(txServiceGroup);}return new GlobalTransactionScanner(applicationName, txServiceGroup); }依赖seata-spring-boot-starter 引入依赖 dependencygroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactIdversion${seata.version}/version /dependency建表仅AT模式需要官方建表语句地址https://github.com/seata/seata/tree/master/script/client/at/db注意这个表和Server端的表不一样这个表要在所有你纳入全局事务涉及的库里面都建一份。数据源代理仅AT模式和XA模式需要 自动代理需使用spring的数据源自动配置若使用AT模式无需配置若使用XA模式则需要设置参数seata.data-source-proxy-modeXA手动代理首先关闭自动代理seata.enable-auto-data-source-proxyfalse 然后进行手动代理 Primary Bean(dataSource) public DataSource dataSource(DataSource druidDataSource) {// 以下两个二选一//AT 代理 return new DataSourceProxy(druidDataSource);//XA 代理return new DataSourceProxyXA(druidDataSource) }依赖spring-cloud-alibaba-seata 引入依赖 dependencygroupIdio.seata/groupIdartifactIdseata-spring-boot-starter/artifactIdversion1.4.2/version /dependency建表仅AT模式需要同依赖seata-spring-boot-starter数据源代理仅AT模式和XA模式需要同依赖seata-spring-boot-starter 参数配置 配置项描述备注registry.type注册中心config.type配置中心service.vgroupMapping.my_test_tx_group事务群组相关概念见链接my_test_tx_group为分组配置项值为TC集群名service.default.grouplistTC服务列表仅注册中心为file时使用service.disableGlobalTransaction全局事务开关默认false。false为开启true为关闭 更多配置见seata参数配置 事务传播 目前 seata-all 中已经支持Apache Dubbo、Alibaba Dubbo、sofa-RPC、Motan、gRpc、httpClient对于 Spring Cloud 的支持需要引用 spring-cloud-alibaba-seata。如果符合以上条件则这一步骤不需要。 如果想了解原理或者是使用的其他自研框架、异步模型、消息消费事务模型则需要进行这一步结合 API 自行支持。 对于异步模型的个人见解: 异步模型可以考虑使用CountdownLaunch需要TC决定提交全局事务前通知TC还有新的分支事务。 在了解如果配置事务传播之前要先明白Seata 的事务上下文。 事务上下文 Seata 的事务上下文由RootContext 来管理。 在开启一个Seate全局事务后RootContext 会自动绑定该事务的XID事务结束后提交或回滚完成RootContext 会自动解绑 XID。 // 绑定 XID RootContext.bind(xid);// 解绑 XID String xid RootContext.unbind();可以通过RootContext获取当前全局事务的XID或者判定当前是否在全局事务中。 // 获取 XID String xid RootContext.getXID();// 当前是否在全局事务中 boolean inGlobalTransaction RootContext.inGlobalTransaction();通过简单的查看源码就可以看到RootContext的实现是依赖于ThreadLocal的。 根据官方文档描述Seata 全局事务的传播机制就是指事务上下文的传播根本上就是 XID 的应用运行时的传播方式。 -这一句很重要理解这一句话做适配的事务传播开发才更得心应手。翻译过来就是所谓的事务传播就是通过RootContext.bind 将不同模块绑定同一个XID的过程。 服务内部的事务传播 默认的RootContext 的实现是基于 ThreadLocal 的即 XID 绑定在当前线程上下文中。所以服务内部的 XID 传播通常是天然的通过同一个线程的调用链路串连起来的。默认不做任何处理事务的上下文就是传播下去的。相关代码可以看源码 io.seata.core.context.ThreadLocalContextCore 同时可以通过RootContext来挂起事务。比如希望某一段流程运行在全局事务外。 // 挂起暂停 String xid RootContext.unbind();// TODO: 运行在全局事务外的业务逻辑// 恢复全局事务上下文 RootContext.bind(xid);跨服务调用的事务传播 通过上述基本原理可以得出 跨服务调用场景下的事务传播本质上就是要把 XID 通过服务调用传递到服务提供方并绑定到 RootContext 中去。 只要能做到这点理论上 Seata 可以支持任意的微服务框架。 Dubbo对全局事务的支持 这里以内置的对Dubbo的事务传播支持机制为例来说明如何实现一个RPC框架对全局事务传播行为的支持。 _org.apache.dubbo.rpc.Filter_是Dubbo提供的拦截器其功能类似web的filter。这里通过他来完成XID的自动装配与绑定。 /*** The type Transaction propagation filter.*/ Activate(group { Constants.PROVIDER, Constants.CONSUMER }, order 100) public class TransactionPropagationFilter implements Filter {private static final Logger LOGGER LoggerFactory.getLogger(TransactionPropagationFilter.class);Overridepublic Result invoke(Invoker? invoker, Invocation invocation) throws RpcException {String xid RootContext.getXID(); // 获取当前事务 XIDString rpcXid RpcContext.getContext().getAttachment(RootContext.KEY_XID); // 获取 RPC 调用传递过来的 XIDif (LOGGER.isDebugEnabled()) {LOGGER.debug(xid in RootContext[ xid ] xid in RpcContext[ rpcXid ]);}boolean bind false;if (xid ! null) { // Consumer把 XID 置入 RPC 的 attachment 中RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);} else {if (rpcXid ! null) { // Provider把 RPC 调用传递来的 XID 绑定到当前运行时RootContext.bind(rpcXid);bind true;if (LOGGER.isDebugEnabled()) {LOGGER.debug(bind[ rpcXid ] to RootContext);}}}try {return invoker.invoke(invocation); // 业务方法的调用} finally {if (bind) { // Provider调用完成后对 XID 的清理String unbindXid RootContext.unbind();if (LOGGER.isDebugEnabled()) {LOGGER.debug(unbind[ unbindXid ] from RootContext);}if (!rpcXid.equalsIgnoreCase(unbindXid)) {LOGGER.warn(xid in change during RPC from rpcXid to unbindXid);if (unbindXid ! null) { // 调用过程有新的事务上下文开启则不能清除RootContext.bind(unbindXid);LOGGER.warn(bind [ unbindXid ] back to RootContext);}}}}} }消费方和提供方都加入这个拦截器就可以进行Dubbo调用的全局事务自动传播了。 更多的事务传播示例可以查看seata-samples或者 seata-integration。 使用 开启全局事务 注解方式使用GlobalTransactional注解即可。 GetMapping(value testCommit) GlobalTransactional public Object testCommit(RequestParam(name id,defaultValue 1) Integer id,RequestParam(name sum, defaultValue 1) Integer sum) {Boolean ok productService.reduceStock(id, sum);if (ok) {LocalDateTime now LocalDateTime.now();Orders orders new Orders();orders.setCreateTime(now);orders.setProductId(id);orders.setReplaceTime(now);orders.setSum(sum);orderService.save(orders);return ok;} else {return fail;} }切点模式 Bean public AspectTransactionalInterceptor aspectTransactionalInterceptor () {return new AspectTransactionalInterceptor(); }Bean public Advisor txAdviceAdvisor(AspectTransactionalInterceptor aspectTransactionalInterceptor ) {AspectJExpressionPointcut pointcut new AspectJExpressionPointcut();pointcut.setExpression(配置切点表达式使全局事务拦截器生效);return new DefaultPointcutAdvisor(pointcut, aspectTransactionalInterceptor); }AT和XA模式开启全局事务即可不需要其它额外的操作。TCC 模式 Tcc模式除了需要开启全局事务之外还需要使用**TwoPhaseBusinessAction**注解来定义try,commitcancel。此注解定义在方法上。 // LocalTCC标识这是一个本地的TCC仅在TCC参与者是 本地bean时需要 LocalTCC public interface TccAction {/*** 定义两阶段提交 name 该tcc的bean名称,全局唯一 commitMethod commit 为二阶段确认方法 rollbackMethod rollback 为二阶段取消方法* useTCCFencetrue 为开启防悬挂* BusinessActionContextParameter注解 传递参数到二阶段中** param params -入参* return String*/TwoPhaseBusinessAction(name beanName, commitMethod commit, rollbackMethod rollback, useTCCFence true)public void insert(BusinessActionContextParameter(paramName params) MapString, String params) {logger.info(此处可以预留资源,或者利用tcc的特点,与AT混用,二阶段时利用一阶段在此处存放的消息,通过二阶段发出,比如redis,mq等操作);}/*** 确认方法、可以另命名但要保证与commitMethod一致 context可以传递try方法的参数** param context 上下文* return boolean*/public void commit(BusinessActionContext context) {logger.info(预留资源真正处理,或者发出mq消息和redis入库);}/*** 二阶段取消方法** param context 上下文* return boolean*/public void rollback(BusinessActionContext context) {logger.info(预留资源释放,或清除一阶段准备让二阶段提交时发出的消息缓存);} }LocalTCC LocalTCC注解标记这是一个本地的TCC。仅在TCC参与者是 本地bean非远程RPC服务时需要在 接口定义中添加 该 注解。如果这是一个远程RPC服务的定义接口则不需要添加这个这个注解。目前TCC支持 Loacl, Dubbo, HSF, Sofa。 GlobalTransactional和Transactional 在AT模式Transactional 可与 DataSourceTransactionManager 和 JTATransactionManager 连用分别表示本地事务和XA分布式事务。Transactional和GlobalTransactional连用Transactional 只能位于标注在GlobalTransactional的同一方法层次或者位于GlobalTransaction 标注方法的内层。这里分布式事务的概念要大于本地事务若将 Transactional 标注在外层会导致分布式事务空提交当Transactional 对应的 connection 提交时会报全局事务正在提交或者全局事务的xid不存在。 全局事务的rollback 和Transactional一样全局事务的回滚需要捕获到异常。因此如果要回滚异常一定要抛到最外层。如果异常在调用的过程中被吞掉的话即使失败也是不会回滚的。 如果不想在调用中抛大量的异常。可以通过返回错误码然后最外层根据错误码抛异常即可。 参考文档https://zhuanlan.zhihu.com/p/561308610 https://juejin.cn/post/6911183702790209549 http://seata.io/zh-cn/docs/overview/what-is-seata.html LCN GitHubhttps://github.com/codingapi/tx-lcnstars: 4k 最新版本 5.0.2.RELEASE Feb 23, 2019 社区比较不活跃 PS 【JAVA核心知识】系列导航 [持续更新中…]
http://www.zqtcl.cn/news/540973/

相关文章:

  • 万户网络做网站如何做网站的企业排名
  • 天猫网站左侧菜单向右滑出的导航菜单阜阳h5网站建设公司
  • 凡科做网站的方法wordpress备份如何安装
  • 网站备案依据四川省广安建设局网站
  • 网站后台管理系统模板品牌营销和品牌推广
  • 网站建设的整个流程图wordpress标题去重
  • 网站手机版模板做拼货商城网站
  • wordpress建自己的网站吗c2c网站的特点
  • 建设网站的成本有哪些龙岩做网站哪家最好
  • wordpress 多站点 子目录安徽望江县城乡建设局官方网站
  • 电子政务网站建设的步骤一般为俱乐部logo免费设计在线生成
  • 网站建设尚品男生学计算机哪个专业最吃香
  • app制作网站收费吗重庆网站产品推广
  • 网站开发预算怎么算厦门建站比较好的公司
  • 涡阳网站优化建设工程公司企业文化
  • 曲靖市住房和城乡建设局网站罗湖区网站公司
  • 购物券网站怎么做wordpress+好用插件
  • 商务网站建设的一般流程是什么?南宁seo费用服务
  • 做企业网站需要什么seminar是什么意思
  • 如何把代码放在网站首页教程深圳建网站哪个公
  • 做的网站第二年续费多钱上传到服务器的网站打开是空白
  • 网站建设花多少钱怎样建移动网站
  • 关键词排名优化网站上海有几个区分别叫什么名字
  • php网站开发基础定制自己的软件
  • 私人装修接单网站wordpress热门文章插件
  • 湘潭网站外包公司宁波妇科医生推荐
  • 企业网站建设可以分为几个层次三亚网站定制
  • 手机网站可以做商城吗如何为公司建立网站
  • 淄博建设银行网站怎么做盗号网站手机
  • 网站建设推广的10种方法精美个人网站