一、MyBatis 概述
1. 框架简介
MyBatis 是一款支持自定义 SQL、存储过程以及高级映射的持久层框架。它避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的操作,使开发人员能够更专注于 SQL 语句的编写和业务逻辑的处理。
2. 核心组件
- SqlSessionFactoryBuilder:用于创建 SqlSessionFactory 实例。
- SqlSessionFactory:是 MyBatis 的核心对象,负责创建 SqlSession 实例。
- SqlSession:提供了执行 SQL 语句、管理事务等功能。
3. 工作原理
MyBatis 通过读取配置文件和映射文件,将 SQL 语句与 Java 方法进行映射。在运行时,根据方法调用生成相应的 SQL 语句,并执行数据库操作,最后将结果映射为 Java 对象返回。
二、MyBatis 基础操作
1. 环境搭建
- 引入 MyBatis 依赖(以 Maven 项目为例):
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version>
</dependency>
- 配置
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><mappers><mapper resource="mapper/EmpMapper.xml" /><mapper resource="mapper/DeptMapper.xml" /></mappers>
</configuration>
2. 单表操作
- 实体类定义:
public class Emp {private Integer empid;private String empname;private String empjob;private BigDecimal empsalary;private Integer empdid;// 省略getter和setter方法
}
- Mapper 接口定义:
public interface EmpDao {List<Emp> findAll();Emp findById(Integer id);int insert(Emp emp);int update(Emp emp);int delete(Integer id);
}
- Mapper 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="org.example.Dao.EmpDao"><resultMap id="BaseResultMap" type="Emp"><id property="empid" column="emp_id" jdbcType="INTEGER" /><result property="empname" column="emp_name" jdbcType="VARCHAR" /><result property="empjob" column="emp_job" jdbcType="VARCHAR" /><result property="empsalary" column="emp_salary" jdbcType="DECIMAL" /><result property="empdid" column="did" jdbcType="INTEGER" /></resultMap><select id="findAll" resultMap="BaseResultMap">select * from tbl_emp</select><select id="findById" resultMap="BaseResultMap">select * from tbl_emp where emp_id = #{id}</select><insert id="insert" keyProperty="empid" useGeneratedKeys="true">insert into tbl_emp(emp_name, emp_job, emp_salary, did)values (#{empname}, #{empjob}, #{empsalary}, #{empdid})</insert><update id="update">update tbl_empset emp_name = #{empname}, emp_job = #{empjob}, emp_salary = #{empsalary}, did = #{empdid}where emp_id = #{empid}</update><delete id="delete">delete from tbl_emp where emp_id = #{id}</delete>
</mapper>
3. 测试类编写
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.Entity.Emp;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class EmpDaoTest {@Testpublic void testFindAll() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);List<Emp> emps = empDao.findAll();for (Emp emp : emps) {System.out.println(emp);}sqlSession.close();}@Testpublic void testFindById() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);Emp emp = empDao.findById(1);System.out.println(emp);sqlSession.close();}@Testpublic void testInsert() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);Emp emp = new Emp();emp.setEmpname("张三");emp.setEmpjob("开发工程师");emp.setEmpsalary(new BigDecimal("8000"));emp.setEmpdid(1);int result = empDao.insert(emp);System.out.println("插入成功,影响行数:" + result);sqlSession.commit();sqlSession.close();}@Testpublic void testUpdate() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);Emp emp = new Emp();emp.setEmpid(1);emp.setEmpname("李四");emp.setEmpjob("高级开发工程师");emp.setEmpsalary(new BigDecimal("10000"));emp.setEmpdid(2);int result = empDao.update(emp);System.out.println("更新成功,影响行数:" + result);sqlSession.commit();sqlSession.close();}@Testpublic void testDelete() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);int result = empDao.delete(1);System.out.println("删除成功,影响行数:" + result);sqlSession.commit();sqlSession.close();}
}
三、MyBatis 高级特性
1. 分页查询
- 引入 PageHelper 依赖:
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>6.0.0</version>
</dependency>
- 在 MyBatis 配置文件中添加插件配置:
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><!-- 可配置参数 --><property name="param1" value="value1" /></plugin>
</plugins>
- 代码示例:
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.example.Dao.EmpDao;
import org.example.Entity.Emp;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class PaginationTest {@Testpublic void testPagination() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);// 开启分页,查询第一页,每页显示3条数据PageHelper.startPage(1, 3);List<Emp> emps = empDao.findAll();// 将查询结果封装到PageInfo中PageInfo<Emp> pageInfo = new PageInfo<>(emps);// 输出相关信息System.out.println("总条数:" + pageInfo.getTotal());System.out.println("总页数:" + pageInfo.getPages());System.out.println("当前页记录:");List<Emp> list = pageInfo.getList();for (Emp emp : list) {System.out.println(emp);}sqlSession.close();}
}
2. 联表查询
- 多对一关系查询(以员工和部门为例):
- 使用
association
标签:
<?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="org.example.Dao.EmpDao"><resultMap id="EmpWithDeptResultMap" type="Emp"><id property="empid" column="emp_id" jdbcType="INTEGER" /><result property="empname" column="emp_name" jdbcType="VARCHAR" /><result property="empjob" column="emp_job" jdbcType="VARCHAR" /><result property="empsalary" column="emp_salary" jdbcType="DECIMAL" /><result property="empdid" column="did" jdbcType="INTEGER" /><association property="dept" javaType="Dept"><id property="deptid" column="dept_id" jdbcType="INTEGER" /><result property="deptname" column="dept_name" jdbcType="VARCHAR" /><result property="deptloc" column="dept_loc" jdbcType="VARCHAR" /></association></resultMap><select id="findAllWithDept" resultMap="EmpWithDeptResultMap">select e.*, d.dept_id, d.dept_name, d.dept_locfrom tbl_emp ejoin tbl_dept d on e.did = d.dept_id</select>
</mapper>
- 一对多关系查询(以部门和员工为例):
- 使用
collection
标签:
<?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="org.example.Dao.DeptDao"><resultMap id="DeptWithEmpsResultMap" type="Dept"><id property="deptid" column="dept_id" jdbcType="INTEGER" /><result property="deptname" column="dept_name" jdbcType="VARCHAR" /><result property="deptloc" column="dept_loc" jdbcType="VARCHAR" /><collection property="emps" ofType="Emp"><id property="empid" column="emp_id" jdbcType="INTEGER" /><result property="empname" column="emp_name" jdbcType="VARCHAR" /><result property="empjob" column="emp_job" jdbcType="VARCHAR" /><result property="empsalary" column="emp_salary" jdbcType="DECIMAL" /><result property="empdid" column="did" jdbcType="INTEGER" /></collection></resultMap><select id="findAllWithEmps" resultMap="DeptWithEmpsResultMap">select d.*, e.*from tbl_dept dleft join tbl_emp e on d.dept_id = e.did</select>
</mapper>
3. 动态 SQL
<trim>:通过修剪 SQL 语句的开头和结尾来动态生成 SQL 片段。它可以用于去除不必要的 SQL 关键字或条件语句,并提供了一些属性来定义修剪规则。
<where>:用于在生成的 SQL 语句中添加 WHERE 子句。它可以自动处理条件语句的前缀,并在有条件语句存在时添加 WHERE 关键字。而且会去除sql的第一个and标签。
<set>:用于在生成的 SQL 语句中添加 SET 子句。它主要用于更新操作,可以根据条件来动态生成需要更新的列。
<foreach>:用于在生成的 SQL 语句中进行循环操作。它可以遍历集合或数组,并根据指定的模板将集合元素或数组元素插入到 SQL 语句中。
<if>:用于在生成的 SQL 语句中添加条件判断。可以根据指定的条件决定是否包含某个 SQL 语句片段。
<choose>:类似于 Java 中的 switch 语句,根据条件选择执行不同的 SQL 语句片段。它可以包含多个 <when> 和一个可选的 <otherwise> 标签。
<when>:用于在 <choose> 标签中定义条件分支。可以根据指定的条件判断是否执行特定的 SQL 语句片段。
<otherwise>:在 <choose> 标签中可选的标签,用于定义当没有任何 <when> 条件匹配时执行的 SQL 语句片段。
if
标签示例(根据条件查询员工):
<?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="org.example.Dao.EmpDao"><select id="selectByCondition" resultMap="BaseResultMap">select * from tbl_emp<where><if test="name!= null and name!= ''">and emp_name like concat('%', #{name}, '%')</if><if test="job!= null and job!= ''">and emp_job = #{job}</if><if test="salary!= null">and emp_salary = #{salary}</if></where></select>
</mapper>
choose
、when
、otherwise
标签示例(根据条件查询员工):
<?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="org.example.Dao.EmpDao"><select id="selectByCondition2" resultMap="BaseResultMap">select * from tbl_emp<where><choose><when test="name!= null and name!= ''">and emp_name like concat('%', #{name}, '%')</when><when test="job!= null and job!= ''">and emp_job = #{job}</when><when test="salary!= null">and emp_salary = #{salary}</when><otherwise>and 1 = 1</otherwise></choose></where></select>
</mapper>
foreach
标签示例(批量删除员工):
<?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="org.example.Dao.EmpDao"><delete id="batchDelete">delete from tbl_emp where emp_id in<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach></delete>
</mapper>