AI 如何重塑存储过程迁移?

0 阅读6分钟

图片

导读

随着国产数据库产品功能不断完善,大量应用系统开始从 Oracle 迁移。看起来像是“换库”,其实是“换心脏”。而存储过程,就是这颗心脏里最复杂的一块。

它牵扯语法差异、功能完整度、稳定性与回归成本,往往是迁移项目里最耗人力、最费时间、也最容易翻车的环节。

作者:平凯数据库技术专家 吴超

/ 为什么存储过程改写最难? /

以从 Oracle 迁移到平凯数据库(TiDB 企业版)的项目为例,流程通常包括数据库对象结构转换、数据迁移、应用代码改造。等到对象和数据都迁完了,真正的硬骨头才开始——应用改造(包含存储过程改写)。

这一步几乎完全依赖应用开发人员的业务理解和工程能力。最容易出问题的三件事是:

(a)业务逻辑被误改或遗漏;

(b)测试覆盖不足,缺陷在割接后才暴露;

(c)成本估算困难,反复返工拖慢周期。

/ 先回答一个问题:存储过程要不要保留? /

方案 1:把 Oracle 存储过程转换为国产数据库兼容的存储过程。听上去很美,但现实里即使宣称兼容 Oracle 语法的国产数据库,也不是 100% 兼容的实现,存储过程仍然要改写和适配。数量一多,改造与测试的工作量就会直线上升。

方案 2:把存储过程转换为上层应用的逻辑模块,例如 Java 或 Python 代码,与应用层有机融合。这更贴合现代分层架构与 DevOps 交付方式,也为后续扩展和重构留出更大空间。

下面讨论的解决思路,选择的是方案 2。

/ 解决思路:把存储过程转为 Java 代码 /

第一,计算与存储分离。存储过程在数据库层执行,消耗的是稀缺的数据库 CPU 和内存;Java 代码运行在应用服务器上,可以通过水平扩展轻松承载高并发,避免数据库成为系统瓶颈。

第二,分布式更友好。平凯数据库(TiDB)等分布式数据库擅长的是海量数据存储与查询,而不是复杂逻辑计算。把逻辑上移到应用层,能更好发挥分布式架构的弹性。

第三,可维护性和研发效率显著提升。Java 拥有完善的 IDE、调试工具与单元测试生态;相比之下,调试几千行存储过程几乎是开发者的噩梦。再加上面向对象设计与 Spring Boot 等框架,业务逻辑更容易解耦、复用与演进。

第四,版本控制与 DevOps 更顺滑。Java 代码可以完全纳入 Git 评审与 CI/CD 流水线,而存储过程的部署和回滚往往依赖复杂脚本管理,难以自动化。

第五,彻底削弱供应商锁定。存储过程里充斥厂商私有语法(如 Oracle 的 PL/SQL),一旦逻辑上移,数据库就回归为更纯粹的数据存储引擎。

第六,众所周知,Vibe Coding 的时代已经到来,实践证明无论是使用哪种主流 AI 编码工具,例如 Claude 或者 Codex,编写 Java 代码对 AI 更友好。

图片

总之,把业务规则迁移到 Java 生态中,才更可维护、可测试、可持续演进,更是拥抱 AI 时代的举措。

/ AI 时代如何提升工程效率 /

平凯数据库的 TMS 工具以存量 Oracle 存储过程为原型,通过解析 AST 语法树并结合 AI LLM 技术,对接上层 Java 开发框架,借助 ORM 与 Java 生态能力,规避异构数据库的语法差异,实现从“语法兼容”到“语义等效”的跨越。

这条流水线通常包括:

(1)对象选取:按清单筛选目标存储过程/函数,支持批量与分阶段迁移;

(2)语义解析:解析 PL/SQL 结构与依赖关系,抽取关键业务语义与调用链;

(3)智能转换:借助 AI agent 生成 Java 代码并遵循目标工程风格;

(4)结果交付:按包结构输出代码树,提供日志、统计与可下载的交付包。

转换示例

Oracle PL/SQL

CREATE OR REPLACE PROCEDURE finish_order(
  p_order_id IN NUMBER,
  p_user_id  IN NUMBER,
  p_amount   IN NUMBER
) AS
  v_points NUMBER;
BEGIN
  -- 1) 更新订单状态
  UPDATE t_order
     SET status = 'DONE',
         done_time = SYSDATE
   WHERE id = p_order_id
     AND user_id = p_user_id;
  -- 2) 计算积分并入账
  v_points := FLOOR(p_amount / 10);
  INSERT INTO t_points(user_id, points, ref_order_id, created_at)
  VALUES (p_user_id, v_points, p_order_id, SYSDATE);
  COMMIT;
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;
    RAISE;
END;
/

Java(示意:服务层 + ORM + 事务)

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class OrderService {
  @Transactional
  public void finishOrder(long orderId, long userId, BigDecimal amount) {
    int affected = orderMapper.markDone(orderId, userId, LocalDateTime.now());
    if (affected == 0) {
      throw new BusinessException("order not found");
    }
    int points = amount.divide(new BigDecimal("10"), RoundingMode.FLOOR).intValue();
    pointsMapper.insert(userId, points, orderId, LocalDateTime.now());
  }
}
@Mapper
public interface OrderMapper {
  @Update("""
      UPDATE t_order
         SET status = 'DONE',
             done_time = #{doneTime}
       WHERE id = #{orderId}
         AND user_id = #{userId}
      """)
  int markDone(
      @Param("orderId") long orderId,
      @Param("userId") long userId,
      @Param("doneTime") LocalDateTime doneTime);
}
@Mapper
public interface PointsMapper {
  @Insert("""
      INSERT INTO t_points(user_id, points, ref_order_id, created_at)
      VALUES (#{userId}, #{points}, #{orderId}, #{createdAt})
      """)
  int insert(
      @Param("userId") long userId,
      @Param("points") int points,
      @Param("orderId") long orderId,
      @Param("createdAt") LocalDateTime createdAt);
}

语义映射要点

UPDATE + INSERT + COMMIT/ROLLBACK 对应 Java 侧的 @Transactional 事务控制;

SYSDATE 对应 LocalDateTime.now() 或统一时间服务;

FLOOR(p_amount/10) 对应 BigDecimal 计算与 RoundingMode.FLOOR;WHEN OTHERS THEN RAISE 对应抛出异常并由事务框架回滚。

/ 价值:不止于“生成代码”/

快:把“人月级”改写压缩到“周级/天级”。以 100 个存储过程为例,人工改写通常需要 30~60 人天;采用智能化自动转换后,整体耗时可压缩到 5~10 人天。

准:不是“照搬 SQL”,而是对关键语义进行等效实现,并通过依赖关系、异常处理、事务边界与函数替换策略进行一致性约束;同时配套日志、结果比对与可回放机制,降低误改与漏改风险。

稳:通过模型连通性自检、兼容性风险识别(如保留字、DB Link 等)、以及全过程日志留存,转换过程具备更强的可审计性与可解释性,显著降低交付风险。

通用:不同业务场景(账务、库存、审批、计费)对性能与一致性的要求差异显著。通过 AI agent 能力、规则库与语法适配策略,可按用途调整生成代码的性能与结构,覆盖不同复杂度与负载特征的存储过程改写需求。

/结语/

存储过程迁移是数据库改造最难的一公里。把它变为可交付、可量化、可复用的自动化能力,才能真正把迁移从“工程风险”转为“标准交付”。如果你正在推进 Oracle 迁移,或计划释放存储过程的业务价值,存储过程转 Java 是一条高效且稳妥的路径。