Mybatis#
约 1299 个字 298 行代码 预计阅读时间 36 分钟
JDBC的不足#
- SQL语句是写在程序中的,当数据库表结构发生变化,需要修改源码。不符合开闭原则。
- prepareStatement需要重复进行参数设置,代码繁琐冗余。
- 结果集的处理繁琐,需要手动处理。
入门案例#
创建项目,引入maven依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.luguosong</groupId>
<artifactId>mybatis-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--java连接MySQL-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<!--注解生成getter和setter-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<scope>provided</scope>
</dependency>
<!-- 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>6.1.0</version>
</dependency>
<!--日志输出-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
</project>
创建核心配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--表示根据驼峰命名法自动匹配结果集-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<environments default="development">
<!--配置连接数据库的环境-->
<environment id="development">
<!--事务管理方式-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/learn_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</dataSource>
</environment>
</environments>
<!--引入映射文件-->
<mappers>
<!--<mapper resource="com/luguosong/hello/mapper/EmployeesMapper.xml"/>-->
<package name="com/luguosong"/>
</mappers>
</configuration>
编写实体类:
package com.luguosong.hello.pojo;
import lombok.Data;
import java.sql.Date;
/**
* @author luguosong
*/
@Data
public class Employees {
private Integer id;
private String firstName;
private String lastName;
private String position;
private Date hireDate;
private Integer departmentId;
}
编写Mapper接口:
package com.luguosong.hello.mapper;
import com.luguosong.hello.pojo.Employees;
/**
* @author luguosong
*/
public interface EmployeesMapper {
Employees getEmployeesById(Integer id);
}
编写Mapper映射文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.hello.mapper.EmployeesMapper">
<select id="getEmployeesById" resultType="com.luguosong.hello.pojo.Employees">
select * from employees where id = #{id}
</select>
</mapper>
配置log4j日志配置文件:
# log4j.rootLogger=<LogLevel>, <Appender1>, <Appender2>, ...
# 设置日志记录器的根记录器的级别和多个输出目标
log4j.rootLogger=debug ,toConsole
#
#设置子logger日志记录器
log4j.logger.com.luguosong.child=debug, toConsole
#不让父输出控制器再输出一遍
log4j.additivity.com.luguosong.child=false
# 控制台输出目标
log4j.appender.toConsole=org.apache.log4j.ConsoleAppender
log4j.appender.toConsole.layout=org.apache.log4j.PatternLayout
log4j.appender.toConsole.layout.conversionPattern=%d{ISO8601} %5p %c{1}:%L - %m%n
创建测试类:
package com.luguosong.hello;
import com.luguosong.hello.mapper.EmployeesMapper;
import com.luguosong.hello.pojo.Employees;
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 java.io.IOException;
import java.io.InputStream;
/**
* @author luguosong
*/
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config-hello.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 表示Java程序与数据库之间的会话
SqlSession sqlSession = factory.openSession();
// 动态创建Mapper接口对应的对象
EmployeesMapper mapper = sqlSession.getMapper(EmployeesMapper.class);
Employees employees = mapper.getEmployeesById(3);
System.out.println(employees);
}
}
Mybatis核心配置文件#
事务管理方式#
type="JDBC"
JDBC事务管理,mybatis框架自己管理事务,底层使用JDBCtype="MANAGED"
由容器管理事务,例如Spring容器
<configuration>
<environments default="development">
<environment id="development">
<!--事务管理方式-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!--...-->
</dataSource>
</environment>
</environments>
</configuration>
数据源类型#
type="POOLED"
使用mybatis自带的连接池type="UNPOOLED"
不使用连接池type="JNDI"
集成第三方连接池,例如c3p0、druid等
<configuration>
<environments default="development">
<environment id="development">
<!--数据源类型-->
<dataSource type="POOLED">
<!--...-->
</dataSource>
</environment>
</environments>
</configuration>
引入外部properties配置文件#
<configuration>
<!--引入外部配置文件-->
<properties resource="jdbc.properties"/>
<environments default="development">
<environment id="development">
<dataSource type="POOLED">
<!--获取properties配置-->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
</configuration>
设置类型别名#
核心配置文件中配置类型别名
:
<configuration>
<typeAliases>
<typeAlias type="com.luguosong.pojo.Car" alias="Car"/>
</typeAliases>
</configuration>
在Mapper映射配置文件中可以直接使用别名:
<mapper namespace="com.luguosong.mapper.CarMapper">
<!--resultType可以直接使用别名表示-->
<select id="selectCarById" resultType="Car">
select * from t_car where id = #{id}
</select>
</mapper>
也可以配置package
,指定包下的类都以类名
作为别名:
<configuration>
<typeAliases>
<package name="com.luguosong.pojo"/>
</typeAliases>
</configuration>
配置映射文件#
方式一:指定每一个xml映射配置文件
<configuration>
<mappers>
<mapper resource="com/luguosong/mapper/Mapper1.xml"/>
<mapper resource="com/luguosong/mapper/Mapper2.xml"/>
<mapper resource="com/luguosong/mapper/Mapper3.xml"/>
</mappers>
</configuration>
方式二:指定映射文件目录
Warning
使用目录方式
配置Mapper映射,映射文件的包名
和文件名
需要与Mapper接口保持一致。
参数获取#
字符串拼接#
${xxx}
表示采用字符串拼接的方式生成sql语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.get_param.string_splicing.mapper.EmployeesMapper">
<!--Employees getEmployeesById(Integer id);-->
<select id="getEmployeesById" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where id = ${id}
</select>
<!--Employees getEmployeesByName(String firstName);-->
<!--如果参数是字符串,需要手动加上引号-->
<select id="getEmployeesByName" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = '${firstName}'
</select>
</mapper>
Warning
这种方式会引起sql注入
占位符赋值👍🏻#
#{xxx}
表示采用占位符赋值的方式生成sql语句
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.get_param.placeholder.mapper.EmployeesMapper">
<!--Employees getEmployeesById(Integer id);-->
<select id="getEmployeesById" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where id = #{id}
</select>
<!--Employees getEmployeesByName(String firstName);-->
<!--如果参数是字符串,需要手动加上引号-->
<select id="getEmployeesByName" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{firstName}
</select>
</mapper>
单个参数#
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.get_param.single_parameter.mapper.EmployeesMapper">
<!--Employees getEmployeesById(Integer id);-->
<select id="getEmployeesById" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where id = #{id}
</select>
<!--Employees getEmployeesByName(String firstName);-->
<!--当只有一个参数时,#{}中键名可以随便写-->
<select id="getEmployeesByName" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{aaaa}
</select>
</mapper>
多个参数传递#
多个参数时,Mybatis会采用默认键名
将参数封装到Mapper集合中。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.get_param.multiple_parameters.mapper.EmployeesMapper">
<!--Employees getEmployeesByName1(String firstName, String lastName);-->
<!--可以使用arg0,arg1,arg2...-->
<select id="getEmployeesByName1" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{arg0}
and last_name = #{arg1}
</select>
<!--Employees getEmployeesByName2(String firstName, String lastName);-->
<!--也可以使用param0,param1,param2...-->
<select id="getEmployeesByName2" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{param0}
and last_name = #{param1}
</select>
</mapper>
多个参数传递-@Param#
@Param
会将参数以指定键名
封装进Mapper集合中。
package com.luguosong.get_param.param_annotation.mapper;
import com.luguosong.get_param.pojo.Employees;
import org.apache.ibatis.annotations.Param;
/**
* @author luguosong
*/
public interface EmployeesMapper {
Employees getEmployeesByName(@Param("firstName") String firstName, @Param("lastName") String lastName);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.get_param.param_annotation.mapper.EmployeesMapper">
<!--Employees getEmployeesByName1(@Param("firstName") String firstName, @Param("lastName") String lastName);-->
<!--可以使用arg0,arg1,arg2...-->
<select id="getEmployeesByName" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{firstName}
and last_name = #{lastName}
</select>
</mapper>
对象和Mapper集合#
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.get_param.object_and_mapper.mapper.EmployeesMapper">
<!--Employees getEmployeesByName1(Employees employees);-->
<select id="getEmployeesByName1" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{firstName}
and last_name = #{lastName}
</select>
<!--Employees getEmployeesByName2(HashMap<String, String> searchMap);-->
<select id="getEmployeesByName2" resultType="com.luguosong.get_param.pojo.Employees">
select *
from employees
where first_name = #{firstName}
and last_name = #{lastName}
</select>
</mapper>
模糊查询#
模糊查询不能直接使用#{xxx}
,需要使用${xxx}
,或者使用CONCAT
关键字进行字符串拼接。
<mapper namespace="com.example.UserMapper">
<!--方式一-->
<!--List<User> selectUserByName(String name); -->
<select id="selectUserByName" resultType="User">
SELECT * FROM user WHERE name LIKE '%${name}%'
</select>
<!--方式二-->
<!--List<User> selectUserByName(String name); -->
<select id="selectUserByName" resultType="User">
SELECT * FROM user WHERE name LIKE CONCAT('%', #{name}, '%')
</select>
<!--方式三👍🏻-->
<!--List<User> selectUserByName(String name); -->
<select id="selectUserByName" resultType="User">
SELECT * FROM user WHERE name LIKE "%"#{name}"%"
</select>
<!--错误方式❌-->
<!--List<User> selectUserByName(String name); -->
<select id="selectUserByName" resultType="User">
SELECT * FROM user WHERE name LIKE '%#{name}%'
</select>
</mapper>
批量操作#
需要批量操作时,只能使用${xxx}
进行字符串拼接,不能使用#{xxx}
<mapper namespace="com.example.UserMapper">
<!--int deleteUsers(@Param("ids") String ids)-->
<delete>
delete from user where id in (${ids})
</delete>
</mapper>
设置自动递增主键#
设置useGeneratedKeys="true"
表示 MyBatis 会在插入记录后自动获取数据库生成的主键值,并将这个值填充到对象的id属性
中。这样你就不需要手动查询数据库来获取新插入记录的主键。
<mapper namespace="com.example.UserMapper">
<!--void insertUser(User user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into user values(null,#{name}, #{age})
</insert>
</mapper>
结果集处理#
查询具体值#
查询具体值可以使用包装类
接收
<mapper namespace="xxx">
<!--Integer getCount();-->
<select id="getCount" resultType="Integer">
select count(*) from t_user
</select>
</mapper>
查询单条数据#
Mapper接口采用实体类
接收
<mapper namespace="xxx">
<!--User selectUserById(Integer id);-->
<select id="selectUserById" resultType="User">
select * from t_user where id = #{id}
</select>
</mapper>
也可以使用Map集合
接收查询结果
<mapper namespace="xxx">
<!--Map<String, Object> selectUserById(Integer id);-->
<select id="selectUserById" resultType="Map">
select * from t_user where id = #{id}
</select>
</mapper>
查询多条数据#
Mapper接口采用List集合
接收
<mapper namespace="xxx">
<!--List<User> selectAllUser();-->
<select id="selectAllUser" resultType="User">
select * from t_user
</select>
</mapper>
表和实体类字段名不一致#
使用别名#
查询结果使用别名
,将表中的字段名改为与实体类字段名一致。
<mapper namespace="xxx">
<!--将phone_number改为与实体类一致的phoneNumber-->
<!--User selectUserById(Integer id);-->
<select id="selectAllUser" resultType="User">
select id,name, phone_number phoneNumber from user where id = #{id}
</select>
</mapper>
mapUnderscoreToCamelCase#
在核心配置文件中进行配置,让数据库字段名自动转换为实体类字段名。
比如:可以自动将phone_number转为phoneNumber
<configuration>
<settings>
<!--表示根据驼峰命名法自动匹配结果集-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
使用ResultMap#
<mapper namespace="xxx">
<resultMap id="UserMap" type="User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="phoneNumber" column="phone_number"/>
</resultMap>
<!--User selectUserById(Integer id);-->
<select id="selectAllUser" resultMap="UserMap">
select id,name, phone_number from user where id = #{id}
</select>
</mapper>
resultMap处理多对一#
需求:用户和部门之间的
多对一
关系,查询员工以及员工所在部门。
package com.luguosong.many_to_one.pojo;
import lombok.Data;
import java.sql.Date;
/**
* 员工
* @author luguosong
*/
@Data
public class Employees {
private Integer id;
private String firstName;
private String lastName;
private String position;
private Date hireDate;
//private Integer departmentId;
// 关联部门
private Departments departments;
}
package com.luguosong.many_to_one.pojo;
import lombok.Data;
/**
* 部门
* @author luguosong
*/
@Data
public class Departments {
private Integer id;
private String departmentName;
}
association标签#
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luguosong.many_to_one.association.mapper.EmployeesMapper">
<resultMap id="employeesResultMap" type="com.luguosong.many_to_one.pojo.Employees">
<id property="id" column="id"/>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
<result property="position" column="position"/>
<result property="hireDate" column="hire_date"/>
<association property="departments" javaType="com.luguosong.many_to_one.pojo.Departments">
<id property="id" column="dept_id"/>
<result property="departmentName" column="department_name"/>
</association>
</resultMap>
<select id="getEmployeesById" resultMap="employeesResultMap">
SELECT e.*,d.id dept_id,d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.id
WHERE e.id = #{id}
</select>
</mapper>
分步查询#
分步查询的好处
- 每个查询是分开的,可以单独使用,也可以合并使用
第一步:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luguosong.many_to_one.step_by_step.mapper.EmployeesMapper">
<resultMap id="employeesResultMap" type="com.luguosong.many_to_one.pojo.Employees">
<id property="id" column="id"/>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
<result property="position" column="position"/>
<result property="hireDate" column="hire_date"/>
<association
select="com.luguosong.many_to_one.step_by_step.mapper.DepartmentsMapper.getDepartmentsById"
column="department_id"
property="departments"/>
</resultMap>
<select id="getEmployeesById" resultMap="employeesResultMap">
SELECT *
FROM employees
WHERE id = #{id}
</select>
</mapper>
第二步:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luguosong.many_to_one.step_by_step.mapper.DepartmentsMapper">
<select id="getDepartmentsById" resultType="com.luguosong.many_to_one.pojo.Departments">
SELECT *
FROM departments
WHERE id = #{id}
</select>
</mapper>
测试类:
package com.luguosong.many_to_one.step_by_step;
import com.luguosong.many_to_one.pojo.Employees;
import com.luguosong.many_to_one.step_by_step.mapper.EmployeesMapper;
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 java.io.IOException;
import java.io.InputStream;
/**
* @author luguosong
*/
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config-hello.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 表示Java程序与数据库之间的会话
SqlSession sqlSession = factory.openSession();
// 动态创建Mapper接口对应的对象
EmployeesMapper mapper = sqlSession.getMapper(EmployeesMapper.class);
Employees employees = mapper.getEmployeesById(5);
//因为开启了延迟加载,如果只是获取员工属性,只会执行第一步sql
System.out.println(employees.getFirstName());
//当获取全部属性(包括部门属性),会执行第二步sql
System.out.println(employees);
}
}
执行结果:
2024-07-21 17:58:37,388 DEBUG getEmployeesById:135 - ==> Preparing: SELECT * FROM employees WHERE id = ?
2024-07-21 17:58:37,413 DEBUG getEmployeesById:135 - ==> Parameters: 5(Integer)
2024-07-21 17:58:37,483 DEBUG getEmployeesById:135 - <== Total: 1
芳
2024-07-21 17:58:37,485 DEBUG getDepartmentsById:135 - ==> Preparing: SELECT * FROM departments WHERE id = ?
2024-07-21 17:58:37,485 DEBUG getDepartmentsById:135 - ==> Parameters: 4(Integer)
2024-07-21 17:58:37,487 DEBUG getDepartmentsById:135 - <== Total: 1
Employees(id=5, firstName=芳, lastName=陈, position=市场专员, hireDate=2016-08-13, departments=Departments(id=4, departmentName=市场部))
resultMap处理一对多#
需求:部门和用户之间的
一对多
关系,查询部门以及部门下的所有员工。
package com.luguosong.one_to_many.pojo;
import lombok.Data;
import java.util.List;
/**
* 部门
* @author luguosong
*/
@Data
public class Departments {
private Integer id;
private String departmentName;
private List<Employees> employees;
}
package com.luguosong.one_to_many.pojo;
import lombok.Data;
import java.sql.Date;
/**
* 员工
* @author luguosong
*/
@Data
public class Employees {
private Integer id;
private String firstName;
private String lastName;
private String position;
private Date hireDate;
}
collection标签#
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luguosong.one_to_many.collection.mapper.DepartmentsMapper">
<resultMap id="departmentsResultMap" type="com.luguosong.one_to_many.pojo.Departments">
<id property="id" column="id"/>
<result property="departmentName" column="department_name"/>
<collection
ofType="com.luguosong.one_to_many.pojo.Employees"
property="employees">
<id property="id" column="e_id"/>
<result property="firstName" column="first_name"/>
<result property="lastName" column="last_name"/>
<result property="position" column="position"/>
<result property="hireDate" column="hire_date"/>
</collection>
</resultMap>
<select id="getDepartmentById" resultMap="departmentsResultMap">
SELECT * , employees.id AS e_id
FROM departments
LEFT JOIN employees on departments.id = employees.department_id
where departments.id = #{id}
</select>
</mapper>
分步查询#
第一步:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luguosong.one_to_many.step_by_step.mapper.DepartmentsMapper">
<resultMap id="DepartmentsResult" type="com.luguosong.one_to_many.pojo.Departments">
<id property="id" column="id"/>
<result property="departmentName" column="department_name"/>
<collection
column="id"
select="com.luguosong.one_to_many.step_by_step.mapper.EmployeesMapper.getEmployeesByDeptId"
property="employees"/>
</resultMap>
<select id="getDepartmentsById" resultMap="DepartmentsResult">
SELECT *
FROM departments
WHERE id = #{id}
</select>
</mapper>
第二步:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.luguosong.one_to_many.step_by_step.mapper.EmployeesMapper">
<select id="getEmployeesByDeptId" resultType="com.luguosong.one_to_many.pojo.Employees">
SELECT *
FROM employees
WHERE department_id = #{id}
</select>
</mapper>
延迟加载#
使用分步查询
时,可以开启延迟加载,第二步查询会延迟执行:
lazyLoadingEnabled
: 表示开启延迟加载aggressiveLazyLoading
: 表示是否按需加载,当等于true
时,任何方法调用都会加载该对象的所有属性。因此开启延迟加载该属性应该设置为false
<configuration>
<settings>
<!--表示开启延迟加载,多表查询分步操作第二步会延迟执行-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
</configuration>
如果全局设置了延迟加载,希望某个查询不延迟加载,可以通过fetchType
属性来控制延迟加载,eager
为不延迟加载,lazy
为延迟加载。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxx">
<resultMap id="xxx" type="xxx">
<!--...-->
<association
fetchType="eager"
select="xxx"
column="xxx"
property="xxx"/>
</resultMap>
<select id="xxx" resultMap="xxx">
...
</select>
</mapper>
动态sql#
if标签#
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.dynamic_sql.sql_if.mapper.EmployeesMapper">
<select id="selectEmployees" resultType="com.luguosong.dynamic_sql.pojo.Employees">
select * from employees where 1=1
<if test="firstName != null and firstName != ''">
and first_name = #{firstName}
</if>
<if test="lastName != null and lastName != ''">
and last_name = #{lastName}
</if>
</select>
</mapper>
测试类:
package com.luguosong.dynamic_sql.sql_if;
import com.luguosong.dynamic_sql.pojo.Employees;
import com.luguosong.dynamic_sql.sql_if.mapper.EmployeesMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author luguosong
*/
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config-hello.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
// 表示Java程序与数据库之间的会话
SqlSession sqlSession = factory.openSession();
EmployeesMapper mapper = sqlSession.getMapper(EmployeesMapper.class);
Employees select1 = new Employees();
select1.setFirstName("强");
List<Employees> employees1 = mapper.selectEmployees(select1);
System.out.println(employees1);
Employees select2 = new Employees();
select2.setLastName("王");
List<Employees> employees2 = mapper.selectEmployees(select2);
System.out.println(employees2);
}
}
where标签#
可以使用where标签
替换where 1=1
这种写法。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.dynamic_sql.sql_where.mapper.EmployeesMapper">
<select id="selectEmployees" resultType="com.luguosong.dynamic_sql.pojo.Employees">
select * from employees
<where>
<if test="firstName != null and firstName != ''">
and first_name = #{firstName}
</if>
<if test="lastName != null and lastName != ''">
and last_name = #{lastName}
</if>
</where>
</select>
</mapper>
trim标签#
可以通过自定义trim标签
来定制where标签
的功能。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace属性指向mapper接口-->
<mapper namespace="com.luguosong.dynamic_sql.sql_where.mapper.EmployeesMapper">
<select id="selectEmployees" resultType="com.luguosong.dynamic_sql.pojo.Employees">
select * from employees
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="firstName != null and firstName != ''">
and first_name = #{firstName}
</if>
<if test="lastName != null and lastName != ''">
and last_name = #{lastName}
</if>
</trim>
</select>
</mapper>
choose、when、otherwise标签#
相当于if...else if ... else
的功能。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
foreach标签#
<select id="selectPostIn" resultType="domain.blog.Post">
SELECT *
FROM POST P
<where>
<foreach
item="item"
index="index"
collection="list"
open="ID in ("
separator=","
close=")"
nullable="true">
#{item}
</foreach>
</where>
</select>
缓存#
一级缓存
:默认开启,同一个SqlSession对象
查询的结果会被缓存起来。可以通过SqlSession对象的clearCache()方法
来清除一级缓存。 二级缓存
:默认关闭,同一个SqlSessionFactory
的查询结果会被缓存起来。
要启用全局的二级缓存,只需要在你的 SQL 映射文件中添加一行:
代码生成(逆向工程)#
通过数据库表自动生成实体类
和Mapper接口
等相关代码
简单实现#
pom依赖中引入插件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.luguosong</groupId>
<artifactId>mybatis-generator</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.3.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!--代码生成插件-->
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.4.2</version>
<!--插件依赖的环境-->
<dependencies>
<!--逆向工程核心依赖-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.4.2</version>
</dependency>
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
代码生成插件配置:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="mysqlToTable1" targetRuntime="MyBatis3Simple">
<!--配置数据库连接-->
<jdbcConnection
userId="root"
password="12345678"
driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/learn_mybatis">
<!---->
<property name="nullCatalogMeansCurrent" value="true"/>
</jdbcConnection>
<!--实体类生成策略-->
<javaModelGenerator
targetPackage="com.luguosong.pojo"
targetProject="./src/main/java">
<!--是否使用子包-->
<property name="enableSubPackages" value="true"/>
<!--去除字符串前后空格-->
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!--mapper映射文件生成策略-->
<sqlMapGenerator
targetPackage="com.luguosong.mapper"
targetProject="./src/main/resources">
<!--是否使用子包-->
<property name="enableSubPackages" value="true"/>
</sqlMapGenerator>
<javaClientGenerator
type="XMLMAPPER"
targetPackage="com.luguosong.mapper"
targetProject="./src/main/java"/>
<!--指定相关表-->
<table tableName="departments" domainObjectName="Departments"/>
<table tableName="employees" domainObjectName="Employees"/>
</context>
</generatorConfiguration>
分页插件#
添加依赖:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>6.1.0</version>
</dependency>
Mybatis核心配置文件配置分页插件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!--⭐配置分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"/>
</plugins>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/learn_mybatis"/>
<property name="username" value="root"/>
<property name="password" value="12345678"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/luguosong/pagination_plugin/mapper/EmployeesMapper.xml"/>
</mappers>
</configuration>
测试类:
package com.luguosong.pagination_plugin;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.luguosong.hello.pojo.Employees;
import com.luguosong.pagination_plugin.mapper.EmployeesMapper;
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 java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @author luguosong
*/
public class Test {
public static void main(String[] args) throws IOException {
InputStream is = Resources.getResourceAsStream("mybatis-config-page.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(is);
SqlSession sqlSession = factory.openSession();
EmployeesMapper mapper = sqlSession.getMapper(EmployeesMapper.class);
PageHelper.startPage(1, 2);
List<Employees> list = mapper.getAll();
System.out.println(list);
}
}
结果:
Page{count=true, pageNum=1, pageSize=2, startRow=0, endRow=2, total=6, pages=3, reasonable=false, pageSizeZero=false}[Employees(id=1, firstName=伟, lastName=张, position=人力资源经理, hireDate=2015-06-01, departmentId=1), Employees(id=2, firstName=娜, lastName=李, position=软件工程师, hireDate=2018-09-15, departmentId=2)]