⚡ Spring JDBC 完整体系 · 第 3 讲 · Spring JDBC 最小案例

⚡ Spring JDBC 完整体系 · 第 3 讲 · Spring JDBC 最小案例

相关开源地址

  1. 核心框架源码:https://gitee.com/gao_zhenzhong/simple-dao
  2. 系统底座:https://gitee.com/gao_zhenzhong/simple-dao-starter
  3. 代码生成器:https://gitee.com/gao_zhenzhong/simple-dao-coder
  4. 实战案例(本集源码):https://gitee.com/gao_zhenzhong/simple-dao-demo

📋 前置知识

你只需要会 你完全不需要会
Java 基础(类、接口、注解、泛型) MyBatis / Hibernate 任何知识
基础 SQL(SELECT、INSERT、WHERE) 连接池原理、事务隔离级别
第 2 讲:Spring 容器(IoC + DI) XML 配置、Spring Boot 自动配置

📚 全套教程总览(20 讲从零到架构师)

篇章 涵盖讲次 核心目标
开篇筑基 第 1-3 讲 认知梳理,建立 Spring JDBC 的底层坐标系
API 精讲 第 4-7 讲 全面掌握 JdbcTemplate + 事务体系
工具封装 第 8-9 讲 手搓条件工具 + 代码生成器,从"使用者"变"创造者"
认知升华 第 10 讲 模板确定性 vs AI 不确定性,建立技术判断力
高阶扩展 第 11-17 讲 多数据源、分库分表、分布式事务
底层观测 第 18-19 讲 SQL 拦截、性能监控、连接池调优
终极收尾 第 20 讲 全链路复盘 + 手搓持久层框架

一、开篇 · 告别裸 JDBC 的繁琐

第 2 讲已经建立了 Spring 容器的认知------本质上就是一个 Map。这一讲正式进入 Spring JDBC ,将 DataSourceJdbcTemplate 注册进容器,开始用 Spring 方式操作数据库。

对比裸 JDBC(第 1 讲)和 Spring JDBC(本讲):

对比项 裸 JDBC Spring JDBC
连接管理 手动 DriverManager.getConnection() JdbcTemplate 自动管理
Statement 创建 手动 conn.createStatement() JdbcTemplate 自动创建
结果集遍历 手动 while(rs.next()) + rs.getString() BeanPropertyRowMapper 一行搞定
资源关闭 手动逆序关闭 JdbcTemplate 自动关闭
SQL 注入风险 字符串拼接,风险高 预编译占位符 ?,根治
代码量 30+ 行 2-3 行

二、极简依赖 · spring-context + spring-jdbc 双核驱动

组织 依赖 作用
org.springframework spring-context Spring IoC 容器,Bean 管理
org.springframework spring-jdbc JdbcTemplate、数据源抽象、事务能力
com.h2database h2 内存数据库,零安装零配置
org.projectlombok lombok 简化 POJO 的 getter / setter
ch.qos.logback logback-classic 日志输出,调试必备
xml 复制代码
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>[3.3.11,4.0.0)</version>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
    </dependency>
</dependencies>

三、核心代码演示

3.1 外部化配置

连接参数抽取到 jdbc.properties,SQL 日志通过 logback 开启,方便观察 JdbcTemplate 执行的 SQL 和参数绑定。

properties 复制代码
# jdbc.properties
jdbc.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false
jdbc.user=sa
jdbc.password=
xml 复制代码
<!-- logback.xml -->
<logger name="org.springframework.jdbc" level="DEBUG" />
<logger name="org.springframework.jdbc.core.StatementCreatorUtils" level="trace" />

3.2 JdbcConfig · 手动注册核心 Bean

DataSource 使用 Spring 内置的 DriverManagerDataSource(无连接池,但足够演示原理)。JdbcTemplate 依赖 DataSource 创建,所有配置透明可见。

java 复制代码
@Configuration
@ComponentScan("com.gzz")
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {

    @Value("${jdbc.url}")      private String url;
    @Value("${jdbc.user}")     private String user;
    @Value("${jdbc.password}") private String password;

    @Bean
    public DataSource dataSource() {
        return new DriverManagerDataSource(url, user, password);
    }

    @Bean
    public JdbcTemplate jdbcTemplate() {
        return new JdbcTemplate(dataSource());
    }
}

3.3 DataInitializer · 启动自动建表插数

DataSourceInitializer 在容器启动时自动执行 data.sql,完成建表和测试数据插入。业务代码无需手动初始化数据库。

java 复制代码
@Slf4j
@Configuration
public class DataInitializer {

    @Bean
    public DataSourceInitializer dataSourceInitializer(DataSource dataSource) {
        DataSourceInitializer initializer = new DataSourceInitializer();
        initializer.setDataSource(dataSource);

        ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
        populator.addScripts(new ClassPathResource("data.sql"));

        initializer.setDatabasePopulator(populator);
        log.info("初始化脚本执行完成");
        return initializer;
    }
}
sql 复制代码
-- data.sql
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(32),
    age INT
);
INSERT INTO t_user(name, age) VALUES ('张三', 10);
INSERT INTO t_user(name, age) VALUES ('李四', 10);
INSERT INTO t_user(name, age) VALUES ('李四光', 20);
INSERT INTO t_user(name, age) VALUES ('王五', 20);

3.4 实体 + DAO · BeanPropertyRowMapper 一行搞定映射

BeanPropertyRowMapper 自动将结果集列名映射到实体类的同名字段,无需手动遍历 ResultSet

java 复制代码
@Setter
@Getter
public class User {
    private Integer id;
    private String name;
    private Integer age;
}
java 复制代码
@Repository
public class UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<User> queryUsers() {
        String sql = "SELECT id, name, age FROM t_user WHERE id > ?";
        return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class), -1);
    }
}

id > ? 中的 ? 是预编译占位符,传入 -1 即查询所有 id > -1 的记录(全部数据)。预编译占位符从根源上杜绝了 SQL 注入。

3.5 Application · 高仿 Spring Boot 启动逻辑

手动创建 AnnotationConfigApplicationContext,传入配置类触发容器启动。@EventListener 在容器完全就绪后执行查询。

java 复制代码
@Slf4j
@Component
public class Application {

    public static void main(String[] args) {
        new AnnotationConfigApplicationContext(JdbcConfig.class);
    }

    @Autowired
    private UserDao dao;

    @EventListener(ContextRefreshedEvent.class)
    public void run() {
        log.info("容器完全启动后执行查询:{}", dao.queryUsers());
    }
}

四、运行结果

log 复制代码
[INFO] 初始化脚本执行完成
[DEBUG] SELECT id, name, age FROM t_user WHERE id > -1
[INFO] 容器完全启动后执行查询:[
    User(id=1, name=张三, age=10),
    User(id=2, name=李四, age=10),
    User(id=3, name=李四光, age=20),
    User(id=4, name=王五, age=20)
]

五、本讲核心总结

能力 裸 JDBC(第 1 讲) Spring JDBC(本讲)
连接管理 手动 DriverManager.getConnection() JdbcTemplate 自动管理
Statement 创建 手动 conn.createStatement() JdbcTemplate 自动创建
结果集遍历 手动 while(rs.next()) BeanPropertyRowMapper 一行搞定
资源关闭 手动逆序关闭 JdbcTemplate 自动关闭
SQL 注入 字符串拼接,风险高 预编译占位符,根治
代码量 30+ 行 2-3 行

关键技术点回顾

技术点 说明
spring-jdbc 依赖 提供 JdbcTemplate、数据源抽象、事务能力
DriverManagerDataSource Spring 内置基础数据源,适合演示
DataSourceInitializer 启动时自动执行 SQL 脚本
BeanPropertyRowMapper 结果集列名 → 实体类同名字段自动映射
预编译占位符 ? 从根源上杜绝 SQL 注入

六、下一讲预告

第 4 讲将引入 HikariCP 连接池DataSourceTransactionManager 事务管理器,从"能跑"升级到"生产可用",补齐性能和事务一致性。

相关推荐
NWU_LK33 分钟前
【WebFlux】第三篇 —— 常用操作符与数据流转换
java
Mr__Miss8 小时前
Java泛型完全指南:从入门到精通
java·开发语言·python
jinyishu_9 小时前
模拟实现 C++ 栈和队列——从适配器模式看懂 STL 容器之美
java·c++·适配器模式
前端工作日常9 小时前
我学习到的Java类和对象区别
java·后端
前端工作日常10 小时前
我学习到的Java类完整结构
java·后端
tryxr10 小时前
Spring Cloud eureka
spring·spring cloud·eureka
什巳10 小时前
JAVA练习309- 二叉树的层序遍历
java·数据结构·算法·leetcode
宠友信息10 小时前
消息序号如何保证即时通讯源码聊天记录稳定加载
java·spring boot·redis·python·mysql·uni-app
圣光SG10 小时前
Java Web入门基础知识笔记
java·前端·笔记
Csvn10 小时前
📊 SQL 入门 Day 6:多表查询 — JOIN 的四种姿势
后端·sql