【JavaWeb】JDBC与Mybatis零基础入门详解

目录

前言

一、JDBC

[1.1 JDBC 介绍](#1.1 JDBC 介绍)

[1.2 查询数据 -- 用户登录案例](#1.2 查询数据 – 用户登录案例)

需求

准备工作

代码实现

[1.3 代码剖析](#1.3 代码剖析)

ResultSet(结果集)

[预编译 SQL](#预编译 SQL)

[1.4 SQL 注入与防范](#1.4 SQL 注入与防范)

性能更高的原因

[1.5 增删改数据](#1.5 增删改数据)

需求

代码实现

二、MyBatis

[2.1 MyBatis 介绍](#2.1 MyBatis 介绍)

[2.2 快速入门](#2.2 快速入门)

[步骤一:创建 SpringBoot 工程,引入依赖](#步骤一:创建 SpringBoot 工程,引入依赖)

步骤二:准备数据与实体类

步骤三:配置数据源

[步骤四:编写 Mapper 接口](#步骤四:编写 Mapper 接口)

步骤五:单元测试

[2.3 辅助配置](#2.3 辅助配置)

[SQL 提示配置](#SQL 提示配置)

[MyBatis 日志输出](#MyBatis 日志输出)

[2.4 JDBC VS MyBatis](#2.4 JDBC VS MyBatis)

[2.5 数据库连接池](#2.5 数据库连接池)

什么是连接池?

常见产品

[2.6 增删改查操作](#2.6 增删改查操作)

[① 删除](#① 删除)

[② 新增](#② 新增)

[③ 修改](#③ 修改)

[④ 查询](#④ 查询)

[2.7 XML 映射配置](#2.7 XML 映射配置)

规范

实现示例

[MyBatisX 插件](#MyBatisX 插件)

[三、SpringBoot 配置文件](#三、SpringBoot 配置文件)

[3.1 从 properties 到 YML](#3.1 从 properties 到 YML)

[3.2 YML 语法规则](#3.2 YML 语法规则)

[3.3 项目配置改造](#3.3 项目配置改造)

总结


前言

在学习 MySQL 时,我们习惯使用图形化工具(如 IDEA、DataGrip)来操作数据库。但作为一名后端开发人员,最终必须通过 Java 程序来完成数据库操作。

在 Java 操作数据库的众多技术中,最底层、最基础的就是 JDBC

JDBC(Java DataBase Connectivity) 是 Java 语言操作关系型数据库的一套 API。它虽然基础,但直接使用会比较繁琐。因此,企业开发中通常会使用基于 JDBC 封装的高级框架,目前市场份额最大的是 MyBatis ,其次是 MyBatis Plus


一、JDBC

1.1 JDBC 介绍

JDBC 的本质 是一套由 Sun 公司定义的操作关系型数据库的规范(接口) 。各数据库厂商(如 MySQL、Oracle)去实现这些接口,并提供相应的驱动 jar 包

我们在 Java 代码中使用 JDBC 接口编程,真正执行的是驱动包中的实现类。

有了 JDBC,就可以在 Java 代码中执行 SQL 了,比如这样一段代码:

复制代码

1.2 查询数据 -- 用户登录案例

需求

基于 JDBC 实现用户登录查询,本质就是执行如下 SQL:

sql 复制代码
SELECT * FROM user WHERE username = 'linchong' AND password = '123456';
准备工作
  1. 创建 Maven 项目

  2. 创建数据库 webuser

    sql 复制代码
    CREATE TABLE user(
        id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT 'ID,主键',
        username VARCHAR(20) COMMENT '用户名',
        password VARCHAR(32) COMMENT '密码',
        name VARCHAR(10) COMMENT '姓名',
        age TINYINT UNSIGNED COMMENT '年龄'
    ) COMMENT '用户表';
    
    INSERT INTO user VALUES 
    (1, 'daqiao', '123456', '大乔', 22),
    (2, 'xiaoqiao', '123456', '小乔', 18),
    (3, 'diaochan', '123456', '貂蝉', 24),
    (4, 'lvbu', '123456', '吕布', 28),
    (5, 'zhaoyun', '12345678', '赵云', 27);
代码实现

1) 引入依赖(pom.xml)

XML 复制代码
<dependencies>
    <!-- MySQL JDBC driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    <!-- JUnit5 单元测试 -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.9.3</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2) 编写测试类

java 复制代码
public class JDBCTest {

    @Test
    public void testJdbc() throws Exception {
        // 1. 获取连接
        Connection conn = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/web", "root", "1234");
        // 2. 预编译 SQL
        PreparedStatement pstmt = conn.prepareStatement(
            "SELECT * FROM user WHERE username = ? AND password = ?");
        pstmt.setString(1, "daqiao");
        pstmt.setString(2, "123456");
        // 3. 执行查询
        ResultSet rs = pstmt.executeQuery();
        // 4. 处理结果集
        while (rs.next()) {
            int id = rs.getInt("id");
            String uName = rs.getString("username");
            String pwd = rs.getString("password");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            System.out.println("ID: " + id + ", Username: " + uName 
                + ", Password: " + pwd + ", Name: " + name + ", Age: " + age);
        }
        // 5. 关闭资源
        rs.close();
        pstmt.close();
        conn.close();
    }
}

实际项目中,用户名和密码应该是动态传入的。我们可以使用 JUnit 参数化测试 来传递不同参数:

java 复制代码
@ParameterizedTest
@CsvSource({"daqiao,123456"})
public void testJdbc(String _username, String _password) throws Exception {
    Connection conn = DriverManager.getConnection(
        "jdbc:mysql://localhost:3306/web", "root", "1234");
    PreparedStatement pstmt = conn.prepareStatement(
        "SELECT * FROM user WHERE username = ? AND password = ?");
    pstmt.setString(1, _username);
    pstmt.setString(2, _password);
    ResultSet rs = pstmt.executeQuery();
    while (rs.next()) { /* 处理结果 */ }
    // 关闭资源...
}

1.3 代码剖析

ResultSet(结果集)

ResultSet 封装了查询结果,常用方法:

  • next():移动光标到下一行,返回布尔值(是否有数据)。

  • getXxx("列名"):获取当前行指定列的值(推荐用列名,而不是列索引)。

预编译 SQL

SQL 语句有静态拼接预编译两种写法:

方式 示例 特点
静态 SQL "SELECT ... WHERE username = 'daqiao'" 参数直接拼接,不安全
预编译 SQL "SELECT ... WHERE username = ? AND password = ?" ? 占位,参数动态传递

预编译 SQL 的两大好处

  1. 防止 SQL 注入

  2. 性能更高(模板缓存)


1.4 SQL 注入与防范

SQL 注入是指攻击者通过输入特殊的参数,改变原始 SQL 语义,从而非法访问数据。最经典的场景就是登录。

例如,攻击者在密码框输入**' or '1'='1**,拼接出的 SQL 变成:

sql 复制代码
SELECT * FROM user WHERE username='任意值' AND password='' or '1'='1';

由于 '1'='1' 恒成立,or 导致条件总为真,于是能查出数据,登录成功。

解决方案 :使用预编译 SQL 。此时 ' or '1'='1 会被当作一个完整的字符串参数处理,SQL 语义不会被改变。

性能更高的原因

预编译的 SQL 语句模板会被数据库编译并缓存,后续执行只需传入参数,减少了编译开销。


1.5 增删改数据

需求

执行更新语句:

sql 复制代码
UPDATE user SET password = '123456', gender = 2 WHERE id = 1;
代码实现
java 复制代码
@ParameterizedTest
@CsvSource({"1,123456,25"})
public void testUpdate(int userId, String newPassword, int newAge) throws Exception {
    // 建立数据库连接
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web", "root", "1234");
    // SQL 更新语句
    String sql = "UPDATE user SET password = ?, age = ? WHERE id = ?";
    // 创建预编译的PreparedStatement对象
    PreparedStatement pstmt = conn.prepareStatement(sql);

    // 设置参数
    pstmt.setString(1, newPassword); // 第一个问号对应的参数
    pstmt.setInt(2, newAge);      // 第二个问号对应的参数
    pstmt.setInt(3, userId);         // 第三个问号对应的参数

    // 执行更新
    int rowsUpdated = pstmt.executeUpdate();

    // 输出结果
    System.out.println(rowsUpdated + " row(s) updated.");

    // 关闭资源
    pstmt.close();
    conn.close();
}

注意区分

  • DQL (查询):调用 executeQuery(),返回 ResultSet

  • DML (增删改):调用 executeUpdate(),返回 int(影响行数)


二、MyBatis

2.1 MyBatis 介绍

MyBatis 是一款优秀的持久层框架 ,用于大幅度简化 JDBC 的开发。它本是 Apache 的开源项目 iBatis,后来更名为 MyBatis(官网:https://mybatis.org/mybatis-3/zh/index.html

)。

持久层:就是负责操作数据库的那一层(DAO 层)。

框架:一个半成品软件,提供可重用的代码基础,让开发更高效、规范。

使用 MyBatis,原本几十行的 JDBC 查询代码,只需简单几行:

java 复制代码
@Select("select * from user")
List<User> findAll();

2.2 快速入门

目标:使用 MyBatis 查询所有用户数据。

步骤一:创建 SpringBoot 工程,引入依赖

在**pom.xml** 中会自动加入 MyBatis 起步依赖和 MySQL 驱动:

复制代码
步骤二:准备数据与实体类

数据库沿用之前的 user 表。创建实体类 User

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id; //ID
    private String username; //用户名
    private String password; //密码
    private String name; //姓名
    private Integer age; //年龄
}
步骤三:配置数据源

在 **application.properties**中配置数据库连接信息:

java 复制代码
#数据库访问的url地址
spring.datasource.url=jdbc:mysql://localhost:3306/web
#数据库驱动类类名
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#访问数据库-用户名
spring.datasource.username=root
#访问数据库-密码
spring.datasource.password=root@1234
步骤四:编写 Mapper 接口

com.itheima.mapper 包下创建 UserMapper 接口:

java 复制代码
import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;

@Mapper
public interface UserMapper {
    /**
     * 查询全部
     */
    @Select("select * from user")
    public List<User> findAll();
}
  • @Mapper:标识 MyBatis 的 Mapper,运行时会生成代理对象交给 Spring IOC 容器。

  • @Select:定义 select 查询语句。

步骤五:单元测试
java 复制代码
@SpringBootTest
class SpringbootMybatisQuickstartApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testFindAll(){
        List<User> userList = userMapper.findAll();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

运行结果将打印所有用户信息。

2.3 辅助配置

SQL 提示配置

在 IntelliJ IDEA 中,为了在注解或 XML 里写 SQL 时有语法提示和表名识别,可以配置数据库连接:

MyBatis 日志输出

添加配置后,控制台可以看到执行的 SQL 语句:

java 复制代码
#mybatis的配置
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.4 JDBC VS MyBatis

JDBC 的缺点 MyBatis 的解决方案
数据库连接信息硬编码 统一配置在 application.properties
结果集手动解析封装 自动映射为实体类
频繁创建/释放连接,资源浪费 内置数据库连接池,复用连接

使用 SpringBoot + MyBatis 时,我们只需重点关注:

  • 配置文件spring.datasource.xxx

  • Mapper 接口:编写 SQL 语句

2.5 数据库连接池

什么是连接池?
  • 没有连接池:每次操作都要新建连接,用完关闭,频繁创建销毁消耗性能。

  • 有了连接池:应用启动时预先创建一定数量的连接放入池中,需要时借用,用完后归还,重复使用。

好处:资源重用、响应更快、避免连接遗漏。

常见产品
  • HikariCP:SpringBoot 默认连接池,性能极佳。

  • Druid:阿里巴巴开源,功能强大,监控能力强。

切换为 Druid

1.引入依赖:

XML 复制代码
<dependency>
    <!-- Druid连接池依赖 -->
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.19</version>
</dependency>

2.配置(.properties.yml):

XML 复制代码
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/web
spring.datasource.druid.username=root
spring.datasource.druid.password=1234

启动后日志中会显示使用了 DruidDataSource。

2.6 增删改查操作

① 删除
java 复制代码
@Delete("delete from user where id = #{id}")
Integer deleteById(Integer id);
  • #{id}:预编译占位符,方法参数会替换它。

  • 返回值 Integer 表示影响行数。

② 新增
java 复制代码
@Insert("insert into user(username, password, name, age) values(#{username}, #{password}, #{name}, #{age})")
void insert(User user);

直接将实体对象的属性填入 #{}

③ 修改
java 复制代码
@Update("update user set username=#{username}, password=#{password}, name=#{name}, age=#{age} where id=#{id}")
void update(User user);
④ 查询
java 复制代码
@Select("select * from user where username = #{username} and password = #{password}")
User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);
  • 当方法有多个简单类型参数时,建议使用 @Param 指定名称。

  • SpringBoot 项目默认保留方法形参名,如果不用 @Param,也可以直接 #{参数名},但显式标注更清晰。

注意:

Mybatis的 提供的符号,有两个,一个是 #{...},另一个是 ${...},区别如下:

|--------|-------------------------------|---------------|-------------|
| 符号 | 说明 | 场景 | 优缺点 |
| #{...} | 占位符。执行时,会将#{...}替换为?,生成预编译SQL | 参数值传递 | 安全、性能高 (推荐) |
| ${...} | 拼接符。直接将参数拼接在SQL语句中,存在SQL注入问题 | 表名、字段名动态设置时使用 | 不安全、性能低 |

那在企业项目开发中, 强烈建议使用 #{...}

2.7 XML 映射配置

对于复杂的 SQL 语句,官方推荐使用 XML 映射文件。

规范
  1. XML 文件与 Mapper 接口同包同名

  2. namespace 必须为 Mapper 接口的全限定名

  3. 每个 SQL 标签的 id 与接口方法名一致resultType 与返回类型一致。

实现示例

resources 下创建 com/itheima/mapper/UserMapper.xml

XML 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">

    <!--查询操作-->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from user
    </select>
    
</mapper>

同时在 UserMapper 接口中去掉 @Select 注解,只保留方法声明(不要同时存在)。

MyBatisX 插件

安装 MyBatisX 插件后,可以快速在接口和 XML 之间跳转,提升开发效率。


三、SpringBoot 配置文件

3.1 从 properties 到 YML

application.properties 采用 key=value 格式,配置一多就显得臃肿,层次不清晰。

SpringBoot 还支持 YAML 格式(.yml / .yaml ),它以数据为中心,结构更直观。

对比示例

3.2 YML 语法规则

​编辑

  • 大小写敏感

  • 键值对使用 key: value,冒号后必须有空格

  • 缩进表示层级关系(只能用空格,不能使用 Tab)

  • 相同层级左侧对齐即可

  • # 表示注释

数据格式示例

  • 对象/Map
XML 复制代码
user:
  name: zhangsan
  age: 18
  password: 123456
  • 数组/List/Set
XML 复制代码
hobby:
  - java
  - game
  - sport

提示:如果值以 0 开头,需要用单引号包起来(否则会被当成八进制),例如 id: '0123'

3.3 项目配置改造

将之前的 application.properties 重命名(例如 _application.properties),然后创建 application.yml

XML 复制代码
#数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/web01
    username: root
    password: root@1234
#mybatis配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

重新运行测试,效果与之前完全一致,且配置文件更加清晰。


总结

  1. JDBC 是 Java 操作数据库的底层基石,需要手动管理连接、编写大量的模板代码,容易产生 SQL 注入风险。通过预编译 SQL 可以有效防注入、提升性能。

  2. MyBatis 在 JDBC 的基础上做了优雅封装:连接信息外置、结果自动映射、集成连接池,让我们只需专注编写 SQL 和 Mapper 接口。

  3. SpringBoot 配置文件支持 YML 格式,简洁直观,推荐在项目中使用。

相关推荐
IT_陈寒15 小时前
Vite静态资源路径这个坑差点让我加班到凌晨
前端·人工智能·后端
掘金酱15 小时前
「TRAE Work 实战帮」征文启动!你沉淀的经验,值得被看见!
前端·人工智能·后端
橙子家15 小时前
Windows 上同时安装多个 node 版本
前端
晓说前端15 小时前
TypeScript 高级特性 —— 类型断言与泛型
前端·typescript
爱勇宝16 小时前
DeepSeek V4-Flash 更新:代码与 Agent 能力全面增强
前端·后端·deepseek
GuWenyue16 小时前
90%前端写React+TS都踩坑!从组件类型、单向数据流到本地存储完整实战
前端·react.js
春生野草16 小时前
个人笔记——C语言字符串、树
c语言·开发语言·笔记
风中芦苇啊16 小时前
Java EasyExcel 导入通用工具类:自定义注解映射字段 + 反射机制
java·开发语言
PieroPc16 小时前
Python 写的 Windows凭据添加工具 第二版 解决Win11 23H2, 25H2,26H1,共享文件和打印 一部份问题,不是全部!
开发语言·windows·python