系统整容纪:用知识来“武装“自己~认识MySQL的锁与事务

作者:京东物流 张小龙

本文通过介绍在实际工作中一次异常排查引发的自我思考与学习,来使得读者受到一定的启发,从而迸发出星星点光,扩展出自己独有的思路,进而在工作中不断的挖掘自我不足之处,同时通过学习与"锻炼"来不断地强大自己。

分享工作中的点点滴滴,贯彻千里之行,始于足下,最终以微不足道的量变引起化蝶的质变精神。以自己为例拒绝在舒适的中央区域安逸的躺着,以便在不知不觉中被社会所淘汰,也不盲目的直接跃迁进困哪区域,在受挫的同时又跌回原有的舒适区域内,造成这样一个浑浑噩噩的让人无法进步的循环怪圈内,保持在舒适边缘的拉伸区,既跳出了舒适区又具有一定的挑战性,使得自己在保持快速进步的同时还能够渐渐树立起自信心,可谓是一举多得,系统的维护改造也是如此道理。如果大家觉得有用,欢迎大家点赞、收藏+关注,哇咔咔😀!

引子

记得那是一个令我印象深刻的周五,那天我湿身了😀,所以印象比较深刻。

系统上线生命周期

需求精研除疑点,上线交付兑诺言。

​方案众评防走偏,编码低保倚规范。

​性能高开凭手段,保量保质不留憾。

​测方以身化利剑,企稳快挥斩漏点。

​功成莫急奔前线,回首剥丝慎查验。

​严谨慎行铺试点,八方云集宏图展。

​待得完验曙光现,成果之命交由天。

​用户口碑传九天,皆大欢喜乐欢颜。

好了,闲话少说,咱们回归正题。😀

那天的雨比较大,风也很大,同时不小心淋雨了,这是比较少有的事情

那天在翻看实操系统的异常日志的时候有这么一个异常日志引起了我的注意:

在这里插入图片描述

而这个的来源居然只是一个普通的select语句

在这里插入图片描述

然后我就尝试的搜索了下当天所有机器报这个错的日志情况,结果是虽然不是很多,但是确实有一批这种异常,而由于traceId的便捷性,很快我便一一确认了下所有报此异常的场景来源,都是同一个场景:内配接单。那么接下来就是要抓取出来关键数据来分析为什么会报事务超时的异常了,为了避免业务的敏感性,以下所有sql均非真实sql,而是采用跟原有sql一致的"虚拟sql"。

以上就是整个时间的起因了,而要弄明白问题的根因则少不了MySQL的一些基本知识,所以在分析问题之前,先来普及一波MySQL基础知识😀。

嘿嘿,这里即兴插入一个小知识问答:假设有个业务要调一些service方法,其中涉及到X表字段a属性值的更新,假设要更新为5,而执行如下代码时当执行service2.doTwo()方法报错被catch住的情况发生时,等整个业务处理方法businessService()执行完后,字段a属性的值应该是多少,日志中又是什么现象,嘿嘿,这个结果可是很有趣的吆

public void changeA() {
        //select a from table,此时a= 1
        businessService();
        //select a from table,此时a= ?
    }

    @Transactional
    public void businessService() {

        //有@Transactional
        service1.doOne();
        //无@Transactional
        service2.doTwo();
        //有@Transactional
        service3.doThree();
    }
    //假设此就是service2.doTwo方法
    public void doTwo() {
        try{
            //...
        }catch (Exception e){
            log.error("XX执行系统异常",e);
        }
    }

一、MySQL的锁

相信大家对于锁并不陌生吧,直白点来讲,锁是一种保护临界资源的机制,就好比如找对象,常规上来讲是一对、两个人,如果分手了那就换人,总归来说不应该出现超过两个人同时一起谈的场景😀(哈哈,常规模式哈,勿多想)。那理解了锁的简单概念后,我们来看看MySQL中的锁是什么样的。

以下所讲皆是基于innodb引擎

从占有模式上来讲,MySQL有共享锁(S:Share Lock)和排他锁(X:Exclusive Lock),顾名思义,共享锁之间可以共享、排他锁只能自己独占,两者的兼容关系如下

XS
X不兼容不兼容
S不兼容兼容

比如我们可以用这种方式加共享锁,sql如下:

SELECT * FROM table WHERE id = 3 LOCK IN SHARE MODE;

而对于插入 INSERT、更新 UPDATE、删除 DELETE 以及显式带 FOR UPDATE 关键字的 SELECT 操作,则会加上排他锁,sql如下:

SELECT * FROM table WHERE id = 3 FOR UPDATE;

INSERT INTO table (id,name) VALUES (3,‘3’);

UPDATE table SET name= ‘3’ WHERE id = 3;

DELETE FROM table WHERE id = 3;

锁的类型

行锁 Record Lock

行锁是数据库管理中的一种细粒度锁,它专门用于锁定数据库中的单独记录。在行锁的机制中,我们通常区分为两种类型:共享锁和独占锁。例如,在操作数据库时,我们可以使用以下SQL命令来请求不同类型的行锁:

当我们希望对特定记录进行独占锁定以执行更新操作时,可以使用如下命令:

SELECT * FROM 表名 WHERE id = 3 FOR UPDATE;

若我们需要一个共享锁,使得多个事务可以同时读取同一记录,但不能进行修改,可以使用如下命令:

SELECT * FROM 表名 WHERE id = 3 LOCK IN SHARE MODE;

需要特别指出的是,行锁的实际生效与否,很大程度上取决于SQL语句是否利用到了索引。如果查询条件没有触及到现有的索引,系统可能会将锁的级别从行锁提升到表锁,这会影响数据库的并发性能。

在InnoDB存储引擎中,表的结构高度依赖于主键索引,即一级索引。因此,当通过非主键索引对记录实施行锁时,不仅会锁定该索引,还会同时对应记录的主键进行锁定。这一点对数据库操作的性能和锁冲突的可能性有重要影响,因此在设计和优化数据库系统时,应充分考虑索引策略。

间隙锁 Gap Lock

MySQL的间隙锁是InnoDB存储引擎的一种锁机制,是一种范围锁定,它锁定一个范围内的空间,但不包括记录本身,是为了解决并发事务中的幻读问题而设计的。

幻读是指当一个事务在读取某个范围内的记录时,另一个事务在这个范围内插入了新的记录,导致前一个事务再次读取时会看到之前不存在的记录。

InnoDB存储引擎使用多版本并发控制(MVCC)机制来提供高并发性能,并使用锁定来维护事务的隔离级别。在可重复读(REPEATABLE READ)和串行化(SERIALIZABLE)隔离级别下,InnoDB会使用间隙锁来防止幻读。

当一个事务执行范围查询并进行更新或删除操作时,为了保证隔离性,InnoDB会对查询范围内的索引记录和索引记录之间的间隙设置锁定。例如,如果有一个索引包含值1, 2, 4,事务在查询大于2小于4的记录时,会锁定2和4之间的间隙。

间隙锁的类型

  1. 共享间隙锁(Shared Gap Lock):允许其他事务读取间隙,但不允许插入。

  2. 排他间隙锁(Exclusive Gap Lock):不允许其他事务读取或插入间隙。

举例说明

考虑以下索引记录:

… | 1 | 3 | 5 | 7 | …

如果事务A想要插入值为4的记录,它需要检查是否存在介于3和5之间的间隙锁。如果事务B已经在这个间隙上设置了间隙锁,那么事务A必须等待,直到事务B提交或回滚,才能插入记录。

间隙锁的图示

| 1 |----间隙锁----| 3 |----间隙锁----| 5 |----间隙锁----| 7 |

在这个图示中,每个"----间隙锁----"代表一个间隙锁区域。事务如果需要在这些区域插入新的记录,必须等待持有间隙锁的事务结束。

注意事项

•间隙锁通常只在可重复读或更高的隔离级别下使用。

•间隙锁可能会增加锁争用,因此可能对性能产生影响。

•在读已提交(READ COMMITTED)隔离级别下,InnoDB不会使用间隙锁来防止幻读,而是使用其他机制,如Next-Key锁或MVCC。

临键锁 Next-Key Lock

MySQL的临键锁是InnoDB存储引擎为了实现可重复读(REPEATABLE READ)隔离级别而设计的一种锁机制。临键锁是行锁与间隙锁的组合,它不仅锁定一条记录,同时也锁定了该记录之前到下一条记录之间的间隙。

在InnoDB中,所有的数据都是按照主键顺序存放在B+树中的。每个索引记录不仅包含键值,还包含了指向实际数据行的指针。当InnoDB对数据行进行搜索时,它会使用B+树的搜索算法。

  1. 行锁(Record Lock):行锁是直接作用于索引记录上的锁。当InnoDB对某个索引记录加锁时,它实际上是在该记录的索引项上加了锁。

  2. 间隙锁(Gap Lock):间隙锁是锁定一个范围,但不包括记录本身。它用于防止其他事务插入“间隙”范围内的值,这样可以避免幻读(Phantom Read)的问题。

  3. 临键锁(Next-Key Lock):结合了行锁和间隙锁,它锁定一个范围,并且包括了范围的起始记录。在可重复读隔离级别下,InnoDB默认会对查询到的索引记录使用临键锁。

假设有以下索引结构,简化为一维的B+树:

±–±–±–±–±–±–+

| 5 | 10| 15| 20| 25| 30|

±–±–±–±–±–±–+

如果事务A执行一个范围查询语句(比如:SELECT * FROM table WHERE key > 10 AND key < 20 FOR UPDATE;),InnoDB会对键值在10到20之间的记录加上临键锁。

图示如下:

±–±----±–±----±–±–+

| 5 | 10 | 15| 20 | 25| 30|

±–±----±–±----±–±–+

^^^^^| |^^^^^

间隙锁 行锁 间隙锁

在这个例子中,事务A会对键值为15的记录加上行锁,并对10到15以及15到20的间隙加上间隙锁。这意味着其他事务不能插入、删除或修改键值在10到20之间的任何记录。

临键锁的影响

  1. 防止幻读:临键锁可以有效防止幻读的出现,因为它锁定了查询范围内的记录和间隙。

  2. 并发性能:由于临键锁锁定了间隙,它可能会降低数据库的并发性能,特别是在大量范围查询和更新的场景下。

  3. 死锁:临键锁可能会增加死锁的出现概率,因为它锁定了更多的资源。

表锁 Table Lock

MySQL中的表锁是一种锁机制,用于控制多个并发事务对数据库表进行访问时的同步。表锁是锁定整个表的一种简单的锁策略,相对于行级锁来说,表锁的粒度较大,开销较小,加锁快,但并发程度较低。表锁适用于读多写少的场景,因为它不适合高并发的写操作。

表锁的类型:

  1. 读锁(共享锁):

多个事务可以同时获得同一张表的读锁。

加读锁的事务可以读表,但不能写表。

其他事务可以读表,但不能写表。

  1. 写锁(排他锁):

只有一个事务可以获得写锁。

加写锁的事务可以读写表。

其他事务既不能读也不能写。

加锁和释放锁的基本流程如下:

  1. 加读锁(LOCK TABLES table_name READ):

检查是否有写锁存在。

如果没有写锁,加读锁成功。

如果有写锁,等待写锁释放。

  1. 加写锁(LOCK TABLES table_name WRITE):

检查是否有其他读锁或写锁存在。

如果没有其他锁,加写锁成功。

如果有其他锁,等待所有锁释放。

  1. 释放锁(UNLOCK TABLES):

释放当前事务持有的所有锁。

允许其他在等待队列中的事务尝试加锁。

表锁的优缺点:

优点:

•实现简单,开销较小,加锁快。

•在查询为主的应用场景下,可以提高系统的吞吐量。

缺点:

•并发能力差,尤其是写操作较多时,会成为瓶颈。

•不能精细控制并发操作,容易产生锁争用。

•如果事务持有锁的时间过长,会导致其他事务长时间等待。

意向锁 Intention Lock

MySQL的意向锁是InnoDB存储引擎实现多粒度锁定(Multiple Granularity Locking, MGL)的一部分,它用于表明事务在某一数据行上请求的锁定类型。意向锁是表级锁,分为两种:

  1. 意向共享锁(Intention Shared Lock, IS锁):表明事务想要在某些行上设置共享锁(S锁)。

  2. 意向排他锁(Intention Exclusive Lock, IX锁):表明事务想要在某些行上设置排他锁(X锁)。

意向锁的实现原理是基于两个主要目的:

允许锁定系统在不检查所有行锁的情况下快速判断是否可以获取表级锁。

提供一种机制来表明事务对行锁的意图,从而避免不必要的锁冲突检查。

通俗讲:意向锁是一种设计用来优化粗粒度锁性能的机制。它通过在实际请求锁定特定资源之前,先对其上层更大范围的资源表达锁定的意图,从而进行预先声明。这种做法有助于提高不同层级锁资源间的协作效率和整体性能。

意向锁的规则如下:

•在对任何行请求共享锁之前,事务必须先获得对应表的IS锁或更强的锁。

•在对任何行请求排他锁之前,事务必须先获得对应表的IX锁。

•如果事务已经持有了对应表的IS或IX锁,它可以请求更多的行锁而无需再次获取表锁。

•其它事务可以同时对表加IS锁,但是IX锁是不兼容的。

•行锁与表上的意向锁是兼容的,例如,一个事务可以对表加IS锁并对一行加X锁。

意向锁的锁兼容矩阵如下:

XIXSIS
X不兼容不兼容不兼容不兼容
IX不兼容兼容不兼容兼容
S不兼容不兼容兼容兼容
IS不兼容兼容兼容兼容

以下是一个意向锁的使用示例,展示了事务如何使用意向锁来获取行锁:

  1. 事务A想要读取表T中的一些行,它首先请求并获得表T的IS锁。

  2. 事务A随后在需要的行上设置共享锁(S锁)。

  3. 同时,事务B想要更新表T中的某些不同的行,它首先请求并获得表T的IX锁。

  4. 事务B随后在需要更新的行上设置排他锁(X锁)。

由于事务A和事务B操作的是不同的行,它们在表级别的意向锁(IS和IX)是兼容的。这样,两个事务可以同时在不同的行上进行操作,提高了并发性能。

死锁

MySQL中的死锁是指多个事务在执行过程中因争夺资源而造成的一种相互等待的现象,每个事务都在等待其他事务释放资源,如果没有外力干涉,这些事务都无法向前推进,形成了一个闭环的等待链条。

例如,事务A已经锁定了资源R1,同时试图锁定资源R2;而事务B已经锁定了资源R2,同时试图锁定资源R1。这时,A等待B释放R2,B等待A释放R1,双方都不愿意让步,就形成了死锁。

死锁的检测与解决

MySQL通过死锁检测算法来处理死锁问题。当事务请求的资源被另一个事务持有,并且发现等待链条中存在循环时,检测算法就会触发。MySQL有两种方式解决死锁:

  1. 等待超时:在innodb_lock_wait_timeout设置的时间之后,如果事务还未能获取所需资源,则会被自动回滚。

  2. 死锁检测和解除:InnoDB存储引擎会动态地检测死锁,并自动选择并回滚死锁链中的某个事务,以解除死锁状态。

下面是一个简单的死锁图示:

事务A 事务B

| |

|----> 锁定资源R1

| |

| |----> 锁定资源R2

| |

|----> 请求资源R2

| |

| |----> 请求资源R1

| |

|<----等待资源R2

| |

| |<----等待资源R1

在这个例子中,事务A锁定了资源R1,然后请求资源R2;事务B锁定了资源R2,然后请求资源R1。它们都在等待对方持有的资源,形成了死锁。

为了避免死锁,可以采取以下策略:

  1. 顺序访问资源:确保所有事务都按照相同的顺序请求资源。

  2. 超时设置:为事务设置合理的超时时间,超时后放弃等待,回滚事务。

  3. 锁粒度控制:尽量使用行锁而不是表锁,减少锁定资源的范围。

  4. 尽早释放锁:在不需要资源时尽快释放锁,减少持有时间。

  5. 减少事务大小:执行小事务,减少长事务运行时间,降低死锁发生的概率。

二、MySQL的事务

上面呢讲解了一些锁的基本概念和一些示例,而锁又是发生在事务里的,接下来让我来了解是一下事务。

MySQL的事务是一组操作序列,这些操作要么全部执行,要么全部不执行,是数据库管理系统执行过程中的一个逻辑单位。通过事务,MySQL能够保证即使在系统或其他故障的情况下,数据库也不会处于不一致的状态。

事务的ACID特性:

  1. 原子性(Atomicity) - 事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。

  2. 一致性(Consistency) - 事务必须使数据库从一个一致性状态转换到另一个一致性状态。

  3. 隔离性(Isolation) - 并发执行的事务之间不能互相干扰,多个并发事务之间要相互隔离。

  4. 持久性(Durability) - 一旦事务提交,则其所做的修改将永久保存在数据库中,即使系统崩溃也不会丢失。

MySQL中,事务的实现依赖于存储引擎,不同的存储引擎对事务的支持不同。以支持事务的InnoDB存储引擎为例,其事务的实现原理包括:

  1. Undo日志:保证事务的原子性。当事务进行中发生错误或者用户执行回滚操作时,系统可以利用Undo日志撤销已经进行的修改。

  2. Redo日志:保证事务的持久性。即使数据库发生故障,已经提交的事务也不会丢失,因为这些修改操作会记录在Redo日志中。

  3. 锁机制:保证事务的隔离性。通过对数据加锁,防止多个事务并发执行时互相干扰。

  4. MVCC(多版本并发控制):也是为了保证隔离性,在InnoDB中,通过保存数据的多个版本,来允许读写操作并发进行,提高性能。

下面是一个简化的图示,展示了事务处理的一般流程:

±----------------+ ±------------------+

| Start | | Commit/Rollback |

| Transaction | | Transaction |

±----------------+ ±------------------+

| ^

| |

| |

v |

±----------------+ ±------------------+

| Execute | | Write Undo |

| SQL Queries | | Log for Rollback|

±----------------+ ±------------------+

| ^

| |

| |

v |

±----------------+ ±------------------+

| Write Redo | | Release Locks |

| Log for | | |

| Durability | ±------------------+

±----------------+

|

|

v

±----------------+

| Apply Locks |

| (if needed) |

±----------------+

在开始一个事务时(Start Transaction),你会执行一系列的SQL查询(Execute SQL Queries)。在这个过程中,如果需要修改数据,会首先写入Redo日志(Write Redo Log for Durability),以确保即使系统崩溃,这些修改也能够被恢复。同时,如果涉及到数据的修改,还会记录Undo日志(Write Undo Log for Rollback),以便在事务失败时回滚这些修改。

在事务执行过程中,根据需要对涉及的数据加锁(Apply Locks),这样可以确保事务的隔离性。当事务完成所有操作并且成功时,会提交事务(Commit Transaction),这时候会释放所有的锁(Release Locks)。如果事务执行过程中遇到问题,或者用户主动回滚事务(Rollback Transaction),则会利用Undo日志撤销之前的操作,并释放锁。

这是一个非常高层次的概述,实际上MySQL的事务处理要复杂得多,涉及到诸如事务隔离级别的设置、死锁检测和解决等多个方面。

在MySQL中,事务的隔离级别通常有以下四种:

  1. 读未提交(READ UNCOMMITTED)

  2. 读已提交(READ COMMITTED)

  3. 可重复读(REPEATABLE READ)

  4. 串行化(SERIALIZABLE)

读未提交

读未提交(Read Uncommitted)是事务隔离的最低级别,它允许事务读取尚未被其他事务提交的数据。这种级别的隔离可能会导致一些问题,如脏读(Dirty Read)。

假设有两个事务,事务A和事务B。

  1. 事务A开始并更新一个记录,但尚未提交。

  2. 事务B在事务A提交之前开始,并读取了相同的记录。

在读未提交的隔离级别下,事务B将看到事务A所做的未提交的更改。如果事务A回滚,那么事务B读取的数据将是不正确的,这就是脏读。

在实际应用中,通常会使用更高级别的隔离,如读提交(Read Committed)、可重复读(Repeatable Read)或串行化(Serializable),以避免脏读等问题。在MySQL中,默认的事务隔离级别是可重复读。

读已提交

读已提交(Read Committed)是数据库事务的四种隔离级别之一,它位于读未提交(Read Uncommitted)与可重复读(Repeatable Read)之间。在MySQL中,读已提交的隔离级别可以通过设置事务的隔离级别为READ COMMITTED来实现。这个隔离级别避免了脏读(Dirty Read,即读取到其他事务未提交的数据)的问题,但是它不能防止不可重复读(Non-repeatable Read)和幻读(Phantom Read)。

MySQL中的InnoDB存储引擎采用了多版本并发控制(MVCC,Multi-Version Concurrency Control)机制来实现不同的隔离级别。在MVCC中,每当一个数据对象被更新时,都不会直接覆盖旧的数据,而是会生成一个新的版本。同时,InnoDB会为每个事务维护一个系统版本号(transaction ID),用来标识事务开始的时间点。

当事务在读已提交模式下运行时,以下是其工作原理的简化流程:

  1. 当事务A开始时,会获得一个唯一的事务ID。

  2. 当事务A需要读取数据时,它会读取所有版本号小于等于自己事务ID的数据行的最新版本(即要求这些版本是已经提交的)。

  3. 如果在事务A读取数据期间,事务B对其中一些数据进行了修改并提交,事务B的修改会创建新的数据版本,并拥有一个新的版本号。

  4. 如果事务A再次读取相同的数据,它会看到事务B提交的新版本,因为这些新版本现在是已提交的,并且其版本号小于等于事务A的事务ID。

事务A开始 | 事务B开始 | 事务B修改数据X | 事务B提交 | 事务A读取数据X

----------|-----------|------------------|-----------|----------------

TID:1 | TID:2 | 生成数据X的新版本| | 读取到数据X的新版本

| | (版本号:2) | |

| | | 提交B | 由于B已提交,A读取到

| | | (数据X的 | 更新后的数据X

| | | 版本号2)|

读已提交的隔离级别提供了一个平衡的选择,它在并发性能和数据一致性之间取得了折中,适用于那些可以容忍不可重复读但要求避免脏读的应用场景。

可重复读

MySQL的读可重复度事务(Repeatable Read)是指在一个事务内,多次读取同一数据的结果是一致的,即使在这些读取操作之间,其他事务对这些数据进行了修改或新增。读可重复度是SQL标准中定义的四个事务隔离级别之一,位于“读已提交”(Read Committed)和“可序列化”(Serializable)之间。

MySQL默认使用InnoDB作为其存储引擎,InnoDB通过以下几种机制来实现读可重复度事务隔离级别:

  1. 多版本并发控制(MVCC):

InnoDB利用MVCC机制来提供读可重复度。每当数据被更新时,InnoDB存储引擎都会为该数据生成一个新版本,并为每个版本附上一个系统版本号(事务ID)。当事务开始时,它会获得一个唯一的事务ID,用于版本控制。

  1. 一致性非锁定读(Consistent Nonlocking Reads):

在读可重复度隔离级别下,普通的SELECT操作不会加锁,而是执行一致性非锁定读。这意味着它会读取那些创建版本号小于等于事务版本号的行的最新版本(即在事务开始之前已经存在的数据版本)。

  1. Undo日志:

当数据被修改时,InnoDB会在Undo日志中保留旧的数据版本。如果一个事务需要查看之前的数据状态,它可以通过Undo日志来访问之前版本的数据。

  1. Next-Key Locks:

InnoDB通过Next-Key锁来避免幻读(Phantom Read)。这种锁是记录锁和间隙锁的组合,它锁定一个范围,防止其他事务在这个范围内插入新的行。


事务T1 事务T2

| |

|---[开始事务] |

| |

|---[读取数据A] |

| | |

| |---[数据A的版本号:1] |

| |

| |---[开始事务]

| |

| |---[更新数据A]

| | |

| | |---[数据A的新版本号:2]

| |

|---[再次读取数据A] |

| | |

| |---[读取到的数据A版本号仍为1] |

| |

|---[提交事务] |

| |

| |---[提交事务]

在上面的示例中,事务T1在读取数据A后,即使事务T2更新了数据A并提交了事务,事务T1在其自身的事务范围内再次读取数据A时,仍然会看到版本号为1的数据,这是因为T1的读取操作是基于事务开始时的数据快照进行的。

通过上述机制,InnoDB存储引擎能够确保在读可重复度隔离级别下,事务可以在其整个过程中看到一个一致的数据快照,从而实现了数据的一致性和隔离性。

串行化

MySQL的串行化事务是指在数据库管理系统中,事务被执行的方式就像它们是依次串行执行的一样,即事务之间没有任何并发执行的现象。串行化是事务隔离级别中最高的级别,它可以防止脏读、不可重复读和幻读这些并发问题。

在这个级别下,一个事务完整执行过程中,不允许其他事务进行写操作,甚至是读操作也可能被限制(取决于具体的实现),以确保不会出现并发带来的问题。

MySQL中实现串行化事务的原理可以通过以下几种机制来完成:

  1. 行级锁定(Row-Level Locking):

在串行化级别下,MySQL会对涉及的数据行施加锁定,当一个事务在对某些行进行操作时,其他事务必须等待前一个事务完成并释放锁定后才能对这些行进行操作。

  1. 锁定读(Locking Reads):

当进行SELECT操作时,可以通过使用FOR UPDATE或LOCK IN SHARE MODE来显式地对读取的行施加排他锁或共享锁。

  1. 隐式锁定:

在串行化级别下,即使没有显式地请求锁定,MySQL也会自动地为事务中涉及的所有数据行施加锁定,以避免数据在事务执行期间被其他事务修改。

  1. 多版本并发控制(MVCC):

尽管在串行化级别下,MVCC可能不是必须的,但在其他隔离级别下,MVCC可以允许读操作不加锁,同时保证数据的一致性。在串行化级别下,MVCC仍然可以帮助系统维护多个版本的数据,以便于实现锁定策略。


+----------------+ +----------------+ +----------------+

| 事务 A 开始 | | 事务 B 等待 | | 事务 B 开始 |

| 对数据 X 加锁 | | 事务 A 执行中 | | 对数据 X 加锁 |

| 读/写数据 X | | 数据 X 被锁定 | | 读/写数据 X |

| 提交/回滚事务 | | 事务 A 提交 | | 提交/回滚事务 |

+----------------+ +----------------+ +----------------+

在这个示意图中,事务A开始执行并对数据X加锁后,事务B必须等待事务A完成并释放锁定,之后事务B才能开始执行并对数据X加锁。这保证了事务在数据库中的串行化执行。

在这个隔离级别下,性能通常会有所下降,因为事务必须严格地一个接一个地执行,但它可以为关键任务提供最严格的数据一致性保证。通常只有在需要绝对的数据一致性,并且可以接受较低并发性能的情况下,才会使用串行化隔离级别。

三、多版本控制(MVCC)

多版本并发控制(MVCC,Multi-Version Concurrency Control)是MySQL中InnoDB存储引擎用来实现高并发的一种技术。MVCC允许在不加锁的情况下进行读取,从而提高了系统的并发性能。下面我会简要介绍MVCC的概念与实现原理。

MVCC通过为每个事务创建一个快照,使得每个事务看到的数据是一致的,并且是在事务开始时或者读取时刻的数据状态。这种方式避免了对读取操作加锁,从而实现了非阻塞的读取,提升了并发性能。

MVCC实现原理

MVCC在InnoDB中的实现依赖于以下几个核心组件:

  1. 事务ID(Transaction ID):每个事务开始时都会分配一个唯一的事务ID,这个ID是递增的。

  2. 隐藏列:在InnoDB中,每行数据后面都会隐式地加上三个字段:DB_TRX_ID、DB_ROLL_PTR和DB_ROW_ID。DB_TRX_ID记录了最后修改该行记录的事务ID,DB_ROLL_PTR是回滚指针,指向该行记录的undo log记录,DB_ROW_ID是InnoDB自动产生的一个行ID(当表没有主键时会使用)。

  3. Read View:当读取操作发生时,InnoDB会为事务创建一个Read View,其中包含了活跃事务的ID列表。活跃事务是指在当前事务开始时还未提交的其他事务。

在MVCC中,Read View是一个逻辑上的结构,它定义了事务可以看到的数据版本。Read View通常包含以下几个关键部分:

  1. 系统版本号(System Version Number, SVN):每当有新的事务开始时,系统版本号会递增。这个版本号用来标记事务的开始时间点。

  2. 活跃事务列表(Active Transaction List):在创建Read View时,系统会记录下当前所有活跃的、未提交的事务的事务ID。这些活跃的事务可能对数据进行修改,因此它们的修改对当前事务来说是不可见的。

  3. 最小活跃事务ID(Min Active Transaction ID):所有活跃事务中最小的事务ID。这个ID之前的所有事务要么已经提交,要么已经回滚。

  4. 创建Read View时的事务ID(Creator Transaction ID):创建该Read View的事务自身的ID。

下面通过一个图来解释Read View的组成和工作原理:


|------------------------------------------------------|

| 数据库系统 |

|------------------------------------------------------|

| |-------| |-------| |-------| |-------| | |

| | TX 1 | | TX 2 | | TX 3 | | TX 4 | | |

| |-------| |-------| |-------| |-------| | |

| SVN = 10 SVN = 20 SVN = 30 SVN = 40 SVN = 50 |

|------------------------------------------------------|

假设上述系统中有四个事务TX 1到TX 4,它们的系统版本号分别是10、20、30和40。当TX 4开始创建Read View时,系统版本号是50,因此TX 4的Read View可能如下所示:


Read View for TX 4:

- System Version Number at Creation: 50

- Active Transaction List: [TX 1, TX 2, TX 3]

- Min Active Transaction ID: ID of TX 1

- Creator Transaction ID: ID of TX 4

当TX 4进行数据读取时,它会根据自己的Read View来确定数据的可见性:

  • 它可以看到TX 1、TX 2和TX 3之前所有提交的事务所做的修改。

  • 它看不到TX 1、TX 2和TX 3的修改,因为这些事务是活跃的,并且在TX 4的Read View创建后可能会进行修改。

  • 它自己的修改对自己是可见的。

通过这种方式,MVCC确保了事务的隔离性,使得读取操作可以在不被写入操作影响的情况下进行,并且不同的事务可以同时运行而不会相互干扰。

  1. Undo日志:当数据被修改时,InnoDB会记录一份修改前的数据副本到Undo日志中。这份数据可以用来在事务回滚时恢复数据,也用于MVCC中构建旧版本的数据。

当一个事务要读取一行数据时,InnoDB会使用以下规则来判断这行数据是否对当前事务可见:

如果数据的DB_TRX_ID等于当前事务的ID,数据对当前事务可见。

如果数据的DB_TRX_ID在Read View的活跃事务ID列表中,说明修改还在进行中,数据对当前事务不可见,需要读取Undo日志中的旧版本数据。

如果数据的DB_TRX_ID小于Read View中最小的活跃事务ID,数据对当前事务可见。

如果数据的DB_TRX_ID大于Read View中最大的活跃事务ID,说明数据是在当前事务开始后被其他已提交的事务修改的,数据对当前事务不可见。


事务A(ID=100) 事务B(ID=101)

开始时间 ------------------->

开始时间 ------------------->

Read View A: [101]

Read View B: []

  


行数据1: {DB_TRX_ID: 100, ...}

行数据2: {DB_TRX_ID: 101, ...}

  


事务A读取行数据1:可见

事务A读取行数据2:不可见,需要读取Undo日志中的旧版本数据

事务B读取行数据1:不可见,需要读取Undo日志中的旧版本数据

事务B读取行数据2:可见

在这个例子中,事务A开始后,事务B也开始了。当事务A和B尝试读取行数据时,它们会根据自己的Read View来判断数据是否可见。如果不可见,它们会读取Undo日志中的数据。

注意:读已提交事务是在每次读取时都会生成一个新的readView,而可重复度是在事务开始时只生成一次readView。

MVCC是一种复杂的机制,但它极大地提高了数据库的并发读写能力,尤其是在读多写少的情况下。通过避免加锁来提高性能,同时确保事务的隔离性,MVCC是现代数据库管理系统中的一个关键特性。

四、加锁示例(大前提:事务隔离级别为可重复读)

通过文章上述内容的MySQL相关基础知识的介绍,相信大家已经对于事务和锁有了基本的了解,尤其是行锁是基于索引建立的,而索引又有唯一约束索引和普通索引,甚至是自增主键,如果命中上述不同的索引或者失效、又或者插入数据时自增主键的竞争,又或是日常的增删改查等,对于上述所说的种种场景其中的锁机制又是怎样执行的呢?来吧,上宝典😀

命中唯一约束键

•如果目标记录存在,则只会针对这一行记录加行锁

•如果目标记录不存在,则会针对所处范围加间隙锁. 如果左右有缺口,则通过 ±∞ 补齐

命中普通索引

此时除了会用行锁锁住记录本身,还会通过间隙锁锁定左右相邻空隙.

之所以需要额外施加间隙锁,就是为了避免在持有锁期间,有其他并发事务插入相同索引值对应的行记录,从而导致幻读问题的发生.

未命中任何索引

锁级别直接上升为表锁

自增键锁

MySQL的自增主键锁(Auto-Increment Locks)是一种特殊类型的锁,用于保护自增主键在插入新记录时的唯一性和连续性。自增主键通常用于那些需要唯一标识符的表中,它允许数据库自动生成下一个序列号,省去了手动插入唯一标识符的麻烦。

在MySQL中,自增锁的实现原理与存储引擎有关,但以最常用的InnoDB存储引擎为例,自增锁的实现可以分为以下几个步骤:

  1. 锁的类型:InnoDB实现了两种类型的自增锁:

表级自增锁:在早期版本的MySQL中,InnoDB使用表级自增锁,当一个事务要插入新记录时,它会锁定整个表来获取下一个自增值。这种锁定机制保证了自增值的唯一性,但在高并发插入时会成为瓶颈。

轻量级锁(interleaved lock):从MySQL 5.1开始,InnoDB引入了一种新的自增锁机制,即轻量级锁或间隙锁(interleaved lock)。在这种机制下,多个事务可以并发地向表中插入数据,只要它们不尝试生成相同的自增值。

  1. 锁的获取:当一个事务试图插入一条新记录时,它会首先获取下一个可用的自增值。在获取过程中,InnoDB会根据需要对内部数据结构加锁,以确保自增值的唯一性和连续性。

  2. 锁的释放:在早期版本中,表级自增锁会在事务结束时释放。而在轻量级锁机制下,自增锁通常在下一个自增值被生成后立即释放,这样可以最大程度地减少锁定时间,提高并发性能。

简化流程图:


事务A 事务B 自增主键值

  


|请求自增值| |1|

|------------------>| |2|

|<------------------| |

|执行插入操作| |

| |请求自增值|

| |------------------>|

| |<------------------|

| |执行插入操作|

|事务提交| |

|<------------------| |

| |事务提交|

在这个例子中,事务A请求一个自增值,它获得了1,然后它开始执行插入操作。在此期间,事务B也请求自增值,并获得了2。由于InnoDB的轻量级锁机制,事务B不需要等待事务A完成插入和提交,就可以进行它的插入操作。这样,两个事务就可以并行执行,提高了性能。

需要注意的是,上述描述是非常简化的版本,实际的并发控制会涉及更多细节,例如事务隔离级别、行锁定以及死锁检测等。此外,自增值的持久性和恢复机制也是自增锁实现中的重要部分。

注意:以上述示例为例,自增值的使用是不会返还的,即:如果事务A成功获取了自增值1,但是在执行事务中由于某种原因进行了回滚,此表释放的自增值1是不会返还的,下次最近的新的事务获取的自增值是3而不是1

insert插入语句锁的执行流程

InnoDB是MySQL默认的存储引擎,它支持事务处理、行级锁定和外键等特性。当执行一个INSERT语句时,InnoDB存储引擎会进行如下的加锁流程:

  1. 解析阶段:MySQL首先会解析SQL语句,检查语法是否正确。

  2. 预处理阶段:进行权限验证,检查是否有对应表的插入权限,以及表是否存在等。

  3. 优化阶段:生成执行计划,选择合适的索引进行数据插入。

  4. 加锁阶段:在执行计划确定后,InnoDB会根据操作的类型来决定加锁的粒度和类型。对于INSERT语句,InnoDB会执行以下加锁流程:

a. 意向锁(Intention Locks):在表级别加上意向锁,这是一个表明接下来会在行级别加锁的信号锁,否则阻塞等待

b. 自增锁(AUTO-INC Locks):如果插入操作涉及到自增主键,InnoDB会对自增计数器加锁,以保证生成的主键值的唯一性和连续性。

c.唯一键冲突校验:校验插入记录是否会和已存在记录发生唯一键冲突,若没有冲突则直接进入步骤d,否则进行加锁尝试解决冲突,解决冲突后继续步骤d或报错

锁定冲突行:

如果检测到冲突,并且有另一个事务正在操作冲突行,DBMS 会尝试为这个行数据加锁。

如果该行已经被另一个事务锁定,当前事务将会等待,直到锁被释放。

冲突解决:

如果当前事务能够获得锁(即没有其他事务正在操作该行),则根据操作类型解决冲突。

如果是插入操作,当前事务将会失败,因为不能违反唯一约束。

如果是更新操作,当前事务会更新这个行,只要更新后的值不违反唯一约束。

d. 行锁(Row Locks):InnoDB实际上会在新插入的行上加上排它锁(X锁)。这意味着其他事务不能修改或删除这个新插入的行,直到当前事务结束。

  1. 执行阶段:执行INSERT语句,实际将数据插入到表中。

  2. 插入缓冲(Insert Buffering):对于非唯一索引的插入操作,InnoDB可能会使用插入缓冲来提高插入效率,减少磁盘I/O操作。

  3. 提交或回滚:如果INSERT语句执行成功,事务会被提交;如果在执行过程中发生错误或者用户主动回滚,之前加的锁会被释放。

由于这个过程中涉及到的锁类型和加锁的细节比较复杂,通常不会通过图形来表示整个加锁流程。然而,可以通过流程图来简要描述上述步骤:


+------------+ +--------------+ +-----------+

| 解析SQL语句 | ---> | 权限验证等预处理 | ---> | 生成执行计划 |

+------------+ +--------------+ +-----------+

| | |

V V V

+----------------+ +--------------------+ +------------------+

| 加意向锁(表级别)| | 加自增锁(如果有自增列)| | 加行锁(行级别) |

+----------------+ +--------------------+ +------------------+

| | |

V V V

+------------------+ +----------------------+ +---------------+

| 执行INSERT操作 | | 使用插入缓冲(如适用) | | 提交或回滚事务 |

+------------------+ +----------------------+ +---------------+

在实际的数据库操作中,InnoDB的加锁机制还涉及到很多其他细节,如事务隔离级别、锁的兼容性等,这些都会影响到具体的加锁行为和性能。

delete删除语句锁的执行流程

delete语句锁的持有情况主要看where条件,即看条件走不走索引,走什么索引等。

命中唯一约束键

•目标记录存在:针对单行记录加排它锁

•目标记录不存在:对所处范围加间隙锁

命中普通索引

•对行记录左右相邻空隙加间隙锁,并加行记录本身加 X Lock

未命中索引

•直接升级为表锁

五、总结

通过文章上述内容,我们对于MySQL锁和事务的基本知识算是有了基本的了解,那么回到文章开篇的问题上来。

起初的怀疑-被推翻

最开始的时候我是怀疑在事务中的普通select语句与非事务中的普通select语句在锁的持有上是有所区别的,认为事务中的select默认持有共享锁,通过查看代码了解到上述的实际业务处理逻辑部分都是同处在同一个"大事务"(因为事务里的业务处理代码实在是太长了😀)的,而报错的select语句后方是紧跟着一个同表的insert语句,同时此表是有非主键外的唯一约束键的(select语句就是通过此唯一约束键进行的查询),于是乎认为问题出在这里

时刻事务A事务B
1select * from table where unique_key=‘123’ lock in share mode 持有行共享锁
2insert into table (unique_key,othercolumns) values (‘123’,```) 持有行X锁
3select * from table where unique_key=‘123’ lock in share mode 阻塞,等待事务B中的行X锁

但是经过查阅相关资料(其实上文中的MVCC中已经也有介绍了)和实际操作验证,发现在MySQL数据库采用InnoDB并且事务隔离级别是可重复读的时候,普通select语句是不带锁的,有这么一个专业名词:一致性读(consistency read),即:此种模式下select语句读的是记录的快照,不会加锁。

那通过上述的分析与实际检验问题的根因不出在这里,不过虽然自己的推测是错的,但是此问题的排查过程中又学习到了不少知识,为以后此类问题的排查以及后续好代码的编写打下了坚实的基础。好了,吹嘘到此为止😀,我们继续回到问题上来,那既然不是出现在数据库层面那还有什么可能性,突然我想到了一个我一直忽略的一个点,spring事务的处理机制。

第二波的怀疑-是对的

大家都知道spring的事务是基于代理来实现的,其中的事务传播行为有多种,而此问题的业务处理采用的默认传播机制:Propagation.REQUIRED,我现在将注意点转移到spring事务超时的可能性上来,又回看了一次代码,发现在业务的声明事务起始处确实设置了事务超时时间为60秒,如下图

在这里插入图片描述

通过日志又查看到报错sql实际执行时间为1毫秒,而整个"大事务"的执行确实超过了60秒,到此问题已经定位清楚了,那接下来治理就好办了,方法简直不要太多😁

哈哈有没有发现写了这么一大篇,其实感觉很乌龙,哇咔咔,我也发现了,不过确实有收货,那就记录下来吧😁

相关推荐

AI 会写代码之后,交付为什么还没变快?

AI 写代码,只是这场变革的起点,而不是终点。真正决定一个组织能否吃到 AI 红利的,不是"能不能用 AI 写出代码",而是敢不敢用 AI 重新设计交付流程、重新划分角色分工、重新组织团队结构。研发视角能把工具和个人推到极致,却会在组织的边界前止步;只有站上组织视角,把AI × 工具一路推进到AI × 组织,那些被 AI 照出来的摩擦,才会真正被抹平。国际技术部 Multi AI Native 想做的,正是这件事——让 Agent 成为你可靠的数字战友,让每一次迭代交付都快一个量级;

京东科技开发者 246

OxygenData-Vibe搭建:用 AI Coding重新定义数据看板搭建

长期以来,数据看板开发主要有两种方式:一种是使用标准化 BI 工具,交付快、成本低,但图表样式、交互体验和功能扩展都受限于 BI 本身的能力;另一种是自研定制开发,能够充分满足复杂和个性化需求,但需要投入大量研发资源,交付周期也更长。比如一个通过 BI 只需要 1 天就能搭建出来的看板,如果采用自研方式,可能需要投入 30 PD 的研发人力。既然 BI 交付这么快,为什么不把所有看板需求都交给 BI?原因在于,业务某些场景需要的不只是把数据展示出来。

京东科技开发者 309

当我谈数据库高可用时我谈些什么

大家都经常听到说数据库的双1,那双1指的是什么呢?参数=1(最安全)≠1(更快但可能丢)每次提交都把 redo 刷盘0/2:攒着刷,崩溃丢最近 1 秒每次提交都把 binlog 刷盘0/N:攒着刷,崩溃丢最近若干条"双 1"(都设为 1)= 单机不丢已提交事务的前提。生产核心库必须双 1;代价是每次提交两次 fsync。小结:单机层用 WAL 提速、用 2PC 保证 redo/binlog 一致、用崩溃恢复裁决半成品事务、用双 1 兜底持久性。

京东科技开发者 271

ScoAI:面向供应链的运筹原生决策智能

ScoAI 关注的并非 AI 能否进入供应链,而是 AI 参与供应链决策之后,哪些内容适合通过数据学习,哪些关系必须显式计算,以及哪些结果需要依据执行记录进行验证。其基本分工是:供应链业务定义问题、资源与行动后果,运筹学表达目标、约束和协同关系,AI 提供可复用的估计与判断。真正用于改进后续决策的,不仅是模型生成的初始结果,还包括实际采取的行动及其产生的业务反馈。

京东科技开发者 367

拆解海博 AI-Native 落地保障:海博团队 AI 知识库能力建设

绕了一大圈,回头看,我们其实一直在解开头那三个结:AI 读不懂系统、影响面靠人脑记、测试预期没处查。做到这里,本质上是把"AI 用不好"这个问题,从"是不是该换个更强的模型"重新定义成了"怎么把上下文经营好"。顺着这个思路,我们攒下了这么几样东西:•。

京东科技开发者 518

从零构建一个生产级记忆型 AI Agent —— AgentScope 项目全景技术与学习指南

domain 层端口接口(domain)职责适配器实现(infra)对话流水账读写经验记忆检索/落库请求级幂等四态会话元数据 CRUD会话级 Skill 选择态Skill 元数据HITL 权限网关(domain 内含逻辑,见第四篇)StreamSink技术中立的流式下沉(client 层桥接)以幂等端口为例,头部注释明确写道:实现 domain 端口,持有实体不出 infra 边界,对外只暴露嵌套视图GateResult。

京东科技开发者 571

数据涅槃:Agentic 重塑搜推数据生产体系

当前大模型已经能够理解需求、生成代码和解释错误,但数据生产的难点并不只是“写出一段 SQL”。一个需求还要经过数据源确认、口径澄清、加工编排、资源规划、任务提交、调度运行、结果交付和故障处置。任何一步缺少都可能让“看起来正确”的任务变成生产事故。

京东科技开发者 337

81.8 秒的视频,我们改了 15 个版本:一次纯 Codex 驱动的 AI-native 视频实践

81.8 秒、15 个版本,这些数字真正想说明什么?视频制作正在从一组专业软件里的复杂操作,变成一场围绕目标、参考和反馈展开的持续对话。AI 已经可以接住从脚本到交付的大量工作。你可以把精力留给更重要的部分:理解观众、选择故事、判断好坏。过去停在 PPT 和脑海里的想法,现在有机会被快速做成一支能看、能改、也愿意转发的视频。如果明天就要介绍你手头的项目,你最想先把哪一步交给 AI?

京东科技开发者 433

Codex 驱动的移动端AI全栈开发:从 Relay 原型图到可交付链路

AI 编程工具降低了跨端开发门槛,但“让 AI 写页面”并不等于“完成移动端交付”。PC 运营端页面通常以功能闭环为中心,设计约束较弱,研发可以基于组件库快速搭建;移动端 C 端页面直接面对用户,Relay 原型图和 UI 设计稿不仅是视觉参考,更是交互、信息层级、状态反馈和业务信任感的综合契约。

京东科技开发者 566

Claude Code vs Codex 记忆体系深度对比

Claude Code —— 分层自动记忆系统四层分层架构(CLAUDE.md / Auto Memory / Session Memory / AutoDream)构成自优化闭环,系统主动捕获、分类、去冗并跨会话接力经验。走的是自动化优先路线——让机器替人记忆、替人整理,以少量可控性的不确定换取强大的经验积累能力。Codex —— 声明式契约系统两层扁平架构(AGENTS.md 静态声明层 + 会话上下文层),记忆完全由人显式订立、显式修改,系统只读契约、绝不擅自变更。走的是可控性优先。

京东科技开发者 605

上游给空、下游拿到 -1,我把故障一直追到了 commons-beanutils 的构造函数

这篇手记是一份事后复盘,写在我们已经把修复推上线、把测试用例跑绿、把约束文档沉淀进团队库之后。非研发同事,可以直接从第八章开始看,前七章都是讲排障和代码分析。故障本身不复杂,修复也不复杂,但这次排查真正让我想写下来的,不是技术本身——而是从问题提报到解决全程AI的作用:问题定位:业务方反馈了一个异常单号说「下发失败」,一线运维同事直接在日志系统捞到相关的系统日志,用IDE打开下游代码库,把异常信息给到JoyCode——AI 直接指向了问题是serialType值非法,系统只接受0和1,而当前上游给的是-1。

京东科技开发者 703

SKill测评:谁才是真正的Skill之王?

巧合的是,阿里近期开源了一款名为 Skill-Up 的测评工具——它专门面向 Agent Skill 开发者,支持在 Claude Code、Codex、Qoder CLI 等真实 Agent Engine 环境中验证 Skill 的功能正确性,并可将失败用例转化为精准的修复指引,同时支持本地与 CI 环境的持续回归。2026年,Skill 的热度不减,已成为 AI 辅助编程领域的标配。在日常研发中,无论是沉淀个人经验,还是将团队的优秀范本标准化,将知识“蒸馏”为 Skill 已是大家的常规操作。

京东科技开发者 618

让AI真正参与工作!JoyDesk已上线京东云

JoyDesk提供覆盖AI资产管理、权限控制、安全策略、审批审计、运营监控等企业级治理能力,支持按组织、角色和项目进行精细化权限管理,并支持私有化部署,确保企业数据边界清晰、AI行为全程可追溯、安全策略灵活可配置,满足金融、政企等行业对数据安全和合规治理的要求,让AI真正成为企业可信赖的生产力。JoyDesk支持MCP协议、标准API、技能等多种开放接入方式,可快速连接企业现有业务系统,将业务能力封装为AI可调用的技能和专家,让AI能够理解业务流程、调用业务系统、完成业务任务,而无需改变企业原有IT架构。

京东科技开发者 652

【全栈实践】第一个 AI Agent 项目:从零搭建 AI 音频创作助手【最终版】

这个项目展示了AI Agent 在垂直内容创作领域端到端自动化:从内容理解到播客输出,全流程 AI 驱动多模态融合:文字、图片、音频、视频统一处理专业级音频质量:音色设计 + 智能混音,输出广播级品质低门槛使用:可视化配置 + 自然语言交互,无需技术背景。

京东科技开发者 556

【全栈实践】第一个 AI Agent 项目:从零搭建 AI 音频创作助手(高级篇)

这是一个 AI 驱动的播客创作助手,专注于从文字/视频/音频内容识别到播客制作的全流程。你可以用自然语言与它对话,也可以上传视频和音频,它会理解意图、调用相应的语音合成工具,把他们变成真实的播客音频。

京东科技开发者 720

【全栈实践】第一个 AI Agent 项目:从零搭建 AI 音频创作助手(进阶篇)

这是一个AI 驱动的音频内容创作助手。你可以用自然语言与它对话,它会理解意图、调用相应的语音合成工具,把文字变成真实的播客音频,并保存在本地。关于项目的详细介绍见第一篇文章:第一个 AI Agent 项目:从零搭建 AI 音频创作助手(入门篇)这篇文章更多介绍进阶篇添加的功能。

京东科技开发者 545

【全栈实践】第一个 AI Agent 项目:从零搭建 AI 音频创作助手(入门篇)

这个项目让我第一次把前端、后端、AI Agent 三块内容独立串联起来。技术选型上每一块都是当下主流的方案,实际跑通整条链路之后对"全栈"有了更具体的感受。框架版本要锁定:LangChain 这类快速迭代的框架,版本差异带来的问题远比你想象的多先跑通链路,再追求完美:新手阶段能把用户输入 → AI 处理 → 结果展示这条链跑通,比深入某个技术点更有价值多看官方文档:相比博客和教程,官方文档更新及时,特别是 LangGraph 这种新框架后续计划继续迭代,欢迎交流!

京东科技开发者 602

ICLR 2026 | 面向序列决策的贝叶斯集成方法

在这篇工作中,我们关注的是。

京东科技开发者 294

ICML 2026|NaviAgent:面向 Oxygen 智能体的可扩展工具编排

大型语言模型(LLM)越来越多地作为函数调用代理,调用外部工具来处理超出其静态知识范围的任务。然而,它们通常一次只调用一个工具,缺乏对任务结构的全局视图。由于工具之间往往相互依赖,这会导致错误累积和可扩展性差,尤其是在扩展到数百或数千个工具时。为了解决这些局限性,我们提出了NaviAgent,一种显式的双层架构,它通过基于图的工具关系建模将任务规划与工具执行解耦。在规划层,基于 LLM 的代理决定是直接响应、澄清意图,还是检索并执行一个独立于工具间复杂性的工具链。

京东科技开发者 383

实测 9 款 AI 架构图工具:从 Mermaid 美化到 GPT-Image2,一份选型清单

支持 5 类图(架构图、工作流图、时序图、数据流图、生命周期/状态机图),主题 4 种(Classic、Signal Flow、Blueprint、Editorial)+ 3 种色彩模式(Dark / Light / System Auto),输出格式含 HTML、PNG、SVG、WebM、Share Card PNG、JSON IR。它把提示词图库、图像生成案例、参考图编辑流程和命令行工具整合在一起,让 AI Agent 能直接调用 GPT Image 2 模型完成文生图、图生图、参考图编辑等任务。

京东科技开发者 895

别再守着 Claude Code 了——学会指挥它自主干活

回到开头那句:别再一句一句地喂它、然后守着屏幕。真正的用法是——把一件事想清楚、划好边界、给它一个能自我验证的目标,然后交出去。你会发现,省下来的时间不是一点半点。把重复的判断和执行还给机器,把真正需要你的判断留给自己。

京东科技开发者 584

CVPR 2026|Oxygen XR 团队在原生鱼眼高斯泼溅技术上带来新突破

京东零售技术团队联合清华大学提出DirectFisheye-GS框架,创新性地将鱼眼相机模型原生嵌入3D高斯泼溅管线,通过跨视角联合优化策略直接处理鱼眼图像,避免了传统去畸变预处理导致的信息损失。该方案在多个公开数据集上达到SOTA性能,有效解决了单视角优化引起的几何畸变和视角不一致问题,同时保持与现有3DGS工具链的兼容性。技术已应用于电商3D重建和4D体积视频等场景,显著提升了沉浸式体验。相关论文被CVPR 2026接收,为宽视场场景重建提供了高效解决方案。

京东科技开发者 353

拆解海博 AI-Native 落地保障:Harness、双 Loop、知识库与技能自主迭代实践

海博研发RoadMap 的落地,彻底终结了 AI 编程“对话式玄学”的旧模式,真正落地了AI Native 研发工程化。它证明 AI 规模化赋能研发的核心,不在于堆砌大模型能力,而在于用工程思维重构 AI 的工作范式:用结构化流程替代随机对话,用固化规则约束模型行为,用持续沉淀实现能力复利,用分层架构支撑规模化落地。

京东科技开发者 633

让 AI 快速「读懂」你的代码仓:Joy-Code-Graph 云端图谱服务的三次进化

代码知识图谱不是要取代 AI 的智能,而是要补齐它对代码全局关系的认知盲区。当 AI 能一眼看清「谁调用了谁、改动会波及哪里」,它写出的代码才真正靠谱;当这份认知安全地留在自己手里、随时被 Joygen 调用、并且永久沉淀在代码仓里——AI 编程的体验,才算真正上了一个台阶。这,就是我们做 Joy-Code-Graph 云端服务的初衷。能力共享,数据自主;一次建图,长期受用。

京东科技开发者 751

【Coding生态】从代码托管到 AI 能力底座:与Coding一起共建 AI 研发生态

前两种框架能够很好地支撑对话式能力和预设流程式能力。它们适合基于提示词或预设工作流完成研发问答、知识查询、流程编排等任务。但在更复杂的研发场景中,仅仅“回答问题”还不够。当用户业务逻辑复杂时,一旦场景进入真实落地阶段,例如下载代码、修改文件、执行命令、安装依赖、运行测试、读取完整代码文件,或者与自有系统联动、将结果渲染到 Coding 页面、推送到京 ME,AI 应用需要的不只是知识能力,还需要真实的代码库操作能力和独立可执行环境。

京东科技开发者 768

GPT-5.6、ChatGPT Work 与 Codex 更新食用指南

三档模型当前都提供 1,050,000 tokens 上下文、922,000 tokens 最大输入和 128,000 tokens 最大输出,接受文本与图像输入、输出文本,并支持 web search、file search、Computer Use、MCP、Tool Search、Skills、Apply Patch 等工具。Work 可以读取你提供的文件,通过插件连接 Slack、Google Drive、SharePoint、邮箱、日历、CRM 或项目系统,调用获批工具,并在执行中展示进度。

京东科技开发者 860

把业务流程沉淀成高质量 Skill 的实践路径

使用Record & Replay创建的Skill,尽管创建流程简单,但它的本质实际是让 AI 去操作页面,这不但有可能影响我们对电脑的操作,还有可能无法稳定复现。创建Skill时,可以使用 Codex 的 Record & Replay 插件,把一次手工操作录下来,再让 AI 生成可复用流程。刚开始切换时,很容易遇到接口报错,可以让Codex排查原因进行优化,直到可以稳定执行;补充相应业务背景,说明这件事为什么要做,谁会用,输入从哪来,输出给谁看。电脑休眠、关机、软件没开时,本地任务可能无法执行。

京东科技开发者 835

政企前台AI-Agent的架构实践:打造可复用的 AI 服务平台-【灯塔计划】

不止是爆火的龙虾,还是各种Skills,MCP、Agent,脱离的具体的场景谈方案,最后只会是一场空。这一套可复用的 AI 服务平台,截止目前,通过前后端对接规范文档,多项能力已快速接入到各个场域的不同端平台,大幅降低研发成本, 并且各业务线新场景的接入从原来的 “开发驱动” 转为 “配置驱动”,接入周期从天维度缩短至小时级。

京东科技开发者 860

京东 Oxygen xLLM 大模型推理引擎正式捐赠开放原子开源基金会,共建国产 AI Infra 生态

下一阶段 AI 基础设施的核心命题,不是简单的算力堆叠,而是让工程本身变得智能——让调度系统能自主感知负载特征并动态优化,让推理引擎能根据模型结构和硬件特性自动生成最优执行方案,让整个 AI 工程链路具备自感知、自决策、自优化的能力。未来,Oxygen xLLM 的项目官网、社区沟通渠道及微信社区将陆续向开发者开放,诚邀芯片厂商、模型厂商、云厂商、企业用户及个人开发者共同参与,让国产大模型推理引擎在开放生态中加速成长。硬件层,原生支持 GPU / NPU / MLU 多类 AI 芯片,深度适配国产芯片。

京东科技开发者 1000

【京东云】全球首个!京东全栈开源JoyAI-VL-Interaction,让大模型从“一问一答”走向“边看边说”

开源一套系统,而不只是一个模型在实时视频流中,JoyAI-VL-Interaction每秒都会做一次判断,比如,继续观察、保持沉默,发现关键事件、主动回应,遇到复杂任务,交给后台Agent处理。一个好的AI 助手,不应该一直打扰用户,而应该知道什么时候该出现,什么时候该安静,以及什么时候自己解决,什么时候交由agent解决。深耕零售、物流、健康、工业等实体产业二十余年,京东拥有全球领先的物理世界运营网络,覆盖仓储、配送、门店、直播、客服、售后海量真实场景,每天都在发生人、货、场的实时互动。

京东科技开发者 1029
上一篇: 高并发系统的艺术:如何在流量洪峰中游刃有余
下一篇: 动态化-罗码(京东科技一码多端解决方案)介绍
京东云开发者
京东云开发者 企业官方账号 企业官方账号
博客等级 码龄8年 1万+粉丝 2139原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值