news 2026/10/21 8:30:25

分布式事务从原理到实战:Seata四大模式选型与避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
分布式事务从原理到实战:Seata四大模式选型与避坑指南

1. 为什么大家都在学分布式事务,以及Seata为什么值得花时间

先说个我自己观察到的现象:很多同学工作两三年,单体应用玩得很溜,本地事务也了如指掌,但一碰到微服务拆分后的数据一致性问题,就立刻露馅。面试的时候问"跨服务调用,A服务扣库存成功,B服务创建订单失败,怎么办",能答出"消息队列+最终一致性"的已经算不错,能顺着讲清楚事务模式选型和回滚细节的凤毛麟角。

这其实不怪大家,因为分布式事务本来就是分布式系统里最难啃的骨头之一。它难在不是"多学一个工具"就能解决,而是需要你把网络通信、并发控制、异常恢复、幂等设计这些东西全都串起来理解。

Seata就是在这个背景下被广泛使用的一套分布式事务中间件。它全称是Simple Extensible Autonomous Transaction Architecture,名字里三个词其实点出了它的设计灵魂:简单、可扩展、自治。我最早接触它是在某公司做电商订单系统重构的时候,十几个微服务,订单、库存、积分、优惠券各管各的库,业务上又要求强一致,当时选型调研了一圈,最后落地用的就是Seata。几年下来,从AT模式到TCC模式到Saga模式都用过,踩过的坑绝对值得写一篇长文说清楚。

这篇文章不是什么官方文档翻译,而是我自己从理论学习到上线维护全过程的经验梳理。我会把Seata的架构原理、四种事务模式的选型思路、实际接入步骤、以及那些文档里不会写的坑,一次讲完。无论你是刚接触这个概念,还是已经在项目里用但遇到了疑难杂症,都能找到有用的部分。

顺便说一句,Seata这个名字经常有人拼错,比如打成"Seat",其实它最早确实有过内部代号叫"塞特事务",但开源后统一叫Seata,学习的时候注意一下就行。

2. 先搞懂Seata的三大角色和两条核心链路

2.1 三大角色:协调者、发起者、参与者

Seata的架构里只有三个角色,理解它们,整个框架就懂了一半。

第一个是Transaction Coordinator,事务协调者,简称TC。它是独立的服务端,负责全局事务的注册、分支事务的状态记录、以及最终的提交或回滚决策。你可以把它理解成"交通警察",所有事务参与者都要向它报备状态,最后由它拍板绿灯(全局提交)还是红灯(全局回滚)。

第二个是Transaction Manager,事务管理器,简称TM。它是全局事务的发起方,通常就是你的业务入口服务。TM负责向TC申请开启一个全局事务、提交全局事务、或者回滚全局事务。注意,TM只是"下达指令",它本身不执行具体的事务操作。

第三个是Resource Manager,资源管理器,简称RM。它是分支事务的管理者,也就是实际操作数据库的那个服务。每个参与全局事务的业务服务都是一个RM,它负责把本地事务的执行结果上报给TC,并且在需要回滚的时候执行反向补偿操作。

这三个角色的关系我打个比方:TM是老板,TC是项目经理,RM是干活的员工。老板说要做一个项目(开启全局事务),项目经理登记项目状态(TC注册记录),员工干完活向项目经理汇报(RM分支上报),项目经理根据所有员工的情况决定项目验收还是返工(全局提交或回滚)。

2.2 两条核心链路:事务生命周期和执行链路

理解了角色,再看Seata处理一次全局事务的两条链路。

第一条是事务生命周期链路。TM调用TC开启全局事务,TC返回全局事务ID,也就是XID。XID会通过调用链传递到每一个参与的服务,服务拿到XID后,向TC注册自己的分支事务。业务执行完后,TM向TC发起全局提交或全局回滚请求,TC根据所有分支的状态作出决策,并通知各个RM执行提交或回滚。

第二条是底层数据链路。这一条不同模式差别很大,但核心思想是一致的:通过代理数据源拦截SQL,在业务操作之外额外记录事务上下文。比如AT模式会解析SQL生成镜像数据,TCC模式会调用你编写的confirm和cancel方法,Saga模式则依赖状态机引擎来串联调用。

这两条链路你不需要死记,但在后续排查问题时非常有用。比如你遇到"全局事务一直不结束",大概率是某个RM的分支事务没有正确上报;遇到"回滚失败",大概率是undo_log表有问题或者是补偿逻辑写错了。知道数据往哪儿流,才能顺着链路找问题。

3. 四种事务模式讲透:AT、TCC、Saga、XA怎么选

3.1 AT模式:无侵入的默认首选

AT模式是Seata最有特色的模式,也是大多数人入门用的模式。它的核心卖点是"对业务代码零侵入"——你不需要改任何业务逻辑,只需要把数据源换成Seata代理的数据源,加几个注解,剩下的框架帮你搞定。

原理其实挺巧妙的。在执行业务SQL之前,Seata会先解析SQL,查询出要修改的原始数据,生成前置镜像(before image);执行业务SQL之后,再查询修改后的数据,生成后置镜像(after image)。这两份镜像连同SQL类型、表名、主键信息,写入一张叫undo_log的日志表。如果后续需要回滚,就用前置镜像反向生成补偿SQL,把数据恢复原样。

这个机制本质上是把"补偿"这件事自动化了,所以业务代码完全不用感知自己参与了一个分布式事务。

但AT模式有个特点必须说清楚:它依赖数据库的本地事务来保证undo_log和业务数据的一致性。也就是说,业务SQL和undo_log的写入必须落在同一个本地事务里,要么都成功,要么都失败。这也是为什么Seata要求你的业务数据库必须支持事务。

AT模式适合大多数"普通CRUD"型业务,尤其是那种没法轻易改造成TCC的老系统。我见过不少团队接到需求"把订单流程拆成微服务,还要保持数据一致",直接用AT模式就搞定了。它最省力,出问题的概率也相对低。

当然AT模式不是没有代价,后面我专门写一节讲它的坑。

3.2 TCC模式:手工补偿,灵活但费人

TCC是Try-Confirm-Cancel三个单词的缩写,中文一般叫补偿事务。和AT模式完全不同,TCC要求你为每一个参与分布式事务的业务操作,手写三个方法。

Try阶段做的事是"资源预留"。比如下单场景,Try阶段不真的扣库存,而是冻结库存;Confirm阶段才是真正的扣减;Cancel阶段是释放冻结。三个方法里,Try必须保证幂等,Confirm和Cancel必须保证只成功执行一次,而且Confirm和Cancel由TC调度,你无法控制它们执行的时机。

TCC模式最大的好处是对性能影响小,锁的粒度更细,而且能处理AT模式不好处理的场景,比如跨异构系统调用——下游不是数据库而是别人家的HTTP接口,你没法给别人的库写undo_log,那就只能用TCC。

但坏处也很明显:开发量大,逻辑复杂,容易写错。尤其是Cancel方法里的补偿逻辑,要把之前Try阶段做的所有操作全部反向做一遍,漏一个就出大事。我个人的建议是:不到万不得已,别用TCC手写补偿。如果团队里没有对事务很熟的资深开发,TCC很容易变成事故多发地。

3.3 Saga模式:长事务的终极形态

Saga模式是最古老的分布式事务方案之一,核心思想是把一个长事务拆成一组有序的子事务,每个子事务都有对应的补偿事务。如果中间某一步失败,就逆序执行之前所有步骤的补偿。

Seata的Saga实现是基于状态机引擎的。你需要用JSON定义状态机,描述每个步骤做什么、成功或失败后跳转到哪个状态、补偿步骤是什么。引擎根据状态机编排执行,整个事务对调用方来说是透明的。

这个模式最典型的应用场景是业务流程特别长的情况,比如一个下单流程要经过十几个微服务,中间还有人工审核环节。AT模式在这种场景下会因为全局锁持有时间太长而拖垮性能,TCC模式补偿逻辑写到崩溃,Saga反而游刃有余。

不过Saga有它自己的牺牲:它做不到隔离性,中间步骤的结果对其他人是可见的。这意味着如果你的业务不允许"半成品状态"被看到,就得在设计上额外加状态字段来兜底。另外状态机JSON写起来容易,维护起来难,业务复杂后状态图会非常庞大。

3.4 XA模式:最标准的"老大哥"

XA是数据库原生支持的分布式事务协议,Seata的XA模式本质上就是把数据库的XA事务能力包装了一下。它是四种模式里最标准的,也是隔离性最好的——事务真正做到了原子提交,要么全成,要么全败,不存在中间可见状态。

但XA的致命伤在于阻塞。XA事务在数据库层面持有资源锁,直到事务全局提交或回滚才会释放。在高并发场景下,锁等待时间会拖垮系统吞吐量。而且XA对数据库版本和配置有要求,MySQL要用XA协议,对连接池、驱动版本都有讲究。

我几乎不推荐新项目用XA模式,除非你的系统并发很低、对一致性要求又极端苛刻。更多时候,XA是作为知识储备存在——面试被问到分布式事务方案对比时,把XA讲清楚反而能体现你的底层功底。

3.5 模式选型:一张表做决策

维度ATTCCSagaXA
代码侵入无高,需手写三方法中,需定义状态机无
隔离性有全局锁机制弱,靠业务设计弱,中间可见强,真原子性
性能中高高低,阻塞严重
开发成本低高中高低
适用场景常规CRUD强一致异构系统需补偿长流程弱隔离低并发强一致

团队里没有精通分布式事务的人时,优先AT;有专门人力且业务确实复杂,才考虑TCC或Saga。这个顺序我踩过坑换来的。

4. AT模式实战接入:从0到1完整步骤

4.1 环境准备:部署TC并初始化数据库

第一步是部署TC。Seata的TC依赖一个数据库来存储全局事务会话、锁等信息,需要先初始化一张全局事务表,也就是global_table、branch_table、lock_table这三张核心表。

我用Docker部署时,会先启动MySQL实例,然后执行Seata官方提供的脚本创建这三张表。具体命名空间需要根据你的部署环境配置,比如我习惯用默认的"public"命名空间,但在多租户场景下要为每个租户创建独立的命名空间表集合。

部署TC过程中最容易出错的是配置文件。Seata 1.4之后的版本把配置拆分成了registry.conf和file.conf两张核心配置。registry.conf负责配置TC如何被服务发现,file.conf负责TC本身的存储、锁等各项配置。很多人报错"无法连接TC",最终排查下来十个里八个是registry.conf里的注册中心类型写错了,比如用Nacos作注册中心,registry.type没配成nacos,或者namespace没对齐。

4.2 客户端接入:事务注解和代理数据源

服务端部署好之后,接入客户端才是大头。客户端要做的事情有三件:

第一,引入Seata客户端依赖。Maven项目里添加seata-spring-boot-starter,版本和TC要严格对应,否则会出现RPC协议不兼容的问题。

第二,加配置。在application.yml里配置事务服务组,比如:

seata: enabled: true application-id: order-service tx-service-group: my_test_tx_group registry: type: nacos nacos: server-addr: 127.0.0.1:8848 namespace: public config: type: nacos

这里的tx-service-group非常关键。TC端会根据service.vgroupMapping配置,把服务组映射到具体的TC集群。如果这个映射没配好,客户端就会报"no available service"的错误,而且这个错非常容易让人误判成网络不通。

第三,把业务数据源替换成Seata的代理数据源。这一步是AT模式无侵入功能的物理基础。不要手动new,直接用配置类返回代理好的DataSource:

@Configuration public class DataSourceConfig { @Bean @Primary public DataSource seataDataSource() { DruidDataSource druidDataSource = new DruidDataSource(); // 设置driver、url、username、password... return new DataSourceProxy(druidDataSource); } }

然后在你业务入口方法上加上全局事务注解:

@GlobalTransactional public void createOrder(OrderDTO orderDTO) { orderMapper.insert(orderDTO); stockService.deductStock(orderDTO.getSkuId(), orderDTO.getCount()); couponService.useCoupon(orderDTO.getCouponId()); }

这里要特别注意:@GlobalTransactional要加在跨服务调用的最外层入口,也就是TM角色的方法上,而不是每个服务内部都加。加错位置会导致多个全局事务嵌套,虽然Seata有处理机制,但性能会大打折扣。

4.3 关键配置项:哪些必须调,哪些默认就好

AT模式下几个配置项我要单独拎出来说。

占位符锁检查的开启状态。AT模式为了防脏写,在执行更新前会检查全局锁,如果记录被其他全局事务锁住,就要等待。默认的检查间隔是100毫秒,最大重试次数默认很大,但实际生产环境建议把重试上限设小一点,不然高并发下大量请求堆积等待锁,反而拖垮系统。

异步提交的超时阈值。Seata允许把某些分支事务设为异步提交,也就是该分支只注册、不等待全局事务的结果,事务结果在后台异步执行。开启后性能会明显提升,代价是极端情况下可能出现提交延迟。我一般只在分支事务执行时间特别短时才开。

事务超时时间必须显式配置。默认的全局事务超时是60秒,但跨服务调用链路一长,60秒很容易不够用,建议根据最坏情况的调用耗时来设置,并且一定要留出余量。

5. 全链路排障实录:Seata实际落地中的五个典型坑

5.1 undo_log表没有创建:回滚静默失败的元凶

AT模式能自动回滚,靠的就是undo_log这张表。我见过不止一个项目,业务跑得贼欢,真到了回滚的时候数据纹丝不动,最后排查半天发现undo_log表压根没建。

表结构长这样,如果你手动建,照抄就行:

CREATE TABLE IF NOT EXISTS `undo_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `branch_id` bigint(20) NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int(11) NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

注意一个细节:undo_log表必须和你的业务表在同一个数据库里。如果业务数据表和undo_log表分库了,本地事务就没法保证原子性了,回滚信息写入失败会直接导致整个事务失败。这个错误在日志里往往表现为"could not find undo_log",但真正含义是表不存在或者不在同一个库。

5.2 代理数据源覆盖不全:部分分支没进全局事务

接入Seata后,如果发现某个服务的操作没有纳入全局事务管理——典型表现是全局回滚了,但那个服务的数据还是变了——先检查它的数据源是不是被代理了。

很多人引入Seata后只代理了主数据源,但项目里还有读库、报表库、或者通过动态数据源切换的库没代理。分支事务执行时拿不到XID上下文,自然就不会向TC注册,也就不会参与回滚。排查方法很简单:看Seata的日志里该服务有没有打印分支注册成功的记录。

如果你的项目用了动态数据源,比如根据用户请求切换到不同数据库,需要在切换的时候手动把代理数据源也切过去,否则会漏掉。

5.3 高并发下AT模式的性能瓶颈:全局锁导致的串行化

AT模式虽然业务代码无侵入,但它的隔离机制依赖全局锁——同一个主键的同一行记录,在全局事务未结束前,其他事务如果也想改这行,就要等待。本质上,这会让原本可以并发执行的写操作变成串行。

有段时间我们的订单服务改动一条商品表记录,并发量一上来,数据库连接池直接被打满。最后定位到是商品表在多次事务里被反复更新,每改动一次商品表的行,就要持有一把全局锁直到事务结束,全链路一长,锁持有时间几十秒,吞吐量自然惨不忍睹。

解决办法有两个思路。第一是减少锁范围,让事务尽早提交,把耗时的操作尽量放到事务外面做。第二是把热点数据的更新改成异步或者分批,从设计上避免跨服务同时改一行。

5.4 二阶段提交超时引发的"幽灵回滚"

Seata的全局事务默认超时时间到了之后,TC会主动发起回滚,把还没执行完的业务中段掉。这个机制本来是保护机制,但配置不当会制造事故。

比如全局事务超时设置过短,而某个分支服务因为网络抖动慢了几秒,TC判定超时后发起回滚,而那个分支可能刚好在回滚前完成了业务操作,结果就是"业务已经执行了,但被回滚了",对用户来说表现为订单生成了又消失,对数据来说则可能出现不一致。

这种问题本地很难重现,因为它依赖于时序。我的处理经验是:全局事务超时要设为链路中最长分支耗时的两倍以上,并且对核心事务做监控告警,一旦出现超时回滚就立刻人工介入检查。

5.5 版本不匹配导致的兼容性报错

Seata客户端和服务端的版本必须一致或者兼容,否则会报各种奇奇怪怪的RPC错误。我踩过最典型的一次是服务端升级到了新版本,客户端没跟着升,结果回调接口返回异常,整个事务全部失败。

尤其是如果你用的是Spring Cloud Alibaba版本管理,要特别小心Seata版本和Spring Boot、Spring Cloud版本之间的兼容矩阵。别只图Seata最新版,先查一下你当前的Spring Boot版本是否在兼容范围里。

6. 进阶调优:事务隔离、并发参数与性能优化实录

6.1 隔离级别的取舍:读已提交还是读未提交

本地事务里我们习惯用数据库默认的隔离级别,但AT模式下的Seata对隔离级别有额外要求。默认情况下Seata要求参与全局事务的数据库的隔离级别是读已提交,不能是可重复读,否则镜像校验会失败。

原因很直接:AT模式的before image和after image是在同一个本地事务里读取的,如果隔离级别是可重复读,另一个事务在同一时间段改了数据又回滚,镜像数据可能对不上,最终导致回滚判断出错。

如果你改不了数据库隔离级别,那就只能放弃AT模式,换TCC或者自己实现补偿。这个限制我在很多项目里都遇到过,尤其是老系统用的是可重复读,接入AT模式第一轮测试就挂。

6.2 分支事务并发控制:连接池与线程池的参数调优

分布式事务比普通事务持有数据库连接的时间更长,因为它要等全局事务的最终结果。这意味着连接池的配置不能简单照搬单机应用。我的经验是把最大连接数在原基础上调高20%到30%,并且把连接池的等待超时时间适当调大,避免快速抛异常。

还有一个容易被忽略的点:Seata的RM会为每个分支事务分配一个异步回调线程,全局事务分支特别多时,线程池很容易被打满。配置线程池参数时,核心线程数建议设置为业务高峰并发数的上限,并且对队列做有界限制,否则OOM会找上门。

6.3 异步化改造:把非关键分支从全局事务中摘除

分布式事务的成本主要体现在锁的持有时间上。如果你的业务流程里有某些步骤其实"失败也可以接受",完全可以把它移出全局事务,改成异步任务或消息驱动。

我做过一次比较成功的改造:订单创建后需要发送通知、更新用户统计信息、生成推荐位内容,这三步原本都在同一个全局事务里,有一个失败整个订单就回滚。后来我把它们拆出去,通过事务消息异步执行,回滚概率降低了一大截,订单主流程的响应时间也明显缩短。

这个思路的核心判断标准是:这个分支业务和主流程是否真正需要原子性?如果不需要,就别拖累主流程。真正的分布式事务设计高手,不是把所有操作都塞进一个全局事务,而是能精准划定事务边界,把必须一致的放进事务,把可以松耦合的剥离出去。

7. 从学习到落地:一套行之有效的Seata上手路径

7.1 理论学习阶段:先把模型研究透彻

很多同学一上来就找Demo跑,跑通了就觉得会了,这是最危险的上手方式。Seata的学习路径,我建议是"先模型、后实操、再源码"。

模型层面要彻底搞清楚三个问题:全局事务ID是如何传播的;分支事务注册的时机和内容;二阶段提交和回滚的完整决策链。这些问题全部在官方架构文档里,但只读一遍记不住,我的办法是自己画一遍时序图,画完你才会发现很多细节。

然后跑一个最简单的Demo:两个服务,一个加@GlobalTransactional,两个服务分别改各自库里的表,故意让第二个服务抛异常,观察回滚后的数据状态。这个实验做一遍,比你读十篇博客都管用。

7.2 压测阶段:在本地复现生产并发问题

把Demo跑通后,别急着上生产,先做一轮并发压测。压测的目的不是看吞吐量,而是要复现前面提到的锁等待问题。

我的做法是用JHM或简单的多线程脚本,模拟50个并发请求同时操作同一行数据。观察三个指标:事务成功率、平均锁等待时间、数据库连接池使用率。如果这三个指标在压测下恶化,基本可以断定全局事务粒度设计有问题,需要在代码层面做调整。

压测过程中要把Seata的监控打开了跟踪指标。一般监控面板上可以看每类事务的提交数与回滚数。回滚比例过高往往说明业务上存在大量竞争性写操作,这时候优化业务SQL或拆分事务,比调参更有效。

7.3 灰度上线策略:新老方案并行与回滚预案

分布式事务改造是高风险变动,一定要做灰度。

我习惯的做法是保留一套老的本地事务方案作为开关,通过配置中心做动态切换。新方案让一定比例的流量逐步切过去,先切5%,观察半小时的报错率和数据一致性,没问题再继续放大比例。一旦出现数据不一致,立即切回老方案,然后用脚本修复存量数据。

这里有个很实用的技巧:灰度期间把Seata的日志级别调成DEBUG,专门收集XID的传播轨迹,线上问题定位会快很多。由于DEBUG日志量巨大,只灰度的那5%流量是可以接受的。

8. 我在实际项目里的几条深度体会

最后聊几句掏心窝子的话。

分布式事务不是银弹,哪怕是Seata这样优秀的框架,也只是把分布式事务的复杂度从业务代码层面转移到了配置和运维层面。你仍然要面对锁等待、网络超时、补偿逻辑正确性这些棘手问题。我用Seata这几年最大的体会是:真正优秀的分布式事务设计,不是让框架帮你处理一切,而是你清楚地知道哪些操作必须在一个全局事务里,哪些完全可以松耦合。事务边界的划定能力,才是分布式系统设计的核心竞争力。

如果你刚开始学,我建议你在自己的电脑上搭一个最小的三服务Demo,亲手把AT模式跑通,然后制造一个异常,观察日志里全局回滚的全过程。这个过程花不了多少时间,但收获远远超过看任何文章。Seata的源码也非常值得读,尤其是全局事务会话管理和分支事务注册器这两块,读完之后你对整个事务编排机制的理解会有一个质的飞跃。

等你把AT模式吃透了,再去看TCC和Saga,会发现它们的设计理念其实一脉相承——都是"事务拆解+补偿"思想的变体。到那个时候,你对分布式事务的畏惧感就彻底消失了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 8:30:25

从序列解读到活性初筛:21肽HLT2的多肽项目完整实操指南

拿到一个多肽项目,标题通常就一行字,比如:HLT2;H2N-VLTKVKTKVPLPTKVEVKVLV-OH。别小看这行字,它已经把序列长度、氨基酸组成、末端状态全部写明白了,后面合成、纯化、鉴定和活性实验的所有决策,…

作者头像 李华
网站建设 2026/10/21 8:30:04

AI编码质量治理:构建可拦截、可回溯的工程化防线

1. 这不是又一个“AI写代码”的热闹故事,而是工程团队正在面对的真实战场“AI Coding 质量治理”这八个字,最近在多个技术团队的周会纪要、架构评审材料和质量复盘报告里高频出现。它不是指“用AI生成几行函数然后提交”,而是当某公司内部92%…

作者头像 李华
网站建设 2026/10/21 8:29:18

深入解析 opencode:双会话与事件溯源架构

如果你跟我一样,平时写代码不习惯开一整套图形化编辑器,而是更愿意窝在终端里解决问题,那你多半已经接触过 opencode 这类 AI 编程代理。说白了,opencode 就是一个跑在终端里的智能编程助手,它把自然语言对话、代码修改…

作者头像 李华
网站建设 2026/10/21 8:29:18

opencode架构拆解:双会话内核与事件溯源实战

我最近一直在折腾终端里的 AI 编程助手,前后试过好几个,最后还是把主要精力放在了一个叫 opencode 的开源项目上。先说结论:它不是又一个套壳 CLI,而是一个把“会话”和“事件”这两个概念做到极致的 Agent 引擎。这篇上篇&#x…

作者头像 李华
网站建设 2026/10/21 8:28:36

Java档案管理系统源码拆解:基于Socket与JDBC的C/S架构实战

简介:这份基于Java的小型档案管理系统完整源码,面向高校软件工程、计算机等专业的课程实验、实训与课设,是一套综合运用C/S架构、Socket通信、多线程与关系数据库的典型项目。系统包含独立的客户端与服务器端,用户登录后按系统管理…

作者头像 李华
网站建设 2026/10/21 8:27:56

Artcraft实战:从创意到代码,构建有灵魂的生成艺术工具

1. 从“artcraft”这个名字说起:它到底想解决什么问题第一次看到“artcraft”这个标题,我脑子里蹦出来的第一反应是“艺术”加“手艺”的组合词。直觉告诉我,这不是一个纯技术向的命名,更像是在强调某种“把创意变成实物”的过程。…

作者头像 李华