Mybatis入门操作

Mybatis入门操作_第1张图片


一、Mybatis入门

1. jdbc编程问题总结

1.1 jdbc程序

@Override
public void insertUser(User user){
    Connection conn = DBUtil.getConnection();
    PreparedStatement stmt = null;
    String sql = "insert into sys_user(NAME,ACCT,PWD,CRTIME,UPTIME) values(?a,?c,?d,now(),now())";
    try {
        stmt = conn.prepareStatement(sql);
        stmt.setString(1, user.getName());
        stmt.setString(2, user.getAcct());
        stmt.setString(3, user.getPwd());
        stmt.executeUpdate();
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        DBUtil.closeAll(conn, stmt, null);
    }
}

1.2 jdbc编程步骤

  1. 加载数据库驱动
  2. 创建并获取数据库链接
  3. 创建PreparedStatement对象
  4. 设置Sql语句中的占位符参数
  5. 通过PreparedStatement执行Sql并获取结果
  6. 对Sql执行结果进行解析处理
  7. 释放资源(Connection、Preparedstatement、ResultSet)

1.3 jdbc问题总结如下

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题
  2. Sql语句在代码中硬编码,造成代码不易维护,实际应用Sql变化的可能较大,Sql变动需要改变java代码
  3. 使用PreparedStatement向占位符号传参数存在硬编码,因为Sql语句的where条件不一定,可能多也可能少,修改Sql还要修改代码,系统不易维护
  4. 对结果集解析存在硬编码(查询列名),Sql变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成pojo对象解析比较方便

2. MyBatis介绍

  MyBatis本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis,实质上MyBatis对iBatis进行一些改进
  MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建Connection、创建Statement、手动设置参数、结果集检索等jdbc繁杂的过程代码
  Mybatis通过xml或注解的方式将要执行的各种Statement(Statement、PreparedStatemnt、CallableStatement)配置起来,并通过java对象和Statement中的Sql进行映射生成最终执行的Sql语句,最后由MyBatis框架执行Sql并将结果映射成java对象并返回

3. MyBatis架构

  1. MyBatis配置文件mybatis-config.xml(名称不固定),此文件作为MyBatis的全局配置文件,配置了MyBatis的运行环境等信息。mapper.xml文件即Sql映射文件,文件中配置了操作数据库的Sql语句。此文件需要在mybatis-config.xml中加载
  2. 通过MyBatis环境等配置信息构造SqlSessionFactory即会话工厂
  3. 由会话工厂创建SqlSession即会话,操作数据库需要通过SqlSession进行
  4. MyBatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器
  5. Mapped Statement也是MyBatis一个底层封装对象,它包装了MyBatis配置信息及Sql映射信息等。mapper.xml文件中一个Sql对应一个Mapped Statement对象,Sql的id即是Mapped statement的id
  6. Mapped Statement对Sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行Sql前将输入的java对象映射至Sql中,输入参数映射就是jdbc编程中对PreparedStatement设置参数
  7. Mapped Statement对Sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程

4. 搭建MyBatis项目

4.1 建立Java项目

  MyBatis是一个持久层框架,操作数据库时使用的。无需创建JavaWEB项目,建立Java项目即可

4.2 导入MyBatis框架jar包

Mybatis入门操作_第2张图片

  • mybatis-3.4.6.jar为核心jar包,必须引入
  • lib目录下的jar包为工具包,可有可无
  • mysql或oracle数据库的驱动包,必须引入

maven依赖配置

<dependencies>
    
    <dependency>
        <groupId>org.mybatisgroupId>
        <artifactId>mybatisartifactId>
        <version>3.4.6version>
    dependency>
    
    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>5.1.38version>
    dependency>
    
    <dependency>
        <groupId>log4jgroupId>
        <artifactId>log4jartifactId>
        <version>1.2.17version>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
        <scope>testscope>
    dependency>
dependencies>

4.3 编写MyBatis中全局配置文件

  作用:配置了数据源、事务等MyBatis运行环境等



<configuration>
	
    <environments default="mysql">
        <environment id="oracle">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
                <property name="driver" value="oracle.jdbc.driver.OracleDriver"/>
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
                <property name="username" value="tom"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
        <environment id="mysql">
            <transactionManager type="JDBC">transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
configuration>

4.4 编写实体类

public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    //get,set方法省略...
}

4.5 编写映射文件




<mapper namespace="emp">
    
    
    
    <select id="findEmpById" parameterType="java.lang.Integer" resultType="com.mybatis.entity.Emp">
      select empno,ename,job,mgr,hiredate,sal,comm from emp where empno=#{abc}
    select>
mapper>

4.6 加载映射文件

  在MyBatis中全局配置文件中添加映射文件位置


<mappers>
    <mapper resource="com/mybatis/entity/Emp.xml"/>
mappers>

4.7 编写测试程序

//1.创建读取全局配置文件的流
InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

//2.通过配置文件流创建会话工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

//3.通过会话工厂创建会话对象(SqlSession)
SqlSession session = factory.openSession();

/*
4.通过会话对象操作数据库
selectOne(String statementId, Object param)查询单条数据
参数1:映射文件中的statementId,命名空间名.statementId
参数2:向sql语句中传入的数据,注意:传入的数据类型必须与映射文件中配置的parameterType保持一致
返回值:就是映射文件中配置的resultType的类型
*/
Emp emp = session.selectOne("emp.findEmpById",8001);
System.out.println(emp);
//5.关闭资源
session.close();

5. 增删改查的基本操作

5.1 查询操作

mapper文件:

    
    <select id="findEmp" resultType="com.mybatis.entity.Emp">
      select empno,ename,job,mgr,hiredate,sal,comm from emp order by empno desc
    select>

Java代码:

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();
List<Emp> list = session.selectList("emp.findEmp");
for (Emp e : list) {
    System.out.println(e);
}
session.close();

5.2 新增操作

mapper文件:

<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" >
    insert into emp(empno,ename,job,mgr,hiredate,sal,comm)
    values(#{empno},#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm})
insert>

Java代码:

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();

Emp emp = new Emp();
emp.setEname("tom");
emp.setJob("clrek");
emp.setMgr(1);
emp.setHiredate(new Date());
emp.setSal(6500.0);
emp.setComm(1200.0);

//在mybaits中事务默认需要手动提交
int result = session.insert("emp.insertEmp",emp);
System.out.println(result);
//执行提交的方法
session.commit();
session.close();

插入数据的主键返回:

  • select last_insert_id(),表示得到刚insert进去记录的主键值,适用与自增主键的数据库
  • select seq_demo.nextval from dual,表示获取下一个序列生成的值,适用于存在序列的数据库
  • keyProperty:将查询到主键值设置到parameterType指定的对象的哪个属性
  • order:selectKey标签中Sql语句,相对于insert语句来说的执行顺序
  • resultType:指定selectKey标签中Sql语句的结果类型

<selectKey resultType="java.lang.Integer" keyProperty="empno" order="AFTER">
    select last_insert_id()
selectKey>

<selectKey resultType="java.lang.Integer" keyProperty="empno" order="BEFORE">
    select seq_demo.nextval from dual
selectKey>

如果是主键自增型数据库还可以使用:

<insert id="insertEmp" parameterType="com.mybatis.entity.Emp" keyProperty="empno" useGeneratedKeys="true">

5.3 修改操作

mapper文件:

<update id="updateEmp" parameterType="com.mybatis.entity.Emp">
    update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},sal=#{sal},comm=#{comm}
    where empno=#{empno}
update>

Java代码:

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();

Emp emp = new Emp();
emp.setEmpno(52);
emp.setEname("jerry");
emp.setJob("manager");
emp.setMgr(10);
emp.setHiredate(new Date());
emp.setSal(8500.0);
emp.setComm(1200.0);

int result = session.update("emp.updateEmp",emp);
System.out.println(result);
//执行提交的方法
session.commit();
session.close();

5.4 删除操作

mapper文件:

<delete id="deleteEmp" parameterType="java.lang.Integer">
    delete from emp where empno=#{empno}
delete>

Java代码:

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();

int result = session.delete("emp.deleteEmp",8000);
System.out.println(result);
//执行提交的方法
session.commit();
session.close();

5.5 条件查询

mapper文件:


<select id="findEmpByEname" parameterType="java.lang.String" resultType="com.mybatis.entity.Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    where ename like #{abc}
select>

<select id="findEmpByEname2" parameterType="java.lang.String" resultType="com.mybatis.entity.Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    where ename like '%${value}%'
select>

Java代码:

InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
SqlSession session = factory.openSession();

List<Emp> list = session.selectList("emp.findEmpByEname", "%tom%");
//List list = session.selectList("emp.findEmpByEname", "tom");
for (Emp e : list) {
    System.out.println(e);
}

session.close();

5.6 总结

5.6.1 parameterType和resultType
  • parameterType:指定输入参数类型,MyBatis通过ognl从输入对象中获取参数值设置在Sql中
  • resultType:指定输出结果类型,MyBatis将Sql查询结果的一行记录数据映射为resultType指定类型的对象
5.6.2 #{} 和 ${}
  • #{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型、pojo、HashMap
    #{}接收简单类型,#{}中可以写成value或其它名称
    #{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值

  • ${}表示一个拼接符号,会引用Sql注入,所以不建议使用${}
    ${}接收输入参数,类型可以是简单类型、pojo、HashMap
    ${}接收简单类型,${}中只能写成value
    ${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性…的方式获取对象属性值

5.6.3 selectOne和selectList
  • selectOne表示查询出一条记录进行映射
    如果使用selectOne可以实现使用selectList也可以实现(list中只有一个对象)
  • selectList表示查询出一个列表(多条记录)进行映射
    如果使用selectList查询多条记录,不能使用selectOne
    如果使用selectOne报错:
    org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 4

6. MyBatis和Hibernate本质区别和应用场景

  • Hibernate:是一个标准ORM框架(对象关系映射)
    入门门槛较高的,不需要程序写Sql,Sql语句自动生成,对sql语句进行优化、修改比较困难的
    应用场景:适用与需求变化不多的中小型项目,比如:后台管理系统,erp、crm、oa…
  • MyBatis:专注是Sql本身,需要程序员自己编写Sql语句,Sql修改、优化比较方便
    MyBatis是一个不完全的ORM框架,虽然程序员自己写Sql,MyBatis也可以实现映射(输入映射、输出映射)
    应用场景:适用与需求变化较多的项目,比如:互联网项目
  • 企业进行技术选型,以低成本高回报作为技术选型的原则,根据项目组的技术力量进行选择

二、MyBatis开发DAO

1. MyBatis API

1.1 SqlSessionFactoryBuilder

  SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量

1.2 SqlSessionFactory

  SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory

1.3 SqlSession

  SqlSession是一个面向用户(程序员)的接口,其中提供了很多操作数据库的方法。如:selectOne(返回单个对象)、selectList(返回单个或多个对象)、insert、update、delete。

  SqlSession的实例不能共享使用,它是线程不安全的,每个线程都应该有它自己的SqlSession实例,因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

2. MyBatis工具类

  为了简化MyBatis的开发,可将MyBatis进一步封装

public class MybatisUtil {
    /**
     * 不让用户在外界创建工具类对象
     */
    private MybatisUtil(){}
    /**
     * 初始化工厂
     */
    private static SqlSessionFactory factory;
    static {
        try {
            InputStream in = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 获取SqlSession对象的方法
     */
    public static SqlSession openSession(){
        return factory.openSession();
    }
}

3. 原始DAO开发方式

  原始Dao开发方法需要程序员编写Dao接口和Dao实现类

接口:

public interface DeptDao {
    public List<Dept> findDept();
    public Dept findDeptById(Integer deptno);
    public void insertDept(Dept dept);
    public void updateDept(Dept dept);
    public void deleteDept(Integer deptno);
}

实现类:

public class DeptDaoImpl implements DeptDao {
    @Override
    public List<Dept> findDept() {
        SqlSession session = MybatisUtil.openSession();
        List<Dept> list = session.selectList("dept.findDept");
        session.close();
        return  list;
    }
    @Override
    public Dept findDeptById(Integer deptno) {
        SqlSession session = MybatisUtil.openSession();
        Dept dept = session.selectOne("dept.findDeptById",deptno);
        session.close();
        return dept;
    }
    @Override
    public void insertDept(Dept dept) {
        SqlSession session = MybatisUtil.openSession();
        session.insert("dept.insertDept",dept);
        session.commit();
        session.close();
    }
    @Override
    public void updateDept(Dept dept) {
        SqlSession session = MybatisUtil.openSession();
        session.update("dept.updateDept",dept);
        session.commit();
        session.close();
    }
    @Override
    public void deleteDept(Integer deptno) {
        SqlSession session = MybatisUtil.openSession();
        session.delete("dept.deleteDept",deptno);
        session.commit();
        session.close();
    }
}

原始DAO开发问题

  • dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量
  • 调用SqlSession方法时将Statement的id硬编码了
  • 调用SqlSession方法时传入的变量,由于SqlSession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发

4. Mapper代理方式

  Mapper代理开发方式只需要程序员编写Mapper接口(相当于Dao接口),由MyBatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法
  程序员编写Mapper接口需要遵循一些开发规范,MyBatis可以自动生成Mapper接口实现类代理对象

开发规范:

  1. 在mapper.xml中namespace等于Mapper接口的全限定名
  2. Mapper接口中的方法名和mapper.xml中statement的id一致
  3. Mapper接口中的方法输入参数类型和mapper.xml中parameterType指定的类型一致
  4. Mapper接口中的方法返回值类型和mapper.xml中resultType指定的类型一致

Mapper接口:

public interface EmpMapper {
    public List<Emp> findEmp();
    public Emp findEmpByEmpno(Integer empno);
    /**
     * 增删改方法的返回值
     * 1.void 无返回值
     * 2.int 返回操作数据库表的记录数
     * 3.boolean 根据返回数据库表影响的记录数,来判断是否成功
     *          注意:影响的记录数大于等于1,返回值为true,否则为false
     */
    public void insertEmp(Emp emp);
    public void updateEmp(Emp emp);
    public void deleteEmp(Integer empno);
}

映射文件:


<mapper namespace="com.mybatis.mapper.EmpMapper">
    
    <select id="findEmpByEmpno" parameterType="java.lang.Integer" resultType="com.mybatis.entity.Emp">
      select empno,ename,job,mgr,hiredate,sal,comm from emp where empno=#{abc}
    select>

    
    <select id="findEmp" resultType="com.mybatis.entity.Emp">
      select empno,ename,job,mgr,hiredate,sal,comm from emp order by empno desc
    select>

    
    <insert id="insertEmp" parameterType="com.mybatis.entity.Emp" >
      insert into emp(ename,job,mgr,hiredate,sal,comm)
      values(#{ename},#{job},#{mgr},#{hiredate},#{sal},#{comm})
    insert>
    
    <update id="updateEmp" parameterType="com.mybatis.entity.Emp">
        update emp set ename=#{ename},job=#{job},mgr=#{mgr},hiredate=#{hiredate},
        sal=#{sal},comm=#{comm} where empno=#{empno}
    update>

    
    <delete id="deleteEmp" parameterType="java.lang.Integer">
       delete from emp where empno=#{empno}
    delete>
mapper>

测试:

SqlSession session = MybatisUtil.openSession();
//通过SqlSession对象获得到你指定Mapper接口的代理对象(就是接口的实现类对象)
EmpMapper mapper = session.getMapper(EmpMapper.class);

三、mybatis-config.xml

  MyBatis的全局配置文件mybatis-config.xml,配置内容如下:

  • properties(属性)
  • settings(全局配置参数)
  • typeAliases(类型别名)
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境集合属性对象)
    • environment(环境子属性对象)
      • transactionManager(事务管理)
      • dataSource(数据源)
  • mappers(映射器)

1. properties(属性)

  将数据库连接参数单独配置在db.properties中,只需要在mybatis-config.xml中加载db.properties的属性值。在mybatis-config.xml中就不需要对数据库连接参数硬编码

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis
mysql.username=root
mysql.password=123456

在mybatis-config.xml加载属性文件:


<properties resource="db.properties">
    
    
properties>

注意: MyBatis将按照下面的顺序来加载属性:

  1. 在properties标签体内定义的属性首先被读取
  2. 然后会读取properties标签中resource或url加载的属性,它会覆盖已读取的同名属性
  3. 最后读取parameterType传递的属性,它会覆盖已读取的同名属性

建议:

  1. 不要在properties标签体内添加任何属性值,只将属性值定义在properties文件中
  2. 在properties文件中定义属性名要有一定的特殊性,如:XXXXX.XXXXX.XXXX

2. settings(全局配置参数)

  MyBatis框架在运行时可以调整一些运行参数
  比如:开启二级缓存、开启延迟加载
  可配置参数如下:

Mybatis入门操作_第3张图片
Mybatis入门操作_第4张图片

3. typeAliases(类型别名)

  在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发

3.1 MyBatis默认支持别名

别名 映射的类型 别名 映射的类型
_byte byte byte java.lang.Byte
_short short short java.lang.Short
_int int int java.lang.Integer
_integer int integer java.lang.Integer
_long long long java.lang.Long
_float float float java.lang.Float
_double double double java.lang.Double
_boolean boolean boolean java.lang.Boolean
string java.lang.String date java.util.Date
map java.util.Map hashmap java.util.HashMap
list java.util.List arraylist java.util.ArrayList
object java.lang.Object

3.2 自定义别名

单个定义别名:

<typeAliases>
    
    <typeAlias type="com.mybatis.entity.Dept" alias="abc"/>
typeAliases>


<select id="findDeptById" parameterType="int" resultType="abc">
    select deptno,dname,loc from dept where deptno=#{deptno}
select>

批量定义别名:

<typeAliases>
    
    <package name="com.mybatis.entity"/>
typeAliases>

4. typeHandlers(类型处理器)

  MyBatis中通过typeHandlers完成jdbc类型和Java类型的转换,MyBatis自带的类型处理器基本上满足日常需求,不需要单独定义

MyBatis支持类型处理器:

类型处理器 Java类型 JDBC类型
BooleanTypeHandler Boolean,boolean 任何兼容的布尔值
ByteTypeHandler Byte,byte 任何兼容的数字或字节类型
ShortTypeHandler Short,short 任何兼容的数字或短整型
IntegerTypeHandler Integer,int 任何兼容的数字和整型
LongTypeHandler Long,long 任何兼容的数字或长整型
FloatTypeHandler Float,float 任何兼容的数字或单精度浮点型
DoubleTypeHandler Double,double 任何兼容的数字或双精度浮点型
BigDecimalTypeHandler BigDecimal 任何兼容的数字或十进制小数类型
StringTypeHandler String CHAR和VARCHAR类型
ClobTypeHandler String CLOB和LONGVARCHAR类型
NStringTypeHandler String NVARCHAR和NCHAR类型
NClobTypeHandler String NCLOB类型
ByteArrayTypeHandler byte[] 任何兼容的字节流类型
BlobTypeHandler byte[] BLOB和LONGVARBINARY类型
DateTypeHandler java.util.Date TIMESTAMP类型
DateOnlyTypeHandler java.util.Date DATE类型
TimeOnlyTypeHandler java.util.Date TIME类型
SqlTimestampTypeHandler java.sql.Timestamp TIMESTAMP类型
SqlDateTypeHandler java.sql.Date DATE类型
SqlTimeTypeHandler java.sql.Time TIME类型
ObjectTypeHandler 任意 其他或未指定类型
EnumTypeHandler Enumeration类型 VARCHAR-任何兼容的字符串类型,作为代码存储(而不是索引)

5. mappers(映射器)

5.1 单个加载映射文件

通过resource加载单个映射文件

<mappers>
    
    <mapper resource="com/mybatis/mapper/DeptMapper.xml"/>
    <mapper resource="com/mybatis/mapper/EmpMapper.xml"/>
mappers>

通过mapper接口加载单个映射文件

  • 前提:使用的是mapper代理方法
  • 遵循规范:需要将Mapper接口类名和mapper.xml映射文件名称保持一致且在一个目录中
<mappers>
    
    <mapper class="com.mybatis.mapper.DeptMapper"/>
    <mapper class="com.mybatis.mapper.EmpMapper"/>
mappers>

5.2 批量加载映射文件

  指定Mapper接口的包名,MyBatis自动扫描包下边所有Mapper接口进行加载
  遵循规范:与mapper接口加载单个映射文件一致

<mappers>
    
    <package name="com.mybatis.mapper"/>
mappers>

四、mapper.xml

  mapper.xml映射文件中定义了操作数据库的Sql,每个Sql是一个statement,映射文件是MyBatis的核心

1. parameterType输入映射

1.1 简单类型

<select id="findUsersByRealname" parameterType="string" resultType="Users">
    select userid,username,password,realname from users where realname like #{realname}
select>

1.2 实体类或pojo类型

  开发中通过实体类或pojo类型传递查询条件,查询条件是综合的查询条件,不仅包括实体类中查询条件还包括其它的查询条件,这时可以使用包装对象传递输入参数

实体类:Users和Pagebean

//实体类
public class Users{
    private Integer userid;
    private String username;
    private String password;
    private String realname;
    //get,set方法省略...
}
//页时使用的pojo对象
public class Pagebean {
    private int page;
    private int pageSize;
    private int maxCount;
    private int maxPage;
    private int offset;
    //get,set方法省略...
}

复合实体类:UsersQuery

public class UsersQuery {
    private Users users;
    private Pagebean pagebean;
    //get,set方法省略...
}

映射文件:

<select id="findUsersByRealnameAndPage" parameterType="UsersQuery" resultType="Users">
    select 
        userid,username,password,realname from users
    where 
        realname like #{users.realname}
    order by userid 
    limit #{pagebean.offset},#{pagebean.pageSize}
select>

1.3 Map类型

<select id="findUsersWithMap" parameterType="map" resultType="Users">
    select 
        userid,username,password,realname from users
    where 
        realname like #{map_realname}
    order by userid 
    limit #{map_offset},#{map_size}
select>

1.4 多输入参数

  MyBatis中允许有多个输入参数,可使用@Param注解来表示

/**
* @Param注解可以实现多个输入参数
* 每个输入参数前必须使用@Param注解
* 注解中value属性的值为获取此参数值的key
*
* 多参数使用了注解之后,mybatis就将这些注解中value属性值与参数值存放一个map集合中
* 其中value属性值为map集合的key
* 参数值为map集合value
*
* 使用此种方法可以省略paramterType的配置
*/
public Users login(@Param(value = "uname") String username, @Param("pwd") String password);

  这种做法类似与Map类型的输入参数,其中@Param注解的value属性值为Map的key,在映射文件中通过ognl可获取对应的value,并且parameterType可以不指定类型

<select id="login" resultType="Users">
    select userid,username,password,realname from users
    where username=#{uname} and password=#{pwd}
select>

2. resultType输出映射

2.1 简单类型

  查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射

public int findUsersCount();
<select id="findUsersCount" resultType="int">
    select count(*) from users
select>

2.2 实体类对象和列表

  不管是输出的实体类是单个对象还是一个列表(list中包括实体类对象),在mapper.xml中resultType指定的类型是一样的
  在原始Dao的方式中,通过selectOne和selectList方法来区分返回值为单个对象或集合列表,而在mapper代理中,则通过接口中定义的方法返回值来区分

public Users findUsersByUserid(Integer userid);
public List<Users> findUsers();
<select id="findUsersByUserid" parameterType="int" resultType="Users">
    select userid,username,password,realname from users where userid=#{userid}
select>
<select id="findUsers" resultType="Users">
    select userid,username,password,realname from users order by userid
select>

2.3 resultMap

  • resultType可以指定将查询结果映射为实体类,但需要实体类的属性名和Sql查询的列名一致方可映射成功
  • 如果Sql查询字段名和实体类的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系,resultMap实质上还会将查询结果映射到实体类对象中
  • resultMap可以实现将查询结果映射为复合型的实体类,比如在查询结果映射对象中包括实体类和list实现一对一查询和一对多查询

定义resultMap


<resultMap id="usersResultMap" type="Users">
    <id property="userid" column="id"/>
    <result property="username" column="uname"/>
    <result property="password" column="pwd"/>
    <result property="realname" column="rname"/>
resultMap>

使用resultMap作为statement的输出映射类型

<select id="findUsersWithResultMap" resultMap="usersResultMap">
    select userid id,username uname,password pwd,realname rname from users
select>

3. 动态Sql

3.1 什么是动态Sql

  动态Sql是指MyBatis核心对Sql语句进行灵活操作,通过表达式进行判断,对Sql进行灵活拼接、组装

3.2 if标签

  将实体类不为空的属性作为where条件

<select id="findEmpUseIf" parameterType="map" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    where 1=1
    
    <if test="ename!=null and ename!=''">
            and ename like #{ename}
    if>
    <if test="sal!=null and sal!=0.0">
        and sal=#{sal}
    if>
    <if test="deptno!=null and deptno!=0">
        and deptno=#{deptno}
    if>
select>

3.2 where标签

  where标签中包含的任意if条件如果成立,它就插入一个where关键字。此外,如果标签返回的内容是以AND 或OR 开头的,则它会自动剔除掉

<select id="findEmpUseWhere" parameterType="map" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    <where>
    <if test="ename!=null and ename!=''">
        and ename like #{ename}
    if>
    <if test="sal!=null and sal!=0.0">
        and sal=#{sal}
    if>
    <if test="deptno!=null and deptno!=0">
        and deptno=#{deptno}
    if>
    where>
select>

3.3 set标签

  当在update语句中使用if标签时,如果前面的if没有执行,则或导致逗号多余错误。使用set标签可以将动态的配置SET关键字,和剔除追加到条件末尾的任何不相关的逗号
  注意:如果set包含的内容为空的话则会出错

<update id="updateEmpUseSet" parameterType="Emp">
    update emp
    <set>
        <if test="ename!=null">
            ename=#{ename},
        if>
        <if test="job!=null">
            job=#{job},
        if>
        <if test="mgr!=null">
            mgr=#{mgr},
        if>
        <if test="sal!=null">
            sal=#{sal},
        if>
        <if test="comm!=null">
            comm=#{comm},
        if>
        <if test="hiredate!=null">
            hiredate=#{hiredate},
        if>
    set>
        where empno=#{empno}
update>

3.4 trim标签

trim标签属性解析:

  • prefix:前缀,包含内容前加上某些字符
  • suffix:后缀,包含内容后加上某些字符
  • prefixOverrides:剔除包含内容前的某些字符
  • suffixOverrides:剔除包含内容后的某些字符

trim来代替where标签的功能

<select id="findEmpUseTrim" parameterType="Emp" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    <trim prefix="where" prefixOverrides="and|or">
        <if test="ename!=null">
            and ename like #{ename}
        if>
        <if test="sal!=null and sal!=0.0">
            and sal=#{sal}
        if>
        <if test="job!=null">
            and job=#{job}
        if>
    trim>
select>

trim来代替set标签的功能

<update id="updateEmpUseTrim" parameterType="Emp">
    update emp
    <trim prefix="set" suffixOverrides=",">
        <if test="ename!=null">
            ename=#{ename},
        if>
        <if test="job!=null">
            job=#{job},
        if>
        <if test="mgr!=null">
            mgr=#{mgr},
        if>
        <if test="sal!=null">
            sal=#{sal},
        if>
        <if test="comm!=null">
            comm=#{comm},
        if>
        <if test="hiredate!=null">
            hiredate=#{hiredate},
        if>
    trim>
    where empno=#{empno}
update>

trim实现insert语句

<insert id="insertEmpUseTrim" parameterType="Emp">
    insert into emp
    <trim suffix="(" prefix=")" prefixOverrides=",">
        <if test="ename!=null">
            ename,
        if>
        <if test="job!=null">
            job,
        if>
        <if test="mgr!=null">
            mgr,
        if>
        <if test="hiredate!=null">
            hiredate,
        if>
        <if test="sal!=null">
            sal,
        if>
        <if test="comm!=null">
            comm,
        if>
    trim>
    <trim prefix=" values(" suffix=")" suffixOverrides=",">
        <if test="ename!=null">
            #{ename},
        if>
        <if test="job!=null">
            #{job},
        if>
        <if test="mgr!=null">
            #{mgr},
        if>
        <if test="hiredate!=null">
            #{hiredate},
        if>
        <if test="sal!=null">
            #{sal},
        if>
        <if test="comm!=null">
            #{comm},
        if>
    trim>
insert>

3.5 foreach标签

  • 向Sql传递数组或list,MyBatis使用foreach解析
  • Sql只接收一个数组参数,这时sql解析参数的名称MyBatis固定为array
  • Sql只接收一个List参数,这时sql解析参数的名称MyBatis固定为list
  • 如果是通过一个实体类或pojo的属性传递到Sql的数组或list,则参数的名称为实体类或pojo中的属性名

属性解析:

  • index:为数组的下标
  • item:每个遍历生成对象中
  • open:开始遍历时拼接的串
  • close:结束遍历时拼接的串
  • separator:遍历的两个对象中需要拼接的串
public void deleteEmpUseForeachArray(int[] empnos);
public List<Emp> findEmpUseForeachList(List<Integer> empnos);
public List<Emp> findEmpUseForeachPojo(EmpQuery query);
<delete id="deleteEmpUseForeachArray" parameterType="int">
    delete from emp where empno in
    <foreach collection="array" open="(" close=")" separator="," item="id">
        #{id}
    foreach>
delete>

<select id="findEmpUseForeachList" parameterType="int" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    where empno in
    <foreach collection="list" open="(" close=")" separator="," item="empno">
        #{empno}
    foreach>
select>

<select id="findEmpUseForeachPojo" parameterType="EmpQuery" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    where deptno in
    <foreach collection="deptnos" open="(" close=")" separator="," item="deptno">
        #{deptno}
    foreach>
select>

3.6 choose,when,otherwise标签

  if-else-if判断

<select id="">
    select...
    <choose>
        <when test="">

        when>
        <when test="">

        when>
        <otherwise>

        otherwise>
    choose>
select>

3.7 Sql片段

  将实现的动态Sql判断代码块抽取出来,组成一个Sql片段,其它的statement中就可以引用Sql片段,方便程序员进行开发
  注意:在sql片段中不要包括where标签

<select id="findEmpUseSql" parameterType="map" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    <where>
        
        <include refid="empSql"/>
    where>
select>

<sql id="empSql">
    <if test="ename!=null">
        and ename like #{ename}
    if>
    <if test="sal!=null and sal!=0.0">
        and sal=#{sal}
    if>
    <if test="deptno!=null and deptno!=0">
        and deptno=#{deptno}
    if>
sql>

五、关联查询

1. 数据模型分析

Mybatis入门操作_第5张图片

表功能介绍

  • 用户表:记录用户的基本信息
  • 订单表:记录用户所创建的订单(购买商品的订单)
  • 订单详情表:记录订单的详细信息即购买商品的信息
  • 商品表:记录商品的基本信息

表与表之间的业务关系

  1. 用户表和订单表:
    用户表---->订单表:一个用户可以创建多个订单,一对多关系
    订单表---->用户表:一个订单只由一个用户创建,一对一关系
  2. 订单表和订单详情表:
    订单表---->订单详情表:一个订单可以包含多个订单详情,因为一个订单可以购买多个商品,每个商品的购买信息在订单详情表中记录,一对多关系
    订单详情表----->订单表:一个订单详情只能包括在一个订单中,一对一关系
  3. 订单详情表和商品表:
    订单详情表---->商品表:一个订单详情只对应一个商品信息,一对一关系
    商品表---->订单详情表:一个商品可以包括在多个订单详情,一对多关系
  4. 订单表和商品表:
    订单表<---->商品表:一个订单中包含多个商品,一个商品可以添加在多个订单中,两者是通过订单详情表建立关系,多对多关系

2. 一对一查询

2.1 resultType

2.1.1 Sql语句
SELECT 
    id, order_number,totalprice,status,u.userid,username,password,realname
FROM 
    orders o,users u 
WHERE 
    o.userid=u.userid
2.1.2 实体类
public class Users {
    private Integer userid;
    private String username;
    private String password;
    private String realname;
    //get,set方法省略...
}
public class Orders {
    private Integer id;
    private String order_number;
    private Double totalPrice;
    private String status;
    //get,set方法省略...
}

原始的Orders类不能映射全部字段,需要新创建的实体类,创建一个包括查询字段较多的实体类
OrdersUsers中包含了Orders以及Users需要查询的属性

public class OrdersUsers {
    /**
     * 对应orders表中的字段
     */
    private Integer id;
    private String order_number;
    private Double totalPrice;
    private String status;
    /**
     * 对象users表中的字段
     */
    private Integer userid;
    private String username;
    private String password;
    private String realname;
}
2.1.3 Mapper接口
public List<OrdersUsers> findOrdersUseResultType();
2.1.4 mapper.xml
<select id="findOrdersUseResultType" resultType="OrdersUsers">
    SELECT 
        id, order_number,totalprice,status,u.userid,username,password,realname
    FROM 
        orders o,users u 
    WHERE 
        o.userid=u.userid
select>
2.1.5 测试
SqlSession session = MybatisUtil.openSession();

OrderMapper mapper = session.getMapper(OrderMapper.class);
List<OrdersUsers> list = mapper.findOrdersUseResultType();
for (OrdersUsers ou : list) {
    System.out.println(ou);
}
session.close();

2.2 resultMap

2.2.1 Sql语句
SELECT 
    id, order_number,totalprice,status,u.userid,username,password,realname
FROM 
    orders o,users u 
WHERE 
    o.userid=u.userid
2.2.2 实体类

  在Orders类中加入Users属性,Users属性用于存储关联查询的用户信息,因为订单关联查询用户是一对一关系,所以这里使用单个Users对象存储关联查询的用户信息

public class Users {
    private Integer userid;
    private String username;
    private String password;
    private String realname;
    //get,set方法省略...
}
public class Orders {
    private Integer id;
    private String order_number;
    private Double totalPrice;
    private String status;
    /**
     * 一对一/多对一依赖关系属性
     */
    private Users users;
    //get,set方法省略...
}
2.2.3 Mapper接口
public List<Orders> findOrdersUseResultMap();
2.2.4 mapper.xml
<resultMap id="ordersUsersResultMap" type="Orders">
    <id column="id" property="id"/>
    <result column="order_number" property="order_number"/>
    <result column="totalprice" property="totalPrice"/>
    <result column="status" property="status"/>
    <association property="users" javaType="Users">
        <id column="userid" property="userid"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="realname" property="realname"/>
    association>
resultMap>
<select id="findOrdersUseResultMap" resultMap="ordersUsersResultMap">
    SELECT 
        id, order_number,totalprice,status,u.userid,username,password,realname
    FROM 
        orders o,users u 
    WHERE 
        o.userid=u.userid
select>
2.2.5 测试
SqlSession session = MybatisUtil.openSession();

OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersUseResultMap();
for (Orders o : list) {
    System.out.println(o);
}
session.close();

2.3 resultType和resultMap实现一对一查询小结

  • resultType:使用resultType实现较为简单,如果实体类中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果查询结果没有特殊要求,建议使用resultType
  • resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射到实体类的属性中
  • resultMap可以实现延迟加载,resultType无法实现延迟加载

3. 一对多查询

3.1 Sql语句

SELECT 
	o.id,order_number,totalprice,status,d.id detailid,amount,goods_id 
FROM 
	orders o,ordersdetail d
WHERE 
    o.id=d.orders_id

3.2 实体类

  在Order类中加入List details属性,details属性用于存储关联查询的订单详情,因为订单关联查询订单详情是一对多关系,所以这里使用集合对象存储关联查询的订单详情信息

public class OrdersDetail {
    private Integer id;
    private Integer amount;
    private Integer goods_id;
    //get,set方法省略...
}
public class Orders {
    private Integer id;
    private String order_number;
    private Double totalPrice;
    private String status;
    /**
     * 一对多,多对多依赖关系属性
     */
    private List<OrdersDetail> details;
    //get,set方法省略...
}

3.2 Mapper接口

public List<Orders> findOrdersAndOrdersDetail();

3.3 mapper.xml

<resultMap id="ordersAndDetailResultMap" type="Orders">
    <id column="id" property="id"/>
    <result column="order_number" property="order_number"/>
    <result column="totalprice" property="totalPrice"/>
    <result column="status" property="status"/>
    
    <collection property="details" ofType="OrdersDetail">
        <id column="detailid" property="id"/>
        <result column="amount" property="amount"/>
        <result column="goods_id" property="goods_id"/>
    collection>
resultMap>
<select id="findOrdersAndOrdersDetail" resultMap="ordersAndDetailResultMap">
    SELECT 
        o.id,order_number,totalprice,status,d.id detailid,amount,goods_id 
    FROM 
        orders o,ordersdetail d
    WHERE 
        o.id=d.orders_id
select>

3.4 测试

SqlSession session = MybatisUtil.openSession();

OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersAndOrdersDetail();
for (Orders orders : list) {
    System.out.println(orders);
}
session.close();

4. 多对多查询

4.1 订单与商品之间的多对多关系

4.1.1 Sql语句
SELECT
    o.id,order_number,totalprice,status,d.id detailid,amount,goods_id,gname,descr,price
FROM
    orders o,ordersdetail d,goods g
WHERE
    o.id=d.orders_id 
AND 
    d.goods_id=g.id
4.1.2 实体类

  将Orderdetail类中Integer goods_id属性修改为Goods goods属性,goods属性用于存储关联查询的商品信息。订单与订单详情是一对多关系,订单详情与商品是一对一关系,反之商品与订单详情是一对多关系,订单详情与订单是一对一关系,所以订单与商品之前为多对多关系

public class Goods {
    private Integer id;
    private String gname;
    private String descr;
    private Double price;
    //get,set方法省略...
}
public class OrdersDetail {
    private Integer id;
    private Integer amount;
    /**
     * 一对一依赖关系属性
     */
    private Goods goods;
    //get,set方法省略...
}
public class Orders {
    private Integer id;
    private String order_number;
    private Double totalPrice;
    private String status;
    /**
     * 一对多,多对多依赖关系属性
     */
    private List<OrdersDetail> details;
    //get,set方法省略...
}
4.1.3 Mapper接口
public List<Orders> findOrdersAndGoods();
4.1.4 mapper.xml
<resultMap id="ordersAndGoodsResultMap" type="Orders">
    <id column="id" property="id"/>
    <result column="order_number" property="order_number"/>
    <result column="totalprice" property="totalPrice"/>
    <result column="status" property="status"/>
    <collection property="details" ofType="OrdersDetail">
        <id column="detailid" property="id"/>
        <result column="amount" property="amount"/>
        <association property="goods" javaType="Goods">
            <id column="goods_id" property="id"/>
            <result column="gname" property="gname"/>
            <result column="descr" property="descr"/>
            <result column="price" property="price"/>
        association>
    collection>
resultMap>
<select id="findOrdersAndGoods" resultMap="ordersAndGoodsResultMap">
    SELECT
        o.id,order_number,totalprice,status,d.id detailid,amount,goods_id,gname,descr,price
    FROM
        orders o,ordersdetail d,goods g
    WHERE
        o.id=d.orders_id 
    AND 
        d.goods_id=g.id
select>
4.1.5 测试
SqlSession session = MybatisUtil.openSession();

OrderMapper mapper = session.getMapper(OrderMapper.class);
List<Orders> list = mapper.findOrdersAndGoods();
for (Orders orders : list) {
    System.out.println(orders);
}
session.close();

4.2 学生与课程之间的多对多关系

4.2.1 Sql语句
SELECT 
    s.id,name,gender,major,course_id,cname 
FROM 
    student s,student_course sc,course c
WHERE 
    s.id=sc.student_id
AND 
    sc.course_id=c.id
4.2.2 实体类
public class Course {
    private Integer id;
    private String cname;
    //get,set方法省略...
}
public class Student {
    private Integer id;
    private String name;
    private String gender;
    private String major;
    /**
     * 多对多的依赖关系属性
     */
    private List<Course> courses;
    //get,set方法省略...
}
4.2.3 Mapper接口
public List<Student> findStudent();
4.2.4 mapper.xml
<resultMap id="studentAndCourseResultMap" type="Student">
    <id column="id" property="id"/>
    <result column="NAME" property="name"/>
    <result column="gender" property="gender"/>
    <result column="major" property="major"/>
    <collection property="courses" ofType="Course">
        <id column="course_id" property="id"/>
        <result column="cname" property="cname"/>
    collection>
resultMap>
<select id="findStudent" resultMap="studentAndCourseResultMap">
    SELECT 
        s.id,name,gender,major,course_id,cname 
    FROM 
        student s,student_course sc,course c
    WHERE 
        s.id=sc.student_id
    AND 
        sc.course_id=c.id
select>
4.2.5 测试
SqlSession session = MybatisUtil.openSession();

StudentMapper mapper = session.getMapper(StudentMapper.class);
List<Student> list = mapper.findStudent();
for (Student student : list) {
    System.out.println(student);
}
session.close();

5. 关联查询总结

5.1 resultType

  作用:将查询结果按照Sql列名与实体类属性名一致性映射到实体类对象中
  场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到实体类中,在前端页面遍历list(list中是实体类)即可

5.2 resultMap

  使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)

5.2.1 association

  作用:将关联查询信息映射到一个实体类对象中
  场合:为了方便查询关联信息可以使用association将关联信息映射为当前对象的一个属性,比如:查询订单以及关联用户信息

5.2.2 collection

  作用:将关联查询信息映射到一个list集合中
  场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。如果使用resultType无法将查询结果映射到list集合中

5.2.3 resultMap的继承

  resultMap标签可以通过extends属性来继承一个已有的或公共的resultMap,避免重复配置的出现,减少配置量。例子如下:


<resultMap id="ordersRusultMap" type="Orders">
    <id column="id" property="id"/>
    <result column="order_number" property="order_number"/>
    <result column="totalprice" property="totalPrice"/>
    <result column="status" property="status"/>
resultMap>

<resultMap id="ordersUsersResultMap" type="Orders" extends="ordersRusultMap">
    <association property="users" javaType="Users">
        <id column="userid" property="userid"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="realname" property="realname"/>
    association>
resultMap>

六、延迟加载

1. 什么是延迟加载

  • 需要查询关联信息时,使用MyBatis延迟加载特性可有效的减少数据库压力,首次查询只查询主要信息,关联信息等用户获取时再加载
  • resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能

2. 打开延迟加载开关

  在MyBatis核心配置文件中配置:lazyLoadingEnabled、aggressiveLazyLoading

设置项 描述 允许值 默认值
lazyLoadingEnabled 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载 true \ false false
aggressiveLazyLoading 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载 true \ false true

<settings>
    
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
settings>

3. 使用association实现延迟加载

  查询员工以及相关联的部门信息

3.1 Mapper接口

public List<Emp> findEmp();

3.2 mapper.xml

  查询员工信息

<select id="findEmp" resultMap="empResultMap">
    select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp
select>

  查询关联的部门信息
  通过上边查询到的员工信息中deptno外键去关联查询部门信息,所以需要定义一个根据ID查询部门的语句

<select id="findDeptByDeptno" parameterType="int" resultType="Dept">
    select deptno,dname,loc from dept where deptno=#{deptno}
select>

  resultMap配置

<resultMap id="empResultMap" type="Emp">
    <id column="empno" property="empno"/>
    <result column="ename" property="ename"/>
    <result column="job" property="job"/>
    <result column="mgr" property="mgr"/>
    <result column="hiredate" property="hiredate"/>
    <result column="sal" property="sal"/>
    <result column="comm" property="comm"/>
    
    
    <association property="dept" javaType="Dept" select="com.mybatis.mapper.DeptMapper.findDeptByDeptno" column="deptno">
    association>
resultMap>

4. 使用collection实现延迟加载

4.1 Mapper接口

public List<Dept> findDept();

4.2 mapper.xml

  查询部门信息

<select id="findDept" resultMap="deptResultMap">
    select deptno,dname,loc from dept
select>

  查询关联的员工详情信息
  通过查询到的部门信息中deptno去关联查询员工详情,所以需要定义一个根据部门ID查询员工详情的语句

<select id="findEmpByDeptno" parameterType="int" resultType="Emp">
    select empno,ename,job,mgr,hiredate,sal,comm from emp
    where deptno=#{deptno}
select>

  resultMap配置

<resultMap id="deptResultMap" type="Dept">
    <id column="deptno" property="deptno"/>
    <result column="dname" property="dname"/>
    <result column="loc" property="loc"/>
    <collection property="empList" ofType="Emp" select="com.mybatis.mapper.EmpMapper.findEmpByDeptno" column="deptno"/>
resultMap>

你可能感兴趣的:(java,mysql,mybatis,orm,java)