JDBC与MyBatis核心攻略
JDBC 与 MyBatis 详解
1. JDBC 简介
JDBC (Java Database Connectivity) 是 Java 提供的一套用于操作关系型数据库的标准 API。它定义了一系列接口和类,使得 Java 程序能够以统一的方式访问各种不同的关系型数据库(如 MySQL, PostgreSQL, Oracle 等)。
JDBC 的核心思想是提供一个抽象层,将应用程序与具体的数据库驱动解耦。开发者通过 JDBC API 编写代码,而具体的数据库操作则由对应的 JDBC 驱动程序来实现。
虽然 JDBC 是访问数据库的基础,但直接使用原始 JDBC API 进行开发通常涉及大量的样板代码(如加载驱动、建立连接、创建 Statement、处理异常、关闭资源等),这使得开发效率较低且容易出错。因此,在实际项目中,常常会使用像 MyBatis 这样的持久层框架来简化 JDBC 的使用。
2. MyBatis 框架概述
MyBatis 是一款优秀的持久层框架,它内部封装了 JDBC,使开发者能够更加专注于 SQL 本身,而无需处理繁琐的 JDBC 代码和手动设置参数以及获取结果集。
MyBatis 的主要优点包括:
- 简化开发:减少了大量重复的 JDBC 样板代码。
- SQL 灵活:允许开发者编写原生 SQL,对 SQL 的控制能力强。
- 易于维护:SQL 语句与 Java 代码分离(通常在 XML 文件中),便于管理和调试。
- 对象映射:提供了强大的对象关系映射(ORM)功能,可以方便地将数据库记录映射到 Java 对象。
2.1 Mapper 接口
在 MyBatis 中,数据访问操作通常定义在接口中,这些接口被称为 Mapper 接口 或 XxxMapper 接口(例如 UserMapper
, OrderMapper
)。
为了使 MyBatis 能够识别并处理这些接口,需要使用 @Mapper
注解标记它们。在 Spring Boot 项目中,也可以在主启动类上使用 @MapperScan
注解来批量扫描指定包下的所有 Mapper 接口。
java
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
// 数据访问方法定义
}
3. 数据库连接池
数据库连接的创建和销毁是一个相对耗时的过程。频繁地打开和关闭连接会严重影响应用程序的性能。
数据库连接池 是一个缓存数据库连接的容器。应用程序启动时,连接池会预先创建一定数量的数据库连接并放入池中。当应用程序需要访问数据库时,它会从连接池中获取一个可用的连接,使用完毕后再将连接归还给连接池,而不是直接关闭它。这样可以复用连接,大大减少了创建和销毁连接的开销。
此外,连接池还能有效管理连接的生命周期,防止连接泄露。
3.1 标准接口:javax.sql.DataSource
DataSource
是 JDBC 提供的标准接口,用于获取数据库连接。所有主流的数据库连接池实现(如 Druid, HikariCP)都实现了这个接口。
3.2 常见的连接池产品
- HikariCP: 一个高性能的 JDBC 连接池,是 Spring Boot 2.x 的默认连接池。
- Druid: 阿里巴巴开源的数据库连接池,功能强大,提供了监控、统计、SQL 防火墙等特性。
- C3P0: 一个老牌的开源连接池,配置灵活。
- DBCP: Apache Commons 提供的连接池实现。
4. MyBatis 增删改查 (CRUD) 操作
MyBatis 提供了基于注解和基于 XML 配置两种方式来定义 SQL 语句。下面介绍使用注解方式实现基本的 CRUD 操作。
4.1 查询 (SELECT
)
SQL 语句: SELECT column1, column2, ... FROM table_name WHERE condition;
Mapper 接口方法:
使用 @Select
注解。
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;// 查询单个用户
@Select("SELECT id, username, email FROM users WHERE id = #{id}")
User selectUserById(int id);// 查询多个用户
@Select("SELECT id, username, email FROM users WHERE age > #{minAge}")
List<User> selectUsersByMinAge(int minAge);// 查询多个参数 (需要 @Param)
@Select("SELECT * FROM users WHERE username = #{name} AND status = #{status}")
List<User> selectUsersByNameAndStatus(@Param("name") String userName, @Param("status") String userStatus);
关于
#{}
和${}
:
#{}
: 是预编译处理,MyBatis 会将 SQL 中的#{}
替换为?
占位符,并通过PreparedStatement
的set
方法安全地设置参数值。这是最常用且推荐的方式,可以有效防止 SQL 注入。${}
: 是字符串替换,MyBatis 会直接将${}
替换为传入的参数值。这种方式不安全,容易引发 SQL 注入风险,通常只用于动态表名、列名等无法使用#{}
的场景。
关于
@Param
:
- 当方法有多个参数时,MyBatis 无法确定
#{}
中应该对应哪个参数。使用@Param("参数名")
可以为参数指定名称。- 在 Spring Boot 项目中,如果编译时保留了方法参数名(默认如此),则可以省略
@Param
注解。
4.2 插入 (INSERT
)
SQL 语句: INSERT INTO table_name (column1, column2, ...) VALUES (value1, value2, ...);
Mapper 接口方法:
使用 @Insert
注解。
import org.apache.ibatis.annotations.Insert;// 插入用户对象
@Insert("INSERT INTO users(username, email, age) VALUES(#{username}, #{email}, #{age})")
int insertUser(User user); // 返回受影响的行数
如果传入的是一个 Java 对象(如
User
),可以直接在#{}
中引用对象的属性名。
4.3 更新 (UPDATE
)
SQL 语句: UPDATE table_name SET column1 = value1, column2 = value2, ... WHERE condition;
Mapper 接口方法:
使用 @Update
注解。
import org.apache.ibatis.annotations.Update;// 更新用户信息
@Update("UPDATE users SET username = #{username}, email = #{email} WHERE id = #{id}")
int updateUser(User user); // 返回受影响的行数
4.4 删除 (DELETE
)
SQL 语句: DELETE FROM table_name WHERE condition;
Mapper 接口方法:
使用 @Delete
注解。
import org.apache.ibatis.annotations.Delete;// 根据ID删除用户
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUserById(int id); // 返回受影响的行数
5. XML 映射配置
当 SQL 语句比较复杂(例如包含动态 SQL、多表关联查询等)时,使用注解可能会使代码变得难以阅读和维护。此时,可以使用 XML 文件来配置 SQL 语句。
5.1 XML 文件命名与位置
- 命名: XML 映射文件的名称通常与对应的 Mapper 接口名称相同,例如
UserMapper.java
对应UserMapper.xml
。 - 位置: XML 文件通常与 Mapper 接口放在同一个包(package)下。如果放在不同位置,需要在 MyBatis 的配置文件(如
mybatis-config.xml
或 Spring Boot 的application.yml/properties
)中进行指定。
5.2 XML 文件结构
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- namespace 必须与 Mapper 接口的全限定名一致 -->
<mapper namespace="com.example.mapper.UserMapper"><!-- id 对应 Mapper 接口中的方法名 --><!-- resultType 指定查询结果映射的 Java 类型 --><select id="selectUserById" resultType="com.example.model.User">SELECT id, username, email FROM users WHERE id = #{id}</select><insert id="insertUser" parameterType="com.example.model.User">INSERT INTO users(username, email, age) VALUES(#{username}, #{email}, #{age})</insert><update id="updateUser" parameterType="com.example.model.User">UPDATE users SET username = #{username}, email = #{email} WHERE id = #{id}</update><delete id="deleteUserById">DELETE FROM users WHERE id = #{id}</delete></mapper>
5.3 关键属性说明
namespace
: 这是 XML 映射文件最重要的属性之一,它的值必须是与之对应的 Mapper 接口的全限定类名(包括包名)。id
: 对应 Mapper 接口中定义的方法名。resultType
: 指定 SQL 查询语句返回结果的类型。对于单条记录,它应该是对应的 Java Bean 类型;对于多条记录,它指的是列表中单个元素的类型(MyBatis 会自动将其包装成List
)。parameterType
: (可选)指定传入 SQL 语句的参数类型。MyBatis 通常可以自动推断,但在某些复杂情况下指定它有助于提高性能或明确意图。
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {// 数据访问方法定义
}
6. 配置文件
6.1 配置文件格式
Spring Boot 会按优先级从高到低依次查找并加载以下配置文件(同名不同格式时,高优先级格式会覆盖低优先级):
./config/application.properties
或./config/application.yml
./application.properties
或./application.yml
classpath:/config/application.properties
或classpath:/config/application.yml
classpath:/application.properties
或classpath:/application.yml
通常,我们会将配置文件放在 src/main/resources
目录下。
6.2 .properties
格式
这是一种传统的键值对格式,每一行都是 key=value
的形式。
示例 (application.properties
):
# 服务器端口
server.port=8081# 数据库连接 (使用 HikariCP, Spring Boot 默认)
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=your_password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# MyBatis 配置
# 指定 MyBatis 的 XML 映射文件位置 (如果与 Mapper 接口不在同一包下)
mybatis.mapper-locations=classpath:mapper/*.xml
# 指定实体类别名包,简化 XML 中 resultType 的写法
mybatis.type-aliases-package=com.example.model# 日志级别
logging.level.com.example.mapper=debug
6.3 .yaml
/ .yml
格式
YAML (YAML Ain’t Markup Language) 是一种更易读的数据序列化标准,它使用缩进来表示层级关系。
示例 (application.yml
):
# 服务器端口
server:port: 8081# 数据库连接 (使用 HikariCP, Spring Boot 默认)
spring:datasource:url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTCusername: rootpassword: your_passworddriver-class-name: com.mysql.cj.jdbc.Driver# MyBatis 配置
mybatis:# 指定 MyBatis 的 XML 映射文件位置 (如果与 Mapper 接口不在同一包下)mapper-locations: classpath:mapper/*.xml# 指定实体类别名包,简化 XML 中 resultType 的写法type-aliases-package: com.example.model# 日志级别
logging:level:com.example.mapper: debug
6.4 配置项说明
server.port
: 设置应用启动的端口号。spring.datasource.*
: 配置数据源。Spring Boot 会根据这些配置自动创建DataSource
Bean。url
: 数据库连接地址。username
: 数据库用户名。password
: 数据库密码。driver-class-name
: JDBC 驱动类名。
mybatis.mapper-locations
: 指定 MyBatis 的 XML 映射文件的位置。如果 XML 文件与 Mapper 接口在同一包下,此项可省略。mybatis.type-aliases-package
: 指定别名包,该包下的类在 MyBatis XML 文件中可以直接使用类名(不带包名)作为resultType
。logging.level.*
: 配置日志级别,例如logging.level.com.example.mapper=debug
表示将com.example.mapper
包下的日志级别设为 DEBUG。
6.5 选择 .properties
还是 .yaml
?
.properties
:- 简单直观,易于理解。
- 语法限制较多(不支持注释嵌套等)。
- 对于复杂的嵌套配置,可读性较差。
.yaml
/.yml
:- 结构清晰,层次分明,可读性好。
- 支持更丰富的数据结构。
- 对缩进敏感,格式错误容易导致配置加载失败。
建议:
对于简单的配置,两种格式都可以。对于结构复杂的配置,推荐使用 .yaml
或 .yml
格式,因为它能更清晰地表达配置项之间的层级关系。
通过合理使用 MyBatis 的注解和 XML 配置,并结合 Spring Boot 强大的外部化配置功能,可以极大地简化数据库操作的开发工作,并保持代码的清晰和可维护性。