当前位置: 首页 > news >正文

思途Mybatis学习 0805

一、MyBatis 简介

  • 定义:MyBatis 是一个 半自动化的 ORM(Object-Relational Mapping)框架,用于将 Java 对象与数据库记录进行映射。
  • 特点
    • 轻量级、灵活、易于掌握。
    • SQL 与代码分离,支持动态 SQL。
    • 相比 Hibernate 等全自动 ORM 框架,MyBatis 提供更高的 SQL 控制能力。

二、Spring Boot 整合 MyBatis 步骤

1. 添加依赖

pom.xml 中引入 MyBatis 启动器:

xml

深色版本

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version> <!-- 推荐使用最新稳定版本 -->
</dependency>

⚠️ 注意:该依赖会自动包含 mybatismybatis-spring 和自动配置模块。


2. 配置文件设置(application.yml)

spring:datasource:url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Drivermybatis:type-aliases-package: com.example.demo.entity    # 别名包路径mapper-locations: classpath:mapper/*.xml         # XML 映射文件位置configuration:map-underscore-to-camel-case: true             # 开启驼峰命名自动映射 a_column -> aColumn

3. 编写 Mapper 接口

使用 @Mapper 注解标记接口,或在启动类上加 @MapperScan 扫描包。

@Mapper
public interface UserMapper {User findById(Long id);
}

或在主启动类上:

@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

4. 编写映射 XML 文件(Mapper XML)

文件路径:resources/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"><mapper namespace="com.example.demo.mapper.UserMapper"><select id="findById" resultType="User">SELECT * FROM user WHERE id = #{id}</select></mapper>

✅ 注意:

  • namespace 必须对应 Mapper 接口的全限定名。
  • id 在同一个 XML 中必须唯一,且与接口方法名一致。
  • #{} 是预编译占位符,防止 SQL 注入;${} 是字符串拼接,需谨慎使用。

5. 安装 MyBatis-X 插件(推荐)

IntelliJ IDEA 插件:MyBatisX

  • 快速跳转:Mapper 接口 ↔ XML 映射文件。
  • 自动生成 CRUD 方法和 SQL 片段。
  • 提高开发效率。

三、动态 SQL 与参数传递

MyBatis 使用 OGNL(Object-Graph Navigation Language)表达式 解析参数,通过反射获取对象属性值。

1. 单个参数(POJO 或 Map)

可以直接通过属性名访问:

public User findByName(User user); // user.getName()
<select id="findByName" resultType="User">SELECT * FROM user WHERE name = #{name}
</select>

#{name} 自动从 User 对象中调用 getName() 获取值。


2. 多个参数(必须指定参数名)

Java 方法:

List<User> findUsers(@Param("name") String name, @Param("age") int age);

XML 使用:

<select id="findUsers" resultType="User">SELECT * FROM userWHERE name LIKE #{name} AND age > #{age}
</select>

❗ 若不使用 @Param,多个参数需用 param1, param2arg0, arg1 引用,可读性差,强烈建议使用 @Param 显式命名


3. 使用 <bind> 标签构造新变量

用于模糊查询等场景:

<select id="findByNameLike" parameterType="string" resultType="User"><bind name="pattern" value="'%' + _parameter + '%'" />SELECT * FROM user WHERE name LIKE #{pattern}
</select>

或:

<bind name="nameLike" value="'%'+name+'%'"/>
AND name LIKE #{nameLike}

🔍 说明:_parameter 表示整个参数对象。若参数是简单类型(如 String),则直接可用。


4. ${} vs #{}

方式是否预编译是否防注入适用场景
#{}✅ 是✅ 安全绝大多数情况(推荐)
${}❌ 否❌ 易被注入动态表名、排序字段等

示例:

ORDER BY ${columnName}  <!-- 只能用 ${} -->

⚠️ 使用 ${} 时务必校验输入合法性!


四、结果映射(ResultMap)

1. 手动映射字段(解决列名与属性不一致)

<resultMap id="userResultMap" type="User"><id property="id" column="user_id"/><result property="name" column="user_name"/><result property="email" column="user_email"/>
</resultMap><select id="findAll" resultMap="userResultMap">SELECT user_id, user_name, user_email FROM user
</select>

2. 关联查询(一对一、一对多)

(1)一对一关联

例如:User ↔ Profile

<resultMap id="userWithProfileMap" type="User"><id property="id" column="id"/><result property="name" column="name"/><association property="profile" javaType="Profile"><id property="id" column="pid"/><result property="bio" column="bio"/></association>
</resultMap><select id="findUserWithProfile" resultMap="userWithProfileMap">SELECT u.id, u.name, p.id AS pid, p.bioFROM user uLEFT JOIN profile p ON u.id = p.user_idWHERE u.id = #{id}
</select>

(2)一对多关联

例如:Department ↔ List<Employee>

<resultMap id="deptWithEmpsMap" type="Department"><id property="id" column="dept_id"/><result property="name" column="dept_name"/><collection property="employees" ofType="Employee"><id property="id" column="emp_id"/><result property="name" column="emp_name"/></collection>
</resultMap><select id="findDeptWithEmployees" resultMap="deptWithEmpsMap">SELECT d.id AS dept_id, d.name AS dept_name,e.id AS emp_id, e.name AS emp_nameFROM department dLEFT JOIN employee e ON d.id = e.dept_idWHERE d.id = #{id}
</select>

五、N+1 查询问题与性能优化

1. 什么是 N+1 问题?

当使用 associationcollection 延迟加载时,MyBatis 可能先查主表(1次),再对每条记录发起关联查询(N次),共 N+1 次 SQL。

2. 解决方案

✅ 方案一:使用 联合查询 + 嵌套映射(推荐)

如上一对多示例,一次性 JOIN 查询,避免 N+1。

✅ 方案二:开启 延迟加载(Lazy Loading)
mybatis:configuration:lazy-loading-enabled: trueaggressive-lazy-loading: false  # false:仅加载被调用的属性

⚠️ 延迟加载会创建新会话,一级缓存失效

✅ 方案三:使用 二级缓存

提升跨会话的数据复用性。

开启步骤:
  1. 全局开启缓存:
mybatis:configuration:cache-enabled: true
  1. 在 Mapper XML 中声明缓存:
<mapper namespace="com.example.mapper.UserMapper"><cache/> <!-- 默认使用 PerpetualCache --><select id="findById" useCache="true" resultType="User">SELECT * FROM user WHERE id = #{id}</select><update id="updateUser" flushCache="true">UPDATE user SET name = #{name} WHERE id = #{id}</update>
</mapper>
  • useCache="true":查询结果放入二级缓存(默认 select 为 true)。
  • flushCache="true":执行后清空缓存(默认 insert/update/delete 为 true)。
  • 实体类需实现 Serializable 接口。

六、自动分页(集成 PageHelper)

1. 添加依赖

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.7</version>
</dependency>

2. 使用

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public PageInfo<User> getUsers(int pageNum, int pageSize) {PageHelper.startPage(pageNum, pageSize);List<User> users = userMapper.findAll();return new PageInfo<>(users);}
}

返回 JSON 示例:

{"pageNum": 1,"pageSize": 10,"total": 100,"pages": 10,"list": [...]
}

七、补充知识点

1. @RestController 与 @ResponseBody

  • @RestController = @Controller + @ResponseBody
  • 所有方法返回值直接作为响应体(JSON/XML),无需额外标注 @ResponseBody

2. 类型处理器(TypeHandler)

自定义 Java 类型与数据库类型的转换,如枚举、LocalDateTime 等。

@MappedTypes(LocalDate.class)
@MappedJdbcTypes(JdbcType.DATE)
public class LocalDateTypeHandler extends BaseTypeHandler<LocalDate> {// 实现 setParameter、getResult 方法
}

注册方式:

@Configuration
public class MyBatisConfig {@Beanpublic ConfigurationCustomizer configurationCustomizer() {return configuration -> configuration.getTypeHandlerRegistry().register(LocalDate.class, new LocalDateTypeHandler());}
}

八、总结

功能推荐做法
参数传递多参数用 @Param 显式命名
模糊查询用 <bind> 构造 pattern,配合 #{}
字段映射列名转驼峰开启 map-underscore-to-camel-case
关联查询优先使用 JOIN + resultMap 避免 N+1
性能优化合理使用一级/二级缓存、延迟加载
分页集成 PageHelper
开发效率安装 MyBatisX 插件
http://www.lryc.cn/news/611444.html

相关文章:

  • LeetCode 刷题【31. 下一个排列】
  • 《Python基础》第3期:使用PyCharm编写Hello World
  • C++ 变量初始化方式总结 | 拷贝初始化 | 列表初始化 | 值初始化
  • 【C语言】动态内存管理详解
  • Kafka 的基本操作(1)
  • 国内办公安全平台新标杆:iOA一体化办公安全解决方案
  • 【基础】第八篇 Java 位运算符详解:从基础到实战应用
  • 【java】大数据insert的几种技术方案和优缺点
  • 一种基于机器学习的关键安全软件WCET分析方法概述与实际工作原理举例
  • 多传感器融合
  • 机器人权利:真实还是虚幻,机器人权利研究如何可能,道德权利与法律权利
  • nodejs 编程基础01-NPM包管理
  • 《计算机“十万个为什么”》之 面向对象 vs 面向过程:编程世界的积木与流水线
  • 【android bluetooth 协议分析 01】【HCI 层介绍 30】【hci_event和le_meta_event如何上报到btu层】
  • 零基础人工智能学习规划之路
  • 电路基础相关知识
  • HBM Basic(VCU128)
  • 翻译的本质:人工翻译vs机器翻译的核心差异与互补性
  • NumPy字符串与数学函数全解析:从基础到实战应用
  • 3. 为什么 0.1 + 0.2 != 0.3
  • ubuntu自动重启BUG排查指南
  • 前端遇到页面卡顿问题,如何排查和解决?
  • C语言:20250805学习(文件预处理)
  • 集成学习与随机森林:从原理到实践指南
  • 高通平台Wi-Fi Display学习-- 调试 Wi-Fi Display 问题
  • 【Git】实现使用SSH方式连接远程仓库时的免密操作
  • 17.8 ChatGLM3/CogVLM一键部署指南:32K长文本+多模态实战,零基础搞定企业级模型微调(附完整代码)
  • 机器学习算法系列专栏:决策树算法(初学者)
  • systemui 的启动流程是怎么样的?
  • VUE2 学习笔记 合集