SQL事务的 ACID 特性解析:深入理解SQL事务的实现原理

sql事务的acid特性包括原子性、一致性、隔离性和持久性,它们共同确保数据库在并发操作和故障恢复中保持数据完整与可靠;原子性通过撤销日志和重做日志实现全有或全无的执行;一致性依赖数据库约束和应用程序逻辑共同维护事务前后数据的有效状态;隔离性通过锁或mvcc机制防止并发事务相互干扰,sql标准定义了读未提交、读已提交、可重复读和串行化四种隔离级别,级别越高并发性能越低;持久性依靠预写式日志(wal)机制,确保事务提交后日志先于数据写入磁盘,系统崩溃后可通过重做日志恢复数据;在分布式系统中,acid面临网络延迟、节点故障和数据复制等挑战,两阶段提交虽能保证原子性但存在单点故障和阻塞问题,强隔离性难以实现,持久性受复制策略影响,需在一致性、可用性和分区容错性之间权衡,因此许多分布式系统采用最终一致性模型以提升可扩展性和性能。

SQL事务的 ACID 特性解析:深入理解SQL事务的实现原理

SQL事务的ACID特性是数据库管理系统(DBMS)确保数据完整性和可靠性的基石,它们分别是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。理解这些特性,就是理解数据库在处理并发操作和故障时如何保障数据不被破坏、不产生混乱的核心原理。在我看来,它们不只是一堆理论概念,更是构建任何健壮数据应用时必须遵守的“契约”。

解决方案

要深入理解SQL事务的实现原理,我们得逐一拆解ACID这四个字母,看看它们各自承担了什么责任,以及数据库系统为了实现它们都做了哪些“幕后工作”。

原子性(Atomicity)说白了,原子性就是“全有或全无”。一个事务要么完全成功执行,所有操作都持久化到数据库中;要么完全失败,所有操作都回滚到事务开始前的状态,就像这个事务从未发生过一样。中间状态是不允许存在的。数据库实现原子性,通常依赖于一种叫做“日志”的机制,具体来说是“撤销日志”(Undo Log)和“重做日志”(Redo Log)的结合,或者更广义的“预写式日志”(Write-Ahead Logging, WAL)。当事务开始时,任何对数据的修改都会先记录到日志中。如果事务成功提交,这些日志会帮助确保数据最终写入磁盘。如果事务意外终止或被回滚,撤销日志就能派上用场,它记录了数据修改前的状态,可以用来撤销所有未提交的修改,将数据恢复到事务开始时的样子。这就像你写一份重要的文档,每次修改都先在草稿纸上记下原内容,万一写错了,可以根据草稿纸恢复。

一致性(Consistency)一致性确保事务执行前后,数据库从一个有效状态转移到另一个有效状态。这里的一致性,不仅仅是数据类型匹配、外键约束满足那么简单,它还包括了所有预定义的业务规则和完整性约束。比如,一个转账事务,从A账户扣钱,给B账户加钱,那么事务结束后,A和B的总金额必须保持不变(假设没有手续费)。数据库系统通过强制执行所有定义的约束(如唯一性约束、外键约束、检查约束等)来维护一致性。更深层次的,应用程序的业务逻辑也必须保证数据的一致性。可以说,一致性是ACID中唯一一个既依赖数据库本身,又高度依赖应用程序设计的部分。数据库提供了工具和环境,但最终的一致性保障,还需要业务逻辑的配合。

隔离性(Isolation)隔离性意味着多个并发执行的事务,彼此之间互不干扰,就好像它们是串行执行的一样。这在多用户、高并发的数据库环境中至关重要。如果没有隔离性,一个事务可能读取到另一个未提交事务的“脏数据”,或者两个事务互相影响,导致数据混乱。实现隔离性是数据库设计中最复杂的部分之一。常见的技术包括锁(Locking)和多版本并发控制(Multi-Version Concurrency Control, MVCC)。锁机制通过限制对数据的并发访问来保证隔离性,但可能导致死锁和性能瓶颈。MVCC则更聪明,它允许读操作不阻塞写操作,写操作也不阻塞读操作,通过为每个事务提供一个数据的“快照”来实现并发。这就像图书馆里,每个人都可以拿到一份书的复印件来阅读,互不影响,只有真正修改书的人才需要排队。

持久性(Durability)持久性保证一旦事务提交,其所做的修改就会永久保存到数据库中,即使系统崩溃、断电,数据也不会丢失。这是对用户最重要的承诺之一。实现持久性,数据库通常也依赖于日志机制,特别是“重做日志”(Redo Log)和“预写式日志”(WAL)。当事务提交时,数据库会确保所有相关的重做日志记录都已写入到稳定的存储介质(如磁盘)上。即使数据页本身还没来得及从内存刷到磁盘,但只要重做日志已经写入,系统在重启后就可以通过重放(replay)这些日志来恢复数据到提交时的状态。此外,一些数据库还会使用“双写缓冲区”(Double Write Buffer)等技术来进一步保障数据页写入的原子性,防止部分写失败。

SQL事务隔离级别有哪些?它们如何影响并发性能?

SQL标准定义了四种隔离级别,从低到高,它们在数据一致性和并发性能之间做出了不同的权衡。理解这些级别,对于优化数据库应用至关重要,因为选择不当可能导致数据问题或性能瓶颈。

读未提交 (Read Uncommitted)

特点: 最低的隔离级别。一个事务可以读取到另一个未提交事务的数据。可能出现的问题:脏读 (Dirty Read): 读取到另一个事务尚未提交的数据。如果那个事务最终回滚,那么你读到的数据就是“脏”的,是无效的。性能: 并发性能最高,因为几乎不加锁,或者只加非常短暂的锁。应用场景: 极少使用,除非对数据准确性要求极低,或者在数据仓库中进行大规模的、不要求精确结果的统计分析。

读已提交 (Read Committed)

特点: 一个事务只能读取到已经提交的数据。这是许多数据库(如PostgreSQL、Oracle)的默认隔离级别。解决的问题: 避免了脏读。可能出现的问题:不可重复读 (Non-Repeatable Read): 在同一个事务中,两次读取同一行数据,结果可能不同。因为在第一次读取之后、第二次读取之前,另一个事务修改并提交了这行数据。性能: 较好的并发性能,是实际应用中常用的折衷选择。实现: 通常通过行级锁(在写操作时)或MVCC(在读操作时)实现。

可重复读 (Repeatable Read)

特点: 确保在同一个事务中,多次读取同一行数据的结果始终一致。这是MySQL InnoDB存储引擎的默认隔离级别。解决的问题: 避免了脏读和不可重复读。可能出现的问题:幻读 (Phantom Read): 在同一个事务中,两次执行相同的查询,第二次查询结果集中的行数比第一次多或少。这是因为在两次查询之间,另一个事务插入或删除了符合查询条件的新行,并提交了。性能: 并发性能有所下降,因为需要更严格的锁定或更复杂的MVCC机制来维护事务内的数据快照。实现: 通常通过MVCC(提供事务开始时的数据快照)和/或间隙锁(Gap Locks,防止新行插入)来实现。

串行化 (Serializable)

特点: 最高的隔离级别。所有事务都像串行执行一样,彼此完全隔离。解决的问题: 避免了脏读、不可重复读和幻读。性能: 并发性能最低,因为通常通过对读取的数据也加锁来实现,导致大量的锁竞争。应用场景: 对数据一致性要求极高,且并发量不大的场景,或者在需要严格审计的金融系统中。

如何影响并发性能?隔离级别越高,数据库为了保证数据的一致性所需付出的代价就越大,通常表现为:

锁粒度更粗或锁持有时间更长: 导致更多的锁等待,降低并发度。MVCC版本链更长或快照管理更复杂: 增加内存和CPU开销。死锁风险增加: 尤其是在高隔离级别下,事务间相互等待资源的概率上升。

因此,在实际开发中,我们通常会选择满足业务需求最低的隔离级别,以平衡数据一致性和系统性能。我个人倾向于在大多数OLTP(联机事务处理)应用中选择“读已提交”或“可重复读”,它们在性能和数据完整性之间提供了一个不错的平衡点。

数据库如何确保事务的持久性?深入探讨日志机制

事务的持久性是数据库系统给用户的核心承诺之一:一旦我提交了,数据就绝不会丢。这背后,日志机制扮演了绝对的主角,尤其是“预写式日志”(Write-Ahead Logging, WAL)原则。

WAL的核心思想很简单:任何数据页的修改,都必须先将对应的日志记录写入到稳定的存储介质(通常是磁盘)上,然后才能将修改后的数据页写入磁盘。这就像是,你不能直接在最终的账本上涂改,必须先在草稿本上写下“我改了什么,原值是什么,新值是什么”,并且确保草稿本上的记录是稳妥的,然后才能去改账本。

钉钉 AI 助理 钉钉 AI 助理

钉钉AI助理汇集了钉钉AI产品能力,帮助企业迈入智能新时代。

钉钉 AI 助理 21 查看详情 钉钉 AI 助理

具体来说,数据库系统会维护几种类型的日志:

重做日志(Redo Log)

作用: 记录了对数据所做的所有修改操作。比如,“将表

users

id=1

name

字段从

'OldName'

改为

'NewName'

”。这些日志记录是幂等的,意味着可以重复应用。工作原理:当事务修改数据时,首先会将修改内容写入到内存中的日志缓冲区(Log Buffer)。事务提交时,数据库会强制将日志缓冲区中与该事务相关的所有重做日志记录刷写(flush)到磁盘上的重做日志文件(Redo Log File)。这一步是确保持久性的关键。即使此时数据页本身还在内存中,没有写入磁盘,但只要日志写入成功,系统就认为事务已提交。如果系统在数据页写入磁盘前崩溃,重启后,数据库的恢复管理器会扫描重做日志文件,并重放(replay)所有已提交但尚未写入磁盘的修改,从而恢复数据到崩溃前的状态。

撤销日志(Undo Log)

作用: 记录了数据被修改前的旧版本信息。它主要是为了实现事务的原子性和隔离性。工作原理:当事务修改数据时,旧的数据版本会被记录到撤销日志中。如果事务需要回滚(Rollback),数据库会读取撤销日志,利用其中的旧版本信息来撤销所有未提交的修改,将数据恢复到事务开始时的状态。在MVCC中,撤销日志也扮演了重要角色,它存储了不同版本的数据,使得并发的读事务可以读取到它们自己事务开始时的“快照”数据,而不会被写事务阻塞。

日志刷盘的策略与检查点(Checkpoint)

为了平衡性能和持久性,数据库并不会每次修改都立即将所有日志和数据页刷到磁盘。

日志刷盘: 通常,日志缓冲区会周期性地刷到磁盘,或者在日志缓冲区满时,或者在事务提交时(最重要),或者在数据库关闭时。检查点(Checkpoint): 这是一个非常重要的机制。数据库会定期执行检查点操作,它会将内存中已修改的数据页(脏页)强制刷写到磁盘,并更新重做日志文件中的一个指针,表明在这个检查点之前的日志记录所代表的数据都已经安全地写入了磁盘。这样做的好处是,在系统崩溃恢复时,数据库不需要从重做日志的开头开始重放,只需要从最后一个检查点之后开始处理,大大缩短了恢复时间。

双写缓冲区(Double Write Buffer)

这是一个额外的持久性保障机制,尤其在某些数据库(如MySQL InnoDB)中。当数据页从内存写入磁盘时,如果发生部分写失败(例如,操作系统或硬件崩溃导致只写入了一半的数据),那么这个数据页就损坏了。双写缓冲区的工作方式是,在数据页真正写入到数据文件之前,它会先写入到一个独立的、连续的“双写缓冲区”区域。成功写入双写缓冲区后,再写入到最终的数据文件。如果发生部分写失败,数据库可以从双写缓冲区中恢复出完整的数据页,避免数据损坏。这有点像先在备用本上完整地抄一遍,确保抄好了,再正式誊写到账本上。

通过这些精巧的日志记录和恢复机制,数据库才能在面对各种突发情况时,依然能兑现其对数据持久性的承诺。

在分布式系统中,ACID特性面临哪些挑战?

当数据库不再是单机运行,而是扩展到多个节点、多台服务器构成的分布式环境时,原本在单机环境下相对容易实现的ACID特性,会突然变得异常复杂,甚至在某些方面不得不做出妥协。这就像你管理一家小店,所有东西都在一个屋檐下,协调起来很简单;但如果你开了多家连锁店,分布在不同城市,要让所有店的数据实时同步、保持一致,那挑战就大了。

最大的挑战来源于网络通信的不可靠性和延迟,以及各个节点可能独立失效的现实。

原子性与一致性:分布式事务的困境在单机数据库中,原子性和一致性相对容易实现,因为所有操作都在同一个事务管理器下。但在分布式系统中,一个逻辑上的事务可能需要跨越多个数据库节点来完成。例如,一个跨银行的转账,可能涉及到A银行的数据库和B银行的数据库。

两阶段提交(Two-Phase Commit, 2PC): 这是最常见的分布式事务解决方案,用于保证分布式环境下的原子性。它分为“准备阶段”(Prepare Phase)和“提交阶段”(Commit Phase)。协调者向所有参与者发送准备请求,参与者如果准备好了就回应“Yes”,否则回应“No”。所有参与者都回应“Yes”后,协调者才发送提交请求;只要有一个参与者回应“No”,或者超时未回应,协调者就发送回滚请求。2PC的挑战:单点故障: 协调者如果崩溃,可能导致部分参与者处于不确定状态(in-doubt),需要人工干预或复杂的恢复机制。同步阻塞: 参与者在准备阶段会锁定资源,直到收到提交或回滚指令。这可能导致长时间的阻塞,严重影响系统吞吐量和可用性。网络延迟: 跨网络的消息传递增加了延迟,使得整个事务的响应时间变长。正因为这些固有的缺陷,2PC在实际大规模高并发分布式系统中很少被直接使用,或者只用于对强一致性要求极高、且事务量不大的场景。

隔离性:跨节点锁和MVCC的复杂性在分布式环境中实现强隔离性(如串行化)几乎是不可行的,因为它意味着需要在所有相关节点上加锁,并协调这些锁。这会带来巨大的性能开销和死锁风险。

分布式锁: 需要一个独立的分布式锁服务(如ZooKeeper、Redis等)来协调跨节点的资源访问,但这增加了系统的复杂性,且本身也存在一致性挑战。分布式MVCC: 比单机MVCC复杂得多,需要协调不同节点上的版本号,确保全局的事务顺序。这通常意味着更高的网络开销和更复杂的实现逻辑。实际中,很多分布式数据库系统会放宽隔离性,例如,允许“读已提交”甚至更低的隔离级别,以换取更高的并发性。

持久性:数据复制与一致性问题在分布式系统中,为了高可用性,数据通常会进行多副本复制。这带来了新的持久性挑战:

数据同步: 如何确保一个事务提交后,其修改能可靠地同步到所有副本?是同步复制(写操作必须等待所有副本确认)还是异步复制(写操作不等待所有副本确认)?同步复制提供了更强的持久性保证,但延迟高;异步复制性能好,但可能在主节点崩溃时丢失少量数据。副本一致性: 在网络分区(Network Partition)发生时,不同节点上的数据副本可能会出现不一致。这就是著名的CAP定理所描述的困境:在分布式系统中,你不可能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition Tolerance)。你必须在这三者之间做出选择和权衡。

总结在分布式世界里,完全实现单机数据库那样的强ACID特性,往往意味着巨大的性能牺牲和系统复杂性。因此,许多现代分布式系统和NoSQL数据库会选择牺牲部分ACID特性,转而采用“最终一致性”(Eventual Consistency)模型,或者提供更弱的隔离级别,以换取更高的可用性和可伸缩性。这并不是说ACID不重要了,而是说在分布式环境下,我们需要更灵活、更务实地去思考如何平衡这些特性,找到最适合业务场景的解决方案。这往往需要架构师和开发者在设计之初就做出明确的取舍。

以上就是SQL事务的 ACID 特性解析:深入理解SQL事务的实现原理的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/598247.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月10日 19:14:59
下一篇 2025年11月10日 19:16:13

相关推荐

  • Uniapp 中如何不拉伸不裁剪地展示图片?

    灵活展示图片:如何不拉伸不裁剪 在界面设计中,常常需要以原尺寸展示用户上传的图片。本文将介绍一种在 uniapp 框架中实现该功能的简单方法。 对于不同尺寸的图片,可以采用以下处理方式: 极端宽高比:撑满屏幕宽度或高度,再等比缩放居中。非极端宽高比:居中显示,若能撑满则撑满。 然而,如果需要不拉伸不…

    2025年12月24日
    400
  • 如何让小说网站控制台显示乱码,同时网页内容正常显示?

    如何在不影响用户界面的情况下实现控制台乱码? 当在小说网站上下载小说时,大家可能会遇到一个问题:网站上的文本在网页内正常显示,但是在控制台中却是乱码。如何实现此类操作,从而在不影响用户界面(UI)的情况下保持控制台乱码呢? 答案在于使用自定义字体。网站可以通过在服务器端配置自定义字体,并通过在客户端…

    2025年12月24日
    800
  • 如何在地图上轻松创建气泡信息框?

    地图上气泡信息框的巧妙生成 地图上气泡信息框是一种常用的交互功能,它简便易用,能够为用户提供额外信息。本文将探讨如何借助地图库的功能轻松创建这一功能。 利用地图库的原生功能 大多数地图库,如高德地图,都提供了现成的信息窗体和右键菜单功能。这些功能可以通过以下途径实现: 高德地图 JS API 参考文…

    2025年12月24日
    400
  • 如何使用 scroll-behavior 属性实现元素scrollLeft变化时的平滑动画?

    如何实现元素scrollleft变化时的平滑动画效果? 在许多网页应用中,滚动容器的水平滚动条(scrollleft)需要频繁使用。为了让滚动动作更加自然,你希望给scrollleft的变化添加动画效果。 解决方案:scroll-behavior 属性 要实现scrollleft变化时的平滑动画效果…

    2025年12月24日
    000
  • 如何为滚动元素添加平滑过渡,使滚动条滑动时更自然流畅?

    给滚动元素平滑过渡 如何在滚动条属性(scrollleft)发生改变时为元素添加平滑的过渡效果? 解决方案:scroll-behavior 属性 为滚动容器设置 scroll-behavior 属性可以实现平滑滚动。 html 代码: click the button to slide right!…

    2025年12月24日
    500
  • 如何选择元素个数不固定的指定类名子元素?

    灵活选择元素个数不固定的指定类名子元素 在网页布局中,有时需要选择特定类名的子元素,但这些元素的数量并不固定。例如,下面这段 html 代码中,activebar 和 item 元素的数量均不固定: *n *n 如果需要选择第一个 item元素,可以使用 css 选择器 :nth-child()。该…

    2025年12月24日
    200
  • 使用 SVG 如何实现自定义宽度、间距和半径的虚线边框?

    使用 svg 实现自定义虚线边框 如何实现一个具有自定义宽度、间距和半径的虚线边框是一个常见的前端开发问题。传统的解决方案通常涉及使用 border-image 引入切片图片,但是这种方法存在引入外部资源、性能低下的缺点。 为了避免上述问题,可以使用 svg(可缩放矢量图形)来创建纯代码实现。一种方…

    2025年12月24日
    100
  • 如何让“元素跟随文本高度,而不是撑高父容器?

    如何让 元素跟随文本高度,而不是撑高父容器 在页面布局中,经常遇到父容器高度被子元素撑开的问题。在图例所示的案例中,父容器被较高的图片撑开,而文本的高度没有被考虑。本问答将提供纯css解决方案,让图片跟随文本高度,确保父容器的高度不会被图片影响。 解决方法 为了解决这个问题,需要将图片从文档流中脱离…

    2025年12月24日
    000
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 如何利用 CSS 选中激活标签并影响相邻元素的样式?

    如何利用 css 选中激活标签并影响相邻元素? 为了实现激活标签影响相邻元素的样式需求,可以通过 :has 选择器来实现。以下是如何具体操作: 对于激活标签相邻后的元素,可以在 css 中使用以下代码进行设置: li:has(+li.active) { border-radius: 0 0 10px…

    2025年12月24日
    100
  • 如何模拟Windows 10 设置界面中的鼠标悬浮放大效果?

    win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…

    2025年12月24日
    200
  • 为什么我的 Safari 自定义样式表在百度页面上失效了?

    为什么在 Safari 中自定义样式表未能正常工作? 在 Safari 的偏好设置中设置自定义样式表后,您对其进行测试却发现效果不同。在您自己的网页中,样式有效,而在百度页面中却失效。 造成这种情况的原因是,第一个访问的项目使用了文件协议,可以访问本地目录中的图片文件。而第二个访问的百度使用了 ht…

    2025年12月24日
    000
  • 如何用前端实现 Windows 10 设置界面的鼠标移动探照灯效果?

    如何在前端实现 Windows 10 设置界面中的鼠标移动探照灯效果 想要在前端开发中实现 Windows 10 设置界面中类似的鼠标移动探照灯效果,可以通过以下途径: CSS 解决方案 DEMO 1: Windows 10 网格悬停效果:https://codepen.io/tr4553r7/pe…

    2025年12月24日
    000
  • 使用CSS mask属性指定图片URL时,为什么浏览器无法加载图片?

    css mask属性未能加载图片的解决方法 使用css mask属性指定图片url时,如示例中所示: mask: url(“https://api.iconify.design/mdi:apple-icloud.svg”) center / contain no-repeat; 但是,在网络面板中却…

    2025年12月24日
    000
  • 如何用CSS Paint API为网页元素添加时尚的斑马线边框?

    为元素添加时尚的斑马线边框 在网页设计中,有时我们需要添加时尚的边框来提升元素的视觉效果。其中,斑马线边框是一种既醒目又别致的设计元素。 实现斜向斑马线边框 要实现斜向斑马线间隔圆环,我们可以使用css paint api。该api提供了强大的功能,可以让我们在元素上绘制复杂的图形。 立即学习“前端…

    2025年12月24日
    000
  • 图片如何不撑高父容器?

    如何让图片不撑高父容器? 当父容器包含不同高度的子元素时,父容器的高度通常会被最高元素撑开。如果你希望父容器的高度由文本内容撑开,避免图片对其产生影响,可以通过以下 css 解决方法: 绝对定位元素: .child-image { position: absolute; top: 0; left: …

    2025年12月24日
    000
  • CSS 帮助

    我正在尝试将文本附加到棕色框的左侧。我不能。我不知道代码有什么问题。请帮助我。 css .hero { position: relative; bottom: 80px; display: flex; justify-content: left; align-items: start; color:…

    2025年12月24日 好文分享
    200
  • 前端代码辅助工具:如何选择最可靠的AI工具?

    前端代码辅助工具:可靠性探讨 对于前端工程师来说,在HTML、CSS和JavaScript开发中借助AI工具是司空见惯的事情。然而,并非所有工具都能提供同等的可靠性。 个性化需求 关于哪个AI工具最可靠,这个问题没有一刀切的答案。每个人的使用习惯和项目需求各不相同。以下是一些影响选择的重要因素: 立…

    2025年12月24日
    300
  • 如何用 CSS Paint API 实现倾斜的斑马线间隔圆环?

    实现斑马线边框样式:探究 css paint api 本文将探究如何使用 css paint api 实现倾斜的斑马线间隔圆环。 问题: 给定一个有多个圆圈组成的斑马线图案,如何使用 css 实现倾斜的斑马线间隔圆环? 答案: 立即学习“前端免费学习笔记(深入)”; 使用 css paint api…

    2025年12月24日
    000
  • 如何使用CSS Paint API实现倾斜斑马线间隔圆环边框?

    css实现斑马线边框样式 想定制一个带有倾斜斑马线间隔圆环的边框?现在使用css paint api,定制任何样式都轻而易举。 css paint api 这是一个新的css特性,允许开发人员创建自定义形状和图案,其中包括斑马线样式。 立即学习“前端免费学习笔记(深入)”; 实现倾斜斑马线间隔圆环 …

    2025年12月24日
    100

发表回复

登录后才能评论
关注微信