东莞市网站建设_网站建设公司_Bootstrap_seo优化
2025/12/29 6:34:50 网站建设 项目流程

🚀 MyBatis 从入门到精通:万字详解(小白必看)

摘要:本文将带你深入了解 Java 持久层框架 MyBatis。从环境搭建到核心配置,再到动态 SQL 和高级映射,结合实际项目代码(学生选课/图书管理系统),手把手教你掌握 MyBatis。文末附带高频面试题,助你从容应对面试!


📖 目录

  1. 什么是 MyBatis?
  2. 快速入门:环境搭建
  3. 核心配置详解 (SqlMapConfig.xml)
  4. MyBatis 核心组件与生命周期
  5. 实战演练:CRUD 操作
  6. 进阶必杀技:动态 SQL
  7. 高级映射与关联查询
  8. 🔥 MyBatis 高频面试题

1. 什么是 MyBatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。

  • 免除 JDBC 代码:MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • XML 或注解配置:可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects)为数据库中的记录。
  • 半自动 ORM:与 Hibernate(全自动)不同,MyBatis 允许程序员直接编写 SQL,更加灵活,适合对 SQL 性能要求高的场景。

2. 快速入门:环境搭建

在 Maven 项目中,我们需要引入 MyBatis 和 MySQL 驱动的依赖。

2.1 引入依赖 (pom.xml)

<dependencies><!-- MyBatis 核心包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.13</version></dependency><!-- MySQL 驱动包 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency><!-- Lombok (可选,用于简化实体类) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version><scope>provided</scope></dependency><!-- 日志框架 (推荐使用,方便查看 SQL) --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.36</version></dependency></dependencies>

3. 核心配置详解 (SqlMapConfig.xml)

这是 MyBatis 的全局配置文件,包含了数据库连接池、事务管理器、映射器文件路径等核心信息。

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEconfigurationPUBLIC"-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 1. Settings: 全局设置 --><settings><!-- 开启驼峰命名自动映射:将数据库的 user_name 自动映射为 Java 的 userName --><settingname="mapUnderscoreToCamelCase"value="true"/><!-- 打印 SQL 日志到控制台 (开发环境推荐) --><settingname="logImpl"value="STDOUT_LOGGING"/></settings><!-- 2. Environments: 环境配置 (开发、测试、生产) --><environmentsdefault="development"><environmentid="development"><!-- 事务管理器: JDBC (使用 Connection 的 commit/rollback) --><transactionManagertype="JDBC"/><!-- 数据源: POOLED (使用连接池,复用连接,提高性能) --><dataSourcetype="POOLED"><propertyname="driver"value="com.mysql.cj.jdbc.Driver"/><propertyname="url"value="jdbc:mysql://localhost:3306/library_system?serverTimezone=Asia/Shanghai&amp;useUnicode=true&amp;characterEncoding=utf-8"/><propertyname="username"value="root"/><propertyname="password"value="your_password"/></dataSource></environment></environments><!-- 3. Mappers: 注册 Mapper XML 文件 --><mappers><!-- 使用 resource 属性指定类路径下的 XML 文件 --><mapperresource="mapper/BookMapper.xml"/><mapperresource="mapper/BorrowRecordMapper.xml"/></mappers></configuration>

💡 知识点解析

  • mapUnderscoreToCamelCase:非常重要!数据库字段通常是下划线命名(create_time),而 Java 属性是驼峰命名(createTime)。开启此配置后,MyBatis 会自动帮我们完成映射,不再需要手动写resultMap
  • POOLED:MyBatis 自带的连接池。生产环境通常会整合 Druid 或 HikariCP。

4. MyBatis 核心组件与生命周期

在代码中,我们通常这样使用 MyBatis:

// 1. 读取配置文件InputStreaminputStream=Resources.getResourceAsStream("SqlMapConfig.xml");// 2. 创建 SqlSessionFactory (工厂模式)SqlSessionFactorysqlSessionFactory=newSqlSessionFactoryBuilder().build(inputStream);// 3. 获取 SqlSession (会话)SqlSessionsqlSession=sqlSessionFactory.openSession(true);// true 表示自动提交事务// 4. 获取 Mapper 接口代理对象 (动态代理)BookMapperbookMapper=sqlSession.getMapper(BookMapper.class);// 5. 执行方法List<Book>books=bookMapper.findAll();
  • SqlSessionFactoryBuilder:用完即丢,用来构建工厂。
  • SqlSessionFactory全局单例,整个应用运行期间存在,用来生产 SqlSession。
  • SqlSession线程不安全,用完必须关闭 (close())。它相当于 JDBC 的Connection
  • Mapper 接口:MyBatis 通过 JDK 动态代理为接口生成实现类,我们只需要定义接口和 XML,不需要写实现类。

5. 实战演练:CRUD 操作

5.1 实体类 (Book.java)

@Data// Lombok 注解,自动生成 Getter/Setter/ToStringpublicclassBook{privateIntegerid;privateStringtitle;privateStringauthor;privateDoubleprice;privateIntegercategoryId;}

5.2 Mapper 接口 (BookMapper.java)

publicinterfaceBookMapper{// 查询所有List<Book>findAll();// 根据 ID 查询BookfindById(Integerid);// 新增intinsertBook(Bookbook);// 更新intupdateBook(Bookbook);// 删除intdeleteBook(Integerid);}

5.3 Mapper XML (BookMapper.xml)

<mappernamespace="com.qcby.dao.BookMapper"><!-- id: 对应接口中的方法名 resultType: 返回结果的全限定类名 (如果开启了驼峰映射,会自动匹配字段) --><selectid="findAll"resultType="com.qcby.entity.Book">SELECT * FROM book</select><!-- parameterType: 参数类型 (可选,MyBatis 能自动推断) --><selectid="findById"parameterType="int"resultType="com.qcby.entity.Book">SELECT * FROM book WHERE id = #{id}</select><!-- useGeneratedKeys="true": 使用数据库自增主键 keyProperty="id": 将生成的主键值回填到 book 对象的 id 属性中 --><insertid="insertBook"useGeneratedKeys="true"keyProperty="id">INSERT INTO book (title, author, price, category_id) VALUES (#{title}, #{author}, #{price}, #{categoryId})</insert></mapper>

6. 进阶必杀技:动态 SQL

MyBatis 最强大的功能之一就是动态 SQL。它摆脱了 JDBC 中拼接 SQL 字符串的痛苦。

6.1<if><where>:多条件查询

场景:用户可能只输入了书名,也可能同时输入了书名和作者,或者什么都没输。

<!-- 动态查询书籍信息 --><selectid="findBooksByCondition"resultType="com.qcby.entity.Book">SELECT * FROM book<where><!-- if test="条件表达式": 如果为 true,则拼接标签内的 SQL --><iftest="book.title != null and book.title !=''">AND title LIKE concat('%', #{book.title}, '%')</if><iftest="book.author != null and book.author !=''">AND author = #{book.author}</if><!-- 处理日期范围 --><iftest="startDate != null">AND publish_date >= #{startDate}</if></where></select>

💡 知识点

  • <where>标签:非常智能。如果标签内部有内容,它会自动插入WHERE关键字。如果内容以ANDOR开头,它会自动剔除掉第一个AND/OR,防止 SQL 语法错误。

6.2<set>:动态更新

场景:只更新用户修改了的字段,没修改的字段保持原样。

<updateid="updateBook">UPDATE book<set><iftest="title != null">title = #{title},</if><iftest="author != null">author = #{author},</if><iftest="price != null">price = #{price},</if></set>WHERE id = #{id}</update>

💡 知识点

  • <set>标签:会自动插入SET关键字,并且会自动剔除最后多余的逗号,

6.3<foreach>:批量插入/查询

场景:一次性插入 100 本书,或者查询 ID 在 [1, 3, 5] 中的书。

<!-- 批量插入 --><insertid="batchInsertBooks">INSERT INTO book (title, author, category_id, publish_date) VALUES<!-- collection: 集合参数的名称 (list, array 或 @Param 指定的名) item: 当前遍历元素的别名 separator: 分隔符 --><foreachcollection="books"item="book"separator=",">(#{book.title}, #{book.author}, #{book.categoryId}, #{book.publishDate})</foreach></insert>

7. 高级映射与关联查询

当数据库表结构比较复杂(如一对多、多对一)时,简单的resultType可能无法满足需求,这时需要使用resultMap

7.1 多对一 / 一对一 (association)

场景:查询借阅记录 (BorrowRecord) 时,同时查出对应的用户 (User) 和书籍 (Book) 信息。

<!-- 定义 ResultMap --><resultMapid="BorrowRecordMap"type="com.qcby.entity.BorrowRecord"><idproperty="id"column="id"/><resultproperty="borrowDate"column="borrow_date"/><!-- 关联 User 对象 --><associationproperty="user"javaType="com.qcby.entity.User"><idproperty="id"column="user_id"/><resultproperty="name"column="user_name"/></association><!-- 关联 Book 对象 --><associationproperty="book"javaType="com.qcby.entity.Book"><idproperty="id"column="book_id"/><resultproperty="title"column="book_title"/></association></resultMap><selectid="findUserBorrowRecords"resultMap="BorrowRecordMap">SELECT br.*, u.id as user_id, u.name as user_name, b.id as book_id, b.title as book_title FROM borrow_record br LEFT JOIN user u ON br.user_id = u.id LEFT JOIN book b ON br.book_id = b.id</select>

8. 🔥 MyBatis 高频面试题

Q1:#{}${}的区别是什么?(必问)

  • #{}:是预编译处理(PreparedStatement)。MyBatis 会将其替换为?,然后调用 JDBC 的set方法赋值。
    • 优点防止 SQL 注入,安全性高。
    • 适用:大部分参数传递。
  • ${}:是字符串替换。MyBatis 会直接将变量的值拼接到 SQL 语句中。
    • 缺点:存在 SQL 注入风险。
    • 适用:动态表名、列名、排序字段(如ORDER BY ${columnName})。

Q2: MyBatis 的一级缓存和二级缓存?

  • 一级缓存 (Local Cache)
    • 作用域SqlSession级别。
    • 默认开启
    • 同一个 SqlSession 中执行相同的 SQL,第一次查库,后续直接从缓存取。
    • commitcloseupdate/insert/delete操作会清空一级缓存。
  • 二级缓存 (Global Cache)
    • 作用域Mapper (Namespace)级别。
    • 默认关闭,需要在 XML 中配置<cache/>开启。
    • 多个 SqlSession 共享。数据需要实现Serializable接口。

Q3: Dao 接口的工作原理是什么?

  • Dao 接口(Mapper 接口)没有实现类,MyBatis 使用JDK 动态代理为接口生成了一个代理对象。
  • 当调用接口方法时,代理对象会拦截调用,根据方法名找到对应的 XML 标签(MappedStatement),然后执行 SQL 并处理结果。

Q4: 如何获取自动生成的主键?

  • <insert>标签中使用useGeneratedKeys="true"keyProperty="id"
  • 执行插入后,MyBatis 会将数据库生成的主键值回填到传入的实体对象的id属性中。

总结:MyBatis 是 Java 开发中必不可少的技能。掌握好动态 SQL 和 ResultMap,能让你在处理复杂业务时游刃有余。希望这篇教程能帮你建立起完整的 MyBatis 知识体系!🚀

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询