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

spring07-JdbcTemplate操作数据库

一、JdbcTemplate 是什么?

JdbcTemplate 是 Spring 提供的一个用来简化 JDBC 操作的工具类

它属于 Spring 的 spring-jdbc 模块,封装了对原生 JDBC 的操作流程,如:

  • 获取连接

  • 创建 Statement

  • 执行 SQL

  • 处理结果集

  • 关闭资源等

你只需要关心:

“我要执行什么 SQL、传什么参数、返回什么类型”,剩下的繁琐操作都交给它。


二、JdbcTemplate 的作用

简而言之,它是用来操作数据库的,支持:

操作类型方法举例
增删改update()插入、删除、更新
查询(返回一个对象)queryForObject()查总数、查单个字段
查询(返回多个对象)query()查表中的所有记录
批处理batchUpdate()一次执行多条插入语句

三、为什么要用 JdbcTemplate?

我们先来看原生 JDBC 写法(写一条 INSERT):

Connection conn = null;
PreparedStatement stmt = null;
try {conn = DriverManager.getConnection(...);stmt = conn.prepareStatement("INSERT INTO user(name, age) VALUES(?, ?)");stmt.setString(1, "Tom");stmt.setInt(2, 20);stmt.executeUpdate();
} catch (Exception e) {...
} finally {stmt.close();conn.close();
}

问题:太繁琐了!大量重复的样板代码,还容易忘关连接、出错。

使用 JdbcTemplate:

jdbcTemplate.update("INSERT INTO user(name, age) VALUES(?, ?)", "Tom", 20);

仅一行代码,干净、清爽、安全、性能好!


四、JdbcTemplate 的使用步骤

使用:Spring 开发规范的三层架构写法

层级说明
Dao 接口UserDao声明操作方法
Dao 实现类UserDaoImpl使用 JdbcTemplate 实现数据库操作
Service 类UserService通过 @Autowired 注入 DAO,实现业务逻辑
依赖注入Spring 容器自动注入 UserDaoImplUserDao 接口

 

步骤一:添加相关依赖

        <!-- 数据库连接池 --><!-- Druid 依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!-- MySQL JDBC 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency><!-- JdbcTemplate 和相关支持 --><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.24</version></dependency>

步骤二:

1、在xml配置文件中配置数据源(DataSource)

2、在xml配置文件中创建 JdbcTemplate Bean

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><!--    基本连接信息    --><property name="driverClassName" value="${db.driverClassName}" /><property name="url" value="${db.url}" /><property name="username" value="${db.username}" /><property name="password" value="${db.password}" /></bean><!-- 配置 JdbcTemplate --><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean>

步骤三:创建DAO 层接口和实现类

public interface UserDao {public void addUser(User user);public List<User> findAll();void updateUser(User user);void deleteUser(int id);}
@Repository
public class UserDaoImpl implements UserDao {@Autowiredprivate JdbcTemplate jdbcTemplate;@Overridepublic void addUser(User user) {// 创建sql语句String sql = "INSERT INTO tb_user VALUES(?,?,?,?,?)";// 实现jdbcTemplate调用update方法,新增一条数据jdbcTemplate.update(sql, user.getId(), user.getUserName(), user.getPassword(), user.getGender(), user.getAddr());}@Overridepublic List<User> findAll() {String sql = "SELECT * FROM tb_user";return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));}@Overridepublic void updateUser(User user) {String sql = "update tb_user set user_name=?, password=? where id=?";Object[] args = {user.getUserName(), user.getPassword(), user.getId()};int update = jdbcTemplate.update(sql, args);System.out.println("成功更新:"+update + "条");}@Overridepublic void deleteUser(int id) {String sql = "delete from tb_user where id=?";int delete = jdbcTemplate.update(sql, id);System.out.println("成功删除:"+ delete + "条");}
}

 【注意】:

在dao层实现类中注入:JdbcTemplate

 

步骤四、编写测试类

    @Testpublic void test01(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userServiceTemp", UserService.class);User user = new User();user.setId(4);user.setUserName("orm");user.setPassword("orm123");user.setGender("女");user.setAddr("清迈");userService.addUser(user);}@Testpublic void test02(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userServiceTemp", UserService.class);userService.findAll();}@Testpublic void testUpdate(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userServiceTemp", UserService.class);User user = new User();user.setId(4);user.setUserName("orm kp");user.setPassword("orm123456");userService.updateUser(user);}@Testpublic void testDelete(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userServiceTemp", UserService.class);userService.deleteUser(4);}

 


五、JdbcTemplate 的优点总结

优点说明
简化代码不用写连接获取、释放、异常处理
安全自动防 SQL 注入(参数绑定)
性能好配合连接池使用
易维护写法规范,容易阅读和维护
易集成与 Spring 完美集成,支持事务管理等

一句话总结:

JdbcTemplate 是 Spring 提供的用于简化数据库访问的工具类,它封装了传统 JDBC 的繁琐步骤,让你更专注于业务逻辑,写出简洁、高效、安全的数据库代码。

六、面向接口编程

UserService里面注入的是接口:UserDao,而不是实现类UserDaoImpl,这正体现了面向接口编程在 Spring 架构中的核心思想之一。

这个问题问得非常好!这正体现了面向接口编程在 Spring 架构中的核心思想之一。


6-1、为什么注入的是接口而不是实现类?

因为这是 解耦、灵活、可替换、易测试 的关键做法。


1. 面向接口编程(OOP 原则)

@Autowired
private UserDao userDao;  // 接口

虽然写的是接口,但 Spring 会在启动时根据实际情况注入接口的实现类(如 UserDaoImpl。这是 OOP 里的“面向接口而不是实现编程”原则。

好处:

  • 不依赖具体实现类,代码更灵活

  • 后期如果你要换成 MyBatisUserDaoImplJpaUserDaoImpl不用改 Service 代码

  • 容易进行单元测试(可以 mock 接口)


2. 实现解耦(降低模块间依赖)

如果写成:

@Autowired
private UserDaoImpl userDao;

这意味着:

  • UserService 直接依赖 UserDaoImpl

  • 如果 UserDaoImpl 替换成了别的实现类,你需要修改 Service 层的代码

  • 违反了 开闭原则(对扩展开放,对修改关闭)

而使用接口:

@Autowired
private UserDao userDao;

就可以轻松切换实现类,只要实现类使用了 @Repository 并被 Spring 扫描到,就会被自动注入。


3. 依赖注入机制 + 多实现支持

Spring 会在启动时:

  • 找到 UserDao 的实现类(如 UserDaoImpl

  • 自动创建 UserDaoImpl 对象并注入到 UserService.userDao

如果有多个实现类,比如:

@Repository
public class JdbcUserDaoImpl implements UserDao {}@Repository
public class MyBatisUserDaoImpl implements UserDao {}

你可以通过 @Qualifier 指定注入哪个:

@Autowired
@Qualifier("jdbcUserDaoImpl")
private UserDao userDao;

6-2、总结对比

写法灵活性耦合度可测试性推荐程度
注入接口 (UserDao)容易 Mock✅✅✅✅✅
注入实现类 (UserDaoImpl)不好替换

你说得非常对 ✅,现在在实际企业项目中确实更常用 MyBatis 或 JPA,而不是直接使用 JdbcTemplate,原因我们可以从以下几个方面来讲解:


七、JdbcTemplate 在 Spring 中的定位

JdbcTemplate 是 Spring 提供的最基础的数据库操作工具,它封装了原生 JDBC,让你不再手写繁琐的连接/释放代码。

但它本质上还是“手写 SQL + 数据映射”,工作量仍然不小,不适合大规模开发。


7-1、现实项目中为什么更常用 MyBatis 或 JPA?

1. MyBatis(半自动 ORM,最流行)

开发者写 SQL,MyBatis 自动将 SQL 映射成 Java 对象。

优势:

  • SQL 可控(性能调优好)

  • XML 或注解方式灵活配置

  • 支持动态 SQL、复杂关联、分页

  • Spring Boot 中集成非常成熟

  • 有插件生态(分页、缓存等)

适合大多数企业项目,特别是互联网、电商、政务等项目。


2. JPA / Hibernate(全自动 ORM)

不写 SQL,直接通过实体类操作数据库。

优势:

  • 开发快,效率高

  • 全自动建表、查询、更新

  • 支持复杂关联(@OneToMany、@ManyToOne)

劣势:

  • 性能调优复杂

  • 对复杂 SQL 支持不如 MyBatis

  • 学习曲线相对更陡

适合快速开发型项目、后台系统、Spring Data 项目。


3. JdbcTemplate 的不足

项目MyBatisJPAJdbcTemplate
SQL 控制👍 完全手写👎 自动生成👍 手写
映射能力👍 自定义、灵活👍 注解/映射多样👎 需写 RowMapper
关联关系支持👍 多表连接容易👍 注解即可👎 全手写
易用性中等(写SQL)简单(不写SQL)低(写很多模板代码)
企业项目常用度✅✅✅✅✅✅✅✅✅(较少)

 

7-2、Spring Boot 项目的主流选择

在 Spring Boot 中,现在主流做法是:

需求推荐方案
想要灵活写 SQL、自定义性能MyBatis + PageHelper
想要开发快、少写代码Spring Data JPA
非常轻量、只有几条 SQLJdbcTemplate

 

7-3、什么时候还是会用 JdbcTemplate?

  • 编写工具类操作数据库(如清理任务)

  • 对性能要求极高且 SQL 简单时

  • 替代原生 JDBC 写法

  • 在框架内部使用(Spring 自身或某些底层库)


7-4、结论

JdbcTemplate 是 Spring 非常重要的数据库工具类,但在现代 Spring Boot 项目中更常用 MyBatis 或 JPA,前者兼具灵活与高性能,后者开发效率高。

八、JdbcTemplate 查询常用三种方式

查询类型方法示例用途
1️⃣ 返回单个值queryForObject()总记录数、最大值、某个字段等
2️⃣ 返回单个对象queryForObject() + RowMapper查询一个 User 对象
3️⃣ 返回对象集合query() + RowMapper查询所有 User 对象

前提准备(假设有如下用户表)

CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),age INT
);

Java 对应实体类:

public class User {private Integer id;private String name;private Integer age;// getter / setter
}

 

8-1、查询某个值:queryForObject()

示例 1:查询总人数

String sql = "SELECT COUNT(*) FROM user";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
System.out.println("总人数:" + count);

示例 2:查询某个名字的年龄

String sql = "SELECT age FROM user WHERE name = ?";
Integer age = jdbcTemplate.queryForObject(sql, Integer.class, "Tom");

⚠️ 注意:

  • 如果查询结果为 null 会抛异常(如找不到记录)

  • 如果返回多行也会抛异常


8-2、查询单个对象:queryForObject() + RowMapper

示例:根据 id 查询一个用户对象

String sql = "SELECT * FROM user WHERE id = ?";
User user = jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<>(User.class), 1);System.out.println(user.getName());

BeanPropertyRowMapper 会自动将查询结果按列名 → Java 属性名进行映射(支持下划线转驼峰)。


8-3、查询对象集合:query() + RowMapper

示例:查询所有用户

String sql = "SELECT * FROM user";
List<User> userList = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(User.class));for (User user : userList) {System.out.println(user.getName() + " - " + user.getAge());
}

8-4、总结对比

类型方法说明
返回一个值queryForObject(String sql, Class<T> requiredType, Object... args)查询数量、某字段
返回单个对象queryForObject(String sql, RowMapper<T> rowMapper, Object... args)一行数据映射为对象
返回对象集合query(String sql, RowMapper<T> rowMapper)多行数据映射为 List

九、批量操作的使用方法

JdbcTemplate 完全支持批量操作(增删改),而且它的效率比单条 update 循环高很多,常用于批量插入或删除数据的场景。

使用:

jdbcTemplate.batchUpdate(String sql, List<Object[]> batchArgs)

它适用于:

  • 批量插入 INSERT

  • 批量更新 UPDATE

  • 批量删除 DELETE


9-1、方法参数说明

public int[] batchUpdate(String sql, List<Object[]> batchArgs)
参数说明
sqlSQL 语句,带 ? 占位符
batchArgs每一行数据对应一个 Object[],多个对象构成 List

返回值是 int[],表示每条 SQL 执行影响的行数。

假设我们有如下 user 表:

CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50),age INT
);

9-2、批量新增(INSERT)

String sql = "INSERT INTO user(name, age) VALUES(?, ?)";List<Object[]> batchArgs = new ArrayList<>();
batchArgs.add(new Object[]{"Tom", 20});
batchArgs.add(new Object[]{"Jerry", 22});
batchArgs.add(new Object[]{"Alice", 18});jdbcTemplate.batchUpdate(sql, batchArgs);

9-3、批量更新(UPDATE)

String sql = "UPDATE user SET age = ? WHERE name = ?";List<Object[]> batchArgs = new ArrayList<>();
batchArgs.add(new Object[]{25, "Tom"});
batchArgs.add(new Object[]{23, "Jerry"});
batchArgs.add(new Object[]{19, "Alice"});jdbcTemplate.batchUpdate(sql, batchArgs);

9-4、批量删除(DELETE)

String sql = "DELETE FROM user WHERE name = ?";List<Object[]> batchArgs = new ArrayList<>();
batchArgs.add(new Object[]{"Tom"});
batchArgs.add(new Object[]{"Jerry"});jdbcTemplate.batchUpdate(sql, batchArgs);

 

9-5、注意事项

项目建议
批量大小控制在 500~1000 条一批,避免 SQL 太大
数据顺序保持和 SQL 中 ? 顺序一致
性能一般比单条 update 快 3~10 倍
返回值int[] 表示每条语句影响行数,可选判断成功与否

相关文章:

  • JSON简介及其应用
  • Geollama 辅助笔记:raw_to_prompt_strings_geo.py
  • 编程江湖-左右互博术(多线程,多进程)
  • [Linux]信号入门
  • 【企业管理】利益分配
  • 《高等数学》(同济大学·第7版)第十章 重积分第三节三重积分
  • 科大讯飞2025AI开发者大赛-用户新增赛道时间规则解析
  • ARFoundation系列讲解 - 100 VisionPro 环境搭建
  • Swift Moya自定义插件打印日志
  • 磁悬浮轴承气隙设计深度解析:微米间的生死时速
  • 蚂蚁百宝箱体验:如何快速创建“旅游小助手”AI智能体
  • Eplan2022导入edz文件并插入使用
  • Java 使用 Easy Excel 进行 Excel 数据导入导出
  • Linux基本指令篇 —— less指令
  • GeoTools 结合 OpenLayers 实现属性查询
  • 阶段二开始-第一章—8天Python从入门到精通【itheima】-118节(继承)
  • 《红黑树实现》
  • 基于esp32s3的自定义唤醒词识别-单元测试
  • 基于CNN卷积神经网络图像识别小程序9部合集
  • 【算法深练】单调栈:有序入栈,及时删除垃圾数据