一、JDBC:Java 操作数据库的基石
1. 什么是 JDBC?
JDBC(Java DataBase Connectivity)是 Java 语言操作关系型数据库的标准 API,定义了一套操作所有关系型数据库的接口规范。其本质是:
- Sun 公司制定接口,数据库厂商(如 MySQL、Oracle)提供实现类(驱动 Jar 包);
- 开发者通过 JDBC 接口编程,底层由驱动 Jar 包的实现类执行实际操作。
2. JDBC 核心操作步骤
使用 JDBC 操作数据库的固定流程如下(以查询为例):
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 1. 注册驱动(MySQL 8.0+推荐使用com.mysql.cj.jdbc.Driver) Class.forName("com.mysql.cj.jdbc.Driver"); // 2. 获取数据库连接 String url = "jdbc:mysql://localhost:3306/web?serverTimezone=UTC"; String user = "root"; String password = "1234"; Connection conn = DriverManager.getConnection(url, user, password); // 3. 预编译SQL(防止SQL注入) PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM user WHERE username = ? AND password = ?"); pstmt.setString(1, "daqiao"); // 设置参数(索引从1开始) pstmt.setString(2, "123456"); // 4. 执行SQL(DQL用executeQuery,DML用executeUpdate) ResultSet rs = pstmt.executeQuery(); // 5. 处理结果集 while (rs.next()) { // 光标移动到下一行,判断是否有数据 int id = rs.getInt("id"); // 通过列名获取数据(推荐) String username = rs.getString("username"); System.out.println("ID: " + id + ", Username: " + username); } // 6. 释放资源(反向关闭,避免内存泄漏) rs.close(); pstmt.close(); conn.close(); |
3. 关键技术点解析
(1)预编译 SQL 的优势
- 防止 SQL 注入 :通过?占位符替代直接字符串拼接,避免恶意 SQL 注入(如' OR '1'='1)。
- 提升性能:SQL 语句仅编译一次,重复执行时直接复用,减少数据库编译开销。
|---------|-----------------------------------------------|-----|----|-------------|
| 方式 | 示例 | 安全性 | 性能 | 适用场景 |
| 静态 SQL | SELECT * FROM user WHERE username = 'daqiao' | 低 | 低 | 固定参数场景(不推荐) |
| 预编译 SQL | SELECT * FROM user WHERE username = ? | 高 | 高 | 动态参数场景(推荐) |
(2)DML 与 DQL 的执行差异
- DML(增删改) :通过executeUpdate()执行,返回影响的行数(int 类型)。
示例:int rows = pstmt.executeUpdate("UPDATE user SET age = 25 WHERE id = 1");
- DQL(查询) :通过executeQuery()执行,返回ResultSet 结果集 ,需通过next()和getXxx()解析。
(3)ResultSet 结果集
- next():光标前移一行,返回true表示当前行有数据;
- getXxx(列名/索引):获取数据(推荐用列名,避免表结构变更影响)。
二、MyBatis:简化 JDBC 开发的持久层框架
1. 什么是 MyBatis?
MyBatis 是一款优秀的持久层框架 ,基于 JDBC 封装,消除了冗余的代码(如注册驱动、结果集解析等),让开发者专注于 SQL 本身。其前身是 Apache 的 iBatis,2010 年更名后迁移至 GitHub,官网:MyBatis 3 | 简介 -- mybatis。
2. MyBatis vs JDBC:为什么选择 MyBatis?
JDBC 的痛点:
- 数据库连接信息(URL、用户名、密码)硬编码在代码中,维护困难;
- 结果集需手动封装为实体类,代码冗余;
- 频繁创建 / 关闭连接,资源浪费严重。
MyBatis 的改进:
- 配置信息集中管理(如 SpringBoot 的application.properties);
- 自动映射结果集到实体类,无需手动解析;
- 集成数据库连接池,复用连接提升性能。
3. MyBatis 入门实战
(1)环境搭建(SpringBoot + MyBatis)
- 创建项目并引入依赖:
在pom.xml中添加 MyBatis 和 MySQL 驱动依赖:
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> |
- 配置数据库连接:
在application.properties中配置数据库信息:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| spring.datasource.url=jdbc:mysql://localhost:3306/web?serverTimezone=UTC spring.datasource.username=root spring.datasource.password=1234 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver |
- 编写实体类:
定义与数据库表字段对应的实体类(如User):
|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public class User { private Integer id; private String username; private String password; private String name; private Integer age; // 省略getter、setter、构造方法 } |
- 编写 Mapper 接口:
通过注解定义 SQL,@Mapper标识为 MyBatis 接口:
|----------------------------------------------------------------------------------------------------------|
| @Mapper public interface UserMapper { // 查询所有用户 @Select("select * from user") List<User> findAll(); } |
- 单元测试:
用@SpringBootTest加载 Spring 环境,注入UserMapper测试:
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| @SpringBootTest public class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void testFindAll() { List<User> users = userMapper.findAll(); users.forEach(System.out::println); } } |
4. 核心功能详解
(1)数据库连接池
连接池是管理数据库连接的容器,复用连接减少资源消耗,核心优势:
- 资源重用:避免频繁创建连接的开销;
- 提升响应速度:连接预先创建,无需等待;
- 防止连接泄漏:自动回收空闲连接。
常见连接池产品:
- Hikari:SpringBoot 默认连接池,性能优异,轻量级;
- Druid:阿里巴巴开源,功能丰富(监控、防 SQL 注入),切换方式:
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <!-- 引入Druid依赖 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.19</version> </dependency> |
|----------------------------------------------------------------------------|
| # 配置Druid连接池 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource |
(2)增删改查操作
MyBatis 通过注解快速实现 CRUD,核心注解:@Select、@Insert、@Update、@Delete。
- 删除(Delete):
|----------------------------------------------------------------------------------------|
| @Delete("delete from user where id = #{id}") Integer deleteById(Integer id); // 返回影响行数 |
- 新增(Insert):
|---------------------------------------------------------------------------------------------------------------------------------------------------|
| @Insert("insert into user(username, password, name, age) values(#{username}, #{password}, #{name}, #{age})") void insert(User user); // 通过实体类属性传参 |
- 更新(Update):
|--------------------------------------------------------------------------------------------------------------|
| @Update("update user set username=#{username}, password=#{password} where id=#{id}") void update(User user); |
- 条件查询:
|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 多参数用@Param指定参数名 @Select("select * from user where username=#{username} and password=#{password}") User findByUsernameAndPassword(@Param("username") String uname, @Param("password") String pwd); |
(3)#{} 与 ${} 的区别(面试高频)
|-----|------------------|-----|----|------------------|
| 符号 | 原理 | 安全性 | 性能 | 适用场景 |
| #{} | 占位符,替换为?,预编译 SQL | 高 | 高 | 传递参数(推荐) |
| ${} | 字符串拼接,直接嵌入 SQL | 低 | 低 | 动态表名 / 字段名(谨慎使用) |
示例:{}可能导致 SQL 注入,如{tableName}若传入user; drop table user;会执行恶意 SQL。
(4)XML 映射配置
复杂 SQL 推荐用 XML 配置,规则:
- XML 文件名与 Mapper 接口名一致,同包存放;
- namespace与 Mapper 接口全限定名一致;
- SQL 标签的id与接口方法名一致。
示例(UserMapper.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.example.mapper.UserMapper"> <!-- 查询所有用户 --> <select id="findAll" resultType="com.example.pojo.User"> select * from user </select> </mapper> |
5. 辅助配置优化
- SQL 提示:在 IDEA 中配置数据库连接,编写 SQL 时获得表 / 字段提示;
- 日志输出:配置 MyBatis 日志,查看执行的 SQL 及参数:
|----------------------------------------------------------------------------|
| mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl |
三、SpringBoot 配置文件:优雅管理项目配置
1. 配置文件类型
SpringBoot 支持 3 种配置文件格式,核心区别在于语法:
- application.properties:传统key=value格式,层级不清晰;
- application.yaml/application.yml:简洁的层级结构,以数据为中心(推荐)。
2. YML 语法规则
- 缩进:用空格表示层级(不支持 Tab,IDEA 自动转换);
- 分隔符 :键与值之间用:+ 空格分隔(如port: 8080);
- 注释 :#开头的内容为注释;
- 数据类型 :
- 对象 / Map:
|-----------------------------------------|
| user: name: 张三 age: 18 password: 123456 |
-
- 数组 / List:
|------------------------------|
| hobby: - java - game - sport |
- 注意 :以0开头的值需用单引号包裹(避免被解析为八进制),如code: '0123'。
3. 配置示例(数据库 + MyBatis)
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| spring: # 应用名称 application: name: mybatis-demo # 数据库配置 datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/web?serverTimezone=UTC username: root password: 1234 # MyBatis配置 mybatis: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 日志输出 map-underscore-to-camel-case: true # 下划线转驼峰命名(如user_name → userName) |
四、总结与实践建议
- 技术选型 :
- 简单项目用 JDBC 原生操作,理解底层原理;
- 企业开发首选 MyBatis,通过注解 + XML 平衡简洁与复杂需求;
- 连接池优先用 Hikari(默认),需监控功能选 Druid。
- 避坑指南 :
- 永远使用预编译 SQL(#{})防止注入;
- 释放 JDBC 资源(ResultSet、Statement、Connection);
- YML 配置注意缩进和特殊值处理(如0开头的字符串)。
- 进阶方向 :
- 学习 MyBatis-Plus(MyBatis 增强工具,简化 CRUD);
- 掌握连接池参数调优(如最大连接数、空闲时间);
- 结合 Spring 事务管理数据库操作。
掌握这些知识点,能让你在 Java 数据库开发中从 "能实现" 到 "写得好",提升代码质量与开发效率。收藏本文,随时回顾核心要点,关注后续进阶内容!