Day06 Java操作数据库

- JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。
- JDBC是Java操作关系数据库的规范(SUN指定的Java接口),各数据库厂商均配置有实现规范的驱动程序。
- MyBatis,MyBatisPlus,Spring Data JPA,Hibernate等均是一JDBC为基础,是JDBC的扩展。
目录
- JDBC
- MyBatis
1. JDBC
1.1 JDBC-介绍

- JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。
- 本质
- sun公司官方定义的一套操作所有关系型数据库的规范,即接口。
- 各个数据库厂商去实现这套接口,提供数据库驱动jar包。
- 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
1.2 JDBC-入门程序 DML
- 需求:基于JDBc程序,执行update语句(
update user set age = 25 where id= 1) - 步骤:
- 创建项目:创建一个maven项目(Java模块 jdbc-demo),引入依赖(mysql驱动、test、lomboc);
- 并准备数据库表user。
- 代码实现:编写JDBC程序,操作数据库

pom.xm 中的依赖
<dependencies>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
</dependencies>
create schema web01 collate utf8mb4_unicode_ci;
create schema web01 collate utf8mb4_general_ci;
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(id, username, password, name, age) values
(1, 'dulaoshi', '123456', '张婧怡', 62),
(2, 'daqiao', '123456', '大乔', 22),
(3, 'xiaoqiao', '123456', '小乔', 18),
(4, 'diaochan', '123456', '貂蝉', 24),
(5, 'lvbu', '123456', '吕布', 28),
(6, 'zhaoyun', '12345678', '赵云', 27);
AI提问词
// JDBC 访问MySQL8,update语句(update user set age = 25 where id= 2)
//1、注册驱动
//2、获取连接
//3、获取SQL语句执行对象
//4、执行SQL
//5、释放资源
src/test/java/cn/zjy/JdbcTest.java
package cn.zjy;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class JdbcTest {
@Test
public void testUpdate() throws Exception {
// JDBC 访问MySQL8,update语句(update user set age = 25 where id= 2)
//1、注册驱动
//2、获取连接
//3、获取SQL语句执行对象
//4、执行SQL
//5、释放资源
// 数据库连接信息
String url = "jdbc:mysql://www.duzhaojiang.cn:3306/web01?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String username = "root";
String password = "***********";
// SQL更新语句
String sql = "update user set age = 25 where id = 2";
Connection conn = null;
Statement stmt = null;
// 1、注册驱动 (MySQL 8.0以上使用com.mysql.cj.jdbc.Driver)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection(url, username, password);
// 3、获取SQL语句执行对象
stmt = conn.createStatement();
// 4、执行SQL
int rowsAffected = stmt.executeUpdate(sql);
System.out.println("更新影响的行数: " + rowsAffected);
// 5、释放资源,先关闭Statement,再关闭Connection
stmt.close();
conn.close();
}
}


1.3 JDBC-查询数据 DQL
- 需求:基于JDBC执行如下select语句,将查询结果封装到User对象中。
- SQL:
select * from user where username = 'daqiao' and password= '123456' - ResultSet(结果集对象):ResultSet rs = statement.executeQuery()
- next():将光标从当前位置向前移动一行,并判断当前行是否为有效行,返回值为boolean。
- true:有效行,当前行有数据
- false:无效行,当前行没有数据
- getXxx(.):获取数据,可以根据列的编号获取,也可以根据列名获取(推荐)。
HelloController.java
提示词
你是一名java开发工程师,帮我基于JDBC程序来操作MySQL8数据库,执行如下SQL语句:select id,username,password,name,age from user where username = 'daqiao' and password = '123456';
并将查询的每一行记录,都封装到实体类User中,然后将User对象的数据输出到控制台中。
User 实体类属性如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Integer age; //年龄
}
src/test/java/cn/zjy/JdbcTest.java 添加testSelect()方法
@Test
public void testSelect() throws Exception {
// 数据库连接信息
String url = "jdbc:mysql://www.duzhaojiang.cn:3306/web01?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String username = "root";
String password = "*********";
// SQL查询语句
String sql = "select id, username, password, name, age from user where username = ? and password = ?";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection(url, username, password);
// 3、获取SQL语句执行对象 (使用PreparedStatement防止SQL注入)
pstmt = conn.prepareStatement(sql);
// 设置参数
pstmt.setString(1, "dulaoshi");
pstmt.setString(2, "123456");
// 4、执行查询
rs = pstmt.executeQuery();
// 处理查询结果
while (rs.next()) {
// 封装到User实体类
User user = new User(
rs.getInt("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("name"),
rs.getInt("age")
);
// 输出User对象数据到控制台
System.out.println(user);//使用Lombok的@Data自动生成的toString方法
}
rs.close();
pstmt.close();
conn.close();
}
@Test
public void testSelectAll() throws Exception {
// 数据库连接信息
String url = "jdbc:mysql://www.duzhaojiang.cn:3306/web01?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String username = "root";
String password = "zjyiang@Ywntj.";
// SQL查询语句
String sql = "select id, username, password, name, age from user";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection(url, username, password);
// 3、获取SQL语句执行对象 (使用PreparedStatement防止SQL注入)
pstmt = conn.prepareStatement(sql);
// 4、执行查询
rs = pstmt.executeQuery();
// 处理查询结果
while (rs.next()) {
// 封装到User实体类
User user = new User(
rs.getInt("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("name"),
rs.getInt("age")
);
// 输出User对象数据到控制台
System.out.print("用户信息:");
System.out.print("ID: " + user.getId());
System.out.print(",用户名: " + user.getUsername());
System.out.print(",密码: " + user.getPassword());
System.out.print(",姓名: " + user.getName());
System.out.println(",年龄: " + user.getAge());
}
rs.close();
pstmt.close();
conn.close();
}
src/test/java/cn/zjy/JdbcTest.java 添加testSelectAll()方法
@Test
public void testSelectAll() throws Exception {
// 数据库连接信息
String url = "jdbc:mysql://www.duzhaojiang.cn:3306/web01?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
String username = "root";
String password = "zjyiang@Ywntj.";
// SQL查询语句
String sql = "select id, username, password, name, age from user";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
// 1、注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
// 2、获取连接
conn = DriverManager.getConnection(url, username, password);
// 3、获取SQL语句执行对象 (使用PreparedStatement防止SQL注入)
pstmt = conn.prepareStatement(sql);
// 4、执行查询
rs = pstmt.executeQuery();
// 处理查询结果
while (rs.next()) {
// 封装到User实体类
User user = new User(
rs.getInt("id"),
rs.getString("username"),
rs.getString("password"),
rs.getString("name"),
rs.getInt("age")
);
// 输出User对象数据到控制台
System.out.print("用户信息:");
System.out.print("ID: " + user.getId());
System.out.print(",用户名: " + user.getUsername());
System.out.print(",密码: " + user.getPassword());
System.out.print(",姓名: " + user.getName());
System.out.println(",年龄: " + user.getAge());
}
rs.close();
pstmt.close();
conn.close();
}


1.4 预编译SQL
- 优势一:可以防止SQL注入,更安全 SQL注入:通过控制输入来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

- 优势二:性能更高


2. MyBatis
什么是MyBatis?
- MyBatis是一款优秀的持久层框架,用于简化JDBC的开发。
- MyBatis本是Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了googlecode,并且改名为MyBatis。2013年11月迁移到Github。
- 官网:https://mybatis.org/mybatis-3/zh_CN/index.html
- MyBatis 是一款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis免除了<几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的注解或XML来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。


2.1 入门程序
使用Mybatis查询所有用户数据
- 准备工作:
- 1.创建SpringBoot工程(模块springboot-mybatis-quickstart)、引入Mybatis相关依赖(Lombok、MyBatis Framework、MySQL Driver)
- 2.准备数据库表user、实体类User
- 3.配置Mybatis(在applscation.properties中数据库连接信息)
- 编写Mybatis程序:编写Mybatis的持久层接口,定义SQL(注解/XML)
- 提示:Mybatis的持久层接口命名规范为XxxMapper,也称为Mapper接口。



applscation.properties
spring.application.name=springboot-mybatis-quickstart
# 配置数据库连接信息
spring.datasource.url=jdbc:mysql://www.duzhaojiang.cn:3306/web01?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=********
cn/zjy/mapper/UserMapper.java
package cn.zjy.mapper;
import cn.zjy.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
// 应用程序在运行时,会自动的为该接口创建一个实现类对象(代理对象),
// 并且会自动将该实现类对象存入IOc容器-bean
public interface UserMapper {
// 查询所有用户
@Select("select * from user")
public List<User> findAll();
}
src/main/java/cn/zjy/SpringbootMybatisQuickstartApplication.java
package cn.zjy;
import cn.zjy.mapper.UserMapper;
import cn.zjy.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class SpringbootMybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List<User> userList = userMapper.findAll();
userList.forEach(System.out::println);
}
}


辅助配置-配置SQL提示
- 产生原因:idea和数据库没有建立连接,不识别表信息
- 解决方式:在idea中配置MySQL数据库连接


辅助配置-配置Mybatis的日志输出
- 默认情况下,在Mybatis中,SQL语句执行时,我们并看不到SQL语句的执行日志。加入如下配置,即可查看日志:
# 配置mybatis的日志输出
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

2.2 JDBC VS Mybatis

2.3 数据库连接池
- 数据库连接池是个容器,负责分配、管理数据库连接(Connection)。
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。
- 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏。
- 优势:
- 1.资源重用
- 2,提升系统响应速度
- 3.避免数据库连接遗漏

- 标准接口:DataSource
- 官方(sun)提供的数据库连接池接口,由第三方组织实现此接口。
- 功能:获取连接
ConnectiongetConnection() throws SQLException;
- 常见产品

图23 数据库连接池常见产品 - Druid(德鲁伊)
- Druid连接池是阿里巴巴开源的数据库连接池项目
- 功能强大,性能优秀,是Java语言最好的数据库连接池之一
切换数据库连接池(从到):
pom.xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.19</version>
</dependency>
src/main/resources/application.properties
# 添加spring.datasource.type设置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# 原有的spring.datasource四大参数
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=1234

小结

2.4 增删改查操作
① 删除用户-delete
- 需求:根据ID删除用户信息
--SQL:
delete from user where id = 5;
- Mapper接口:UserMapper.java
// 不带参变量
@Delete("delete from user where id = 5")
public void deleteById();
// 不带返回值,带参变量
@Delete("delete from user where id = #[id}")
public void deleteById(Integer id);
// 带返回值 影响的记录数
@Delete("delete from user where id = #[id}")
public Integer deleteById(Integer id);
- 注意:DML语句执行完毕的返回值,表示该DML语句执行完毕影响的行数。

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


② 新增用户-insert
- 需求:添加一个用户
-- SQL:
insert into user(username,password,name,age) values('zhouyu','123456','周瑜',20);
- Mapper接口:UserMapper.java
@Insert("insert into user(username,password,name,age) values('zhouyu', '123456', '周瑜', 20)")
public void insert();
@Insert("insert into user(username,password,name,age) values(#{username},#{password},#{name},#{age})") //对象属性名
public void insert(User user);

③ 修改用户-update
- 需求:根据ID更新用户信息
- SQL:
update user set username = 'zhouyu', password = '123456', name = '周瑜', age = 20 where id = 1;
Mapper接口:
@Update("update user set username=#{username}, password=#{password}, name=#{name}, age=#{age} where id=#{id}")
public void update(User user);
④ 查询用户-select
- 需求:根据用户名和密码查询用户信息
- SQL:
select * from user where username = 'zhouyu' and password = '666888';
- Mapper接口:
@Select("select * from user where username=#{username} and password=#{password}")
public User findByUsernameAndPassword(
@Param("username") String username, @Param("password") String password);
@Param注解的作用是为接口的方法形参起名字的。
说明:基于官方骨架创建的springboot项目中,接口编译时会保留方法形参名,@Param注解可以省略 (#{形参名})。
@Select("select * from user where username=#{uname} and password=#{pwd}")
public User findByUsernameAndPassword(String uname, String pwd);

cn/zjy/mapper/UserMapper.java
package cn.zjy.mapper;
import cn.zjy.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
@Mapper
// 应用程序在运行时,会自动的为该接口创建一个实现类对象(代理对象),
// 并且会自动将该实现类对象存入IOc容器-bean
public interface UserMapper {
// 查询所有用户
@Select("select * from user")
public List<User> findAll();
/**
* 根据ID删除用户
*/
@Delete("delete from user where id = #{id}")
//public void deleteById(Integer id);
public Integer deleteById(Integer id);
/**
* 新增用户
*/
@Insert("insert into user(username, password, name, age) values (#{username},#{password}, #{name}, #{age})")
public void insert(User user);
/**
* 更新用户
*/
@Update("update user set username = #{username}, password = #{password}, name = #{name}, age = #{age} where id = #{id}")
public void update(User user);
/**
* 根据用户名和密码查询用户
*/
@Select("select * from user where username = #{username} and password = #{password}")
public User findByUsernameAndpassword(@Param("username") String username, @Param("password") String password);
/**
* 根据用户名和密码查询用户
*/
@Select("select * from user where username = #{uname} and password = #{pword}")
public User findByUsernameAndpassword2(String uname, String pword);
}
src/test/java/cn/zjy/SpringbootMybatisQuickstartApplicationTests.java
package cn.zjy;
import cn.zjy.mapper.UserMapper;
import cn.zjy.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
class SpringbootMybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List<User> userList = userMapper.findAll();
userList.forEach(System.out::println);
}
@Test
public void testDeleteById() {
Integer i = userMapper.deleteById(4);
System.out.println("执行完毕,影响的记录数:" + i);
}
/**
* 测试新增
*/
@Test
public void testInsert() {
User user = new User(null,"gaoyuanyuan","666888","高圆圆",18);
userMapper.insert(user);
}
/**
* 测试更新
*/
@Test
public void testUpdate() {
User user = new User(2, "zhouyu", "666888", "周瑜", 8);
userMapper.update(user);
}
/**
* 测试查询
*/
@Test
public void testFindByUsernameAndPassword(){
User user= userMapper.findByUsernameAndpassword("zhouyu","666888");
System.out.println(user);
}
/**
* 测试查询
*/
@Test
public void testFindByUsernameAndPassword2(){
User user= userMapper.findByUsernameAndpassword2("zhouyu","666888");
System.out.println(user);
}
}

@Param注解的使用场景?
- 如果接口方法形参中,需要传递多个参数,需要通过@Param注解为参数起名字;
- 在基于SpringBoot官方骨架创建的SpringBoot项目中,该注解可以省略;

2.5 XML映射配置
- Mybatis中,既可以通过注解配置SQL语句,也可以通过XML配置文件配置SQL语句。
- 默认规则:
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
- XML映射文件的namespace属性为Mapper接口全限定名一致。
- XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。

src/main/java/cn/zjy/mapper/UserMapper.java 定义了下列方法
// 查询所有用户
// src/main/resources/cn/zjy/mapper/UserMapper.xml 配置了映射关系
public List<User> findAll2();
src/main/resources/cn/zjy/mapper/UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:绑定对应的Java接口全类名 -->
<mapper namespace="cn.dzj.mapper.UserMapper">
<!-- 所有SQL标签(select/insert/update/delete)写在这里 -->
<select id="findAll2" resultType="cn.dzj.pojo.User">
select ID, USERNAME, PASSWORD, NAME, AGE from user
</select>
</mapper>
src/test/java/cn/dzj/SpringbootMybatisQuickstartApplicationTests.java 添加了下列的测试方法
@Test
public void testFindAll2() {
List<User> userList = userMapper.findAll();
userList.forEach(System.out::println);
}

小结

XML映射文件--辅助配置
application.properties
#指定XML映射配置文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml

3.SpringBoot配置文件
3.0 问题的提出

3.1 配置文件格式
- SpringBoot项目提供了多种属性配置方式(properties、yaml | yml)。

3.2 yml配置文件

application.yml
spring:
application:
name: springboot-mybatis-quickstart
#数据库的连接信息
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/web01
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 1234
#Mybatis的相关配置
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
mapper-locations: classpath:mapper/*.xml
# 定义对象/Map集合
user:
name: 张三
age: 18
password: 123456
# 定义数组/List/Set集合
hobby:
- java
- game
- sport

3.3 springboot application配置文件的优先级
在 Spring Boot 中,application.properties 和 application.yml 是两种常用的配置文件格式,它们的优先级规则主要取决于文件位置和文件类型,核心结论如下:
1. 同目录下:application.properties 优先级高于 application.yml
- 当两种文件位于同一配置目录(如
src/main/resources/或外部配置目录)时,.properties文件的配置会覆盖.yml文件中的同名配置。例如:- application.properties
中配置:server.port=8080` - 同目录的
application.yml中配置:server: port: 8081 - 最终生效的端口是
8080(.properties覆盖.yml)。
- application.properties
2. 不同目录下:遵循「位置优先级」,与文件类型无关
- Spring Boot 会从多个位置加载配置文件,位置的优先级高于文件类型。无论文件是
.properties还是.yml,优先级高的目录中的配置会覆盖优先级低的目录中的配置。 - 常见的配置文件位置优先级(从高到低):
- ①命令行参数(如
java -jar app.jar --server.port=8082) - ②项目根目录下的
config/文件夹(./config/) - ③项目根目录(
./) - ④
src/main/resources/config/文件夹 - ⑤src/main/resources/ 根目录
- ①命令行参数(如
3. 总结
- 同位置:
.properties优先级 >.yml(同名配置前者覆盖后者)。 - 不同位置:位置优先级更高的文件(无论类型)覆盖位置优先级低的文件。
- 两种文件可以共存,不同配置会合并,相同配置以「高优先级」为准。
①②③④⑤⑥⑦⑧⑨⑩
MyBatis 的 XML 映射文件
MyBatis 的 XML 映射文件核心是通过 <mapper> 根节点组织 SQL 语句,每个 SQL 操作对应特定标签(如 <select>、<insert>),并通过属性与 Java 接口 / 方法绑定。以下是完整的格式规范、核心标签及示例:
一、整体结构(根节点 <mapper>)
所有 SQL 语句必须包裹在 <mapper> 标签内,其唯一核心属性 namespace 用于绑定 Java 接口全类名(确保接口与 XML 映射一一对应)。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- namespace:绑定对应的Java接口全类名 -->
<mapper namespace="com.example.mapper.UserMapper">
<!-- 所有SQL标签(select/insert/update/delete)写在这里 -->
</mapper>
二、核心 SQL 标签(CRUD 操作)
每个标签对应一种数据库操作,需通过 id 绑定接口中的方法名,并通过 parameterType(可选)、resultType/resultMap(必选)定义参数和返回值。
1. 查询:<select>
用于执行 SELECT 语句,核心是指定返回类型(简单类型用 resultType,复杂对象映射用 resultMap)。
| 属性 | 说明 |
|---|---|
id |
与接口方法名完全一致,唯一标识 |
parameterType |
传入参数类型(全类名或别名,如 java.lang.Long/String,MyBatis 可自动推断,可选) |
resultType |
返回值类型(简单类型 / JavaBean 全类名,适用于字段名与属性名完全匹配的场景) |
resultMap |
引用自定义的 <resultMap>(适用于字段名与属性名不匹配、关联查询等复杂场景) |
示例 1:查询单个对象(字段名与属性名一致)
<!-- 接口方法:User selectById(Long id); -->
<select id="selectById" parameterType="java.lang.Long" resultType="com.example.entity.User">
SELECT id, username, age, create_time
FROM user
WHERE id = #{id} <!-- #{}:参数占位符(预编译,防止SQL注入) -->
</select>
示例 2:查询列表(返回 List
<!-- 接口方法:List<User> selectByAge(Integer age); -->
<select id="selectByAge" parameterType="java.lang.Integer" resultType="com.example.entity.User">
SELECT id, username, age, create_time
FROM user
WHERE age > #{age}
</select>
2. 新增:<insert>
用于执行 INSERT 语句,支持返回自增主键(如 MySQL 的 AUTO_INCREMENT)。
| 特殊属性 | 说明 |
|---|---|
useGeneratedKeys |
是否使用自增主键(true/false,仅支持支持自增的数据库,如 MySQL) |
keyProperty |
自增主键对应的 JavaBean 属性名(如 id),用于将主键值回写到对象中 |
示例:新增用户并返回自增主键
<!-- 接口方法:int insertUser(User user); -->
<insert id="insertUser" parameterType="com.example.entity.User"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO user (username, age, create_time)
VALUES (#{username}, #{age}, #{createTime}) <!-- #{属性名}:匹配User类的getter/setter -->
</insert>
3. 更新:<update>
用于执行 UPDATE 语句,无特殊属性,核心是通过参数动态更新字段。
示例:根据 ID 更新用户信息
<!-- 接口方法:int updateUserById(User user); -->
<update id="updateUserById" parameterType="com.example.entity.User">
UPDATE user
SET username = #{username},
age = #{age},
create_time = #{createTime}
WHERE id = #{id}
</update>
4. 删除:<delete>
用于执行 DELETE 语句,结构最简单,仅需绑定参数和 SQL 逻辑。
示例:根据 ID 删除用户
<!-- 接口方法:int deleteById(Long id); -->
<delete id="deleteById" parameterType="java.lang.Long">
DELETE FROM user
WHERE id = #{id}
</delete>
三、复杂场景:<resultMap> 与动态 SQL
1. <resultMap>:自定义结果映射
当数据库字段名与 JavaBean 属性名不匹配(如字段 create_time vs 属性 createTime),或需要关联查询(如一对一、一对多)时,需定义 <resultMap>。
示例:解决字段名与属性名不匹配
<!-- 1. 定义resultMap:映射user表字段到User类属性 -->
<resultMap id="UserResultMap" type="com.example.entity.User">
<!-- id:主键映射 -->
<id column="id" property="id"/>
<!-- result:普通字段映射(column=数据库字段名,property=JavaBean属性名) -->
<result column="username" property="username"/>
<result column="age" property="age"/>
<result column="create_time" property="createTime"/> <!-- 字段名与属性名不一致 -->
</resultMap>
<!-- 2. 在select中引用resultMap -->
<select id="selectById" parameterType="java.lang.Long" resultMap="UserResultMap">
SELECT id, username, age, create_time
FROM user
WHERE id = #{id}
</select>
2. 动态 SQL:条件拼接
MyBatis 提供动态标签解决「条件不确定」的 SQL 拼接(如多条件查询、非空字段更新),常用标签如下:
| 动态标签 | 说明 |
|---|---|
<if> |
单条件判断(test 属性写判断表达式,如 test="username != null") |
<where> |
自动处理 AND/OR 前缀,避免 SQL 语法错误(替代 WHERE 1=1) |
<foreach> |
遍历集合(如 List/Array,用于 IN 条件或批量操作) |
示例:多条件动态查询(用户名 + 年龄筛选)
<!-- 接口方法:List<User> selectByCondition(User user); -->
<select id="selectByCondition" parameterType="com.example.entity.User" resultMap="UserResultMap">
SELECT id, username, age, create_time
FROM user
<where> <!-- 自动移除多余的AND/OR -->
<if test="username != null and username != ''">
AND username LIKE CONCAT('%', #{username}, '%') <!-- 模糊查询 -->
</if>
<if test="age != null">
AND age = #{age}
</if>
</where>
</select>
四、关键注意事项
- 参数占位符:优先使用
#{}, 生成预编译 SQL(防止注入);${}直接拼接字符串(仅用于非用户输入的场景,如表名动态切换)。 - 标签闭合:所有 XML 标签必须正确闭合(如
<select>...</select>,不可省略结束标签)。 - 命名规范:
namespace必须与接口全类名一致,id必须与接口方法名一致,否则 MyBatis 无法绑定。 - 注释:支持 XML 标准注释
<!-- 注释内容 -->,建议标注 SQL 功能和参数说明。