XML语言
XML语言
在开始介绍Mybatis之前,先介绍一下XML语言,XML语言发明最初是用于数据的存储和传输,它是由一个一个的标签嵌套而成
<?xml version="1.0" encoding="UTF-8" ?>
<outer> <name>阿伟</name><desc>怎么又在玩电动啊</desc> <inner type="1"> <age>10</age> <sex>男</sex> </inner>
</outer>
JDK为我们内置了一个叫做org.w3c
的XML解析库,我们来看看如何使用它来进行XML文件内容解析:
// 创建DocumentBuilderFactory对象
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 创建DocumentBuilder对象
try {DocumentBuilder builder = factory.newDocumentBuilder();Document d = builder.parse("file:mappers/test.xml");// 每一个标签都作为一个节点NodeList nodeList = d.getElementsByTagName("test"); // 可能有很多个名字为test的标签Node rootNode = nodeList.item(0); // 获取首个NodeList childNodes = rootNode.getChildNodes(); // 一个节点下可能会有很多个节点,比如根节点下就囊括了所有的节点//节点可以是一个带有内容的标签(它内部就还有子节点),也可以是一段文本内容for (int i = 0; i < childNodes.getLength(); i++) {Node child = childNodes.item(i);if(child.getNodeType() == Node.ELEMENT_NODE) //过滤换行符之类的内容,因为它们都被认为是一个文本节点System.out.println(child.getNodeName() + ":" +child.getFirstChild().getNodeValue());// 输出节点名称,也就是标签名称,以及标签内部的文本(内部的内容都是子节点,所以要获取内部的节点)}
} catch (Exception e) {e.printStackTrace();
}
依赖管理
如果使用Maven可以直接引入:
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.16</version>
</dependency>
依赖变多之后,我们可以将其放到一个单独的文件夹,不然会很繁杂:
依赖导入完成后,我们就可以编写Mybatis的配置文件了(现在不是在Java代码中配置了,而是通过一个XML文件去配置
配置文件架构
创建mybatis-config.xml
作为全局配置入口
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 加载 Mapper 文件 --> <mappers> <!--映射文件方式1:一个一个的配置 --> <mapper resource="mapper/UserMapper.xml"/> <!--<mapper resource="com/demo14/mapper/UserMapper.xml"/>--> <!-- <mapper class="mapper.UserMapper.xml"/> 根据实际路径调整 --> <!--映射方式2,自动扫描包内的Mapper接口与配置文件--> <!--<package name="com.demo14.mapper"/>--> </mappers>
</configuration>
实体类与映射文件
UserMapper.xml
是 MyBatis 实现 数据访问层 的核心文件,通过将接口方法与 SQL 绑定,简化数据库操作
<select id="唯一标识(必须与Mapper接口中的方法名一致用于绑定SQL与方法)" parameterType="传入参数类型(可省略),MyBatis通过方法参数自动推断" resultType="返回结果类型,MyBatis将查询结果自动映射到该实体类">
</select>
- 创建与数据库表对应的Java实体类,属性名需与字段名严格对应:
@Data
package com.demo14.entity; /** * 用户实体类 */
public class User { private Integer userid; private String userName; private String userPwd; private Integer userage; ...}
/** * 用户接口类 */
@WebServlet
public interface UserMapper { public User queryUserByName(String userName); }
- 编写Mapper XML文件
TestMapper.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">
<!-- 命名空间需与 Mapper 接口全限定名一致 -->
<mapper namespace="com.demo14.mapper.UserMapper"> <!-- id: 对应 Mapper 接口方法名 parameterType: 参数类型(可省略) resultType: 返回结果实体类全限定名 --> <!-- MyBatis 代理 --><select id="queryUserByName" parameterType="string" resultType="com.demo14.entity.User"> <!--SQL 执行-->SELECT * FROM tb_user WHERE userName = #{userName} </select>
</mapper>
_`resultType`指定结果映射的实体类全路径_
属性外部化
- 创建jdbc.properties
文件管理数据库参数
jdbc.driver=com.mysql.cj.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/web_studyjdbc.username=testjdbc.password=123456
- 配置文件引用:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration> <!-- properties 标签中的配置可以供整个配置文件使用,在任何位置都可以引入其中配置的值 properties 标签可以通过标签property标签来配置一些子元素信息,也可以配置外部的动态文件 --> <!-- 加载外部属性文件(如 jdbc.properties)(支持多环境配置)--> <properties resource="jdbc.properties"/> <!-- 全局参数优化(生产环境必调参数) --><settings> <!-- 启用下划线转驼峰 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 启用日志输出 --> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!-- 全局设置 --> <!--<settings> 启用字段下划线转驼峰 <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> --> <!-- 配置类型别名(可选) --> <!--<typeAliases> 实体类包路径 <package name="com.example.entity"/> </typeAliases>--> <!-- 数据库环境配置(需与 jdbc.properties 中的参数匹配) --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!-- 加载 Mapper 文件 --> <mappers> <!--映射文件方式1:一个一个的配置 --> <mapper resource="mapper/UserMapper.xml"/> <!--<mapper resource="com/demo14/mapper/UserMapper.xml"/>--> <!-- <mapper class="mapper.UserMapper.xml"/> 根据实际路径调整 --> <!--映射方式2,自动扫描包内的Mapper接口与配置文件--> <!--<package name="com.demo14.mapper"/>--> </mappers> </configuration>
为什么需要 MyBatis 的 <select>
标签配置?
1. 解耦 SQL 与 Java 代码
- 传统 JDBC 问题
SQL 与 Java 代码混杂,导致代码臃肿且难以维护。例如:// 传统 JDBC 代码(硬编码 SQL) String sql = "SELECT * FROM user WHERE name = ?"; PreparedStatement stmt = connection.prepareStatement(sql); stmt.setString(1, "admin"); ResultSet rs = stmt.executeQuery();
- 缺点:SQL 修改需重新编译 Java 代码,且字符串拼接易引发 SQL 注入。
- MyBatis 解决方案
将 SQL 独立到 XML 文件中,实现 业务逻辑与数据访问逻辑分离:<!-- UserMapper.xml --> <select id="getUserByName" resultType="User">SELECT * FROM user WHERE name = #{name} </select>
2. 自动结果集映射
- 传统 JDBC 问题
手动解析ResultSet
到 Java 对象,代码重复且易错:User user = new User(); while (rs.next()) {user.setId(rs.getInt("id"));user.setName(rs.getString("name"));// ...其他字段 }
- MyBatis 解决方案
通过resultType
或resultMap
自动映射查询结果到对象:<select id="getUserByName" resultType="com.example.User">SELECT id, name, email FROM user WHERE name = #{name} </select>
3. 动态 SQL 支持
-
传统 JDBC 问题
拼接动态 SQL 易出错且难以维护:String sql = "SELECT * FROM user WHERE 1=1 "; if (name != null) {sql += "AND name = '" + name + "' "; // 存在 SQL 注入风险 }
-
MyBatis 解决方案
使用<if>
,<where>
,<foreach>
等标签实现动态 SQL:<select id="searchUsers" resultType="User">SELECT * FROM user<where><if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where> </select>
-
核心机制
MyBatis 通过 接口绑定 将 Mapper 接口与 XML SQL 关联:
public interface UserMapper { public User queryUserByName(String userName);
}
- **工作流程**:1. 调用 `userMapper.queryUserByName("admin")`。2. MyBatis 动态代理接口,根据方法名 `getUserByName` 找到对应的 XML SQL。3. 执行 SQL 并返回结果。
替代方案:简单项目可用注解,但 XML 仍是 MyBatis 的推荐实践
为何需要分别两个 mapper
目录?
这样做的原因是为了遵循Maven或Gradle的项目结构约定,构建工具会自动处理资源文件的打包和路径问题
职责分离
构建与部署规范
- Java 代码目录 (
src/main/java
)- 存放可编译的 Java 源文件(如
UserMapper.java
)。 - 构建工具(如 Maven/Gradle)会将其编译为
.class
文件。
- 存放可编译的 Java 源文件(如
- 资源目录 (
src/main/resources
)- 存放非代码文件(如 XML、配置文件)。
- 构建时,资源文件会被复制到
target/classes
(类路径),供 MyBatis 运行时加载。
流程:
-
开发者编写
UserMapper.java
接口。 -
在
UserMapper.xml
中编写对应的 SQL。 -
构建工具将 Java 代码编译为
.class
文件,资源文件复制到类路径 -
MyBatis 启动时,通过 接口名 + 方法名 动态绑定 XML 中的 SQL。
若合并目录:
- 将 XML 文件放在 Java 包目录中,可能导致构建工具忽略资源文件,引发 SQL 映射加载失败
MyBatis 的约定与配置
-
默认映射规则
MyBatis 要求 XML 文件的路径与接口包名一致。例如:- 接口路径:
com.demo14.mapper.UserMapper
- XML 路径:
resources/mapper/UserMapper.xml
- 接口路径:
-
配置验证
在mybatis-config.xml
或 Spring Boot 配置中需指定 XML 文件位置:<!-- MyBatis 配置 --> <mappers><mapper resource="mapper/UserMapper.xml"/> </mappers>
-
在 Mapper 接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值类型一致