news 2026/9/30 15:23:09

高并发DAO层测试稳定之道:连接池管控、错峰与限流实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
高并发DAO层测试稳定之道:连接池管控、错峰与限流实战

压测一跑起来,连接池先被打满,接口报错堆成山,日志里全是Connection is not available。我盯着监控面板,数据库连接数一路飙到上限,线程全卡在获取连接的等待队列里,整个应用像被掐住脖子一样喘不上气。这是高并发下做 Java DAO 层测试最常见的修罗场。

这篇文章不聊虚的,就讲清楚三件事:连接数怎么管、请求怎么错峰、并发怎么限流。这套方法论我是在多个项目的压测实战里反复打磨出来的,适用场景很明确——大批量、高并发的 DAO 层测试,比如数据迁移校验、批处理回放、接口压测前置数据准备。无论你是刚接触压测的新人,还是被测试环境稳定性折腾得头疼的老手,照着这篇文章的思路去搭,至少能让你的 DAO 层测试从"随机崩"变成"稳如狗"。

1. 高并发下的 DAO 层测试,问题到底出在哪

1.1 崩溃点一:连接池被"借空"的连锁反应

用生活化的方式理解连接池,它就是数据库连接的水龙头。正常情况下水龙头够用,但并发一上来,每个线程都要开一个水龙头接水,池子里的连接是有限的,比如 HikariCP 默认maximumPoolSize = 10,而你有 50 个线程同时去抢,那 40 个线程就只能排队等着。

真正让系统崩溃的不是排队本身,而是排队引发的连锁反应。等不到连接的线程会一直占着线程池的 worker 不释放,而线程池的 worker 数量也是有限的。线程池被打满后,新的任务开始进入拒绝策略,这时候如果你的业务代码对拒绝异常处理不友好,轻则报错重试,重则直接丢数据。我在一个批处理项目里就踩过这个坑:数据回放任务一启动,2 分钟内连接池满,10 分钟内线程池满,30 分钟后整个应用无响应,最后只能靠重启恢复。

1.2 崩溃点二:测试数据"互相踩踏"

高并发下 DAO 层测试的另一个隐形杀手是测试数据干扰。举个例子:你为了测批量插入,开了 20 个并发线程同时往同一张用户表里写数据,假设每条数据的业务主键是手机号,而你在测试数据里用了同一个手机号段,那就会有大量Duplicate entry报错。

更隐蔽的是数据统计类的测试。你的 DAO 层如果包含"统计今日订单金额"这类聚合查询,多个线程同时写订单数据、同时做统计,跑出来的结果很可能是错的——不是因为 SQL 写得不对,而是读写并发没有做隔离。这种问题在修复上特别浪费时间,因为你要花很多精力去排查"是不是 SQL 逻辑本身有问题",最后才发现是数据被并发写乱了。

1.3 崩溃点三:资源竞争把正常流量一起拖死

这是很多人忽略的一点:DAO 层测试不是在一个"真空"环境里跑的。你的测试环境里可能还部署着别的服务实例,或者同一个实例上还有其他业务在跑。高并发的 DAO 层压测会占满数据库 CPU、吃掉大量带宽和内存,轻则影响同一数据库上的其他应用,重则把整个测试环境搞瘫。

数据库的资源是有限的。一次全表扫描可能就吃掉几秒 CPU,20 个并发全表扫描那就是 20 倍的 CPU 开销。我在一次压测里观察过,数据库的 CPU 使用率从正常的 15% 直接飙升到 98%,响应时间从 5ms 涨到了 800ms。连带着同一个库的其他业务接口全部超时。所以高并发 DAO 层测试,不单要管住连接数,还要管住你对数据库资源的总消耗。

2. 连接数管控:把"水管"拧到可控范围

2.1 HikariCP 核心参数怎么调才算稳

既然连接池是第一个被打穿的点,那第一步就是把连接池参数降到一个可控的范围。注意,我说的是"可控",而不是"越大越好"。很多人有一个误区:测试要快,所以把连接池设得特别大。但连接池大的代价是数据库线程数飙升、上下文切换加剧、整体吞吐反而不升反降。

以 HikariCP 为例,我推荐这套参数作为起点:

HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://your-db:3306/test_db"); config.setUsername("test_user"); config.setPassword("test_pass"); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(3000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); config.setPoolName("daoTestsPool");

maximumPoolSize设 20 是因为大多数 DAO 层压测场景下,20 个连接足够支撑每秒几百次的简单增删改查。如果你要跑的是复杂查询,建议调到 30 封顶,再多收益就很有限了。connectionTimeout设 3000ms 非常关键,这是给线程"等不到就放弃"的保底机制,避免线程无限排队把线程池拖垮。

这里要强调:连接池参数不应该是"拍脑袋"定的。有一个简单的计算公式:连接数 = 线程数 * (单次任务占用连接的时间 / 单次任务总耗时)。如果你的线程数是 50,每个任务里真正拿连接执行 SQL 的时间是 10ms,任务总耗时是 50ms,那连接数只需要 50 * (10/50) = 10 个就够用。按这个公式算出来的值,再留个 1.5 到 2 倍的冗余,就是比较合理的配置。

2.2 连接数上限的设计逻辑

我在实际项目中,还会做一层"连接数上限"的业务侧管控,而不是完全依赖连接池。什么意思?就是在代码层面加一个计数器或信号量,把 DAO 层测试实际用到的并发连接数卡在连接池的 80% 左右。

原因很简单:连接池还有一部分连接可能被其他业务占用。如果你把池子设成 20,测试却用满 20,那同一实例上的其他业务就一条连接都拿不到了。我在测试基类里的做法是加一个静态信号量,同一时间最多只让 16 个线程同时访问数据库:

private static final Semaphore DB_ACCESS_LIMIT = new Semaphore(16); protected void executeWithLimit(Runnable task) throws InterruptedException { DB_ACCESS_LIMIT.acquire(); try { task.run(); } finally { DB_ACCESS_LIMIT.release(); } }

这个设计的好处是,即使你后续不小心把某个测试类的线程数调到了 50,也不会真的同时有 50 个线程去抢数据库连接——信号量会帮你拦一道。

2.3 用监控验证连接池状态

参数调完了,不是就结束了。你要能随时看到连接池的实时状态。我在压测期间会在测试代码里加一点监控埋点,定期输出连接池的关键指标:

HikariPoolMXBean poolMXBean = hikariDataSource.getHikariPoolMXBean(); logger.info("active={}, idle={}, total={}, waiting={}", poolMXBean.getActiveConnections(), poolMXBean.getIdleConnections(), poolMXBean.getTotalConnections(), poolMXBean.getThreadsAwaitingConnection());

这里我最关心的是waiting这个值。如果它持续大于 0,说明连接已经不够用了;如果它一直在涨,说明线程积压在加剧。正常情况下,连接池应该有少量空闲连接,等待线程数为 0 或者偶尔出现 1。如果观察到的数据和这个正常状态偏离很大,就需要回头检查参数设置。

注意:压测过程中的监控输出要控制频率,别每执行一次 SQL 就打一条日志,否则日志本身会成为新的性能瓶颈。我一般每 3 秒打一次,或者用定时任务在后台单独输出。

3. 错峰访问:把压力摊到时间轴上

3.1 错峰的核心思路

连接数管住了,接下来要管的是"访问模式"。高并发 DAO 层测试最容易出现的问题就是波峰叠加——所有线程都集中在同一秒去访问数据库。比如你开了 20 个线程,每个线程的第一次查询都发生在启动后的 100ms 内,那数据库在那一瞬间收到的请求数就是 20 倍的平均值。波峰叠加会导致短时间的数据库 CPU 飙高,然后触发锁等待,接着所有请求都变慢,形成一个恶性循环。

错峰访问的思路很简单:把并发请求的发起时间在时间轴上"抹匀"。不让 20 个线程同时起步,而是让它们在 0 到 2 秒内依次启动。这样数据库收到的请求量是平滑的,而不是陡峭的尖峰。

3.2 基于时间窗口的任务调度实现

具体怎么做?我用的是固定速率启动的方式,配合一个简单的调度器。比如我要并发 20 个任务,希望它们在 2 秒内全部启动,那每个任务之间的启动间隔就是 2000ms / 20 = 100ms。

一个实用的小技巧是用Thread.sleep()加一个递增的延迟参数来模拟启动间隔:

public class StaggeredRunner { private final int concurrency; private final Duration window; private final ExecutorService executor; public StaggeredRunner(int concurrency, Duration window) { this.concurrency = concurrency; this.window = window; this.executor = Executors.newFixedThreadPool(concurrency); } public void run(List<Runnable> tasks) throws InterruptedException { long intervalNanos = window.toNanos() / tasks.size(); long startNanos = System.nanoTime(); for (int i = 0; i < tasks.size(); i++) { long targetStart = startNanos + i * intervalNanos; long currentDelay = targetStart - System.nanoTime(); if (currentDelay > 0) { Thread.sleep(currentDelay / 1_000_000, (int) (currentDelay % 1_000_000)); } final int taskIndex = i; executor.submit(() -> { try { tasks.get(taskIndex).run(); } catch (Exception e) { logger.error("task {} failed", taskIndex, e); } }); } executor.shutdown(); executor.awaitTermination(1, TimeUnit.HOURS); } }

你可能会问:这不就是加了个sleep吗?对,原理就是这么朴素。但核心在于:每个任务不是启动后立刻执行 SQL,而是精确控制到"什么时候才开始执行",这样数据库接收到的流量是均匀分布的。

3.3 错峰与批处理结合

错峰不仅适用于任务启动阶段,还适用于 DAO 层测试里的批量操作。我在做大批量数据回放测试时,会把数据分成多个批次,每个批次的执行时间错开。比如总共 1000 万条数据,分成 100 个批次,每批 10 万条,批次之间的启动间隔控制在 50ms 到 200ms 之间。

用代码表示就是:

int totalBatches = 100; int batchSize = 100_000; for (int i = 0; i < totalBatches; i++) { int start = i * batchSize; int end = start + batchSize; executor.submit(() -> batchProcessor.process(start, end)); Thread.sleep(100); // 批次之间错开 100ms }

这个模式特别适合数据迁移校验、对账跑批这一类重 IO 的 DAO 层测试场景。既能让整个压测过程看起来像一个连续的负载流,又不会瞬间把数据库的 IO 能力吃干抹净。

注意:错峰间隔不要设成固定值就完事了。我建议根据数据库的响应时间动态调整——如果数据库平均响应时间在上升,说明负载已经接近临界点,需要调大间隔;如果响应时间很稳定,可以适当调小间隔,加快测试进度。

4. 并行限流:控制"同时出发的人数"

4.1 线程池限流 vs 信号量限流

错峰解决的是启动时间分布问题,但还有一个维度需要控制:同一时刻到底允许多少任务并行执行。这就涉及并行限流了。

实现并行限流有两种主流方式:线程池限流和信号量限流。它们各有适用场景。

线程池限流是把任务扔到一个固定大小的线程池里执行。如果线程池大小是 10,那同一时刻最多只有 10 个任务在跑,第 11 个任务会在队列里排队。它的特点是:不仅限制了并发度,还限制了资源占用,因为线程池的 worker 是真实占用系统资源的。

信号量限流则是在任务执行前获取一个许可,拿到许可才能继续,否则就阻塞等待。它不限制线程数量,只限制"同时进入临界区"的任务数量。它的特点是更轻量,适合在已经有线程池的基础上再加一道保护。

我个人的做法是:如果任务是 IO 密集型的 DAO 操作,优先用线程池限流,因为数据库连接、网络 IO 这些资源都会被线程直接占用;如果任务是 CPU 密集型的计算逻辑加少量 SQL 查询,用信号量限流更灵活,不会把 CPU 核心数浪费在线程排队上。

4.2 信号量 Semaphore 实战

下面是一个信号量限流的典型用法,我用在测试基类里,让所有 DAO 测试在同一个并发上限下执行:

public abstract class BaseDaoConcurrencyTest { private static final int MAX_CONCURRENCY = 12; private static final Semaphore CONCURRENCY_GATE = new Semaphore(MAX_CONCURRENCY); protected <T> List<T> runConcurrently(int taskCount, Supplier<T> daoCall) throws InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(taskCount); List<Future<T>> futures = new ArrayList<>(); CountDownLatch readyLatch = new CountDownLatch(taskCount); CountDownLatch startLatch = new CountDownLatch(1); for (int i = 0; i < taskCount; i++) { futures.add(executor.submit(() -> { readyLatch.countDown(); startLatch.await(); // 所有线程就绪后同时出发 CONCURRENCY_GATE.acquire(); try { return daoCall.get(); } finally { CONCURRENCY_GATE.release(); } })); } readyLatch.await(); startLatch.countDown(); // 收尾 executor.shutdown(); executor.awaitTermination(1, TimeUnit.HOURS); List<T> results = new ArrayList<>(); for (Future<T> future : futures) { results.add(future.get()); } return results; } }

这段代码有几个值得注意的设计点:

  1. readyLatch和startLatch的组合是为了保证所有线程真正就绪后再同时出发,避免"线程还在创建过程中"对测试结果造成干扰。
  2. CONCURRENCY_GATE是限流的核心,它保证不管taskCount设置成多少,同一时刻最多只有 12 个任务真正执行 DAO 操作。
  3. 信号量要放在startLatch.await()之后获取,否则拿不到许可的线程会一直阻塞在acquire(),导致后面的线程根本无法就绪。

4.3 限流参数怎么定

限流的数值不能拍脑袋。我的经验是结合两个指标来确定:数据库的连接池大小和数据库的吞吐能力。

连接池大小是一个硬约束。MAX_CONCURRENCY不应该超过连接池maximumPoolSize的 80%。假设连接池设的 20,那限流最多设 16。这样即使每个并发任务都占用一个连接,也还有 4 个连接作为缓冲留给其他业务。

数据库吞吐能力是另一个参考维度。你可以先做一个单连接压测,测出数据库能承受的 QPS 上限,然后用这个值反推限流数。比如单连接下你的 DAO 方法能跑 50 QPS,数据库的合理负载是 800 QPS,那限流数可以设为 800 / 50 = 16。这是理论值,实际建议再打个七折,设置为 12 左右,给波动留余量。

5. 完整测试基类落地示例

5.1 配置样例

有了前面的思路,我把整套方案整合成一个可直接落地的测试基类。先看配置部分,我使用的是 Testcontainers 加 MySQL 的测试环境,方便本地复现。当然你也可以用已有的测试库,配置逻辑是一样的。

# application-test.properties spring.datasource.hikari.maximum-pool-size=20 spring.datasource.hikari.minimum-idle=5 spring.datasource.hikari.connection-timeout=3000 spring.datasource.hikari.idle-timeout=600000 spring.datasource.hikari.max-lifetime=1800000 # 自定义配置:DAO测试专用 dao-test.max-concurrency=12 dao-test.stagger-window-ms=2000 dao-test.task-count=20 dao-test.retry-count=3

这些配置我都加了详细注释,方便你根据自己项目的实际参数调整。

5.2 测试基类代码

基类里我整合了三个阶段:启动前的连接池预检、任务执行时的错峰限流、结束后的数据清理。这三个阶段缺一不可。

@SpringBootTest @ActiveProfiles("test") public abstract class BaseDaoHighConcurrencyTest { @Autowired protected JdbcTemplate jdbcTemplate; @Value("${dao-test.max-concurrency:12}") private int maxConcurrency; @Value("${dao-test.stagger-window-ms:2000}") private long staggerWindowMs; @BeforeEach void preCheckConnectionPool() { // 连接池预检:确保数据库连接池可用 Integer result = jdbcTemplate.queryForObject("SELECT 1", Integer.class); Assertions.assertEquals(1, result); } protected void executeDaoTest(int taskCount, String taskName, Consumer<Integer> daoTask) throws Exception { long startTime = System.currentTimeMillis(); Semaphore concurrencyGate = new Semaphore(maxConcurrency); ExecutorService executor = Executors.newFixedThreadPool(taskCount); CountDownLatch doneLatch = new CountDownLatch(taskCount); List<Throwable> errors = Collections.synchronizedList(new ArrayList<>()); long intervalNanos = TimeUnit.MILLISECONDS.toNanos(staggerWindowMs) / taskCount; long startNanos = System.nanoTime(); for (int i = 0; i < taskCount; i++) { final int taskIndex = i; long targetStart = startNanos + i * intervalNanos; long delayNanos = targetStart - System.nanoTime(); if (delayNanos > 0) { Thread.sleep(delayNanos / 1_000_000, (int) (delayNanos % 1_000_000)); } executor.submit(() -> { try { concurrencyGate.acquire(); try { daoTask.accept(taskIndex); } finally { concurrencyGate.release(); } } catch (Throwable t) { errors.add(t); } finally { doneLatch.countDown(); } }); } // 等待所有任务完成 boolean completed = doneLatch.await(30, TimeUnit.MINUTES); executor.shutdown(); if (!completed) { throw new IllegalStateException("DAO测试任务超时未完成"); } if (!errors.isEmpty()) { throw new RuntimeException("DAO测试执行过程中存在异常", errors.get(0)); } long elapsed = System.currentTimeMillis() - startTime; logger.info("任务 {} 完成,耗时 {} ms,并发数 {}", taskName, elapsed, taskCount); } @AfterEach void cleanTestData() { // 清理测试数据,避免脏数据影响下一次测试 jdbcTemplate.execute("DELETE FROM test_order WHERE test_flag = 1"); jdbcTemplate.execute("DELETE FROM test_user WHERE test_flag = 1"); } }

这段代码的每一步都有明确的目的,我再拆解一下:

  • preCheckConnectionPool在每轮测试前检查数据库连接是否正常。这个很关键,如果数据库连接不正常,后面所有测试跑出来的结果都没有参考价值。
  • executeDaoTest是核心方法。它把错峰启动和信号量限流整合在一起,任务按照staggerWindowMs指定的窗口内均匀启动,同时受限于maxConcurrency。
  • cleanTestData在每轮测试后清理脏数据。我在测试数据里统一加了test_flag字段,就是为了方便这批清理操作。

5.3 执行效果验证

这个基类的效果,我实际跑过的压测数据是这样的:任务数 50,错峰窗口 3 秒,最大并发 12。跑下来耗时 42 秒,数据库连接池的active稳定在 10 到 12 之间,waiting始终为 0,数据库 CPU 峰值从之前的 98% 降到了 40% 左右。测试全程没有出现连接超时或任务失败,整个过程完全可控。

而对比之前不设限的裸并发测试:50 个任务同时启动,20 秒内数据库 CPU 飙到 98%,连接池被占满,30 个任务报连接超时,测试结果完全不可信。这个对比数据说明,连接数管控、错峰、限流这三板斧不是拍脑袋想出来的,是有实际效果支撑的。

6. 常见问题与排查实录

6.1 连接泄漏怎么排查

高并发 DAO 层测试最常遇到的隐形问题就是连接泄漏。症状是:测试跑着跑着,连接池的active数只会涨不会跌,最后所有连接都被占满,新的请求全部超时。

排查思路分三步:

第一步,在测试基类里加一个连接池状态定时输出,观察active会不会在任务结束后回落。正常情况下,任务结束后active应该在几秒内降到minimumIdle附近。

第二步,如果发现active持续不降,去看是不是有线程拿完连接后没有释放。我这边遇过一种情况:代码里手动调用了Connection但忘了在finally里close()。这种问题在普通测试里很难发现,因为连接池有空闲连接兜底;但并发一上来,泄漏几轮就把池子堵死了。

第三步,在测试代码里给数据源包一层代理,记录每次拿连接和释放连接的调用栈。用到的是 HikariCP 的leakDetectionThreshold参数。这个参数设成 60000,连接被持有超过 60 秒就会在日志里打印获取连接时的调用栈,直接定位到是哪一行代码泄漏的。

6.2 超时参数设多少合适

超时参数是另一个容易踩坑的地方。连接池的connectionTimeout设太短,比如 500ms,在高并发下会出现大量"正常排队但被判定超时"的误杀;设太长,比如 30000ms,又会让线程无限等待,把线程池拖垮。

我的建议是:connectionTimeout设为 3000ms 到 5000ms 之间。这个值比数据库的慢查询阈值(一般 1 到 2 秒)要长,又不会让线程等太久。如果你发现 3000ms 内拿不到连接,那几乎可以肯定连接数已经不够用了,你需要做的是调整并发上限,而不是调高超时时间。

还有一个参数容易被忽略:validationTimeout。HikariCP 默认是 5000ms,但这个值必须小于connectionTimeout,否则会出现校验连接本身就把超时时间耗光的情况。我一般设成 3000ms 或更短。

6.3 测试数据污染问题

测试数据污染表现为:上一轮测试的脏数据影响下一轮的查询结果,或者导致Duplicate entry报错。我在第 5 章提供了cleanTestData的清理方案,这里补充两个细节。

第一,清理操作要在连接池空闲的时候做。比如你刚跑完一个高并发测试,连接池可能还有部分连接在做慢查询,这时候执行大范围 DELETE 会拖慢整个清理过程。我一般会先调用一次连接池的evictIdleConnections(),把空闲连接清掉,再执行清理 SQL。

第二,清理字段要有独立标识,不要用业务主键判断。我在测试表里统一加test_flag字段,所有测试数据写入时都置为 1,清理时就按这个字段删。这种方式最稳妥,避免了误删线上数据或者清理不彻底。

6.4 避坑清单速查

我整理了日常最容易踩的 5 个坑,直接看图:

坑点表现解决方案
连接池过大数据库 CPU 飙高、线程切换频繁按公式计算并限制在 20 以内
并发任务同时启动波峰叠加、瞬时请求量大使用错峰启动,任务散布在时间轴上
信号量限流缺失线程无限排队、连接耗尽用 Semaphore 限制最大并发数
连接泄漏未监控连接池 active 只涨不跌开启 leakDetectionThreshold 定位
测试数据无清理脏数据污染、Duplicate 报错统一 test_flag 字段、跑后清理

提示:以上配置都以 MySQL 8 + Spring Boot 3 + HikariCP 为参考环境。如果你用的数据库是 PostgreSQL,连接池参数基本通用,但清理 SQL 的语法要做相应调整。

我个人在实际操作中的体会是,DAO 层测试的稳定性问题,说到底是一个资源预算问题。数据库的连接池、线程数、吞吐能力都是有限的资源,你要做的不是把每一份资源都榨干,而是为每类测试任务分配合理的"资源配额"。连接数管控解决的是总量配额,错峰访问解决的是时间分布,并行限流解决的是瞬时速率。三方面配合起来,你的 DAO 层测试既能保持高吞吐,又能稳稳当当地跑完。

最后再分享一个小技巧:把这三套参数全部抽到配置文件里,每个测试任务可以独立覆盖。这样即使换了不同的压测场景,比如从批量插入换成复杂报表查询,也不用改测试代码,只调配置就能适配不同的资源需求。我在项目里就是这么干的,实测下来切换场景特别顺。

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

英文论文查AI率:Turnitin与GPTZero的选择与报告解读指南

从去年开始&#xff0c;我周围写英文论文的朋友几乎人手一份“AI检测报告”。一开始大家还只是拿ChatGPT润色个摘要&#xff0c;后来学校、期刊编辑部陆续开始对稿件做AIGC内容筛查&#xff0c;退稿理由里会直接出现“AIGC检出率高”这种字眼。很多同学来问我&#xff1a;英文论…

作者头像 李华
网站建设 2026/9/30 15:18:21

Windows组策略应用笔记:从本地配置到安全加固实战

简介&#xff1a;一份针对Windows组策略深层次应用与故障排错的实战文档&#xff0c;目标读者是系统管理员、网络运维人员以及需要精细化管控域环境的IT从业者。文档围绕‘巧限程序&#xff0c;谨防自锁’这一高频问题&#xff0c;详细拆解了启用‘只允许运行Windows应用程序’…

作者头像 李华
网站建设 2026/9/30 15:16:02

Model-Optimizer:大模型推理优化的工程化方法论与实战指南

1. 项目概述&#xff1a;Model-Optimizer不是工具&#xff0c;而是一套工程化落地的思维范式 “Model-Optimizer”这个名称在当前AI工程圈里被高频提及&#xff0c;但它本身 不是某个官方发布的独立软件产品 &#xff0c;而是开发者、MLOps工程师和推理服务部署人员在实战中…

作者头像 李华
网站建设 2026/9/30 15:09:27

2026-09-24 AI最新资讯日报

AI时报 | 2026-09-24 AI最新资讯日报 一句话摘要&#xff1a; Claude参与生物系统发现&#xff0c;心理健康评测与AI眼镜继续演进&#xff0c;澳大利亚披露的越权访问事件则凸显智能体的执行边界。 时间范围&#xff1a; 2026-09-24 00:00–23:59&#xff08;UTC8&#xff09; …

作者头像 李华
网站建设 2026/9/30 15:09:17

SQL中MD5加密的实现与避坑:从批量初始化到跨库校验

最近帮业务部门处理了一桩挺典型的存量数据改造&#xff1a;一张几十万行的用户表要批量初始化密码。我第一反应是写个Python脚本连上数据库循环UPDATE&#xff0c;结果跑了大半天才推进不到一半&#xff0c;旁边的DBA瞄了一眼说&#xff1a;SQL里直接算md5不就行了&#xff0c…

作者头像 李华