达梦数据库JAVA外部函数实现手机号动态脱敏实战指南
年初做国产化迁移的时候接了个挺折腾的需求一批报表要在数据库层直接做手机号和证件号的动态脱敏规则还不简单掩码位数、保留位数要根据号码段和长度实时判断纯SQL写出来又臭又长存储过程也绕得不行。最后我盯上了达梦数据库的JAVA外部函数这个能力把脱敏逻辑写在一个Java静态方法里数据库里声明成函数报表SQL直接调用彻底解了这口气。这篇文章就把整个落地过程完整复盘一下包括Java类怎么写、jar怎么部署、SQL里怎么注册以及我在测试和生产环境里踩过的几个坑。不管你是正在做信创迁移的DBA还是被复杂计算逻辑困在SQL里的开发应该都能从中找到能直接搬走的东西。1. 项目概述为什么要让数据库直接调用Java逻辑1.1 这个项目解决了什么问题外部函数说人话就是让SQL语句能直接调用外部编程语言写好的方法。达梦数据库支持JAVA外部函数和C外部函数Java这种模式对咱们团队来说门槛最低因为大家日常都在写Java服务业务逻辑基本上都能在一个静态方法里复现不需要额外去啃C的手动内存管理。我这次遇到的场景是数据脱敏。数据从生产库同步到报表库之后报表库需要给外包人员开放部分查询权限但手机号、身份证号这些敏感字段不能明文出现。脱敏规则又特别细运营商号段要识别、短号要特殊处理、长度不同保留位数也不同。如果全用SQL写CASE WHEN嵌套到第三层基本就看不懂了而且以后规则一改改SQL比改Java类难受得多。把这段逻辑放到Java外部函数里以后SQL调用变得非常干净SELECT F_MASK_TEL(phone_number) FROM user_report;规则迭代只需要改Java类、重新部署、刷新函数SQL侧一个字符都不用动。这本身就是很典型的“让数据库去做数据库不擅长的事”的场景外部函数的价值就体现在这里。1.2 为什么选择JAVA外部函数而不是存储过程或C函数很多人第一反应是写存储过程不就行了吗没必要引一个Java虚拟机进来。这个想法对了一半。简单的判断和循环存储过程确实能扛但一旦遇到以下情况存储过程就很尴尬一是需要复杂的字符串处理、编码转换、加密摘要逻辑。达梦的SQL函数库虽然一直在丰富但和Java标准库比起来覆盖面还是差不少。比如我要做Base64解码后按字节处理SQL写起来非常痛苦Java里两行搞定。二是团队维护成本和技能匹配。大多数业务开发团队对Java的熟悉程度远高于PL/SQL出了问题Java代码堆栈大家好排查存储过程调半天找不到根因。三是复用性。同一个脱敏逻辑Java类既能在服务端做接口层脱敏又能在数据库层兜底一套代码两个出口逻辑不会出现“应用层脱敏和数据库层脱敏规则不一致”的问题。那为什么不选C外部函数C的效率确实高JNI调用链也更短但开发调试成本太高稍不注意内存越界就能把数据库实例带崩。我们这种以Java为主的团队选Java外部函数是质量和交付速度之间的最优解。当然我也要提前说明Java外部函数有JVM初始化开销不适合高频小查询这一点后面性能章节会专门讲。2. 环境准备与JAVA运行环境接入2.1 达梦与JDK的必备版本组合先把环境版本搞清楚这一步经常被忽略但恰恰是后面各种诡异问题的根源。达梦数据库从8.1开始就比较完整地支持Java外部函数我这里用的是达梦8.1系列JDK用的OpenJDK 8也就是1.8版本。为什么要强调JDK 8因为数据库内置的Java虚拟机适配是跟着稳定版本走的你用JDK 11编译出来的class字节码版本是55而达梦内置JVM如果只支持到52对应Java 8加载的时候直接报UnsupportedClassVersionError。我最初就吃过这个亏用本机JDK 17写了个小工具类部署上去秒报错后来老老实实全部按JDK 8编译。如果你不确定当前环境行不行先看两样东西Java的版本以及达梦数据库实例的版本。可以在disql里执行SELECT * FROM V$VERSION;如果版本支持Java外部函数那么你去找安装目录下的dm.ini里面通常能看到跟Java虚拟机相关的配置项。不同小版本叫法会有差异建议以实际安装版本的参数手册为准。2.2 JAVA_HOME和CLASSPATH配置检查写好Java类本身不是难点难点是让达梦的实例能发现你的类。这里就涉及JAVA_HOME和CLASSPATH的配置。我实际操作中达梦并不会自动去读操作系统环境变量里那个JAVA_HOME而是需要在数据库服务器上把Java环境装好之后通过一些配置项把它指给实例。比如Linux环境下我会检查/etc/profile或~/.bash_profile里的JAVA_HOME是否指向了正确的JDK路径同时需要把编译好的jar所在目录配置到达梦能找到的加载路径里。这里有个容易犯的错很多人以为把jar放到任意路径classpath写了就能被数据库加载。实际上达梦在启动JVM的时候对路径的处理有自己的规则比较稳妥的做法是把jar放到达梦安装目录下的一个固定子目录里例如/dm/dmdbms/jars/这种约定位置或者按官方文档指定加载目录然后创建函数时使用全限定类名。配置完成以后在disql里可以查一下和Java相关的运行参数SELECT * FROM V$PARAMETER WHERE NAME LIKE %JAVA%;确认参数值不是空。这个查询结果是判断“数据库层面是否已经做好Java支持”的最直接依据。如果查到有JVM相关配置但状态异常后面就要按JVM启动问题来处理了。2.3 验证数据库实例是否成功加载了Java虚拟机配置到底生效没有最简单的办法是直接创建一个最简单的Java外部函数来验证。我习惯写一个返回固定字符串的“探针类”public class Probe { public static String ping() { return java-external-function-ok; } }编译后用jar打包部署到指定目录然后执行CREATE OR REPLACE FUNCTION F_JAVA_PING() RETURN VARCHAR AS LANGUAGE JAVA NAME Probe.ping() return java.lang.String; SELECT F_JAVA_PING() FROM DUAL;如果能正常返回java-external-function-ok说明JVM加载、class扫描、函数注册这条链路都是通的后面写复杂函数就是水到渠成。如果这一步就报错那就别往下做业务逻辑了先把环境链路打通。我也把这种探针保留在脚本里每次换新环境都会先跑一遍避免在业务功能上线时才发现环境问题。3. JAVA外部函数的落地全流程3.1 编写符合外部函数要求的Java类写完探针类之后你基本上理解了Java外部函数的核心约束达梦能调用的不是任意Java对象方法而必须是public static修饰的方法也就是静态方法。这也是为什么我说“一个静态方法就能复现业务逻辑”的原因因为它不需要new对象JVM加载类时方法就直接可用。编写时有几个细节必须注意第一方法签名要完整。在SQL声明函数时JAVA NAME字符串里要写清包名.类名.方法名(参数类型) return 返回类型参数类型必须是Java的全限定类型名比如java.lang.String不能只写String。第二参数和返回值的映射要符合达梦的约定。我的经验是能用VARCHAR、INT、DOUBLE、BIGINT这些常规类型就先别碰数组和自定义对象映射简单坑少。下面是我整理的一份常用映射参考SQL类型Java参数/返回类型VARCHAR / NVARCHARjava.lang.StringINTint 或 java.lang.IntegerBIGINTlong 或 java.lang.LongDOUBLEdouble 或 java.lang.DoubleDATE / TIMESTAMPjava.sql.Date / java.sql.TimestampBLOBbyte[]第三方法内不要依赖外部文件、网络资源或线程上下文。数据库里的外部函数执行环境和普通Java应用不一样你无法保证当前工作目录、环境变量或者网络策略都可用把逻辑做成无状态纯函数是最安全的。3.2 编译、打包与部署jar写好的Java源码需要先编译成class再打成jar。很多人会问直接放class文件行不行以我的使用经验打包成jar更稳妥class文件如果嵌套在目录中很容易因为路径扫描问题找不到类。演示一个带包名的完整例子。首先准备目录结构mkdir -p /tmp/javafunc/com/dmsample把源码放到/tmp/javafunc/com/dmsample/StringFuncs.javapackage com.dmsample; public class StringFuncs { public static String reverse(String input) { if (input null) { return null; } return new StringBuilder(input).reverse().toString(); } public static String md5(String input) throws Exception { if (input null) { return null; } java.security.MessageDigest digest java.security.MessageDigest.getInstance(MD5); byte[] bytes digest.digest(input.getBytes(UTF-8)); StringBuilder builder new StringBuilder(); for (byte b : bytes) { String hex Integer.toHexString(0xFF b); if (hex.length() 1) { builder.append(0); } builder.append(hex); } return builder.toString(); } }然后编译并打包cd /tmp/javafunc javac -encoding UTF-8 com/dmsample/StringFuncs.java jar cf dmsample-funcs.jar com/dmsample/StringFuncs.class打包完成后把jar拷贝到达梦实例的加载目录。以Linux环境为例常见路径是达梦安装目录下的jars子目录cp dmsample-funcs.jar /dm/dmdbms/jars/这里需要说明不同达梦版本的jar加载机制可能不太一样。有的版本只要放在服务器任意固定路径下并在数据库参数里指定classpath就行有的版本则需要在创建函数前先执行一个加载动作。我的处理方式是先放到jars目录然后观察探针函数是否能直接加载如果不行再去查对应版本的SQL语法手册中关于Java类加载的部分。这种“先试最简单方案再逐级排查”的思路能节省大量翻文档的时间。3.3 在达梦中注册外部函数SQL声明jar部署好之后最关键的一步是在达梦里创建外部函数。语法和Oracle的Java存储过程非常像CREATE OR REPLACE FUNCTION F_STR_REVERSE(INPUT_STR VARCHAR) RETURN VARCHAR AS LANGUAGE JAVA NAME com.dmsample.StringFuncs.reverse(java.lang.String) return java.lang.String;这里逐段拆开看CREATE OR REPLACE FUNCTION后面的部分和我们平时建函数没区别AS LANGUAGE JAVA告诉达梦这是一个Java外部函数NAME后面的字符串是调用映射格式是包名.类名.方法名(参数类型列表) return 返回值类型。构造函数名上是区分大小写的。类名、方法名、包名写得和Java源码不一致创建时不一定报错但调用时百分之百报找不到方法。注册之后建议用系统视图确认一下函数状态SELECT OWNER, OBJECT_NAME, OBJECT_TYPE, STATUS FROM ALL_OBJECTS WHERE OBJECT_NAME F_STR_REVERSE;状态是VALID就代表SQL对象创建成功。注意这只能说明SQL侧的函数存在不能说明它背后对应的Java类已经能被加载真正的验证必须通过实际调用来完成。3.4 SQL调用与验证调用外部函数和普通函数没有任何区别直接把它当成内置函数用就行SELECT F_STR_REVERSE(达梦数据库) FROM DUAL;如果返回库据数梦达说明整个链路通了。还可以测试一下md5方法CREATE OR REPLACE FUNCTION F_MD5(INPUT_STR VARCHAR) RETURN VARCHAR AS LANGUAGE JAVA NAME com.dmsample.StringFuncs.md5(java.lang.String) return java.lang.String; SELECT F_MD5(abc) FROM DUAL;调用动态拼接的场景也很多。比如你想在SQL条件里调用Java方法做判断SELECT * FROM t_user WHERE F_MD5(secret_key) 900150983cd24fb0d6963f7d28e17f72;虽然这种用法会让索引失效但在小数据量、一次性分析场景里非常灵活。外部函数的意义就是我们不再拘泥于SQL的边界理论上Java能做的事情都能在SQL层复现。4. 实战案例用JAVA外部函数做号码脱敏4.1 需求背景与规则设计前面铺垫了这么多我用这次真正让我下定决心采用外部函数的脱敏需求来完整演示一遍。需求是这样报表库给外包人员开放查询但phone_number字段不能原样展示也不能全部打码。规则有三条11位手机号保留前3位和后4位中间4位用星号代替7位短号保留前2位和后2位其他长度号码保留前1位和后1位其余打码。同时如果是座机号码要按区号自动识别。但座机规则涉及区号表我把这个场景先简化只处理纯数字串。规则看着不复杂用SQL写出来也就几个SUBSTR拼接但问题出在后面的“规则还要继续演进”据说后续要按不同运营商号段做差异化脱敏还要支持港澳台号码格式。这种频繁变动的规则用SQL CASE WHEN写就是给自己埋坑。4.2 脱敏函数的Java实现Java实现我写成一个工具方法逻辑很直白package com.dmsample; public class MaskUtils { public static String maskPhone(String phone) { if (phone null) { return null; } String num phone.trim(); int len num.length(); if (len 11) { return num.substring(0, 3) **** num.substring(7, 11); } if (len 7) { return num.substring(0, 2) *** num.substring(5, 7); } if (len 3) { return num.substring(0, 1) *** num.substring(len - 1, len); } return num; } }这个方法没有任何外部依赖输入输出都是字符串天然满足外部函数对静态方法的要求。规则集中在Java里以后后面要按号段脱敏、按归属地脱敏都是在代码里加分支的事。4.3 从编译到SQL调用的完整指令序列编译打包部署一套带走cd /tmp/javafunc javac -encoding UTF-8 com/dmsample/MaskUtils.java jar cf dmsample-mask.jar com/dmsample/MaskUtils.class cp dmsample-mask.jar /dm/dmdbms/jars/然后在disql里注册函数CREATE OR REPLACE FUNCTION F_MASK_TEL(TEL VARCHAR) RETURN VARCHAR AS LANGUAGE JAVA NAME com.dmsample.MaskUtils.maskPhone(java.lang.String) return java.lang.String;写一条测试SQL验证效果SELECT phone_number, F_MASK_TEL(phone_number) AS masked_phone FROM t_user_report;我实际测试了一批数据结果符合预期。比如13812345678变成了138****56781234567变成了12***67。这里有一个小细节如果源数据里手机号带空格或短横线会在SQL层影响判断所以我在Java方法里先trim()但更彻底的做法是业务数据入库前就统一清洗外部函数只负责兜底不能指望它修正数据质量。4.4 对比纯SQL方案的效果差异同样的功能如果纯SQL写大概是这个画风SELECT CASE WHEN LENGTH(TRIM(phone_number)) 11 THEN CONCAT(CONCAT(SUBSTR(TRIM(phone_number), 1, 3), ****), SUBSTR(TRIM(phone_number), 7, 4)) WHEN LENGTH(TRIM(phone_number)) 7 THEN CONCAT(CONCAT(SUBSTR(TRIM(phone_number), 1, 2), ***), SUBSTR(TRIM(phone_number), 6, 2)) WHEN LENGTH(TRIM(phone_number)) 3 THEN CONCAT(CONCAT(SUBSTR(TRIM(phone_number), 1, 1), ***), SUBSTR(TRIM(phone_number), -1, 1)) ELSE TRIM(phone_number) END AS masked_phone FROM t_user_report;当初这样写只是有点啰嗦但后面“运营商号段识别”需求一加这条SQL就彻底失控了。Java方案变更只需要改maskPhone代码逻辑然后重新打包部署SQL调用点完全不动。这就是我坚持用外部函数的核心原因把容易变化的业务规则收敛到代码里让SQL保持稳定。5. 踩坑记录与故障排查5.1 ClassNotFoundException类找不到先检查classpath这个报错应该是出现频率最高的。我遇到的第一种情况是jar路径不对类根本没被数据库的类加载器扫到。解决方法是把jar放到达梦约定的加载目录比如/dm/dmdbms/jars/然后确认操作系统用户对jar有读权限。权限问题很隐蔽如果你用root装的数据库但启动实例的用户是dmdbajar权限是600且属主root那么实例一样读不到。第二种情况是jar包名和内部结构不对。jar包内部必须能对应到class的实际包路径。用jar tf查看jar tf dmsample-funcs.jar输出里应该有com/dmsample/StringFuncs.class这样的路径如果你打包时目录结构错了比如打成StringFuncs.class丢在根目录那你需要在NAME里去掉包名前缀或者在SQL里写不带包的类名。5.2 签名不匹配Java方法名、参数类型对不上报错信息通常比较隐晦不是直接说“方法名不对”而是类似找不到指定的方法。最常见的原因类名和包名大小写写错参数类型字符串写错比如把java.lang.String写成StringSQL参数个数和Java方法参数个数不匹配Java方法是public但没有static外部函数要求必须是静态方法。我的排查顺序是先在Java源码里确认方法签名再编译出一个可以被普通Java命令行调用的测试程序验证方法能跑最后再对着创建函数的NAME字符串逐字符核对。多花两分钟做这一步比在SQL报错里反复试要快得多。5.3 JVM没有起来数据库启动期常见的Java虚拟机问题还有一种比较容易让人懵的情况前面探针函数都能用某天重启数据库后再调用函数报错信息和Java虚拟机有关系说什么初始化失败。这种我遇到过两次一次是JDK被系统更新升级导致JAVA_HOME失效另一次是服务器内存不足导致JVM创建失败。达梦要执行Java外部函数本质上是启动一个内嵌JVM来运行Java字节码所以JVM的内存占用是真实存在的。如果你给数据库实例分配的内存已经很小再叠加默认JVM堆设置系统内存一紧张就直接创建失败。我的处理办法优先保证数据库核心缓冲区内存给JVM设置合理的堆上限同时避免在同一个实例上挂过多外部函数依赖的jar类。能把多个功能合并到一个工具类里就尽量合并减少类加载器的负担。5.4 性能与并发外部函数不是免费午餐性能这部分我必须说点实在话。Java外部函数在达梦里的执行路径是SQL引擎调用JVMJVM首次加载类和方法时会有初始化开销。我第一次做完脱敏功能后在一张几十万行的表上跑全表脱敏更新速度明显比内置函数慢一个量级。对于报表查询、数据清洗这种批处理场景慢点可以接受但如果你的系统要在高并发事务路径里每条SQL都调外部函数那就得慎重评估。我有一个优化经验大批量数据处理时与其在SQL循环里逐行调用外部函数不如把数据导出到中间表后用Java服务离线处理完再导回或者用达梦的批处理脚本先把需要调用的数据集合算出来一次性交给Java方法处理。外部函数更适合低频、结果集小、逻辑复杂的计算场景别当常规函数用。5.5 快速排查速查表把零散的经验整理成一张速查表遇到问题可以直接对着查报错特征可能原因处理动作ClassNotFoundExceptionjar路径不对、权限不足、类名拼错检查jar部署目录和jar tf内容核对全限定类名方法找不到/参数异常方法名或参数类型映射写错核对NAME字符串确认参数全限定类型UnsupportedClassVersionErrorclass编译版本高于数据库内置JVM支持版本改用JDK 8重新编译JVM初始化失败JDK环境失效、内存不足检查JAVA_HOME、查看系统内存合理分配JVM堆中文乱码class编译编码与运行时编码不一致编译时加-encoding UTF-8保证源文件也是UTF-8函数状态INVALIDSQL函数创建或依赖对象异常查询ALL_OBJECTS确认状态用探针函数回退验证用探针函数回退验证是我特别想强调的方法。不要一开始就在复杂业务函数上排查永远先跑一个最简单的Probe.ping()它能快速区分“环境链路坏了”和“业务代码坏了”这个二分排查思路能帮你省下大量时间。最后再分享一个小技巧把每次部署的外部函数JAR都单独按版本命名保存比如dmsample-mask-v2.jar并在jar的同级目录放一个记录函数创建语句的sql脚本。以后线上规则出问题回滚到旧版本就是换jar、执行一遍旧函数创建脚本的事整个操作不超过五分钟。这种细节没法在官方文档里学到都是经历过生产事故以后沉淀下来的经验。

相关新闻

LabVIEW调用Halcon语义分割:工业视觉检测从原理到PLC联动实战

LabVIEW调用Halcon语义分割:工业视觉检测从原理到PLC联动实战

如果你也是个LabVIEW工程师,八成遇到过这种尴尬场景:通信、界面、报表、PLC联动都做得底朝天,结果一到图像分割就栽了——焊点反光找不准边界,复合材料纹理没法定阈值,产线光照稍微一变,上一版调好的参数马…

2026/10/9 6:29:23 阅读更多 →
Loop Engineering 实战:Claude Code 与 Codex 自主循环编程指南

Loop Engineering 实战:Claude Code 与 Codex 自主循环编程指南

1. 从“会用工具”到“驾驭工具”:Loop Engineering 到底在解决什么问题这两年 AI 编程工具迭代的速度,快到让人有点喘不过气。Claude Code、Codex、Cursor 这几个名字,几乎每隔几周就会出现在各种技术社区的讨论里。但真正上手之后你会发现一…

2026/10/9 6:29:23 阅读更多 →
Agent-Reach:本地AI工具链的CLI编排运行时

Agent-Reach:本地AI工具链的CLI编排运行时

1. 项目概述:Agent-Reach 是什么?它解决的不是“能不能跑”,而是“值不值得跑”Agent-Reach 这个名字乍看像某个开源模型或框架的代号,但结合 CLI、Python、YouTube、Reddit 这些高频热词,再叠加“zcode cli”“codex …

2026/10/9 6:29:23 阅读更多 →

最新新闻

Windows下make安装与Makefile实战指南:从报错到跑通

Windows下make安装与Makefile实战指南:从报错到跑通

很多Windows用户在第一次跑开源项目、编译别人的C/C代码时,都会被同一个报错砸懵:打开终端敲了make,结果不是“无法将‘make’项识别为 cmdlet、函数”,就是“make: *** 没有指明目标并且找不到makefile”。这个make工具在Linux和…

2026/10/9 7:03:48 阅读更多 →
1米高精度开放空间TIF数据集:ArcMap栅格裁剪与掩膜提取实战

1米高精度开放空间TIF数据集:ArcMap栅格裁剪与掩膜提取实战

前几天群里有人转发了"全球首个1米高精度特大城市开放空间数据集(Tif)"的消息,文件名就带一个TIF后缀,很多朋友下载解压后对着一个栅格图层发呆,不知道这个数据到底能干什么。我做GIS数据处理这些年,对"高精度&quo…

2026/10/9 7:03:48 阅读更多 →
船舶信息管理系统实战:Django+Vue前后端分离开发与联调要点

船舶信息管理系统实战:Django+Vue前后端分离开发与联调要点

接到“船舶信息管理系统”这个需求的时候,我脑子里第一反应不是“又要写CRUD了”,而是“这套系统到底该怎么搭才不像个玩具”。尤其是标题里同时出现了python、vue、django、flask、pycharm这几个关键词,说明提问者大概率是个刚接触全栈开发的…

2026/10/9 7:03:48 阅读更多 →
Java Web老项目实战:HR系统源码部署与底层链路解析

Java Web老项目实战:HR系统源码部署与底层链路解析

简介:这是一套完整的Java企业级人力资源管理系统源码,面向Java初学者及中级开发者,聚焦Web应用开发实战,覆盖员工管理、部门架构、考勤薪酬、权限控制等核心HR业务场景。资源包含1234个文件,主体为405个htm/5个html页面…

2026/10/9 7:03:48 阅读更多 →
宇视VM接入第三方相机:GB28181配置与排障完整指南

宇视VM接入第三方相机:GB28181配置与排障完整指南

在安防项目里摸爬滚打这些年,被问得最多的就是“宇视VM怎么接第三方相机”。其实真不难,核心就是GB28181。这个协议一开,海康、大华、宇视、甚至一排杂牌相机,都能注册到宇视VM上统一出图。今天我把从方案选型到参数填写、从黑屏到…

2026/10/9 7:03:48 阅读更多 →
可靠性测试别只会跑温箱振动台:失效物理与加速寿命是关键

可靠性测试别只会跑温箱振动台:失效物理与加速寿命是关键

干我们这行的,提起“可靠性测试”,不少人第一反应是:把样品扔进温箱里烤一烤、冻一冻,再放振动台上摇一摇,出来没坏就算通过。要是真这么想,那可靠性测试就白做了。作为一个和温箱、振动台、耐久跑法打了十…

2026/10/9 7:02:48 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →