孟凡的博客blog.mengfanyaoapp.com
课程资料库›Spring + SpringMVC + MyBatis›第10次 · JdbcTemplate完成数据访问
模块总览

第10次 · JdbcTemplate完成数据访问

2026-09-08 · Spring + SpringMVC + MyBatis · 课程笔记
课堂练习资料 10-JdbcTemplate完成数据访问.zip
下载 ZIP 压缩包

第10次 · JdbcTemplate完成数据访问

第1/7页 · 先知道今天要做什么

今天只做一件看得见的事:用 Java 操作自己的练习账户。

今天的场景

你已经会用 SQL 查表。现在有了一个 Java 程序:点一次运行,就能查出账户名单;再运行另一段程序,把你的学号和余额存到数据库。最后把自己的余额从30元改成45元。

下课时拿出这三样结果

做到什么 在哪里看 完成的证据
查到名单 IDEA 的 Run 控制台 账户名单里能看到“小林”以及后来新增的自己。
新增自己 AddAccount 控制台 + MySQL 查询 新增行数为1;记下实际打印的账户编号;表里有自己的学号、30.00。
修改余额 UpdateBalance 控制台 + MySQL 查询 修改行数为1;同一个账户变成45.00;小林仍是100.00。

你只需要带着这些基础来

会写 main、变量、方法调用和 if;能看懂 SELECT、INSERT、UPDATE。List 就是一组字符串,例如 [小林, 2510101]。如果还不熟,先照着查询例子运行,再看第2页解释。

两课时怎么上(按每课时45分钟)

时间 老师带着做 学生留下什么
第一课时 0—8分钟 运行一次查询,展示 Java 输出与数据库同一份数据。 知道程序在哪里运行,结果在哪里看。
8—18分钟 解释连接工具、SQL、问号和返回值,只看查询例子的核心三行。 能指出 SQL 字符串和 names 列表。
18—35分钟 边演示边让学生新增自己的账户。 一个真实账户编号。
35—45分钟 巡视并一起查表,解决卡住的步骤。 新增成功、数据库核对通过。
第二课时 0—15分钟 用真实编号演示改余额,先预测再运行。 理解“影响1行”和“影响0行”。
15—33分钟 学生独立完成第5页的30→45练习。 三项检查记录。
33—45分钟 抽查数据库结果,让学生说明问号和值的对应关系。 提交三份 Java 文件和练习记录。

从哪里开始

老师已经配好机房环境:按第3页看例子,再跟第4页操作。自己学习或电脑第一次运行:先完成第4页“准备好工程”与“建库连接”,然后回第3页。安装 JDK/MySQL、首次下载依赖放在课前;90分钟用于读懂和练习。

今天先掌握到这里

先会调用 JdbcTemplate 查询、新增和修改。分层、接口、对象映射、事务留到后续课;这课用普通 main,所有关键文件都在课堂包中。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。

第2/7页 · 把新词说清楚

把新名字对应到你已经会的 Java 和 SQL。

四个新名字就够了

名字 用熟悉的话理解 本课里长什么样
数据源 dataSource 保存“去哪台数据库、用哪个账号连接”的对象。 Db.java 读取 db.properties 中的地址、账号和密码。
JdbcTemplate 一个现成的 Java 工具对象,负责把 SQL 和参数交给数据库,并把结果带回来。 JdbcTemplate jdbc = Db.connect();
参数占位符 ? SQL 中留出来的“值的位置”。后面的参数按顺序填进去。 VALUES (?, ?) 后依次传学号、余额。
影响行数 rows 这次新增或修改影响了多少条记录,是一个整数。 int rows = jdbc.update(…); 成功新增一条,通常是1。

把名字分清

JdbcTemplate 是类名;jdbc 是我们给这个对象起的变量名;sql 是保存 SQL 文字的 String 变量;account 是数据库里的表名。变量名不会自动变成数据库里的列。

本课只用三个方法

方法 什么时候用 结果是什么
queryForList(sql, String.class) 查询 username 这一列的多行文字。 List,例如 [小林, 2510101];空表是 []。
update(sql, 参数…) 执行 INSERT 或 UPDATE。名字虽然叫 update,也可以新增。 int,表示影响行数。
queryForObject(sql, 类型.class, 参数…) 查询明确只应该有一个结果的编号或余额。 一个 Integer 编号或 Double 金额;本课只在确认账户存在后查询。

String.class 是什么

这里先把它读成“把查到的这一列按字符串取回来”。它不是数据库的列名,也不是要打印的内容。查编号时写 Integer.class,查本例的金额时写 Double.class。

只看这两行:两个问号怎样收值

本课课堂练习工程

String sql = "INSERT INTO account(username, balance) VALUES (?, ?)";
int rows = jdbc.update(sql, "2510101", 30.0);

按位置一一对应

SQL中的位置 Java传入的值 写到哪里
第一个 ? “2510101” username 列
第二个 ? 30.0 balance 列

先口头预测

如果第二个参数改成50.0,数据库哪一列会变化?答案是 balance。sql 中的问号不加引号,值通过 update 的参数传入;本课不把学号拼进 SQL 字符串。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。

第3/7页 · 先看一个小例子

先只查名单。下面是完整文件,不是从大工程截下来的半段代码。

先看数据库里的一行

执行课堂包 schema.sql 后,account 表至少有示例账户“小林”,余额100.00。id 是数据库自动分配的,实际值以自己的查询为准。查询程序只读数据,不会新增账户。

在 MySQL 工具里先执行一次

本课课堂练习工程

SELECT username FROM account ORDER BY id;

预期看见什么

第一次建好练习库时,查询结果有一行“小林”。如果你已经做过新增练习,还会有自己的学号,这是正常的。

QueryAccounts.java:完整文件

src/main/java/campus/QueryAccounts.java

package campus;

import java.util.List;
import org.springframework.jdbc.core.JdbcTemplate;

public class QueryAccounts {
    public static void main(String[] args) throws Exception {
        JdbcTemplate jdbc = Db.connect();
        String sql = "SELECT username FROM account ORDER BY id";
        List<String> names = jdbc.queryForList(sql, String.class);
        System.out.println("账户名单:" + names);
    }
}

在 IDEA 怎么运行

完成第4页的工程与数据库准备后,打开 src/main/java/campus/QueryAccounts.java,点击 main 左侧绿色三角,选择 Run QueryAccounts.main()。在底部 Run 控制台找“账户名单:”这一行。

第一次运行的预期输出

本课初始数据库的预期输出,不是替你运行过的结果

账户名单:[小林]

把核心代码一行一行读懂

这一行 它做了什么 你检查什么
JdbcTemplate jdbc = Db.connect(); 调用包中已经写好的连接工具,得到一个可用的 JdbcTemplate 对象。 Db.java 和 db.properties 都在包中;你要填的是数据库连接。
String sql = “SELECT username FROM account ORDER BY id”; 准备查询语句。此时只是保存一段文字,还没查询。 和上面在 MySQL 工具里执行的 SQL 相同。
List names = jdbc.queryForList(sql, String.class); 把 SQL 交给数据库,取回 username 这一列的所有值。 names 保存一组名字,不是表本身。
System.out.println(“账户名单:” + names); 把取回来的名单打印到控制台。 看到小林;新增之后再运行会看到新学号。

在纸上走一遍

main → Db.connect() 读取连接设置 → queryForList 把 SELECT 交给 MySQL → MySQL 返回名字 → println 打印。数据库中保存数据,Java 程序这次只是把数据读出来。

先做一个不会改数据的小练习

只把输出前缀“账户名单:”改成“软件251的账户名单:”,保存并重新运行 QueryAccounts。前缀变了,数据库中的“小林”没有变。先把这个结果做出来,再学新增。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。

第4/7页 · 一步一步做出来

跟老师完成“查一次 → 加一条 → 改同一条”,每一步都有检查点。

准备好工程:先把文件放对

  1. 点讲义顶部“下载课堂练习”,或到“课程资料”下载“第10课 · JdbcTemplate课堂练习包”,取得 lesson-10-jdbc-practice.zip。解压为普通文件夹,进入直接有 pom.xml、schema.sql 和 src 的 lesson-10-jdbc-practice 文件夹。
  2. IDEA:File → Open,选择这个 pom.xml,选 Open as Project / 新窗口打开。看到 src/main/java/campus 下的 QueryAccounts、AddAccount、UpdateBalance、Db 四个类。
  3. 需要 JDK17 时点“下载jdk17”,将 Windows x64 ZIP 全部提取到固定位置,例如 D:\Java\jdk-17.0.20.1+1。选择直接含 bin、lib、conf 的目录,bin 里应有 java.exe 和 javac.exe。
  4. File → Project Structure → Project:SDK 选17;没有就 Add SDK → JDK / Add JDK from disk,选刚解压的根目录。Language level 选17;Modules → Dependencies → Module SDK 选 Project SDK。
  5. File → Settings → Build, Execution, Deployment → Build Tools → Maven:Importing 中 JDK for importer 选17,Runner 中 JRE 选17。菜单名称因 IDEA 版本略有差异,可搜索 importer 和 Runner。
  6. 打开 Maven 面板,Reload All Maven Projects,等依赖下载完成。pom.xml 已指定 Java17 和所需库。main 的运行配置若单独指定 JRE,也选17。以 Run 的 java.exe 路径为准。

建库连接:先确认 MySQL 能查到小林

  1. 先启动自己的 MySQL。打开机房使用的 Navicat / MySQL Workbench,连接自己的本机或教师分配的数据库实例;本机通常为127.0.0.1:3306,账号和密码用实际 MySQL 凭据。
  2. 在 SQL 查询窗口执行下面完整脚本,也可以打开课堂包根目录的 schema.sql 执行。脚本不会删表,不会覆盖已有账户。若使用教师分配的独立库名,同时修改建库/USE 和 db.properties 中的库名。
  3. 查看最后 SELECT 的结果,至少有“小林,100.00”。若已有同名 account 表但列或唯一约束不同,先让教师检查;IF NOT EXISTS 只是不重复建表,不会修改旧结构。
  4. 在 IDEA 打开 src/main/resources/db.properties,把 YOUR_MYSQL_USER 和 YOUR_MYSQL_PASSWORD 换成刚才连接成功的账号密码;地址、端口、库名也要一致。Ctrl+S 保存。
  5. 运行 QueryAccounts.main()。先成功看见账户名单,再往下做新增。连接失败先对照第6页,不要一边改账号一边改 SQL。

schema.sql:本课独立练习库

课堂包/schema.sql

-- Run in your own MySQL practice environment. No existing rows are deleted.
CREATE DATABASE IF NOT EXISTS jdbc_lesson10 DEFAULT CHARACTER SET utf8mb4;
USE jdbc_lesson10;

CREATE TABLE IF NOT EXISTS account (
    id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    balance DECIMAL(10, 2) NOT NULL
);

-- Add the sample only if it is missing; rerunning keeps students' changes.
INSERT INTO account (username, balance)
SELECT '小林', 100.00
WHERE NOT EXISTS (SELECT 1 FROM account WHERE username = '小林');

SELECT id, username, balance FROM account ORDER BY id;

db.properties:只改连接值,键名保持原样

src/main/resources/db.properties

# Fill in the credentials of YOUR local or teacher-assigned MySQL database.
db.driver=com.mysql.cj.jdbc.Driver
db.url=jdbc:mysql://127.0.0.1:3306/jdbc_lesson10?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
db.username=YOUR_MYSQL_USER
db.password=YOUR_MYSQL_PASSWORD

老师演示1:先让学生猜,再新增

打开 AddAccount.java。先指给学生看 teacher_demo 和20.0,问“运行后会多哪两个值”。只运行一次 AddAccount.main();在控制台找“新增行数:1”和“我的账户编号:实际数字”。把实际编号记到黑板上,不预先写成1或2。

AddAccount.java:完整文件

src/main/java/campus/AddAccount.java

package campus;

import org.springframework.jdbc.core.JdbcTemplate;

public class AddAccount {
    public static void main(String[] args) throws Exception {
        JdbcTemplate jdbc = Db.connect();
        String myName = "teacher_demo"; // 学生练习:改成自己的学号,保留双引号
        double startingBalance = 20.0;
        String sql = "INSERT INTO account(username, balance) VALUES (?, ?)";
        int rows = jdbc.update(sql, myName, startingBalance);
        System.out.println("新增行数:" + rows);
        Integer myId = jdbc.queryForObject(
                "SELECT id FROM account WHERE username = ?", Integer.class, myName);
        System.out.println("我的账户编号:" + myId);
    }
}

学生跟做1:看见新增真的落到了表里

  1. 先观察老师运行前后的表。INSERT 没写 id,因为 id 由数据库自动生成。
  2. 自己跟做时先运行一次本地 AddAccount(保持 teacher_demo、20.0),记下编号;再运行 QueryAccounts,名单里应多一个 teacher_demo。若已经跟做过,不重复新增。
  3. 在 MySQL 工具执行 SELECT id, username, balance FROM account ORDER BY id;,找到 teacher_demo 的编号和20.00。新增行数、Java 名单、数据库这一行对得上,才继续。
  4. 同一个 username 在本课表中不能重复。不要连续点击 AddAccount;出现 Duplicate entry 就先查已有记录,不要删库重来。

老师演示2:只改刚才那一条

打开 UpdateBalance.java,把 myId 的0换成刚才实际打印的编号,myName 保持 teacher_demo,newBalance 设35.0。先问学生“哪一行会变、变成多少”,然后运行 UpdateBalance.main()。预期打印“修改行数:1”“修改后的余额:35.0”。

UpdateBalance.java:完整文件

src/main/java/campus/UpdateBalance.java

package campus;

import org.springframework.jdbc.core.JdbcTemplate;

public class UpdateBalance {
    public static void main(String[] args) throws Exception {
        JdbcTemplate jdbc = Db.connect();
        int myId = 0; // 改为 AddAccount 实际打印的账户编号,不猜编号
        String myName = "teacher_demo"; // 与自己 AddAccount 中的名字完全一致
        double newBalance = 35.0;
        String sql = "UPDATE account SET balance = ? WHERE id = ? AND username = ?";
        int rows = jdbc.update(sql, newBalance, myId, myName);
        System.out.println("修改行数:" + rows);
        if (rows == 1) {
            Double balance = jdbc.queryForObject(
                    "SELECT balance FROM account WHERE id = ?", Double.class, myId);
            System.out.println("修改后的余额:" + balance);
        } else {
            System.out.println("没有修改到账户,请检查编号和学号是否属于同一行。");
        }
    }
}

修改语句的三个问号

位置 传入变量 意思
第1个 ? newBalance 要改成的余额35.0
第2个 ? myId 只找这个编号
第3个 ? myName 同时确认这行属于这个名字

最后再查表

重新执行 SELECT id, username, balance FROM account ORDER BY id;。teacher_demo 应为35.00,小林应仍为100.00。控制台35.0与数据库35.00表示同一数值。rows 为0时先核对编号和名字,不要删掉 WHERE 来让它“成功”。

Db.java 到底做了什么

它读取 db.properties,创建 DriverManagerDataSource 保存连接设置,再 new JdbcTemplate(dataSource)。完整文件已放在包中,本课先会填连接值和调用它;老师可打开这两行演示工具对象怎样创建,不要求学生当堂重写配置工具。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。

第5/7页 · 换成自己的代码

现在关掉老师的示范结果,用自己的学号独立做一遍。

开始前:在 IDEA 确认 JDK17

  1. 需要安装时点顶部“下载jdk17”,解压到固定位置,例如 D:\Java\jdk-17.0.20.1+1;选择直接含 bin、lib、conf 的根目录。
  2. File → Project Structure → Project:SDK 选17;没有就 Add SDK → JDK 选择解压目录;Language level 选17,Modules → Dependencies → Module SDK 选 Project SDK。
  3. File → Settings → Build Tools → Maven(也可搜索 Maven):Importing 的 JDK for importer、Runner 的 JRE 均选17。Reload Maven;main 运行配置若另选 JRE,也改为17。
  4. 先运行 QueryAccounts。能看到实际账户名单,再开始下面的个人练习;数据库尚未准备好时按第4页执行 schema.sql 并填写 db.properties。

你的任务

创建 username 为自己学号、初始余额30.00的账户;记下它的真实编号;把同一账户余额改为45.00。最后证明小林和老师的账户没有被你改动。

按这张操作单完成

步骤 打开哪个文件、改哪里 运行后应该看到什么
1 查询基线 QueryAccounts.java:运行 main,不改 SQL。 看见现有名单;记录当前是否已有自己的学号。
2 新增自己的账户 AddAccount.java:myName 改为自己的学号(保留双引号);startingBalance 改为30.0。只运行一次。 新增行数1;记录自己的真实 id。
3 重新查名单 QueryAccounts.java:再运行 main。 名单里有自己的学号。
4 修改同一个账户 UpdateBalance.java:myId 换自己的真实 id;myName 填同一个学号;newBalance 改成45.0。 修改行数1;修改后的余额45.0。
5 到数据库核对 MySQL 查询窗口执行下面的检查 SQL。 自己的行是45.00;小林仍是100.00。

检查结果:把学号换成自己的

本课课堂练习工程

SELECT id, username, balance
FROM account
WHERE username IN ('小林', '2510101')
ORDER BY id;

自己的学号已经存在怎么办

先 SELECT 查出自己的 id 和余额。如果是刚才已新增成功,直接从步骤3继续,记录原余额;不要再次 INSERT。课堂第一次完整练习必须有一次新增记录;需要重新完整演练时,在自己的学号后加 _2 作为本轮标记,并在后续文件和记录里保持一致。

做完基础任务后,再验证一次“没有改到”

  1. 先记录自己的正确 id 与45.00余额。把 UpdateBalance 的 myId 临时改为 -1,其他内容不变,运行。
  2. 应显示修改行数0,并提示检查编号和学号。再次查自己的余额,应仍为45.00。这说明没有匹配到记录,不是程序自动改好了。
  3. 把 myId 恢复正确编号,保存。把这一次对照结果写进练习记录。

最低完成标准:先把这三项做实

检查 通过条件
查 QueryAccounts 能显示自己的学号。
加 记录了新增行数1和真实编号。
改 自己的余额确实变为45.00,其他账户未变。

最后交什么

将自己实际运行的 QueryAccounts.java、AddAccount.java、UpdateBalance.java 和练习记录.md 放到代码任务中提交。记录写真实编号、运行输出和数据库查询结果。db.properties 含你的数据库密码,不提交它。

网站已有旧草稿的同学

先保留旧草稿文件,再按课堂包中的真实文件名添加这三份 Java 文件与记录。网站不会替你运行 Java;保存草稿后再正式提交,查看提交版本是否增加。

卡住也能清楚求助

写清卡在操作单第几步、运行的类名、改过的值、第一条错误文字。没有运行成功就写未完成,保留你已经查到的线索;先解决这个步骤,再做下一步。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。

第6/7页 · 出错时从哪里查

先看发生在哪一步,再只改一处。

把现象和检查动作对上

看到什么 先检查哪里 修好后怎样确认
IDEA 的 JdbcTemplate 标红 Maven 是否 Reload 完成;pom.xml 是否作为项目打开;依赖下载是否报错。 import 不再报红,QueryAccounts 能编译。
invalid target release: 17 / UnsupportedClassVersionError 项目 SDK、Maven Runner、main 运行配置是否使用 JDK17。 重新运行,Run 启动路径指向你的 JDK17。
Access denied for user db.properties 的账号、密码及该账号的库权限。 先用同样凭据在 MySQL 工具连接,再运行 QueryAccounts。
Communications link failure / Connection refused MySQL 服务是否启动;地址和端口是否正确。 同一地址的 MySQL 工具能够连接。
Unknown database / Table … doesn’t exist schema.sql 是否执行成功;db.url 库名与 USE 的库是否相同。 在该库查 account 能看到小林。
Duplicate entry 是否第二次运行了相同学号的 AddAccount。 查出现有账户编号;保留这行,继续查询和修改。
修改行数:0 myId 和 myName 是否来自同一条真实记录,是否忘了把默认0换掉。 条件对上后影响1行,并查到新余额。
输出还是旧文字或旧金额 是否保存文件;运行的是否是刚改的那个 main。 看 Run 标签中的类名,重新运行并到数据库查同一 id。

查自己的编号与当前余额

本课课堂练习工程

SELECT id, username, balance
FROM account
WHERE username = '2510101';

不要用这些办法“修复”

修改行数0时,不删 WHERE;新增重复时,不清空全表;找不到库时,不修改正在使用的教学网站数据库。始终在自己的练习库里核对一条账户。

老师巡视时只问三句话

你运行的是哪个 main?你期待哪一行变成什么?现在数据库里实际查到什么?先让学生指出文件和记录,再一起看报错,不直接替学生改完全部文件。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。

第7/7页 · 用自己的话讲一遍

用自己的程序和数据解释,能说清动作比背定义更重要。

先自己答,再对照

问题 可以这样说
JdbcTemplate 帮我做了什么? 接收我写的 SQL 和参数,连接数据库执行,再把查询结果或影响行数交回来。
queryForList 与 update 有什么区别? 前者读出一组结果;后者执行新增或修改,返回影响了几行。
INSERT 的两个问号分别收到什么? 第一个是我的学号,第二个是初始余额,顺序与列名对应。
为什么要记真实 id? 数据库自动分配编号,我不能假设它是1;修改时要找到自己的那一行。
修改行数0能算完成吗? 不能。说明没有匹配到要修改的行,要核对编号和学号。

一分钟展示

打开自己的 AddAccount 指出学号和30.0;打开 UpdateBalance 指出真实 id、同一学号和45.0;展示 Run 输出与数据库那一行。最后说明“小林为什么没有被我改动”。

老师怎么检查

检查项 看得到的证据 分值
查询 运行查询,名单含自己的学号。 2
新增 新增行数与生成的编号有实际记录。 3
修改 同一账户变为45.00,其他账户未变。 3
解释 能对应问号和值,说明影响行数0。 2

课后只留一个小任务

把自己的目标余额改成60.0,先写预测,再运行并查表。记录你改了哪个 Java 变量、传给第几个问号、数据库哪一列改变。无需新增功能或改工程结构。

下一课怎么接上

今天每次只改一条 SQL。下一课再讨论“两条修改必须一起成功”的情况,届时再引入事务。保留本课工程与练习记录即可。

来源:本课自编课堂练习;API依据 Spring Framework 6.1 JdbcTemplate;教材第4章作为课后选读。