百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Seata,让分布式事务不再是难题!实战分享带你领略Seata的魅力!

ccwgpt 2025-05-02 16:54 34 浏览 0 评论

终身学习、乐于分享、共同成长!

前言

Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata将为用户提供了AT、TCC、SAGA和XA事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务),不过该服务在2023年开始停止支持了。

作为一个分布式事务框架,Seata可以支持多种数据源和多个服务的协同工作,从而实现分布式事务的管理。它的出现大大简化了开发人员的工作。下面,我们就来探究一下Seata的魅力,看看它究竟是如何让分布式事务变得不再困难的。

官网:
https://seata.io/zh-cn/index.html(opens new window)

源码:
https://github.com/seata/seata(opens new window)

官方Demo:
https://github.com/seata/seata-samples(opens new window)

本文使用的seata版本:v1.6.1

Seata的核心

Seata的核心组件包括三个部分:

  1. Transaction CoordinatorTC):事务协调器,负责全局事务的协调和管理。
  2. Resource ManagerRM):资源管理器,负责管理分支事务所涉及的资源。
  3. Transaction ManagerTM):事务管理器,提供全局事务的创建、提交、回滚等操作。

其中,TC 为单独部署的 Server 服务端,TM 和 RM 为嵌入到应用中的 Client 客户端

Seata的工作流程如下:

  1. TM请求TC开启一个全局事务。TC会生成一个XID作为该全局事务的编号。XID,会在微服务的调用链路中传播,保证将多个微服务的子事务关联在一起。当一进入事务方法中就会生成XID ,global_table表存储的就是全局事务信息。
  2. RM请求TC将本地事务注册为全局事务的分支事务,通过全局事务的XID进行关联。当运行数据库操作方法,branch_table表存储事务参与者信息。
  3. TM请求TC告诉XID对应的全局事务是进行提交还是回滚。
  4. TC驱动RM们将XID对应的自己的本地事务进行提交还是回滚。

seata-server(TC)

  • global_table全局事务表,记录全局事务的基本信息,例如全局事务ID、事务状态等。每当有一个全局事务发起后,就会在该表记录全局事务ID。
  • branch_table分支事务表,记录分支事务的基本信息,例如分支事务ID、所属全局事务ID、分支事务状态等。
  • lock_table全局锁,记录分布式锁的信息,例如锁定的资源、锁的持有者等。

Seata快速开始

使用官方实验例子,模拟用户购物下单的业务操作。原理图如下:

Seata具体实现步骤:

  1. TM端使用@GlobalTransaction进行全局事务的开启、提交、回滚。
  2. TM端开始远程调用业务服务。
  3. RM端(seata客户端)通过扩展DataSourceProxy,实现自动生成undo_logTC上报。
  4. TM告知TC提交/回滚事务。
  5. TC通知RM各自提交/回滚事务操作,同时删除undo_log。

搭建seata-server(TC 协调者)

  • 下载seata-server

我用的seata是截止目前最新的版本1.6.1,下载地址:
https://github.com/seata/seata/releases

下载后解压文件如下:

  • 修改seata/conf/application.yml配置文件
#  Copyright 1999-2019 Seata.io Group.
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#  http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.

server:
  port: 7091

spring:
  application:
    name: seata-server

logging:
  config: classpath:logback-spring.xml
  file:
    path: ${user.home}/logs/seata
  extend:
    logstash-appender:
      destination: 127.0.0.1:4560
    kafka-appender:
      bootstrap-servers: 127.0.0.1:9092
      topic: logback_to_logstash

console:
  user:
    username: seata
    password: seata

seata:
  config:
    # support: nacos, consul, apollo, zk, etcd3
    type: nacos
    nacos: 
      server-addr: 127.0.0.1:8848  # nacos的ip端口
      group: DEFAULT_GROUP  # 对应的组,默认为DEFAULT_GROUP
      #namespace: 707f9b70-7c86-4278-bd74-83cef490a824 # 对应的命名空间,在nacos中配置
      username: nacos
      password: nacos
      data-id: seata-server.properties # nacos中存放seata的配置文件,后面会提该文件的使用方式,相当于seata服务启动的时候需要注册到nacos,并使用nacos中的配置文件

  registry:
    # support: nacos, eureka, redis, zk, consul, etcd3, sofa
    type: nacos
    nacos: 
      server-addr: 127.0.0.1:8848  # nacos的ip端口
      group: DEFAULT_GROUP  # 对应的组,默认为DEFAULT_GROUP
      #namespace: 707f9b70-7c86-4278-bd74-83cef490a824 # 对应的命名空间,在nacos中配置
      username: nacos
      password: nacos

  store:
    # support: file 、 db 、 redis
    mode: file
#  server:
#    service-port: 8091 #If not configured, the default is '${server.port} + 1000'
  security:
    secretKey: SeataSecretKey0c382ef121d778043159209298fd40bf3850a017
    tokenValidityInMilliseconds: 1800000
    ignore:
      urls: /,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-fe/public/**,/api/v1/auth/login

seata.config.typeseata.registry.type 都要修改为nacos

修改configregistry中nacos的配置,其中namespacegroup须提前在nacos中进行配置。

  • 在Nacos配置中心新增dataid为seata-server.properties的properties配置。

内容如下:

#For details about configuration items, see https://seata.io/zh-cn/docs/user/configurations.html
#Transport configuration, for client and server
transport.type=TCP
transport.server=NIO
transport.heartbeat=true
transport.enableTmClientBatchSendRequest=false
transport.enableRmClientBatchSendRequest=true
transport.enableTcServerBatchSendResponse=false
transport.rpcRmRequestTimeout=30000
transport.rpcTmRequestTimeout=30000
transport.rpcTcRequestTimeout=30000
transport.threadFactory.bossThreadPrefix=NettyBoss
transport.threadFactory.workerThreadPrefix=NettyServerNIOWorker
transport.threadFactory.serverExecutorThreadPrefix=NettyServerBizHandler
transport.threadFactory.shareBossWorker=false
transport.threadFactory.clientSelectorThreadPrefix=NettyClientSelector
transport.threadFactory.clientSelectorThreadSize=1
transport.threadFactory.clientWorkerThreadPrefix=NettyClientWorkerThread
transport.threadFactory.bossThreadSize=1
transport.threadFactory.workerThreadSize=default
transport.shutdown.wait=3
transport.serialization=seata
transport.compressor=none

#Transaction routing rules configuration, only for the client
# 此处的mygroup名字可以自定义,只修改这个值即可
service.vgroupMapping.mygroup=default
#If you use a registry, you can ignore it
service.default.grouplist=127.0.0.1:8091
service.enableDegrade=false
service.disableGlobalTransaction=false

#Transaction rule configuration, only for the client
client.rm.asyncCommitBufferLimit=10000
client.rm.lock.retryInterval=10
client.rm.lock.retryTimes=30
client.rm.lock.retryPolicyBranchRollbackOnConflict=true
client.rm.reportRetryCount=5
client.rm.tableMetaCheckEnable=true
client.rm.tableMetaCheckerInterval=60000
client.rm.sqlParserType=druid
client.rm.reportSuccessEnable=false
client.rm.sagaBranchRegisterEnable=false
client.rm.sagaJsonParser=fastjson
client.rm.tccActionInterceptorOrder=-2147482648
client.tm.commitRetryCount=5
client.tm.rollbackRetryCount=5
client.tm.defaultGlobalTransactionTimeout=60000
client.tm.degradeCheck=false
client.tm.degradeCheckAllowTimes=10
client.tm.degradeCheckPeriod=2000
client.tm.interceptorOrder=-2147482648
client.undo.dataValidation=true
client.undo.logSerialization=jackson
client.undo.onlyCareUpdateColumns=true
server.undo.logSaveDays=7
server.undo.logDeletePeriod=86400000
client.undo.logTable=undo_log
client.undo.compress.enable=true
client.undo.compress.type=zip
client.undo.compress.threshold=64k
#For TCC transaction mode
tcc.fence.logTableName=tcc_fence_log
tcc.fence.cleanPeriod=1h

#Log rule configuration, for client and server
log.exceptionRate=100

#Transaction storage configuration, only for the server. The file, db, and redis configuration values are optional.
# 默认为file,一定要改为db,我们自己的服务启动会连接不到seata
store.mode=db
store.lock.mode=db
store.session.mode=db
#Used for password encryption

#These configurations are required if the `store mode` is `db`. If `store.mode,store.lock.mode,store.session.mode` are not equal to `db`, you can remove the configuration block.
# 修改mysql的配置
store.db.datasource=druid
store.db.dbType=mysql
store.db.driverClassName=com.mysql.cj.jdbc.Driver
# 指定seata的数据库,下面会提
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&rewriteBatchedStatements=true
store.db.user=root
store.db.password=123456
store.db.minConn=5
store.db.maxConn=30
store.db.globalTable=global_table
store.db.branchTable=branch_table
store.db.distributedLockTable=distributed_lock
store.db.queryLimit=100
store.db.lockTable=lock_table
store.db.maxWait=5000


#Transaction rule configuration, only for the server
server.recovery.committingRetryPeriod=1000
server.recovery.asynCommittingRetryPeriod=1000
server.recovery.rollbackingRetryPeriod=1000
server.recovery.timeoutRetryPeriod=1000
server.maxCommitRetryTimeout=-1
server.maxRollbackRetryTimeout=-1
server.rollbackRetryTimeoutUnlockEnable=false
server.distributedLockExpireTime=10000
server.xaerNotaRetryTimeout=60000
server.session.branchAsyncQueueSize=5000
server.session.enableBranchAsyncRemove=false
server.enableParallelRequestHandle=false

#Metrics configuration, only for the server
metrics.enabled=false
metrics.registryType=compact
metrics.exporterList=prometheus
metrics.exporterPrometheusPort=9898

【注意】

  1. 修改service.vgroupMapping.mygroup=default该值,其中mygroup可以自定义,后面我们自己的服务启动时,配置文件中需要指定该group。
  2. 修改store.mode store.lock.mode store.session.mode这三个值为db,才能让seata连接到下面的数据库中。
  3. 修改store.db配置项下的配置,连接到自己的数据库。
  4. 该文件参数的具体作用参考官网:seata配置文件详解(官网 (opens new window))
  5. 该配置源文件存放在seata目录下:seata/script/config-center/config.txt
  • 在mysql数据库中新建seata所用到的数据库及数据表

数据库的名称与上述seata配置文件中的store.db.url保持一致。

添加seata的配置表,sql文件存放在:
seata/script/server/db/mysql.sql

-- -------------------------------- The script used when storeMode is 'db' --------------------------------
-- the table to store GlobalSession data
CREATE TABLE IF NOT EXISTS `global_table`
(
    `xid`                       VARCHAR(128) NOT NULL,
    `transaction_id`            BIGINT,
    `status`                    TINYINT      NOT NULL,
    `application_id`            VARCHAR(32),
    `transaction_service_group` VARCHAR(32),
    `transaction_name`          VARCHAR(128),
    `timeout`                   INT,
    `begin_time`                BIGINT,
    `application_data`          VARCHAR(2000),
    `gmt_create`                DATETIME,
    `gmt_modified`              DATETIME,
    PRIMARY KEY (`xid`),
    KEY `idx_status_gmt_modified` (`status` , `gmt_modified`),
    KEY `idx_transaction_id` (`transaction_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store BranchSession data
CREATE TABLE IF NOT EXISTS `branch_table`
(
    `branch_id`         BIGINT       NOT NULL,
    `xid`               VARCHAR(128) NOT NULL,
    `transaction_id`    BIGINT,
    `resource_group_id` VARCHAR(32),
    `resource_id`       VARCHAR(256),
    `branch_type`       VARCHAR(8),
    `status`            TINYINT,
    `client_id`         VARCHAR(64),
    `application_data`  VARCHAR(2000),
    `gmt_create`        DATETIME(6),
    `gmt_modified`      DATETIME(6),
    PRIMARY KEY (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

-- the table to store lock data
CREATE TABLE IF NOT EXISTS `lock_table`
(
    `row_key`        VARCHAR(128) NOT NULL,
    `xid`            VARCHAR(128),
    `transaction_id` BIGINT,
    `branch_id`      BIGINT       NOT NULL,
    `resource_id`    VARCHAR(256),
    `table_name`     VARCHAR(32),
    `pk`             VARCHAR(36),
    `status`         TINYINT      NOT NULL DEFAULT '0' COMMENT '0:locked ,1:rollbacking',
    `gmt_create`     DATETIME,
    `gmt_modified`   DATETIME,
    PRIMARY KEY (`row_key`),
    KEY `idx_status` (`status`),
    KEY `idx_branch_id` (`branch_id`),
    KEY `idx_xid` (`xid`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

CREATE TABLE IF NOT EXISTS `distributed_lock`
(
    `lock_key`       CHAR(20) NOT NULL,
    `lock_value`     VARCHAR(20) NOT NULL,
    `expire`         BIGINT,
    primary key (`lock_key`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('AsyncCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryCommitting', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('RetryRollbacking', ' ', 0);
INSERT INTO `distributed_lock` (lock_key, lock_value, expire) VALUES ('TxTimeoutCheck', ' ', 0);
  • 启动seata-server
sh seata-server.sh -p 8091 -h 127.0.0.1

参数解释:

-h: 将地址暴露给注册中心,其他服务可以访问seata服务

-p:要侦听的端口

启动成功后,即可访问http://127.0.0.1:7091/#/login (opens new window)该地址进入seata的webui,用户名与密码默认为seata,用户名和密码可在application.yml配置项:console.user中修改。

并且查看nacos中的服务注册中心是否可以看到seata-server

至此,seata-server就搭建成功了。

搭建seata-client(TM、RM)

再来回顾一下前面的业务场景,如图:

因此这里需要搭建三个客户端应用:tm-serverorder-serverstorage-server,源码:

工程源码:
https://gitee.com/it-codelab/springcloudalibaba-study/tree/main/seata-demo

新建数据库表,只有order-serverstorage-server这两个应用需要用到数据库,新建两个对应的数据库:

  • storage数据库对应的库表
create table storage
(
    id         bigint(11) auto_increment
        primary key,
    product_id bigint(11) null comment '产品id',
    total      int        null comment '总库存',
    used       int        null comment '已用库存'
)
    charset = utf8;

create table undo_log
(
    id            bigint auto_increment
        primary key,
    branch_id     bigint       not null,
    xid           varchar(100) not null,
    context       varchar(128) not null,
    rollback_info longblob     not null,
    log_status    int          not null,
    log_created   datetime     not null,
    log_modified  datetime     not null,
    ext           varchar(100) null,
    constraint ux_undo_log
        unique (xid, branch_id)
)
    charset = utf8;
  • order数据库对应的库表
create table t_order
(
    id         bigint(11) auto_increment
        primary key,
    user_id    bigint(11)  null comment '用户id',
    product_id bigint(11)  null comment '产品id',
    count      int         null comment '数量',
    money      decimal(11) null comment '金额',
    status     int(1)      null comment '订单状态:0:创建中;1:已完成'
)
    charset = utf8;

create table undo_log
(
    id            bigint auto_increment
        primary key,
    branch_id     bigint       not null,
    xid           varchar(100) not null,
    context       varchar(128) not null,
    rollback_info longblob     not null,
    log_status    int          not null,
    log_created   datetime     not null,
    log_modified  datetime     not null,
    ext           varchar(100) null,
    constraint ux_undo_log
        unique (xid, branch_id)
)
    charset = utf8;

每个RM服务对应的数据库都需要添加undo_log表。

主要配置以及核心代码:

  • 添加seata依赖,三个应用都一样
 <!--seata-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-spring-boot-starter</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>io.seata</groupId>
                    <artifactId>seata-all</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.seata</groupId>
            <artifactId>seata-spring-boot-starter</artifactId>
            <version>1.6.1</version>
        </dependency>
  • bootstrap.yml文件加入seata的相关配置
seata:
  enabled: true
  #application-id: ${spring.application.name}
  # 事务群组(可以每个应用独立取名,也可以使用相同的名字),要与服务端nacos-config.txt中service.vgroup_mapping的后缀对应
  tx-service-group: my_test_tx_group # 事务分组名称,要和服务端对应
  service:
    vgroup-mapping:
      my_test_tx_group: default # key是事务分组名称 value要和服务端的机房名称保持一致
  config:
    type: nacos
    # 需要和server在同一个注册中心下
    nacos:
      #namespace: cab17056-9954-4e45-9223-eb33692f60f7
      serverAddr: 127.0.0.1:8848
      # 需要server端(registry和config)、nacos配置client端(registry和config)保持一致
      group: SEATA_GROUP
      username: "nacos"
      password: "nacos"
      namespace: 707f9b70-7c86-4278-bd74-83cef490a824
  registry:
    type: nacos
    nacos:
      # 需要和server端保持一致,即server在nacos中的名称,默认为seata-server
      application: seata-server
      server-addr: 127.0.0.1:8848
      group: DEFAULT_GROUP
      #namespace: cab17056-9954-4e45-9223-eb33692f60f7
      username: "nacos"
      password: "nacos"

这里有一个深坑,启动应用后会报如下错误:

seata can not get cluster name in registry config ‘service.vgroupMapping.XXX‘

解决办法就是需要再Nacos配置中心增加service.vgroupMapping.XXX配置,XXX是可以自定义的,value默认为default。

注:核心业务代码可查看项目源码:
https://gitee.com/it-codelab/springcloudalibaba-study/tree/main/seata-demo

AT模式原理

AT模式的核心优势是对业务无侵入,是一种改进后的两阶段提交。

  • 一阶段:业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。
  • 二阶段:提交异步化,非常快速地完成。回滚通过一阶段的回滚日志进行反向补偿。

其设计思路如图:

  • 第一阶段

业务数据和回滚日志记录在同一个本地事务中提交,释放本地锁和连接资源。核心在于对业务sql进行解析,转换成undolog,并同时入库,这是怎么做的呢?先抛出一个概念DataSourceProxy代理数据源,通过名字大家大概也能基本猜到是什么个操作,后面做具体分析

参考官方文档:
https://seata.io/zh-cn/docs/dev/mode/at-mode.html

  • 第二阶段

第一种情况:分布式事务操作成功,则TC通知RM异步删除undolog。

第二种情况:分布式事务操作失败,TM向TC发送回滚请求 TC收到回滚请求后,向RM发送回滚请求 RM收到协调器TC发来的回滚请求 通过XID和Branch ID找到相应的回滚日志记录 通过回滚记录生成反向的更新SQL并执行,以完成分支的回滚。

完整执行流程:

读写隔离机制

写隔离

  • 一阶段本地事务提交前,需要确保先拿到 全局锁
  • 拿不到 全局锁 ,不能提交本地事务。
  • 全局锁 的尝试被限制在一定范围内,超出范围将放弃,并回滚本地事务,释放本地锁。

以一个示例来说明:

两个全局事务 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(AT 模式)的默认全局隔离级别是 读未提交(Read Uncommitted)

如果应用在特定场景下,必需要求全局的 读已提交 ,目前 Seata 的方式是通过 SELECT FOR UPDATE 语句的代理。

SELECT FOR UPDATE 语句的执行会申请 全局锁 ,如果 全局锁 被其他事务持有,则释放本地锁(回滚 SELECT FOR UPDATE 语句的本地执行)并重试。这个过程中,查询是被 block 住的,直到 全局锁 拿到,即读取的相关数据是 已提交 的,才返回。

出于总体性能上的考虑,Seata 目前的方案并没有对所有 SELECT 语句都进行代理,仅针对 FOR UPDATE 的 SELECT 语句。

总结

  • alibaba seata框架总体使用下来是比较简单的,AT模式对业务代码零侵入的优势特点使得seata在业界得到了广泛的应用。
  • 框架使用起来越简单,那它内部的实现原理就越复杂、越抽象,本文也只是对seata的使用入了门,更原理性的内容后续持续深挖钻研。





相关推荐

WAIC2024丨明日上午9点,不见不散!共同探讨智能社会与全球治理框架

大咖云集,硕果闪耀WAIC2024世界人工智能大会智能社会论坛将于7月5日9:00-12:00与你相约直播间WAIC2024上海杨浦同济大学哔哩哔哩多平台同步直播探讨智能社会与全球治理框架WAIC...

约基奇:森林狼换来戈贝尔时大家都在嘲笑 他们的阵容框架很不错

直播吧5月4日讯西部季后赛半决赛,掘金将迎战森林狼,约基奇赛前接受采访。约基奇说道:“当蒂姆-康纳利(森林狼总经理、前掘金总经理&曾选中约基奇)做了那笔交易(换来戈贝尔)时,每个人都在嘲笑他...

视频号带货为什么一个流量都没有?顶级分析框架送给你

视频号带货为什么一个流量都没有?遇到问题,一定是步步来分析内容,视频号带货一个流量都没有,用另外一个意思来讲,就可以说是零播放。为什么视频号带货一个流量都没有?跟你说再多,都不如来个分析框架。1、是否...

基建狂魔!开工仅一年,黄河足球场主体框架已经建好

直播吧8月3日讯根据博主“鲁蜜之声”的消息,可容纳6万人的黄河足球场的主体框架已经建好。黄河足球场位于济南新旧动能转换起步区,于在2022年7月1日正式开工,今年7月7日项目主体结构顺利封顶。黄河足...

TA:NBA已与亚马逊达成新转播合同框架 预计长达10年

直播吧04月27日讯据美媒TheAthletic报道,消息人士透露,NBA已经与亚马逊达成了新转播合同的框架。据报道,合同中预计将包括重要的常规赛和季后赛(的转播权),甚至可能包括一部分分区决赛。...

美记:截止日前老鹰曾提出科林斯换比斯利+范德彪交易框架

直播吧5月26日讯据雅虎名记JakeFischer报道,消息人士透露,在二月份交易截止日期之前,有很多球队有意马利克-比斯利。消息人士称,老鹰队曾与爵士探讨了比斯利和范德比尔特换约翰-科林斯交易框...

遥望科技:公司计划基于GPT技术框架做直播带货的AIGC生成

遥望科技2月14日在互动平台表示,公司计划基于GPT技术框架做直播带货的AIGC生成,目前仅处于研究阶段,未来能否稳定实现商业化尚没有定论。

遥望科技:计划基于GPT技术框架做直播带货的AIGC生成

遥望科技3月6日在互动平台表示,公司计划基于GPT技术框架做直播带货的AIGC生成,目前正处于研究阶段,能否稳定商业化尚没有结论。

遥望科技:基于GPT技术框架做直播带货AIGC生成,目前正处于研究阶段

遥望科技2月13日在投资者互动平台表示,公司计划基于GPT技术框架做直播带货的AIGC生成,目前正处于研究阶段,能否稳定商业化尚没有结论。

单场 50W 的茶叶直播话术框架 【完整版】

《单场50W的茶叶直播话术框架》完整版话术框架,文末附获取方式!分享一份《单场50W的茶叶直播话术框架》内容包含:开场预热、活动话术、互动话术、福利话术、配合话术、人设话术、预设话术、商品展示...

想要做好直播,就要明白直播话术的框架和逻辑#直播技巧#...

当你熟练运用话术框架,你会发现直播转化变得轻而易举。一个直播间话术结构包含三个关键点,想要做好直播,一定要点赞收藏此视频,仔细研究。·首先,要具备利他思维。为什么用户会在直播间停留、互动、购买?因为你...

[一张图]直播电商运营模型,直播架构,直播变现,直播电商产业链

直播电商运营模型直播架构直播变现直播电商产业链~~~~~~~~~~~~~~~~~~~...

图解如何对商业模式进行分析及其分析框架和实例

建立结构分析框架(如何构建分析框架)

建立结构分析框架结构性分析的方法只有三种:划分结构、寻找因果关系和分类。采用"相互独立/完全穷(MECE)"的分类方法后,通过逐项展开,就可以按排除的难易程度对所有可能的原因进行筛选...

投资的基本分析框架(投资的基本分析框架是什么)

大道至简。投资的基本分析框架其实非常简单,就是两个概念,一是护城河,二是安全边际。护城河说的是一个企业要能够长长久久地赚钱,安全边际说的要以一个适当的价格获得企业的股权。因此,投资基本上就是在分析一个...

取消回复欢迎 发表评论: