普通视图

Received yesterday — 2026年2月18日技术博客
Received before yesterday技术博客

Redis开篇

2021年12月29日 00:00

栏目持续更新中

一、Redis概述

Redis即Remote Dictionary Server(远程字典服务)是完全开源的,使用ANSIC语言编写的,遵守BSD协议的高性能的Key-Value数据库。Redis提供了丰富的数据结构,例如String、Hash、List、Set、ZSet等等。数据是存在内存中的,同时Redis支持事务、持久化、LUA脚本、发布/订阅、缓存淘汰、流技术等多种功能特性,提供了主从模式、Redis Sentinel和Redis Cluster集群架构方案。

Redis的作者是意大利程序员Antirez,作者个人博客:https://antirez.com/latest/

Redis的官网是:https://redis.io,源码位于GitHub上:https://github.com/redis

二、Redis的主要用途

  • 配合关系型数据库快速读取

    主流应用基本都是80%的读取和20%写入,Redis拿来配合MyMQL等实现读写分离,MySQL数据存储在硬盘,关系型数据库需要执行复杂SQL,相比下Redis基于内存按key读取明显效率更高,Redis在一些场景下的使用明显优于MySQL,例如计数器,排行榜,抢红包等。Redis通常用于一些特定场景,需要与MySQL一起配合使用,两者并不是相互替换和竞争关系,而是共用和配合使用

  • 分布式锁

    synchronized关键字和各种锁只能在一个JVM进程中有效,多服务器的集群环境下利用Redis的单线程特点,可以做分布式环境下的并发控制

  • 队列

    Reids提供list和set操作,这使得Redis能作为一个很好的消息队列平台来使用。我们常通过Reids的队列功能做购买限制。比如到节假日或者推广期间,进行一些活动,对用户购买行为进行限制,限制今天只能购买几次商品或者一段时间内只能购买一次,也比较适合适用。

  • 消息中间件

    Reids具有发布订阅消息功能,因此可以作为一个简单的消息中间件来使用,例如修改了数据字典后通知应用程序执行刷新缓存的方法

  • 分布式会话

    将session或token对应的用户信息保存到Redis,实现集群环境下会话共享

三、Redis的优势

  • 性能极高

    Redis能读的速度是110000次/秒,写的速度是81000次/秒

  • 数据类型丰富

    不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储

  • 支持数据的持久化

    可以将内存中的数据保持在磁盘中重启的时候可以再次加载进行使用Redis支持数据的备份,即master-slave模式的数据备份

四、Redis版本历史

  • 2009,诞生
  • 2010,1.0,Redis Data Types
  • 2012,2.6,Lua,PubSub,Redis Sentinel V1
  • 2013,2.8,Redis Sentinel V2,IPv6
  • 2015,3.0,Redis Cluster,GEO
  • 2016,4.0,RDB,AOF
  • 2017,5.0,Stream
  • 2020,6.0,ACLs,SSL,Threaded I/O
  • 2022,7.0,ACLv2,Redis Functions,listpack代替ziplist,Multi-part AOF

五、Redis版本规则

Redis版本号第二位是奇数的为非稳定版本,例如2.7、2.9、3.1。第二位是偶数的为稳定版本,例如2.6、2.8、3.0。当前奇数版本就是下一个稳定版本的开发版本,例如3.0就是2.9的稳定版,2.9就是3.0的开发版。

根据官网安全漏洞提示,升级redis6一定要选择6.0.8以上版本,或者直接升级到7。

六、Redis7新特性

  • 多AOF文件支持

    7.0版本中一个比较大的变化就是aof文件由一个变成了多个,主要分为两种类型:基本文件(base files)、增量文件(incr files),请注意这些文件名称是复数形式说明每一类文件不仅仅只有一个。在此之外还引入了一个清单文件(manifest)用于跟踪文件以及文件的创建和应用顺序(恢复)

  • Config命令增强

    对于Config Set和Get命令,支持在一次调用过程中传递多个配置参数。例如我们可以在执行一次Config Set命令中更改多个参数: config set maxmemory 10000001 maxmemory-clients 50% port 6399

  • 限制客户端内存使用 Client-eviction

    一旦Redis连接较多,再加上每个连接的内存占用都比较大的时候,Redis总连接内存占用可能会达到maxmemory的上限,可以增加允许限制所有客户端的总内存使用量配置项。
    redis.config中可以用两种配置形式:指定内存大小 maxmemory-clients 1g、基于maxmemory的百分比 maxmemory-clients 10%

  • listpack紧凑列表调整

    listpack是用来替代ziplist的新数据结构,在7.0版本已经没有ziplist的配置了(6.0版本仅部分数据类型作为过渡阶段在使用),listpack已经替换了ziplist类似hash-max-ziplist-entries的配置

  • 访问安全性增强ACLV2

    在redis.conf配置文件中,protected-mode默认为yes,只有当你希望你的客户端在没有授权的情况下可以连接到Redis Server的时候可以将protected-mode设置为no

  • Redis Functions

    Redis函数,一种新的通过服务端脚本扩展Redis的方式,函数与数据本身一起存储。

  • RDB保存时间调整

    持久化文件RDB的保存规则发生了改变,尤其是时间记录频度变化

  • 命令新增和变动

    1.ZSet(有序集合)增加ZMPOP、BZMPOP、ZINTERCARD 等命令。
    2.Set(集合)增加SINTERCARD命令。
    3.LIST(列表)增加LMPOP、BLMPOP,从提供的键名列表中的第一个非空列表键中弹出一个或多个元素。

  • 性能资源利用率、安全性等改进

    自身底层部分优化改动:Redis核心在许多方面进行了重构和改进:
    1.主动碎片整理V2:增强版主动碎片整理,配合Jemalloc版本更新,更快更智能,延时更低。
    2.HyperLogLog改进:在Redis5.0中,HyperLogLog算法得到改进,优化了计数统计时的内存使用效率,7.x更好的内存统计报告。
    3.如果不为了API向后兼容,我们将不再使用slave(奴隶)一词(政治正确)

七、Redis基础篇

使用Redis前需要编译安装以及进行基本的配置,Redis的编译安装、运行,基本配置和客户端命令使用具体见:

7.1 数据结构

Redis的数据结构指的是Value的数据结构类型,Key都是字符串。Redis官网的介绍:https://redis.io/technology/data-structures/

截止到目前的7.x版本,Redis共有10大数据结构,常用的经典数据结构类型有String、List、Hash、Set、ZSet

序号文章名概述
1Redis数据结构之String字符串
2Redis数据结构之List列表
3Redis数据结构之Hash哈希表
4Redis数据结构之Set集合
5Redis数据结构之ZSet(SortedSet) 有序集合

Redis进化过程中又陆陆续续推出了GEO、HyperLogLog、Bitmap、Bitfleid、Stream这几种更加高级的数据结构

序号文章名概述
1Redis数据结构之HyperLogLog用来做基数统计的算法
2Redis数据结构之GEO地理空间
3Redis数据结构之Bitmap位图,二进制位的bit数组
4Redis数据结构之Bitfleid位域
5Redis数据结构之Stream流,主要用于消息队列

参考

  1. 尚硅谷Redis零基础到进阶,作者:尚硅谷,哔哩哔哩,2023.02.21

Docker开篇

2022年1月15日 00:00

一、Docker概述

  Docker是一个开源的平台,是基于GO语言实现的开源项目,旨在让应用程序更简单地创建、部署和运行,解决了运行环境和配置问题。它是linux容器技术的落地实现,依赖已经存在的linux环境,实现应用程序及其依赖环境的打包,使得软件可以带着环境安装,一次镜像,处处运行,不受具体操作系统环境的限制。

  Docker官网:https://www.docker.com/

  Docker必须部署在Linux内核的系统上,实质上是在一个运行中的Linux环境上创建了一个隔离的文件环境。

Docker的优点

  • 快速的交付和部署
  • 提高硬件利用率
  • 便捷的升级和扩容缩容
  • 更简单的系统运维

二、Docker和虚拟机

  虚拟机就是带环境安装的一种解决方案,它可以在一种操作系统上面虚拟出硬件后,在上面完整运行另一种操作系统,再从这个操作系统上运行自己的软件,比如在Windows10系统里面运行Linux Centos7,应用程序对此毫无感知,因为虚拟机看起来和真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响,这类虚拟机完美的运行了另一套系统,能够使应用程序,操作系统和硬件三者之间逻辑不变。

  虚拟机存在明显的缺点:资源占用多,冗余步骤多,启动也很慢,因此Linux发展出了另一种虚拟化技术: Linux容器(Linux Containers,缩写LXC),Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需的全部文件,容器提供的镜像包含了应用的所有依赖项。

  Linux容器不是模拟一个完整的操作系统而是对进程进行了隔离,有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中,容器与虚拟机不同,不需要捆绑一整套操作系统,容器内进程直接运行于宿主机的内核,容器没有自己的内核也没有虚拟的硬件,只需要软件工作所需的库资源和设置。容器之间相互隔离,每个容器有自己的文件系统,容器之间进程不会互相影响,系统因此变得高效轻量。

  总结:Docker是在操作系统层面实现虚拟化,直接复用本地的操作系统,而传统虚拟机则是在硬件层面虚拟化,因此和虚拟机相比,Docker启动更加的快速,占用体积明显减小。

三、Docker的三要素

  • 镜像 (Image)

  镜像是只读的模板,用于创建docker容器,一个镜像可以创建多个容器,相当于一个root文件系统

  • 容器 (Container)

  Docker利用容器独立运行一个或一组应用,容器是一个简易版的Linux运行环境(包括root权限,进程空间,用户空间和网络),以及运行在上面的应用程序,应用程序运行在容器里面,容器相当于一个虚拟化的运行环境,是利用镜像创建的运行实例,镜像是静态的,容器为镜像提供了一个标准的隔离的运行实体,容器可以被启动,开始,停止,删除,每个容器都是相互隔离,保证安全的。

  • 仓库 (Repository)

  Docker公司提供了一个保存各种Docker镜像的仓库,称之为DockerHub,地址: https://hub.docker.com
  还可以根据需要,搭建自己的私有仓库

四、Docker的架构和运行流程

  从其架构和运行流程快来看,Docker是一个C/S模式的架构,后端是一个松耦合架构,众多模块各司其职。

Docker的基本运行流程为:

  1. 用户使用Docker Client与Docker Daemon建立Socket通信,并发送请求给后者。
  2. Docker Daemon作为Docker架构中的主体部分,首先提供Docker Server的功能使其可以接受Docker Client的请求。
  3. Docker Engine执行Docker内部的一些列工作,每一项工作都是以一个Job的形式存在。
  4. Job在运行过程中,当需要镜像时,从Docker Registry中下载镜像,并通过镜像管理驱动Graph driver将下载镜像以graph的形式存储。
  5. 当需要为Docker创建网络环境时,通过网络管理驱动Network driver创建并配置Docker容器网络环境。
  6. 当需要限制Docker容器运行资源或执行用户指令操作时,则通过Exec driver来完成。
  7. Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。

五、Docker基础篇

序号文章名概述
1Docker的安装和配置docker的安装及常见的命令
2Docker的离线安装下载二进制文件并注册系统服务
3Docker的镜像操作镜像的一些操作,拉取,搜索,删除等
4Docker的容器操作容器的操作,新建,启动,停止,查看日志和容器内操作等
5Docker容器数据卷实现和宿主机共享文件
6Docker网络docker的4种网络类型以及自定义网络
7Dockerfile使用dockerfile构建镜像
8Docker Composedocker官方的容器编排工具,实现同时部署多个应用
9DockerHubDocker官方提供的全球最大的容器镜像、扩展和插件集合

六、Docker高阶篇

序号文章名概述
1Docker与联合文件系统docker镜像加载原理

参考

1.尚硅谷Docker实战教程,尚硅谷,2022-01-05

Java开篇

2021年12月29日 00:00

栏目持续更新中

一、引言

Java基础是全站的开篇,但是这个系列只会整理Java基础类库的使用和最新特性以及一些底层原理和源码解读,不会赘述JDK的安装配置和面向对象等最基础的内容。

二、Java版本发展

  • 1990年末, Sun公司成立了一个由James Gosling领导的”Green 计划”,准备为下一代智能家电 (如电视机、微波炉、电话)编写一个通用控制系统,在尝试了使用C++和改造C++未果后,决定创造一种全新的语言: Oak
  • 1992年夏,Green计划己经完成了新平台的部分功能,包括Green操作系统、Oak的程序设计语言、类库等
  • 1994年,互联网和浏览器的出现,开发组意识到Oak非常适合于互联网,对Oak进行了小规模的改造运行在浏览器,并更名为Java
  • 1995年初,Sun推出了Java语言
  • 1996年初,发布JDK1.0,这个版本包括两部分: 运行环境(JRE)和开发环境(JDK)
  • 1997年2月,发布JDK1.1,增加了JIT(即时编译)编译器
  • 1998年12月,Sun发布了Java历史上最重要的JDK版本:JDK1.2,伴随JDK1.2一同发布的还有JSP/Servlet、EJB等规范,并将Java分成了J2EE、J2SE和J2ME三个版本
  • 2002年2月,Sun发布了JDK历史上最为成熟的版本: JDK1.4
  • 2004年10月,发布里程式板本:JDK1.5,为突出此版本的重要性,更名为JDK5.0(Java5),同时,Sun将J2EE、J2ME也相应地改名为Java EE和Java ME,增加了诸如泛型、增强的for语句、可变数量的形参、注释 (Annotations)、自动拆箱和装箱等功能
  • 2006年12月,Sun公司发布了JDK1.6(Java6)
  • 2009年4月20日,Oracle宣布将以每股9.5美元的价格收购Sun
  • 2011年,发布JDK1.7(Java7),是Oracle来发布的第一个Java版本,引入了二进制整数、支持字符串的switch语句、菱形语法、多异常捕捉、自动关闭资源的try语句等新特性。
  • 2014年,发布Java8,是继Java5以来变化最大的版本,带来了全新的Lambda表达式、流式编程等大量新特性,具体见:Java8的新特性
  • 2017年9月,发布Java9,提供了超过150项新特性,主要包括模块化系统,jshell交互工具,jdk编译工具,java公共API以及安全增强,而且采用了更高效、更智能的G1垃圾回收器,完全对Java体系进行了改变,让庞大的Java语言更轻量化。从Java9开始,Java版本更迭从特性驱动改为时间驱动,每个版本之间的更迭周期调整为6个月,但是LTS版本的更迭时间为3年。同时将Oracle JDK的原商业特性进行开源。
  • 2018年3月,发布Java10
  • 2018年9月,发布Java11

三、Java核心类库

3.1 JDK基础类库

待续

3.2 数据结构 (Collection,Map,Set)

待续

3.3 输入输出 (IO/NIO)

在Java中,和IO有关的操作封装在java.iojava.nio中,传统IO(java.io)是以流的形式实现输入输出操作的,还有基于通道和缓冲区的NIO(java.nio

I/O操作,有阻塞和非阻塞之分:

  • 阻塞:发起读取数据的线程是被阻塞的
  • 非阻塞:发起读取数据的线程不被阻塞,直接返回

也有同步和异步之分:

  • 同步:数据读取完成后,直接在接收到数据的线程上,紧接着进行拷贝操作
  • 异步:数据读取完成后,通过一个回调函数,在新的线程处理数据的拷贝

阻塞非阻塞和同步异步,描述的阶段和描述的事情是不同的,因此可以自由组合,Java语言将其组合为分为BIO,NIO,和AIO三种不同的IO,与Linux的IO模型(详见:浅谈Linux(Unix)的I/O模型)对应的话,BIO对应的是Blocking I/O

  • BIO

    同步的,阻塞的IO,位于java.io包下,是Java的传统IO,基于流,IO流的分类方式有很多,按照方向分为输入流和输出流,按照数据传输单位又能分为字节流和字符流

  • NIO

    同步的,非阻塞的IO,位于java.nio包下

  • AIO

    异步的,非阻塞的IO,也位于java.nio包下

3.4 网络 (Socket)

3.5 线程 (Thread)

本部分主要讲述了使用Java语言来实现多线程的程序,包括线程的创建方式,线程基本方法的使用,多线程操作共享数据导致的安全问题以及死锁现象的原因和避免死锁,多线程运行过程中的协作和通信机制以及调用各种线程的方法时线程状态和生命周期的改变等。

序号文章名概述
1Java的线程和常见方法进程和线程,并发和并行,线程的创建和常见方法
2Java线程安全和同步机制多线程导致的问题,线程的同步机制,死锁
3Java线程间的通信机制线程的通信,等待唤醒机制wait/notify
4Java线程的状态不同线程状态之间的转换过程
5volatile作用分析volatile关键字的作用,可见性、原子性和重排序

3.6 并发编程 (JUC)

JUC就是Java在并发编程中使用的工具包java.util.concurrent的简称,包括java.util.concurrentjava.util.concurrent.atomicjava.util.concurrent.locks等,起始于JDK1.5,是Java语言中增强版的多线程和高并发工具,拥有更加强大的多线程实现,本章内容会介绍些JUC中常用的并发编程工具类及其实现原理,需要在理解了第3.5小节的线程一章的基础上学习

主要涉及:

  • 锁,可重入锁,公平/非公平锁java.util.concurrent.locks.Lockjava.util.concurrent.locks.Condition
  • 读写锁相关java.util.concurrent.locks.ReadWriteLock
  • 异步计算 java.util.concurrent.CompletableFuturejava.util.concurrent.FutureTaskjava.util.concurrent.Callable
  • 阻塞队列 java.util.concurrent.BlockingQueue
  • 线程池 java.util.concurrent.ExecutorService
  • 任务拆分合并工具 java.util.concurrent.ForkJoinPooljava.util.concurrent.ForkJoinTask
  • 线程安全容器 java.util.concurrent.CopyOnWriteArrayListjava.util.concurrent.ConcurrentHashMapjava.util.concurrent.CopyOnWriteArraySet
  • 并发控制工具 java.util.concurrent.CountDownLatchjava.util.concurrent.CyclicBarrierjava.util.concurrent.Semaphore
  • 各种原子类,例如java.util.concurrent.atomic.AtomicIntegerjava.util.concurrent.atomic.AtomicReference
  • 多线程编程的一些问题:缓存行对齐、锁的粗化,消除等

3.7 反射 (Reflect)

待续

3.8 JDK其他工具和类

序号文章名概述
1Java实现LDAP登录使用Java与LDAP进行交互

四、Java的设计模式

序号文章名概述
1Java单例Java中单例模式的几种实现形式

五、参考

  1. 《疯狂Java讲义》,作者:李刚,电子工业出版社,2018年1月
  2. 《深入理解Java核心技术》,作者:张洪亮,电子工业出版社,2022年5月
  3. 《Effective Java》,作者:Joshua Bloch,机械工业出版社,2009年1月

MySQL开篇

2021年12月29日 00:00

栏目持续更新中

一、MySQL概述

MySQL数据库由瑞典MySQL AB公司开发。公司名中的”AB”是瑞典语”aktie bolag”股份公司的首字母缩写。该公司于2008年1月16日被SUN公司收购,2009年,SUN公司又被Oracle收购。因此,MySQL数据库现在属于Oracle公司。MySQL中的”My”是其作者Michael Widenius根据其大女儿My的名字来命名的。

本文系MySQL系列的开篇,主要基于MySQL8并部分结合5.7,主要介绍SQL语句和语法、MySQL的数据库对象、架构和性能调优以及一些高级特性的运用和原理等。

二、MySQL的优势

  • 可移植性

    MySQL数据库几乎支持所有的操作系统,如Linux、Solaris、FreeBSD、Mac和Windows。

  • 免费

    MySQL的社区版完全免费,一般中小型网站的开发都选择MySQL作为网站数据库。

  • 开源

    2000年,MySQL公布了自己的源代码,并采用GPL许可协议正式进入开源的世界。开源意味着可以让更多人审阅和贡献源代码,可以吸纳更多优秀人才的代码成果。

  • 关系型数据库

    MySQL可以利用标准SQL语法进行查询和操作。

  • 速度快、体积小、容易使用

    与其他大型数据库的设置和管理相比,其复杂程度较低,易于学习。MySQL的早期版本(主要使用的是MYISAM引擎)在高并发下显得有些力不从心,随着版本的升级优化(主要使用的是InnoDB引擎),在实践中也证明了高压力下的可用性。从2009年开始,阿里的”去IOE”备受关注,淘宝DBA团队再次从Oracle转向MySQL,其他使用MySQL数据库的公司还有Facebook、Twitter、YouTube、百度、腾讯、去哪儿等,自此,MySQL在市场上占据了很大的份额。

  • 安全性和连接性

    十分灵活和安全的权限和密码系统,允许基于主机的验证。当连接到服务器时,所有的密码传输均采用加密形式,从而保证了密码安全。因为MySQL是网络化的,所以可以在互联网上的任何地方访问,提高数据共享的效率。

  • 丰富的接口

    提供了用于C、C++、Java、PHP、Python、Ruby、Eiffel、Perl等语言的API。

  • 灵活

    MySQL并不完美,但是却足够灵活,能够适应高要求的环境。同时,MySQL既可以嵌入应用程序中,也可以支持数据仓库、内容索引和部署软件、高可用的冗余系统、在线事务处理系统等各种应用类型。

  • 存储引擎架构

    MySQL最重要、最与众不同的特性是它的存储引擎架构,这种架构的设计将查询处理及其他系统任务和数据的存储/提取相分离。这种处理和存储分离的设计可以在使用时根据性能、特性,以及其他需求来选择数据存储的方式。MySQL中同一个数据库,不同的表格可以选择不同的存储引擎。其中使用最多的是InnoDB和MyISAM,MySQL5.5之后InnoDB是默认的存储引擎。

三、MySQL的版本

针对不同用户,MySQL提供了3个不同的版本。

  • MySQL Enterprise Server (企业版)

    能够以更高的性价比为企业提供数据仓库应用,该版本需要付费使用,官方提供电话技术支持。

  • MySQL Cluster (集群版)

    MySQL集群版是MySQL适合于分布式计算环境的高可用、高冗余版本。它采用了NDB Cluster存储引擎,允许在1个集群中运行多个MySQL服务器。它不能单独使用,需要在社区版或企业版基础上使用,集群版是免费的,但是高级集群版MySQL Cluster CGE需要付费。

  • MySQL Community Server (社区版)

    在开源GPL许可证之下可以自由地使用。该版本完全免费,但是官方不提供技术支持。本书是基于社区版讲解和演示的。在MySQL社区版开发过程中,同时存在多个发布系列,每个发布系列处在不同的成熟阶段。

MySQL 5.7(RC)是当前稳定的发布系列。RC版(Release Candidate 候选版本)只针对严重漏洞修复和安全修复重新发布,没有增加会影响该系列的重要功能。从MySQL 5.0、5.1、5.5、5.6直到5.7都基于5这个大版本,升级的小版本。5.0版本中加入了存储过程、服务器端游标、触发器、视图、分布式事务、查询优化器的显著改进,以及其他的一些特性。这也为MySQL 5.0之后的版本迈向高性能数据库的发展奠定了基础。

MySQL 8.0.26(GA)是最新开发的稳定发布系列。GA(General Availability 正式发布的版本)是包含新功能的正式发布版本。这个版本是MySQL数据库又一个新时代的开始。

四、MySQL基础篇

使用MySQL前需要进行安装,并进行简单配置(修改字符集,打开远程连接等),为了更加贴合实际应用场景,本章关于MySQL的一切,无特殊说明的,都基于运行在Linux系统环境上的MySQL。

Linux系统安装MySQL,最简单的方式就是采用rpm包安装,这里我采用常用的CentOS7环境来安装MySQL用于后续学习测试,具体步骤见:

除了rpm包安装,还可以通过自行编译源码的方式安装MySQL,因为CentOS7逐步不再更新,因此这里我尝试基于另一个RHEL系的Linux发行版RockyLinux9的环境来编译安装,具体步骤见:

MySQL的基础部分,主要包括以下内容:

SQL语言,数据类型、约束、DDL/DML语句以及SELECT语句等

序号文章名概述
1MySQL数据定义语言DDL语句以及数据类型
2MySQL插入修改和删除数据的添加和更新,DML语句
3MySQL查询数据的查询,SELECT语句,JOIN查询
4MySQL事务事务的特性,隔离级别,TCL语句

一些基础的数据库对象(视图、存储过程、函数、触发器、变量等)的使用

序号文章名概述
1MySQL函数常见函数使用和自定义函数
2MySQL存储过程存储过程的定义和调用
3MySQL视图视图创建、修改和使用
4MySQL变量用户变量和系统变量,变量的查询和设置

五、MySQL高级篇

本博客MySQL高级部分的内容,侧重点是后端开发中怎样写出更高性能的SQL,基本不会深入到DBA领域。

内容包括MySQL的字符集,语法模式,用户和权限DCL语句,MySQL架构和执行流程,索引和索引优化,锁机制,事务和日志以及主从复制等。

序号文章名概述
1MySQL字符集及底层原理基于MySQL5.7解读MySQL字符集和排序实现原理
2MySQL5.7x的主从复制负载均衡、备份和高可用性

结束语

更多MySQL相关的内容,可以查阅官方文档:

参考

  1. 《剑指MySQL 8.0:入门、精练与实战》,作者:尚硅谷教育,电子工业出版社,2023年2月
  2. 《高性能MySQL(第三版)》,作者:Baron Schwartz、Peter Zaitsev、Vadim Tkachenko,电子工业出版社,2013年5月
  3. MySQL数据库入门到大牛,作者:尚硅谷,哔哩哔哩,2021-11-17

Python的数据结构

2026年1月1日 00:00

未完待续

【新年开篇】让我们拿出跃马扬鞭的勇气,激发万马奔腾的活力,保持马不停蹄的干劲,一起为梦想奋斗、为幸福打拼,把宏伟愿景变成美好现实。

1.概述

在Python中,有四种常见的数据结构

数据结构是否可变是否允许重复是否有序定义符号
列表(List)可变允许有序[]
元组(Tuple)不可变允许有序()
字典(Dict)可变键不允许,值允许有序{}
集合(Set)可变不允许无序{}

2.列表(List)

列表是一种有序的数据结构,元素写在[]中间,用,隔开通过下标访问。

列表创建有三种,直接创建,通过list()方法,以及推导式。

列表的特点:

  • 可以被索引(从左到右和从右到左)和切片(substring)
  • 可以使用+操作符进行拼接
  • 列表中的元素是可变的
  • 元素可以是任意类型
  • 元素允许重复

2.1 创建,索引和切片

#直接创建list1 = [1,2,3,4,5]list2 = ['abc', 2, 1.55]# 索引 => 1print(list1[0])# 第2到第4的元素,不含第4个 => [2, 3]print(list1[1:3])# 从第3个元素开始到末尾 => [3, 4, 5]print(list1[2:])# list1复制成两份拼接一起 => [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]print(list1 * 2)# 拼接 => [1, 2, 3, 4, 5, 'abc', 2, 1.55]print(list1 + list2)

Python列表可以倒序索引,且元素可变

list1[-1] = 100print(list1[-1]) #100

python可以用list()方法创建一个空的集合

empty_list = list()print(empty_list)

list()方法从字符串创建数组

s = 'hello'l = list(s)print(l) #['h', 'e', 'l', 'l', 'o']

3.元组(Tuple)

4.字典(Dict)

5.集合(Set)

Spring AI集成多模态模型

2025年12月31日 00:00

未完待续

模态和多模态的概念等前置知识,已经在以下文章中提到

Spring AI对于多模态也做了支持,本文介绍Spring AI对接多模态模型的用法。

1.视觉理解

很多多模态大模型产品也都支持OpenAI的协议,因此还是使用spring-ai-starter-model-openai

pom.xml

<parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>3.5.7</version></parent><dependencyManagement>    <dependencies>        <dependency>            <groupId>org.springframework.ai</groupId>            <artifactId>spring-ai-bom</artifactId>            <version>1.1.2</version>            <type>pom</type>            <scope>import</scope>        </dependency>    </dependencies></dependencyManagement><dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>        <scope>test</scope>    </dependency>    <dependency>        <groupId>org.springframework.ai</groupId>        <artifactId>spring-ai-starter-model-openai</artifactId>    </dependency>    <!-- Lombok -->    <dependency>        <groupId>org.projectlombok</groupId>        <artifactId>lombok</artifactId>    </dependency></dependencies><build>    <plugins>        <plugin>            <groupId>org.apache.maven.plugins</groupId>            <artifactId>maven-compiler-plugin</artifactId>            <configuration>                <source>21</source>                <target>21</target>                <encoding>UTF-8</encoding>            </configuration>        </plugin>    </plugins></build>

application.yml

spring:  ai:    openai:      base-url: https://dashscope.aliyuncs.com/compatible-mode      api-key: ${QWKEY}      chat:        options:          model: qwen3-vl-pluslogging:  level:    org.springframework.ai: debug

配置类不变,使用OpenAI协议的模型

package org.example;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;import org.springframework.ai.chat.memory.ChatMemory;import org.springframework.ai.openai.OpenAiChatModel;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configurationpublic class SpringAiConfig {        @Bean    public ChatClient chatClient(OpenAiChatModel model, ChatMemory chatMemory) {        return ChatClient.builder(model)                .defaultAdvisors(                         SimpleLoggerAdvisor.builder().build(),                         MessageChatMemoryAdvisor.builder(chatMemory).build()                )                .build();    }}

新建测试类,测试多模态模型。user提示词中使用.user(e -> e.text("图片中的统计数据是谁发布的,大学学历网民占比是多少。").media(media))传递图片内容

package org.example.test;import jakarta.annotation.Resource;import lombok.extern.slf4j.Slf4j;import org.example.Main;import org.junit.jupiter.api.Test;import org.springframework.ai.chat.client.ChatClient;import org.springframework.ai.chat.memory.ChatMemory;import org.springframework.ai.content.Media;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.http.MediaType;@SpringBootTest(classes = Main.class)@Slf4jpublic class UnitTest {    @Resource    private ChatClient chatClient;    @Value("classpath:image.png")    private org.springframework.core.io.Resource resource;    @Test    public void test() {        Media media = new Media(MediaType.valueOf("image/png"), resource);        String content = chatClient.prompt()                .user(e -> e.text("图片中的统计数据是谁发布的,大学学历网民占比是多少。")                        .media(media))                .advisors(advisor -> advisor.param(ChatMemory.CONVERSATION_ID, 1))                .call()                .content();        log.info("************** {}", content);    }}

然后得到大模型分析结果

2026-01-13T09:11:37.737+08:00 DEBUG 8620 --- [           main] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : request: ChatClientRequest[prompt=Prompt{messages=[UserMessage{content='图片中的统计数据是谁发布的,大学学历网民占比是多少。', metadata={messageType=USER}, messageType=USER}], modelOptions=OpenAiChatOptions: {"streamUsage":false,"model":"qwen3-vl-plus","temperature":0.7}}, context={chat_memory_conversation_id=1}]2026-01-13T09:11:44.273+08:00 DEBUG 8620 --- [           main] o.s.a.c.c.advisor.SimpleLoggerAdvisor    : response: {  "result" : {    "metadata" : {      "finishReason" : "STOP",      "contentFilters" : [ ],      "empty" : true    },    "output" : {      "messageType" : "ASSISTANT",      "metadata" : {        "role" : "ASSISTANT",        "messageType" : "ASSISTANT",        "refusal" : "",        "finishReason" : "STOP",        "annotations" : [ { } ],        "index" : 0,        "id" : "chatcmpl-47c0652b-2526-9dd5-8d56-b3067f837901"      },      "toolCalls" : [ ],      "media" : [ ],      "text" : "根据图片信息:\n\n1. **统计数据发布方**:  \n   该数据由 **CNNIC(中国互联网络信息中心)** 发布,来源于其《中国互联网络发展状况统计调查》。\n\n2. **大学本科及以上学历网民占比**:  \n   - 在 **2016年12月** 的数据中,占比为 **11.5%**。  \n   - 在 **2017年6月** 的数据中,占比为 **11.6%**。\n\n因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。\n\n✅ 总结:\n- 发布机构:**CNNIC**\n- 大学本科及以上学历网民占比(2017.6):**11.6%**"    }  },  "metadata" : {    "id" : "chatcmpl-47c0652b-2526-9dd5-8d56-b3067f837901",    "model" : "qwen3-vl-plus",    "rateLimit" : {      "requestsLimit" : null,      "requestsRemaining" : null,      "requestsReset" : null,      "tokensLimit" : null,      "tokensRemaining" : null,      "tokensReset" : null    },    "usage" : {      "promptTokens" : 457,      "completionTokens" : 178,      "totalTokens" : 635,      "nativeUsage" : {        "completion_tokens" : 178,        "prompt_tokens" : 457,        "total_tokens" : 635,        "prompt_tokens_details" : { },        "completion_tokens_details" : { }      }    },    "promptMetadata" : [ ],    "empty" : false  },  "results" : [ {    "metadata" : {      "finishReason" : "STOP",      "contentFilters" : [ ],      "empty" : true    },    "output" : {      "messageType" : "ASSISTANT",      "metadata" : {        "role" : "ASSISTANT",        "messageType" : "ASSISTANT",        "refusal" : "",        "finishReason" : "STOP",        "annotations" : [ { } ],        "index" : 0,        "id" : "chatcmpl-47c0652b-2526-9dd5-8d56-b3067f837901"      },      "toolCalls" : [ ],      "media" : [ ],      "text" : "根据图片信息:\n\n1. **统计数据发布方**:  \n   该数据由 **CNNIC(中国互联网络信息中心)** 发布,来源于其《中国互联网络发展状况统计调查》。\n\n2. **大学本科及以上学历网民占比**:  \n   - 在 **2016年12月** 的数据中,占比为 **11.5%**。  \n   - 在 **2017年6月** 的数据中,占比为 **11.6%**。\n\n因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。\n\n✅ 总结:\n- 发布机构:**CNNIC**\n- 大学本科及以上学历网民占比(2017.6):**11.6%**"    }  } ]}2026-01-13T09:11:44.273+08:00  INFO 8620 --- [           main] org.example.test.UnitTest                : ************** 根据图片信息:1. **统计数据发布方**:     该数据由 **CNNIC(中国互联网络信息中心)** 发布,来源于其《中国互联网络发展状况统计调查》。2. **大学本科及以上学历网民占比**:     - 在 **2016年12月** 的数据中,占比为 **11.5%**。     - 在 **2017年6月** 的数据中,占比为 **11.6%**。因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。✅ 总结:- 发布机构:**CNNIC**- 大学本科及以上学历网民占比(2017.6):**11.6%**

LangChain Tools工具使用

2025年12月24日 00:00

未完待续

关于大模型工具使用有关前置知识和原理,已经在下面文章提到:

1.概述

本文介绍基于langchain开发具有工具使用(Function calling)功能的智能体Agent

2.实现

langchain开发Agent,需要安装包

pip install langchain==1.1.2pip install langchain-openaipip install langchain-classic

实现工具方法供大模型调用,并通过函数装饰器@tools修饰工具方法

@tools常用属性

属性类型描述
name_or_callablestr | Callable名称
descriptionstr描述工具的功能,会作为上下文发送给大模型
args_schemaArgsSchema可选择性地指定参数格式
return_directbool是否直接从工具返回

/my_tools.py

from langchain.tools import toolfrom pydantic import BaseModelfrom pydantic import Fieldclass FiledInfo(BaseModel):    """    定义参数信息    """    city: str = Field(description='城市')@tool(args_schema=FiledInfo, description='根据城市名称获取温度')def tp_tool(city: str) -> int:    print('=======tp_tool=======')    if city == '北京':        return 12    elif city == '武汉':        return 23    elif city == '沈阳':        return -10    elif city == '泉州':        return 27    else:        return Noneif __name__ == '__main__':    print( tp_tool.invoke({'city': '沈阳'}) )

使用create_agent创建智能体agent,绑定模型和工具,然后调用invoke()执行

/test_tool2.py

import osfrom langchain.agents import create_agentfrom langchain.chat_models import init_chat_modelfrom my_tool import tp_toolllm = init_chat_model(    model = 'deepseek-chat',    model_provider = 'openai',    api_key = os.getenv('DSKEY'),    base_url = 'https://api.deepseek.com')# 创建 Agent,绑定tp_tool工具agent = create_agent(    llm,    tools=[tp_tool],    system_prompt="""你是一个天气查询助手""")# 执行result = agent.invoke({    "messages": [{"role": "user", "content": "泉州温度多少"}]})for msg in result['messages']:    if hasattr(msg, 'content'):        print(f"{msg.__class__.__name__}: {msg.content}")

输出结果

=======tp_tool=======HumanMessage: 泉州温度多少AIMessage: 我来帮您查询泉州的温度。ToolMessage: 27AIMessage: 根据查询结果,泉州的当前温度是**27°C**。

LangChain4j多模态

2025年12月30日 00:00

未完待续

1.多模态概述

模态,就是感知事物的方式,比如视觉,听觉等,对应的信息传播媒介可以是文字,图片,视频,音频等。多模态就是从多个模态表达和感知事物。

很多模型都是单模态,输入和输出都只能是文本,是语言模型,例如deepseek,即使能上传图片,也是识别图片中的文字。但是除了语言模型,还有除语言外还支持其他模态的模型,便是多模态的模型。

即便多模态模型支持很多模态,也很难像人类一样,完完全全支持全模态。

多模态模型实现形式有很多,有的能根据文字生成图片视频,有的则是根据图片生成文字;有的还能根据图片生成图片实现AI试衣,有的不仅支持图文,还支持其他的媒体,比如会议转录文字,听歌识曲等。

LangChain4j框架当然也对多模态模型接入使用提供了支持,本文以阿里巴巴qwen3-vl-plus模型为例介绍。

2.图片内容理解(图生文)

以这张图片(src/main/resources/image.png)为例

pom.xml中和简单的prompt工程需要的依赖是一样的

<parent>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-parent</artifactId>    <version>3.5.4</version>    <relativePath/></parent><dependencyManagement>    <dependencies>        <dependency>            <groupId>dev.langchain4j</groupId>            <artifactId>langchain4j-bom</artifactId>            <version>1.8.0</version>            <type>pom</type>            <scope>import</scope>        </dependency>    </dependencies></dependencyManagement><dependencies>    <dependency>        <groupId>dev.langchain4j</groupId>        <artifactId>langchain4j-spring-boot-starter</artifactId>    </dependency>    <dependency>        <groupId>dev.langchain4j</groupId>        <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>org.projectlombok</groupId>        <artifactId>lombok</artifactId>        <scope>provided</scope>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>        <scope>test</scope>    </dependency></dependencies><repositories>    <repository>        <name>Central Portal Snapshots</name>        <id>central-portal-snapshots</id>        <url>https://central.sonatype.com/repository/maven-snapshots/</url>        <releases>            <enabled>false</enabled>        </releases>        <snapshots>            <enabled>true</enabled>        </snapshots>    </repository></repositories><build>    <plugins>        <plugin>            <groupId>org.apache.maven.plugins</groupId>            <artifactId>maven-compiler-plugin</artifactId>            <configuration>                <source>21</source>                <target>21</target>                <encoding>UTF-8</encoding>            </configuration>        </plugin>    </plugins></build>

application.yml配置也是和简单的prompt工程需要的依赖是一样的,阿里云百炼多模态支持模型同样适用OpenAI接口协议格式。

langchain4j:  open-ai:    chat-model:      base-url: https://dashscope.aliyuncs.com/compatible-mode/v1      api-key: ${QWKEY}      model-name: qwen3-vl-plus      log-requests: true      log-responses: true      return-thinking: truelogging:  level:    dev.langchain4j: debug

编写测试类测试多模态,将图片上传给大模型,并根据图片内容提问:图片中的统计数据是谁发布的,大学学历网民占比是多少。

package org.example.test;import dev.langchain4j.data.message.*;import dev.langchain4j.model.chat.ChatModel;import dev.langchain4j.model.chat.response.ChatResponse;import jakarta.annotation.Resource;import lombok.extern.slf4j.Slf4j;import org.example.Main;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Value;import org.springframework.boot.test.context.SpringBootTest;import java.io.IOException;import java.util.Base64;import java.util.List;@SpringBootTest(classes = Main.class)@Slf4jpublic class MTest {    @Resource    private ChatModel chatModel;    @Value("classpath:image.png")    private org.springframework.core.io.Resource resource;    @Test    public void imageToText() throws IOException {        byte[] byteArray = resource.getContentAsByteArray();        String base64 = Base64.getEncoder().encodeToString(byteArray);        UserMessage userMessage = UserMessage.from(                TextContent.from("图片中的统计数据是谁发布的,大学学历网民占比是多少。"),                ImageContent.from(base64, "image/png")        );        ChatResponse chatResponse = chatModel.chat(List.of(userMessage));        log.info("******** chatResponse: {}", chatResponse);    }}

发送base64形式图片时,url参数会标记为data:image/png;base64,,并将base64图片放到url中,上传到大模型

有的大模型服务平台,图片URL除了base64外,还可以写图片的http网络地址

2026-01-10T18:42:56.278+08:00  INFO 20808 --- [           main] d.l.http.client.log.LoggingHttpClient    : HTTP request:- method: POST- url: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions- headers: [Authorization: Beare...48], [User-Agent: langchain4j-openai], [Content-Type: application/json]- body: {  "model" : "qwen3-vl-plus",  "messages" : [ {    "role" : "user",    "content" : [ {      "type" : "text",      "text" : "图片中的统计数据是谁发布的,大学学历网民占比是多少。"    }, {      "type" : "image_url",      "image_url" : {        "url" : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA5YAAAHmCAIAAACH1IbBAAAQAElEQVR4Aez9C6BsSVUf/u/aux93BmYYQBAZGGZ4DEKEAQOaqIAkDIkIo0RgAgaBqKhAYghEjREBo1F5hGgEeUVAIwpojMA/0UCigJrkB0YGlPCSGV4SHgIDzMzp197/T+3qU71P9znnvu89fW73Xad61apVVbu+tWrV2rW7+5bN5nWIEKjrejqdjsfjm266aTKZnK2RjcbjG268cS+68cYbRyMq41ldn60rPCX9wnlra2uvYZLftLVlnLP2dUp6PNcagdyEQXubzYAJ0kRMiAwa0ptGoySUbm1tkZBv6NQi0AX5hptuqusazpwMzBPduLWVhEqTRGo6jnoZqZalNGpfsketcsgUjB1WexFT50OWYLEmYJur4E0H6s4IOAFFqIWseVSGsoVm71jqUVPrQq7cqNPV4oGzOmrDBLvSpNZNYduFkVoq1SZIu+adm9UFtW4tvFqayjoYOoQbOrUIlMXmtf4IsAkLjN/h7KwTu77YMK3PszK4Qb/f7/Wqsgyd7kNZllU1GAyGw+FgEFXK0C3vqB54FuDQ5qFE4UsXa1BlWfaqajgYIOOURUtqm+w+CIB3OpttMeXxeDqZzKbTEELV6+UqTVEweFny0MhhWwJ0ecZ8WtvjOicR5/aOlzHv7y56XVSbBviQrqoqj94s1E0TSDua2tds1ukyqcgKEhaYZy7LjFMm76qdIzxvyVGgiF/Y4RU        ......

大模型回复如下,可以看出精准理解了图片内容,并且能进行一定的分析推理。

2026-01-10T18:43:04.808+08:00  INFO 20808 --- [           main] d.l.http.client.log.LoggingHttpClient    : HTTP response:- status code: 200- headers: [vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding], [x-request-id: 3ac74322-599b-9042-b069-0d381d984c69], [x-dashscope-call-gateway: true], [content-type: application/json], [content-length: 1276], [req-cost-time: 7143], [req-arrive-time: 1768041778270], [resp-start-time: 1768041785413], [x-envoy-upstream-service-time: 6827], [date: Sat, 10 Jan 2026 10:43:05 GMT], [server: istio-envoy]- body: {"choices":[{"message":{"content":"根据图片信息:\n\n1. **统计数据发布方**:  \n   图片底部明确标注“来源:CNNIC 中国互联网络发展状况统计调查”,因此该数据是由 **中国互联网络信息中心(CNNIC)** 发布的。\n\n2. **大学学历网民占比**:  \n   图表中“大学本科及以上”学历对应的数据显示:\n   - **2016年12月**:占比为 **11.5%**\n   - **2017年6月**:占比为 **11.6%**\n\n✅ 因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。\n\n---\n\n📌 补充说明:  \n“大学本科及以上”通常包括本科、硕士、博士等高等教育学历,是衡量网民受教育程度的重要指标。从数据看,该比例在半年内略有上升,但整体仍低于初中和高中/中专/技校学历群体。","reasoning_content":"","role":"assistant"},"finish_reason":"stop","index":0,"logprobs":null}],"object":"chat.completion","usage":{"prompt_tokens":457,"completion_tokens":211,"total_tokens":668,"prompt_tokens_details":{"image_tokens":437,"text_tokens":20},"completion_tokens_details":{"text_tokens":211}},"created":1768041785,"system_fingerprint":null,"model":"qwen3-vl-plus","id":"chatcmpl-3ac74322-599b-9042-b069-0d381d984c69"}2026-01-10T18:43:04.839+08:00  INFO 20808 --- [           main] org.example.test.MTest                   : ******** chatResponse: ChatResponse { aiMessage = AiMessage { text = "根据图片信息:1. **统计数据发布方**:     图片底部明确标注“来源:CNNIC 中国互联网络发展状况统计调查”,因此该数据是由 **中国互联网络信息中心(CNNIC)** 发布的。2. **大学学历网民占比**:     图表中“大学本科及以上”学历对应的数据显示:   - **2016年12月**:占比为 **11.5%**   - **2017年6月**:占比为 **11.6%**✅ 因此,截至2017年6月,**大学本科及以上学历的网民占比为 11.6%**。---📌 补充说明:  “大学本科及以上”通常包括本科、硕士、博士等高等教育学历,是衡量网民受教育程度的重要指标。从数据看,该比例在半年内略有上升,但整体仍低于初中和高中/中专/技校学历群体。", thinking = null, toolExecutionRequests = [], attributes = {} }, metadata = OpenAiChatResponseMetadata{id='chatcmpl-3ac74322-599b-9042-b069-0d381d984c69', modelName='qwen3-vl-plus', tokenUsage=OpenAiTokenUsage { inputTokenCount = 457, inputTokensDetails = OpenAiTokenUsage.InputTokensDetails { cachedTokens = null }, outputTokenCount = 211, outputTokensDetails = OpenAiTokenUsage.OutputTokensDetails { reasoningTokens = null }, totalTokenCount = 668 }, finishReason=STOP, created=1768041785, serviceTier='null', systemFingerprint='null', rawHttpResponse=dev.langchain4j.http.client.SuccessfulHttpResponse@3fe8ad3f, rawServerSentEvents=[]} }

Bun × Ai 时代的工程基座:一次正在发生但仍未定型的技术转向

2026年1月10日 15:54
时间过得很快。回头再看近一两年的前端与 JavaScript 生态,会发现许多变化并不是突然发生的,而是在不知不觉中逐渐累积,直到某一个节点,人们才意识到:原来方向已经发生了偏移。 Bun,正处在这样一个节点上。 它并不是凭空出现的新概念,也不是一夜之间取代谁的“颠覆者”。相反,它更像是在长期工程实践中,被一步步推到台前的产物。而当它与 AI 公司的工程体系产生强关联时,这种变化开始显得不再普通。 这篇文章并不试图给 Bun 下一个过于激进的结论,而是希望在事实与趋势之间,梳理一条相对克制、但清晰的技术脉络。 ## 一、起点:Bun 并不是为了“取代”而生 最初谈起 Bun,几乎绕不开“性能”这个关键词。 启动速度、依赖安装速度、构建速度、测试速度——这些都是 Bun 最直观、也最容易被感知到的优势。在大量工程实践对比中,它确实在多个维度上展现出了明显的效率提升。 但如果只把 Bun 理解为“一个更快的 Node.js 替代品”,其实是一种过于表层的看法。 从设计层面看,Bun 的目标并不完全是兼容既有模式,而是试图在 **运行时、构建、测试、包管理** 这些长期被拆散的工程能力之间,重新建立统一的抽象。 换句话说,它关注的不是“某一个环节更快”,而是 **整个工程生命周期是否足够顺畅**。 这也是为什么 Bun 会选择: - 内置 TypeScript 与 JSX 支持 - 自带 bundler 与 test runner - 强调 Web API 风格而非 Node 专属 API 这些选择,在早期看起来多少有些“激进”,但它们背后指向的是同一个目标:**降低工程复杂度,提高系统整体可预测性**。
图片
> 我自己接触 Bun 的时间也不算长。是在目前公司的项目中开始使用的——公司需要做一个 AI 应用,后端框架是 Node.js,因此在主管的安排下我们开始用 Bun。起初我并没有过多考虑选择它的原因,只是按流程去做。但在实际开发过程中,我确实能切身体会到它在启动速度、构建和测试上的性能优势。随着项目推进,我也才慢慢对 Bun 的设计理念和更深层的工程价值有了更全面的理解。 ### 工程方式的变化 在更深层的工程语境中,Bun 的出现并不只是工具层面的改良,而是与工程形态本身的变化高度同步。 过去相当长一段时间里,前端与 JavaScript 工程的核心假设是:**人类开发者是工程的唯一组织者**。工具的职责,是围绕人类的使用习惯不断拆分、组合与优化。 而今天,这一假设正在被动摇。 当代码开始由 AI 生成、修改、运行,工程系统所面对的对象,已经不再只是“人”。它需要同时服务于 **人类开发者与自动化系统**。在这种前提下,工程工具的可组合性、启动成本、语义一致性,都会被重新放大。 也正是在这样的背景下,Bun 所强调的“统一运行时”价值,才开始真正显现。 ## 二、变化出现:当 AI 开始真正参与“写代码”和“跑代码” 真正让 Bun 进入更广泛讨论视野的,并不只是性能数据本身,而是 AI 技术形态的变化。 在早期,AI 更多是作为一种“能力服务”存在: - 提供 API - 生成文本或代码片段 - 由人类开发者完成最终集成 但随着 AI 编程工具的发展,情况正在发生变化。 AI 不再只是给出建议,而是开始: - 主动创建项目结构 - 直接生成可运行的代码 - 参与调试、测试与重构 在这种模式下,**代码的执行环境本身,开始成为 AI 能力的一部分**。 运行时不再只是“被动承载者”,而是 AI 工程体系中的关键基础设施。 ## 三、AI 工程场景中的 Bun 与 Anthropic 收购 随着 AI 不仅参与“写代码”,还开始直接“跑代码”,Bun 的价值逐渐凸显: - 高性能的启动与构建速度,适合高频、短生命周期的任务 - Web API 风格统一,降低跨端出错概率 - 一体化工具链,压缩工程抽象层,便于自动化系统使用 正是在这种背景下,AI 公司开始将目光投向 Bun。Bun 不再只是一个高性能的 Node.js 替代选项,而是成为 AI 工程体系中可以直接利用的关键基础设施。 因此,Bun 与 AI 公司 Anthropic 的关系,也就不仅仅是“合作”那么简单。事实上,**Bun 团队已被 Anthropic 正式收购**。这次收购不仅涉及核心团队成员的纳入,也包括 Bun 框架及其相关技术在 Anthropic 的 AI 工程体系中的战略整合。 公开信息显示,收购后情况包括: - **团队纳入**:Bun 核心团队成员正式加入 Anthropic,直接参与 Claude Code 等 AI 工程项目的开发和基础设施优化 - **技术整合**:Bun 框架及其运行时、构建、测试和包管理功能被用于提升 AI 工程效率,同时继续作为独立开源项目存在 - **保持开源与独立演进**:Bun 项目继续遵循 MIT 许可,核心开发由原团队主导,确保社区生态和技术创新不受影响 - **战略意义**:通过收购,Anthropic 可以直接利用 Bun 的高性能运行时和统一工具链,提升 AI 自动化开发、调试和部署能力 这次收购的价值,不仅在于团队和技术的整合,更体现在 **对未来 AI 驱动开发模式的战略布局**: - **底层基础设施的强化**:统一的运行时与工具链降低跨工具出错风险,提高工程可预期性 - **技术自主性与社区延续**:框架继续开源,使技术发展不被公司战略完全绑定,同时吸引更多开发者贡献与使用 - **支撑指数级 AI 应用增长**:为 AI 编程工具的快速迭代和扩展提供稳定、高效的基础设施 因此,在严肃的技术讨论中,把这次事件理解为: > **一次 AI 公司对 JavaScript 运行时层的战略收购与深度整合** 比简单称之为“合作”或“团队整合”更加准确,也更能体现其对工程体系和未来 AI 开发模式的深远影响。 ## 四、为什么 Bun 会进入 AI 公司的视野 如果抛开市场叙事,只从工程角度看,Bun 与 AI 应用之间的契合并不难理解。 ### 1. 启动成本与短生命周期任务 AI 生成与执行代码的场景,往往具有以下特征: - 高频启动 - 生命周期短 - 资源创建与销毁频繁 在这种情况下,运行时的冷启动成本会被无限放大。Bun 在启动速度和任务调度上的优势,使它在此类场景中具备天然适配性。 ### 2. Web API 语义的统一性 Bun 大量采用 Web 标准 API,而不是依赖 Node 特有接口。这意味着: - 浏览器与服务端语义更加一致 - AI 在生成跨端代码时面对的心智负担更低 对 AI 来说,语义越统一,出错概率就越低。 ### 3. 工程工具的一体化 当运行、构建、测试、依赖管理被拆分为多个工具时,人类尚且容易出错,更不用说自动化系统。 Bun 将这些能力收敛到同一运行时之中,本质上是在 **压缩抽象层级**。 而这,恰恰是 AI 系统最需要的特性之一。 ### 4. Bun 仍然付出的代价 当然,这种契合并非没有代价。 从现实工程角度看,Bun 仍然面临一些无法回避的约束: - 部分 Node 原生生态与底层依赖仍需适配 - 社区体量与长期稳定性尚在验证中 - 在复杂、超大规模系统中,其成熟度仍需时间检验 这意味着,Bun 目前更适合被视为 **“新型工程场景中的最优解之一”**,而非通用答案。 但需要注意的是,AI 工程体系本身,也并不追求完全通用。它更关注的是:**在可控边界内,是否存在更适合自动化执行的技术栈**。 ## 五、2026:可以讨论,但不必急于定论 关于“Bun 是否会成为 AI 应用的原生基座”,现在下结论显然为时尚早。 Node.js 仍然拥有极其庞大的生态与成熟度,其他运行时也在持续演进。工程世界的惯性,从来不是轻易被打破的。 但可以确定的是: - AI 公司已经开始认真对待运行时这一层 - JavaScript 执行环境正在从“工具选择”变成“战略资源” 在这样的背景下,Bun 所处的位置,已经不再只是一个“更快的选项”。 它更像是一次提前出现的尝试: > 如果未来的代码,有相当一部分不是由人写,而是由 AI 写并运行,那么运行时应该长成什么样? ### 工程师视角的落点 从工程师的视角看,或许并不需要急于站队。 Bun 值得关注的,并不是它是否会“取代”谁,而是它所代表的那种工程取向: **为自动化系统与人类协作而设计的运行时。** 在可预见的未来,JavaScript 生态很可能会长期处于多运行时并存的状态。而 Bun 的价值,也许正是在这些交汇点上,被逐步放大。 ## 六、回望:真正的变化往往发生在地基层 很多技术变革,在发生时并不喧哗。 它们不会以“全面替代”的姿态出现,而是先进入最敏感、也最苛刻的工程场景中,被反复打磨。 等人们意识到时,地基往往已经换过一次了。 Bun 是否会成为 AI 时代的原生运行时,目前没有人能给出确定答案。 但可以肯定的是,它已经不再只是一个实验性的项目,而是一次正在进行中的工程选择。 而所有真正重要的技术转向,往往正是从这种尚未定型的阶段开始的。

LangChain开篇

2025年5月24日 00:00

本系列未完待续

关于大语言模型驱动的应用程序有关前置知识,可以移步:

1.概述

LangChain(https://www.langchain.com/)是2022年10月,由哈佛大学的哈里森·蔡斯发起的一个开源框架,采用Python为主要语言编写,用于开发由大语言模型驱动的应用程序,一经推出便获得广泛支持,是最早推出,也是截止成文日期最成熟,支持场景最多的一个大模型应用框架

LangChain顾名思义,Lang指的就是大语言模型,Chain指的就是将大语言模型和各种相关的外部的组件连成一串,这个也是LangChain的核心设计思想。LangChain提供各种支持链式组装的组件,完成高级的特定任务,让复杂的逻辑变得结构化,易于组合和拓展。

LangChain提供整套大模型应用开发的工具集,支持LLM接入,Prompt对话工程构建,记忆管理,工具调用Tools,检索增强生成RAG等多种形态的应用开发。

LangChain类似Spring又分为Spring Framework,Spring Boot, Spring MVC那样,狭义上的LangChain就是LangChain本身,但广义的LangChain除了本身,还包括:LangGraph,LangSmith等组件,LangGraph在的基础上进一步封装,能够协调多个Chain,Tool,Agent完成更复杂的任务和更高级的功能。

本系列将基于Python 3.13.x + LangChain 1.1.x,通过常见形态大模型应用的例子介绍LangChain的使用

2.快速开始

虚拟环境中安装相关包,并设置好python版本

pip install langchain==1.1.2pip install langchain-openai
import sysimport langchainprint(sys.version)print(langchain.__version__)
3.13.11 (tags/v3.13.11:6278944, Dec  5 2025, 16:26:58) [MSC v.1944 64 bit (AMD64)]1.1.2

一个简单的调用大模型例子

from langchain.chat_models import init_chat_modelimport osllm = init_chat_model(    model = 'deepseek-chat',    model_provider = 'openai',    api_key = os.getenv('DSKEY'),    base_url = 'https://api.deepseek.com')print(llm.invoke('你是谁').content)

3. LangChain使用案例

序号文章名概述
1LangChain Prompt提示词工程大模型对话,会话记忆
2LangChain Tools工具使用Tools(Function calling)实现
❌