当前位置: 首页 > news >正文

Spring JDBC实战:参数处理与嵌入式数据库

以下内容是 Spring Framework 官方文档中关于 JDBC 支持的两个重要章节(3.8 和 3.9),主要讲解了在使用 Spring 的 JdbcTemplate 和相关工具时,如何处理一些常见的、复杂的数据库操作问题,以及如何使用嵌入式数据库(Embedded Database)进行开发和测试。

下面我将用通俗易懂的方式,帮你系统地理解这段内容的核心思想和关键知识点,并说明它们在实际开发中的意义。


🧩 一、整体结构概览

章节主题用途
3.8参数与数据值处理常见问题解决 JDBC 操作中的特殊场景
3.9嵌入式数据库支持快速搭建轻量级数据库用于开发/测试

🔍 二、深入理解 3.8 节:参数与数据值处理的常见问题

✅ 3.8.1 提供 SQL 类型信息(SQL Type for Parameters)

❓ 问题背景:

Java 中的 null 值传给数据库时,JDBC 不知道它对应的是 VARCHAR 还是 INTEGER,所以无法正确设置类型。这会导致插入 NULL 失败。

✅ 解决方案:

Spring 允许你在设置参数时显式指定 SQL 类型(来自 java.sql.Types 的常量)。

三种方式:
  1. int 数组方式(适用于位置参数)

    jdbcTemplate.update("INSERT INTO users(name, age) VALUES(?, ?)","Tom", 25,new int[]{Types.VARCHAR, Types.INTEGER}  // 显式指定类型
    );
    
  2. 使用 SqlParameterValue 包装参数

    new SqlParameterValue(Types.VARCHAR, "Tom")
    

    可以更精细控制,比如设置 scale(小数位数)。

  3. 命名参数 + SqlParameterSource
    使用 MapSqlParameterSourceBeanPropertySqlParameterSource 并注册类型:

    MapSqlParameterSource params = new MapSqlParameterSource();
    params.addValue("name", "Tom", Types.VARCHAR);
    params.addValue("age", 25, Types.INTEGER);
    

💡 关键点:主要用于处理 NULL 插入或类型模糊的情况。


✅ 3.8.2 处理 BLOB 和 CLOB(大对象)

❓ 什么是 BLOB / CLOB?
  • BLOB:Binary Large Object → 图片、音频、PDF 等二进制文件。
  • CLOB:Character Large Object → 大段文本(如文章、日志)。
❓ 为什么需要特殊处理?

普通 Stringbyte[] 在读写大文件时会占用大量内存。理想做法是流式处理

✅ Spring 的解决方案:LobHandler + LobCreator
功能接口方法
写入 LOBLobCreatorsetBlobAsBinaryStream, setClobAsCharacterStream
读取 LOBLobHandlergetBlobAsBytes, getClobAsString
示例:插入图片和文本文件
jdbcTemplate.execute("INSERT INTO docs(id, content, image) VALUES (?, ?, ?)",new AbstractLobCreatingPreparedStatementCallback(lobHandler) {protected void setValues(PreparedStatement ps, LobCreator lc) throws SQLException {ps.setLong(1, 1L);lc.setClobAsCharacterStream(ps, 2, reader, (int)file.length()); // CLOBlc.setBlobAsBinaryStream(ps, 3, inputStream, (int)image.length()); // BLOB}}
);

⚠️ 注意:lobHandler 通常是 DefaultLobHandler,但注意它不支持流式读取超过 Integer.MAX_VALUE 的数据。

优势:避免一次性加载整个大文件到内存。


✅ 3.8.3 为 IN 子句传递列表(List in IN Clause)

❓ 问题:

SQL 不允许预编译语句动态占位符数量,比如:

SELECT * FROM users WHERE id IN (?)

但如果要传 (1,2,3),就需要三个 ?

✅ Spring 的解决方案:

自动拼接 SQL,根据 List 长度生成对应数量的 ?

List<Long> ids = Arrays.asList(1L, 2L, 3L);
List<User> users = jdbcTemplate.query("SELECT * FROM users WHERE id IN (:ids)",new MapSqlParameterSource("ids", ids),userRowMapper
);

✅ 使用 NamedParameterJdbcTemplate 自动处理。

⚠️ 注意限制

  • 大多数数据库对 IN 列表有上限(如 Oracle 是 1000)。
  • 如果超过,应分批查询。

✅ 3.8.4 存储过程调用中的复杂类型(Complex Types)

❓ 问题:

某些数据库(如 Oracle)支持自定义对象类型(如 STRUCT, ARRAY),Java 如何传递和接收?

✅ 解决方案:
  1. 输出参数(返回复杂类型)→ SqlReturnType

    declareParameter(new SqlOutParameter("item", OracleTypes.STRUCT, "ITEM_TYPE",(cs, idx, sqlType, typeName) -> {STRUCT struct = (STRUCT) cs.getObject(idx);// 转换为 Java 对象return new TestItem(...);}));
    
  2. 输入参数(传入复杂类型)→ SqlTypeValue

    SqlTypeValue value = new AbstractSqlTypeValue() {protected Object createTypeValue(Connection conn, ...) {StructDescriptor desc = new StructDescriptor("ITEM_TYPE", conn);return new STRUCT(desc, conn, new Object[]{id, name, date});}
    };
    

    然后作为参数传入:

    Map<String, Object> in = new HashMap<>();
    in.put("item", value);
    storedProc.execute(in);
    

✅ 适用于 Oracle、PostgreSQL 等支持复杂类型的数据库。


🛠️ 三、深入理解 3.9 节:嵌入式数据库(Embedded Database)

✅ 3.9.1 为什么要用嵌入式数据库?

  • 轻量快速:无需安装 MySQL/PostgreSQL。
  • 启动快:内存中运行,适合单元测试。
  • 隔离性好:每个测试独立数据库,不污染真实数据。
  • 便于自动化测试:CI/CD 中无需外部依赖。

常见用途:单元测试、集成测试、原型开发


✅ 3.9.2 通过 XML 创建嵌入式数据库

<jdbc:embedded-database id="dataSource" generate-name="true"><jdbc:script location="classpath:schema.sql"/><jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
  • 自动创建 HSQL 内存数据库。
  • 执行建表脚本和测试数据脚本。
  • 生成一个 DataSource Bean,可注入 DAO。

✅ 3.9.3 编程方式创建(推荐用于测试)

EmbeddedDatabase db = new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(H2).addScript("schema.sql").addScripts("data.sql").build();

EmbeddedDatabase 实现了 DataSource,可以直接传给 JdbcTemplate

✅ 测试结束后记得 db.shutdown()


✅ 3.9.4 支持的嵌入式数据库类型

类型说明
HSQL默认,老牌嵌入式数据库
H2功能强大,支持 MySQL 模式、Web 控制台
DerbyApache 开源,Java 编写

推荐使用 H2,功能最全,调试方便。


✅ 3.9.5 测试数据访问逻辑(最佳实践模板)

class DataAccessTest {private EmbeddedDatabase db;@BeforeEachvoid setUp() {db = new EmbeddedDatabaseBuilder().generateUniqueName(true).addDefaultScripts() // 自动加载 schema.sql + data.sql.build();}@Testvoid shouldFindUserById() {JdbcTemplate template = new JdbcTemplate(db);List<User> users = template.query("SELECT * FROM users WHERE id = ?", new Object[]{1}, userRowMapper);assertThat(users).hasSize(1);}@AfterEachvoid tearDown() {db.shutdown();}
}

✅ 这是典型的 集成测试模板


✅ 3.9.6 为什么需要“唯一数据库名”?

❓ 问题:

多个测试类都用相同的配置创建嵌入式数据库,Spring 会复用同一个实例(因为默认名字是 testdb),导致数据污染。

✅ 解决方案:

启用唯一名称生成:

.generateUniqueName(true)

或 XML 中:

<jdbc:embedded-database generate-name="true">

✅ 每次创建都是独立数据库,避免冲突。


✅ 3.9.7 扩展支持(高级)

你可以自定义:

  • 新的嵌入式数据库类型(实现 EmbeddedDatabaseConfigurer
  • 新的 DataSource 工厂(如连接池)

一般开发者不需要做,但框架开发者可以贡献扩展。


🎯 四、总结:这些知识能用来做什么?

技术点实际应用场景
SqlParameterValue插入 NULL 字段,确保类型正确
LobHandler存储图片、文档、大文本(如博客内容)
IN 子句传 List批量查询用户、订单等
SqlTypeValue调用 Oracle 存储过程传对象
嵌入式数据库单元测试、快速原型、CI/CD 自动化

📌 五、学习建议

  1. 先掌握 JdbcTemplate 基础用法(查询、更新)
  2. 再学命名参数和 IN 子句(日常开发高频)
  3. 测试时使用嵌入式数据库(提升测试效率)
  4. 只有对接 Oracle 存储过程时才深入 SqlTypeValue

📘 补充:现代 Spring 推荐替代方案

虽然这些技术仍然有效,但在现代 Spring Boot 项目中:

传统技术现代替代
JdbcTemplate + LobHandler使用文件存储服务(如 MinIO、S3)+ 数据库存路径
手动创建嵌入式数据库使用 @DataJpaTest + H2(Spring Boot 自动配置)
SqlTypeValue使用 JPA + Hibernate 映射复杂类型,或 MyBatis

如果你告诉我你目前在做什么项目(比如:Web 后端?单元测试?还是对接 Oracle?),我可以给出更具体的建议 😊

http://www.dtcms.com/a/540157.html

相关文章:

  • 图片转PPT:用Java高效处理PowerPoint的秘籍
  • Custom Animations for PPT (PowerPoint)
  • 沈阳网站哪家做的好做视频网站设备需求
  • 【数据工程】16. Notions of Time in Stream Processing
  • AOI在传统汽车制造领域中的应用
  • 搭建网站复杂吗微信公众号怎么做链接网站
  • 网站优化推广招聘wordpress后台打开超慢
  • Linux软件编程笔记三——标准IO(二进制)文件IO
  • 如何使用 TinyEditor 快速部署一个协同编辑器
  • pgsql常用函数
  • 企业落地 NL2SQL,需要的是 AI-ready data 和小模型
  • 最好的购物网站排名厦门的推广公司有哪些
  • PyTorch2 Python深度学习 - 初识PyTorch2,实现一个简单的线性神经网络
  • 外贸网站建设gif制作软件app
  • 我回来了,依然关注新能源汽车研发测试,
  • Go 语言数组
  • Go语言-->sync.WaitGroup 详细解释
  • 从“造机器”到“造生态”:中国智能时代的系统跃迁——从宇树实训平台到视频神经系统的启示
  • YOLOV5_TensorRT_C++部署
  • 海南省住房和城乡建设官方网站网站域名不备案
  • 网络空间引擎
  • VANCHIP射频芯片:智能汽车的“第六感”觉醒
  • C++——二叉搜索树——数据结构进阶——附加超详细解析过程/代码实现
  • 网站页面两侧漂浮的怎样做电商网站前端页面内容编写
  • PCIE学习
  • API Key 管理与计费系统模块(API Gateway 模块)需求文档
  • 2024-2025年技术发展趋势深度分析:AI、前端与后端开发的革新之路
  • vue3 实现贪吃蛇 电脑版01
  • 做网站带后台多少钱东莞做网站 动点官网
  • 郑州做网站建设wordpress数据控查看密码