mybatis所有要点

Mybatis

一、Mybatis简介

1.1 认识mybatis

​ MyBatis 是Apache的一个开源项目iBatis,是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。

​ 简单的说:MyBatis是一个半自动ORM框架,其本质是对JDBC的封装。使用MyBatis重点需要程序员编写SQL命令,不需要写一行JDBC代码。

1.2 mybatis和Hibernate

  • Mybatis半自动化框架
表需要手动进行设计
依赖数据库平台
优化灵活,合适做互联网项目
  • Hibernate自动化ORM框架
表可以通过框架自动创建
省略一些基本的SQL
不依赖于数据库平台
优化难度大,不适合做大型互联网项目

二、Mybatis环境搭建

2.1 创建java项目

2.2 导入jar包

2.2.1 mybatis核心包

在这里插入图片描述

2.2.2 mybatis依赖jar包

在这里插入图片描述

2.2.3 数据库驱动jar包

在这里插入图片描述

2.3 配置mybatis.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>
    <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/xxxx/mappers/DeptMapper.xml"/>
        <mapper resource="com/homework/mapper/EmpMapper.xml"/>
    </mappers>
</configuration>

2.4 mybatis SQL映射文件

<?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">
<!--namespace:映射文件的包名+xml的名称-->
<mapper namespace="com.xxxx.mappers.DeptMapper">
    <select id="queryAll" resultType="com.xxxx.pojo.Dept">
    select deptno,dname,loc from dept
  </select>
</mapper>

2.5 log4j

​ log4j分为五个级别:DEBUG(人为调试信息)、INFO(普通信息)、WARN(警告)、ERROR(错误)和FATAL(系统错误)。

​ 这五个级别的顺序分别为:DEBUG < INFO < WARN < ERROR < FATAL。

注意:使用log4j打印时除了要导入相应的jar包之外,还要在src下建立一个log4j.properties的配置文件

# Set root category priority to INFO and its only appender to CONSOLE.
# log4j.rootCategory=DEBUG, CONSOLE
#log4j.rootCategory=INFO, CONSOLE, LOGFILE
log4j.rootLogger=info,stdout

# 单独设置SQL语句的输出级别为DEBUG级别
# 方法级别
# log4j.logger.com.xxxx.mappers.EmpMapper.queryAll=DEBUG
# 类级别
# log4j.logger.com.xxxx.mappers.EmpMapper=DEBUG
# 包级别
log4j.logger.com.xxxx.mappers=DEBUG

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.SimpleLayout

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender 
log4j.appender.LOGFILE.File=D:/test.log
log4j.appender.LOGFILE.Append=true 
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout 
log4j.appender.logfile.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %l %F %p %m%n

2.6测试

public class DeptDemo01 {
    public static void main(String[] args) throws IOException {
        //获取配置文件
        InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

        //创建SqlSessionFactory
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(in);

        //获取会话对象
        SqlSession sqlSession = sessionFactory.openSession();

        //执行sql语句
        List<Dept> list = sqlSession.selectList("com.xxxx.mappers.DeptMapper.queryAll");
        list.forEach(System.out::println);

        sqlSession.close();
    }
}

三、Mybatis配置的完善

3.1 使用别名alias

作用:用来减少类完成全限定名的多于部分,别名都是大小写不敏感的

不使用别名

<!--要指定返回类型的具体类型-->
<select id="queryAll" resultType="com.xxxx.pojo.dept">
    select deptno,dname,loc from dept
</select>

使用package指定某个包下所有类的默认别名

<!--表示pojo包下的所有实体类的别名就是类名,存在mybatis的配置文件中-->
<typeAliases>
   <package name="com.xxxx.pojo"/>
</typeAliases>

使用别名之后

<select id="queryAll" resultType="dept">
    select deptno,dname,loc from dept
</select>

3.2 引入属性文件(properties)

用法:将driver,url,userName,passWord分装进一个src目录下的jdbc.properties当中,需要使用的时候取出

<configuration>
    <properties resource="db.properties"/>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/xxxx/mappers/DeptMapper.xml"/>
    </mappers>
</configuration>

四、parameterType入参类型

4.1 传入一个参数的查询

<select id="queryById" parameterType="int" resultType="emp">
     select * from emp where empno=#{empno}
</select>
//通过ID查询员工信息
Emp  emp = sqlSession.selectOne("com.xxxx.mappers.EmpMapper.queryById", 7369);

4.2 多个参数查询

<!-- 根据员工姓名和薪资查询员工信息 -->
<select id="queryByEmp" parameterType="emp" resultType="emp">
    select * from emp where ename = #{ename} and sal = #{sal}
</select>
Emp e = new Emp();
e.setename("SMITH");
e.setSal(800.00);
List<Emp> list4 = sqlSession.selectList("com.xxxx.mappers.EmpMapper.queryByEmp",e);

4.3 入参类型

parameterType类型有:基本数据类型(四类八种) 包装类 String Date Javabean Map List 数组

4.3.1 基本数据类型、包装类、String
<!-- 通过ID查询员工信息 -->
<select id="queryById" parameterType="int" resultType="emp">
   select * from emp where empno=#{empno}
</select>
Emp  emp = sqlSession.selectOne("com.xxxx.mappers.EmpMapper.queryById", 7369);
4.3.2 javaBean类型
<!-- 根据员工姓名和薪资查询员工信息 -->
<select id="queryByEmp" parameterType="emp" resultType="emp">
    select * from emp where ename = #{ename} and sal = #{sal}
</select>
Emp e = new Emp();
e.setename("SMITH");
e.setSal(800.00);
List<Emp> list4 = sqlSession.selectList("com.xxxx.mappers.EmpMapper.queryByEmp",e);
4.3.3 map
<!-- 入参类型: Map 根据多个id,查询用户信息-->
<select id="queryUserByIdMap" parameterType="map"
resultType="user">
select * from t_user where id = #{id1} or id=#{id2}
</select>
Map<String,Object> paras = new HashMap();
paras.put("id1", 131);
paras.put("id2", 132);
List<User>
list=session.selectList("com.shsxt.mapper.UserMapper.queryUserByIdMap", paras);
4.3.4 List、数组
<!-- 根据员工编号信息,collection表示传入的集合 -->
<select id="queryByList"  resultType="emp">
   select * from emp where empno in (
    <foreach collection="list" item="args" separator=",">
        #{args}
     </foreach>
    )
</select>
List list5= Arrays.asList(7369,7521,7900);
List<Emp> list6 = sqlSession.selectList("com.xxxx.mappers.EmpMapper.queryByList", list5);

4.3.5 Date

<!-- 查看指定日期入职的员工信息 -->
<select id="queryByDate" parameterType="date" resultType="emp">
   select * from emp where hiredate=#{hiredate}
</select>
//查看指定日期入职的员工信息
Date date = new SimpleDateFormat("yyyy/MM/dd").parse("1981/12/3");
List<Emp> list3 = sqlSession.selectList("com.xxxx.mappers.EmpMapper.queryByDate",date);

五、普通查询方式

5.1 三个查询方法(无接口)

  • selectList(“命名空间.id”) 用户查询多条数据情况,返回一个List集合, 没有
    查到数据返回空集合,不是null
List<User> list =
session.selectList("com.shsxt.mappers.UserMapper.queryAll");
System.out.println(list);
  • selectOne(“命名空间.id”) 用于查询单条数据,返回一个数据, 如果没有查
    到返回null
String name = session.selectOne("com.xxxx.mappers.EmpMapper2.queryNameById",7369);
  • selectMap(“命名空间.id”,key的字段名) 用于查询多条记录情况, 返回Map
    集合, 需要指定那个属性作为key, sql查询结果作为value,指定的字段值作
    为key, 如果查不到, 返回一个空map集合,不是null
//3)selectMap("namespace.id","执行作为key的属性")
Map<Integer,User> map =
session.selectMap("com.shsxt.mappers.UserMapper.queryAll",
"id");

六、使用Mapper代理(接口绑定)(重点)

​ 前面已经使用MyBatis完成了对Emp表的CRUD操作,都是由SqlSession调用自身方法发送SQL命令并得到结果的。

6.1 使用Mapper代理的方式

6.1.1 接口的定义
public interface EmpMapper {
    //查询所有
    List<Emp> findAll();
}
6.1.2 映射文件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.xxxx.mappers.EmpMapper">
    <select id="findAll" resultType="emp">
        select * from emp
    </select>
</mapper>
6.1.3 在核心配置文件中扫描接口

(1)扫描单个接口

<mappers>
   <mapper class="com.shsxt.mapper.UserMapper"/>
</mappers>

(2)扫描多个接口

<mappers>
    <package name="com.shsxt.mapper"/>
</mappers>
6.1.4 使用方式
public void test(){
//获取session会话对象,MybatisUtils为自己封装的工具类
SqlSession session = MybatisUtils.getSession();
//获取接口的实现类对象
UserMapper mapper=session.getMapper(UserMapper.class);
//通过对象调用方法
List<User> list = mapper.queryAll();
list.foreach(System.out::println);
session.close();
 }

6.2 Mapper代理模式下的参数处理

6.2.1 多参数传递
  • 方式一:在接口中直接传递多个参数

    映射文件中,参数可以使用param1,param2…表示,或者使用arg0,arg1…表示,可读性低。

<select id="selectStudent" resultType="student">
    select * from t_student where sname=#{param1} and spassword=#{param2}
</select>
  • 方式二:在接口中使用Param注解传递多个参数

    映射文件中参数可以使用Param注解指定的名称来表示,同时保留使用param1, param2…表示,但是不可以再使用arg0,arg1…表示。

<select id="selectStudent" resultType="student">
   select * from t_student where sname=#{sName} and spassword=#{sPassword}
</select>
Student selectStudent(@Param("sName") String sName,@Param("sPassword") String sPassword);
  • 方式三:使用JavaBean传递多个参数

    映射文件中的参数直接使用JavaBean的属性来接收,可读性高。底层调用是相应 属性的getter方法。

<insert id="insertStudent" parameterType="student">
    insert into t_student(sno,sname,gender,sbirthday,spassword) values(sq_class_id.nextval,#{sName},#{gender},#{sBirthday},#{sPassword})
</insert>
int insertStudent(Student student);
  • 方式四:使用Map传递多个参数

    映射文件中使用相应参数在map中的key来表示。

七、动态SQL

7.1 if

用于进行条件判断, test 属性用于指定判断条件,为了拼接条件, 在 SQL 语句
后强行添加 1=1 的恒成立条件。(test中的username就是#{username})

<select id="sel" resultType="user">
    select * from t_user where 1=1
    <if test="username != null and username != ''"> 
        and username=#{username} 
    </if>
    <if test="password != null and password != ''"> 
        and password=#{password}
    </if>
</select>

7.2 where

使用这个就不用提供where 1=1 这样的条件了。它的功能有:

  • 会自动添加where关键字
  • 如果第一个条件中存在and,那么将它除去
<select id="selectEmpNameDeptno" resultType="emp">
        select * from emp
        <where>
            <if test="ename!=null and ename!=''">
                and ename=#{ename}
            </if>
            <if test="deptno!=null and deptno!=''">
                and deptno=#{deptno}
            </if>
        </where>
</select>

7.3 choose…when…otherwise

这个相当于switch…case…default

<!--只能根据其中任意一个条件去查-->
<select id="selectEmpno" resultType="emp">
        select * from emp
        <where>
            <choose>
                <when test="ename!=null and ename!=''">
                    and ename=#{ename}
                </when>
                <when test="deptno!=null">
                    and deptno=#{deptno}
                </when>
            </choose>
        </where>
</select>

7.4 set

功能有:

  • 会自动添加set关键字
  • 会自动除去最后一条语句后面的逗号
<update id="updateEmp" parameterType="Emp">
        update emp
        <set>
            empno=#{empno},
            <if test="sal>0">
                sal=#{sal},
            </if>
            <if test="ename!=null and ename!=''">
                ename=#{ename}
            </if>
        </set>
        where empno=#{empno}
</update>

7.5 trim

用于在前后添加或删除一些内容

  • prefix, 在前面添加内容

  • prefixOverrides, 从前面去除内容

  • suffix, 向后面添加内容

  • suffixOverrides, 从后面去除内容

<update id="updateEmp" parameterType="emp">
         update emp
        <trim prefix="set" suffixOverrides=",">
            empno=#{empno},
            <if test="sal>0">
                sal=#{sal},
            </if>
            <if test="ename!=null and ename!=''">
                ename=#{ename},
            </if>
        </trim>
        where empno=#{empno}
</update>

7.6 bind

用于数据的连接,一般多用于模糊查询上面,对所需的数据进行加工

<select id="selectEmpByEname" resultType="emp">
        select <include refid="emp_all"/> from emp
        <where>
            <if test="ename!=null and ename!=''">
                <bind name="ename" value="'%'+ename+'%'"/>
                and ename like #{ename}
            </if>
        </where>
</select>

7.7 foreach

用于在 SQL 语句中遍历集合参数, 在 in 查询中使用

  • collection: 待遍历的集合

  • open: 设置开始符号

  • item: 迭代变量

  • separator: 项目分隔符

  • close: 设置结束符

<select id="selIn" parameterType="list" resultType="user">
     select * from t_user where id in
     <foreach collection="list" open="(" separator="," close=")"item="item"> 
         #{item} 
     </foreach>
</select>

7.8 sql…include

sql用于将相同的、常用的属性给提取出来,include用于引用提取出来的属性

<!--写在与select同级之下-->
<sql id="mySql"> id, username, password </sql>
<select id="selIn" parameterType="list" resultType="user">
    select <include refid="mySql" /> from t_user where id in
    <foreach collection="list" open="(" separator=","close=")"item="item"> 
        #{item}
    </foreach>
</select>

八、 mybatis中的批量处理操作

8.1 批量插入

在测试类中同时创建多个对象,将这些对象批量插入进数据库当中

//批量插入
Emp emp1 = new Emp();
emp1.setEmpno(1);
emp1.setename("zhangsan");
emp1.setDeptno(10);
Emp emp2 = new Emp();
emp2.setEmpno(2);
emp2.setename("李lisi");
emp2.setDeptno(20);
List<Emp> list = Arrays.asList(emp1,emp2);
int rows = mapper.insertEmpSome(list);//Mapper代理接口
System.out.println(rows);
<!-- 批量插入-->
<insert id="insertEmpSome" parameterType="list">
        insert into emp(empno,ename,deptno)
        <foreach collection="list" item="item" separator="union">
            select #{item.empno},#{item.ename},#{item.deptno} from dual
        </foreach>
</insert>

注意:这样写每条插入语句中的select这一段语句是通过union进行连接

insert into emp(empno,ename,deptno)
select #{item.empno},#{item.ename},#{item.deptno} from dual
union
select #{item.empno},#{item.ename},#{item.deptno} from dual

8.2 批量修改

Emp emp1 = new Emp();
emp1.setEmpno(1);
emp1.setename("张三丰");//未修改前为zhangsan,想要修改为张三丰
emp1.setDeptno(10);
Emp emp2 = new Emp();
emp2.setEmpno(2);
emp2.setename("李四丰");//未修改前为lisi,想要修改为李四丰
emp2.setDeptno(20);
List<Emp> list = Arrays.asList(emp1,emp2);
mapper.updateEmpSome(list);
<!--批量修改-->
<update id="updateEmpSome" parameterType="list">
        <foreach collection="list" item="item" open="begin" close=";end;" separator=";">
            update emp set ename=#{item.ename} where empno=#{item.empno}
        </foreach>
</update>

注意:这个实际的sql语句是以begin开头,用分号进行间隔,用;end;结尾

begin
update emp set ename=#{item.ename} where empno=#{item.empno};
update emp set ename=#{item.ename} where empno=#{item.empno};
end;

8.3 批量删除

List<Integer> list2=Arrays.asList(1,2);//传入需要删除的条件(empno)
int rows2=mapper.deleteEmpSome(list2);
System.out.println(rows2);
<!--批量删除-->
<delete id="deleteEmpSome" parameterType="list">
      delete from emp where empno in
      <foreach collection="list" item="item" separator="," open="(" close=")">
            #{item}
       </foreach>
</delete>

注意:这个实际上就是先循环获取传入的empno,循环完毕之后再进行删除

delete from emp where empno in(#{item},#{item},#{item})

九、 mybatis中的缓存机制

9.1 一级缓存

  • 线程级别的缓存,sqlsession级别的缓存,默认是开启的
  • 在一个sqlsession生命周期中有效,当使用同一个会话去对数据库进行查询操作时,只会与数据库进行一次交互
  • 在同一个sqlsession中,mybatis会把执行的方法和参数通过算法生成的键值,将键值存放到一个map中,如果后面有一样的键,那么就能拿到map中的值,从而不再与数据库进行交互,提高了效率
  • 不同的sqlsession之间的缓存是相互隔离的
  • 当sqlsession关闭了,缓存清空
  • 使用update,insert,delete语句会清空缓存

9.2 二级缓存

  • 进程级别的缓存,sqlsessionFactory级别的缓存,默认关闭

  • 在一个sqlsessionFactory生命周期中有效,当使用同一个sqlsessionFactory创建会话去对数据库进行查询操作时,只会与数据库进行一次交互

  • 二级缓存是以namespace为单位的,不同namespace下的操作互不影响

  • 使用insert、update、delete会清空缓存

    开启二级缓存的三个开关:

    1.mybatis核心配置文件中全面开启二级缓存

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    

    2.Mapper映射文件中开启局部二级缓存

    <mapper namespace="com.bjsxt.mapper.EmployeeMapper">
        <cache/>
    </mapper>
    

注意:只有在测试类中执行了commit()操作或者close()操作之后才能将查询的结果从一级缓存放到二级缓存当中

SqlSession sqlSession = factory.openSession();
EmpMapper3 mapper = sqlSession.getMapper(EmpMapper3.class);
Emp emp = mapper.findEmp(7499);
System.out.println(emp);
// sqlSession 只有提交或者close之后才会将数据放入二级缓存
sqlSession.commit();
sqlSession.close();

十、 数据库中列名和实体类的属性名不一致

查询的时候时候使用resultType属性,表示采用mybatis中的Auto-Mapping(自动映射)机制,既相同的列名和表名的属性会自动匹配,但是当数据库的列名和类的属性名不同时,这种自动映射机制就会失效,这时候便需要我们进行手动映射。

10.1 给列取别名

写SQL语句进行查询的时候,对查询的数据库中的列取别名,别名和类的属性名要一致,但是这种方式十分的麻烦。

<select id="selAll" resultType="user">
   select id id1, username username1, password password2 from t_user
</select>

10.2 使用resultMap

使用resultMap去代替resultType。

注意:column等号后面的属性名是数据库中的列名,property等号后面的属性名是实体类中的属性名

<resultMap type="user" id="umap"> 
	<id column="id" property="id1" /> 
	<result column="username" property="username1" />
	<result column="password" property="password1" />	
</resultMap>
<select id="selAll" resultMap="umap"> 
    select id,username,password from t_user
</select>

十一、 多表联合查询

11.1 一对一关联查询

例子:一个员工只能有一个所属部门,emp表中的一条数据对应的dept表中的一条数据

在emp实体类中:

public class Emp  implements Serializable {
    // 对应Emp表格的八个属性
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
    // 对应部门的属性
    private Dept dept;

在映射文件中配置:

<mapper namespace="com.bjsxt.mapper.EmpMapper">
    <!--使用resultMap定义一对一映射关系-->
    <resultMap id="empJoinDept" type="emp">
        <!--处理emp原有的8个属性  名称相同也不能省略 -->
        <id property="empno" column="empno"></id>
        <result property="ename" column="ename"></result>
        <result property="job" column="job"></result>
        <result property="sal" column="sal"></result>
        <result property="hiredate" column="hiredate"></result>
        <result property="mgr" column="mgr"></result>
        <result property="comm" column="comm"></result>
        <result property="deptno" column="deptno"></result>
        <association property="dept" javaType="dept">
            <!--处理一对一属性映射 名称相同也不要省略 -->
            <id property="deptno" column="deptno"></id>
            <result property="dname" column="dname"></result>
            <result property="loc" column="loc"></result>
        </association>
    </resultMap>
   <select id="findEmpJoinDept" resultMap="empJoinDept">
        select * from emp e left outer join dept d on e.deptno=d.deptno where e.empno =#{empno}
   </select>
</mapper>

11.2 一对多关联查询

例子:一个部门中可以有多个员工,dept表中的一条数据可以对应emp表中的多条数据。

在Dept实体类中:

public class Dept implements Serializable {
    private Integer deptno;
    private String dname;
    private String loc;
    private List<Emp> emps;

在映射文件当中:

<mapper namespace="com.bjsxt.mapper.DeptMapper">
    <!--使用resultMap 处理一对多映射关系-->
    <resultMap id="deptJoinEmps" type="dept">
        <!--dept原本的三个属性的映射关系-->
        <id property="deptno" column="deptno"></id>
        <result property="dname" column="dname"></result>
        <result property="loc" column="loc"></result>
        <!--dept 关联多个emp对象的映射关系-->
        <collection property="emps" ofType="emp">
            <!--处理一对多的每个字段映射关系 -->
            <id property="empno" column="empno"></id>
            <result property="ename" column="ename"></result>
            <result property="job" column="job"></result>
            <result property="sal" column="sal"></result>
            <result property="hiredate" column="hiredate"></result>
            <result property="mgr" column="mgr"></result>
            <result property="comm" column="comm"></result>
            <result property="deptno" column="deptno"></result>
        </collection>
    </resultMap>

    <select id="getDeptJoinEmps" resultMap="deptJoinEmps">
        select * from dept d left outer join emp e on d.deptno =e.deptno where d.deptno =#{deptno}
    </select>

</mapper>

11.3 多对多关联查询

**例子:**一个员工可能参与了多个项目的研发,一个项目由多个员工参与,员工表中的一条数据对应项目表中的多条数据,项目表中的一条数据对应员工表中的多条,这就是多对多,多对多关系要借助中间表来体现,中间表将一个多对多关系转换为两个一对多。

**需求:**根据员工工号查询该员工参与了哪些项目的研发

项目类:

public class Projects implements Serializable {
    private Integer pid;
    private String pname;
    private Integer money;

项目数(中间表):

public class ProjectRecords implements Serializable {
    private Integer empno;
    private Integer pid;
    /*关联一个对应的项目属性*/
    private Projects projects;

员工类:

public class Emp  implements Serializable {
    // 对应Emp表格的八个属性
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;
    // 对应项目记录的属性
    private List<ProjectRecords> records;

映射文件:

<resultMap id="empJoinProjects" type="emp">
    <id property="empno" column="empno"></id>
    <result property="ename" column="ename"></result>
    <result property="job" column="job"></result>
    <result property="sal" column="sal"></result>
    <result property="hiredate" column="hiredate"></result>
    <result property="mgr" column="mgr"></result>
    <result property="comm" column="comm"></result>
    <result property="deptno" column="deptno"></result>
    <collection property="records" ofType="projectRecords">
        <id property="empno" column="empno"></id>
        <id property="pid" column="pid"></id>
        <association property="projects" javaType="projects">
           <id property="pid" column="pid"></id>
           <result property="pname" column="pname"></result>
           <result property="money" column="money"></result>
        </association>
    </collection>
</resultMap>
<select id="findEmpJoinProjects"  resultMap="empJoinProjects">
    select * from
    emp  e left outer join projectrecords  p
    on e.empno =p.empno
    left outer join projects pc
    on p.pid =pc.pid
    where e.empno = #{empno}
</select>

十二、 多表级联查询

级联查询分为:积极加载策略、延迟加载策略

12.1 级联查询之积极加载

需求:

查询10号部门及该部门的员工信息 。

分析:

可以将需求分为两个部分,一个是根据部门编号查询一个部门,另一个是根据部门编号查询所有员工。

1. 实体类:

public class Dept implements Serializable {
    private Integer deptno;
    private String dname;
    private String loc;
    /*组合部门下所有的员工List集合作为属性*/
    private List<Emp> emps;

public class Emp  implements Serializable {
    // 对应Emp表格的八个属性
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double comm;
    private Integer deptno;

2. 两个接口中定义的查询方法

接口1
public interface EmpMapper {
    List<Emp> getEmpByDeptno(int deptno);
}
接口2
public interface DeptMapper {
    Dept getDeptByDeptno(int deptno);
}

3. Mapper映射文件

EmpMapper映射文件
<mapper namespace="com.bjsxt.mapper.EmpMapper">
    <select id="getEmpByDeptno" resultType="emp">
        select * from emp where deptno =#{deptno}
    </select>
</mapper>
DeptMapper映射文件
<mapper namespace="com.bjsxt.mapper.DeptMapper">
    <resultMap id="deptJoinEmp" type="dept">
        <id property="deptno" column="deptno"></id>
        <result property="dname" column="dname"></result>
        <result property="loc" column="loc"></result>
        <collection
                property="emps"
                ofType="emp"
                column="deptno"
                select="com.bjsxt.mapper.EmpMapper.getEmpByDeptno"
                fetchType="eager"
        />
    </resultMap>
    <select id="getDeptByDeptno" resultMap="deptJoinEmp">
        select * from dept where deptno = #{deptno}
    </select>
</mapper>

总结:

级联查询通过collection/association标签实现, property代表关联多个对象的属性 ofType/javaType代表关联属性或者集合中元素的数据类型.select属性表示要调用的其他sql语句column表示用上一级中的那个字段的值作为下一级查询的参数。fetchType用来表示级联查询策略

12.2 级联查询之延迟加载

延迟加载又称为按需加载。延迟加载的内容等到真正使用时才去进行加载(查询)。多用在关联对象或集合中。

延迟加载的设置:

第一步:全局开关:在mybatis.xml中打开延迟加载的开关。配置完成后所有的association和collection元素都生效

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

lazyLoadingEnabled:是否开启延迟加载。是Mybatis是否启用懒加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态

aggressiveLazyLoading:当开启时,任何方法的调用都会懒加载对象的所有属性。否则,每个属性会按需加载,

第二步:fetchType=“lazy”。

十三、 注解开发

当进行简单的CRUD对数据库进行基本操作的话,使用注解的方式是十分的方便的。但如果需要配置resultMap的时候还使用注解的话,这个时候便比较麻烦了,这个时候建议使用mapper.xml进行配置。

注意:当即使用注解开发又使用xml配置,这个时候xml配置的方式会覆盖注解方式。

13.1 CRUD注解

  • @Select:类似于select标签
  • @Insert:类似于insert标签
  • @Update:类似于update标签
  • @Delete:类似于delete标签
public interface EmpMapper {
    @Select("select * from emp")
    public List<Employee> findAll();

    @Select("select * from emp where empno = #{param1}")
    public Employee findById(int empno);

    @Select(value= "select * from emp where job =#{job} and deptno = #{deptno}")
    public List<Employee> findEmp(String job,int deptno);

    @Insert("insert into emp values(null,#{ename},#{job}," +
            "#{mgr},#{hireDate},#{sal},#{comm},#{deptno})")
    int saveEmp(Employee emp);

    @Update("update emp set job =#{job},sal =#{sal} where empno =#{empno}")
    int updateEmp(Employee emp);

    @Delete("delete from emp where empno = #{param1}")
    int deleteEmp(Employee emp);
}

13.2 其它注解

  • @Results:类似于resultMap标签
  • @Result:类似于的子标签
  • @One:类似于association标签
  • @Many:类似于collection标签
public interface StudentMapper {
    @Select("select * from t_student")
    @Results(
        value = { @Result(column="id", property="id",
                          id=true),
                 @Result(column="name", property="name"),
                 @Result(column="age", property="age"),
                 @Result(column="gender", property="gender"),
                 @Result(column="cid", property="cid"),
                 @Result(property="clazz",
                         one=@One(select="com.bjsxt.mapper.ClazzMapper.selById"),
                         column="cid")
                }
    )
    List<Student> sel();
}

十五、 注意点

10.1 mybatis中的sql语句的书写

​ sql语句后面不能带";",如果写了分号会出现找不到标识符的错误。

<insert id="insertDept" parameterType="dept">
   insert into dept values(#{deptno},#{dname},#{loc})
</insert>

10.2 mybatis的主配置文件中标签顺序

循序为:properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory, plugins,environments,databaseIdProvider, mappers

<properties resource="db.properties"/>
<typeAliases>
   <package name="com.xxxx.pojo"/>
</typeAliases>
<environments default="development">

10.3 当传入的参数为一个集合

当需要往Mapper.xml中的sql语句中传入一个集合或者数组时,这个集合或者数组中含有多个值,那么这时parameterType可以省略不写。

<!-- 根据员工编号信息,collection表示传入的集合 -->
<select id="queryByList"  resultType="emp">
   select * from emp where empno in (
    <foreach collection="list" item="args" separator=",">
        #{args}
     </foreach>
    )
</select>
List list5= Arrays.asList(7369,7521,7900);
List<Emp> list6 = sqlSession.selectList("com.xxxx.mappers.EmpMapper.queryByList", list5);

10.4 使用Mapper接口代理要满足的要求

  • 接口中不能出现重载方法

  • xml和接口要放在同一个包下面

  • xml文件名要和接口名一致

  • namespace属性值必须与接口的全限定名一致

  • id属性名必须与抽象方法名保持一致

  • xml中resultType的值必须与抽象方法的返回值一致

10.5 在核心配置文件中对写sql语句的xml进行扫描

10.5.1 不存在Mapper代理接口
<!--只能用mapper resource这种方式扫描xml文件-->
<mappers>
    <mapper resource="com/xxxx/mappers/DeptMapper.xml"/>
    <mapper resource="com/homework/mapper/EmpMapper.xml"/>
</mappers>
10.5.2 存在Mapper代理接口
<!--这种两种方式可以扫描mappers包中的接口-->
<mappers>
     <mapper class="com.shsxt.mapper.UserMapper"/>
     <package name="com.xxxx.mappers"/>
</mappers>

10.6 mybatis中对数据库中数据的查询顺序

(1)二级缓存

(2)一级缓存

```

10.3 当传入的参数为一个集合

当需要往Mapper.xml中的sql语句中传入一个集合或者数组时,这个集合或者数组中含有多个值,那么这时parameterType可以省略不写。

<!-- 根据员工编号信息,collection表示传入的集合 -->
<select id="queryByList"  resultType="emp">
   select * from emp where empno in (
    <foreach collection="list" item="args" separator=",">
        #{args}
     </foreach>
    )
</select>
List list5= Arrays.asList(7369,7521,7900);
List<Emp> list6 = sqlSession.selectList("com.xxxx.mappers.EmpMapper.queryByList", list5);

10.4 使用Mapper接口代理要满足的要求

  • 接口中不能出现重载方法

  • xml和接口要放在同一个包下面

  • xml文件名要和接口名一致

  • namespace属性值必须与接口的全限定名一致

  • id属性名必须与抽象方法名保持一致

  • xml中resultType的值必须与抽象方法的返回值一致

10.5 在核心配置文件中对写sql语句的xml进行扫描

10.5.1 不存在Mapper代理接口
<!--只能用mapper resource这种方式扫描xml文件-->
<mappers>
    <mapper resource="com/xxxx/mappers/DeptMapper.xml"/>
    <mapper resource="com/homework/mapper/EmpMapper.xml"/>
</mappers>
10.5.2 存在Mapper代理接口
<!--这种两种方式可以扫描mappers包中的接口-->
<mappers>
     <mapper class="com.shsxt.mapper.UserMapper"/>
     <package name="com.xxxx.mappers"/>
</mappers>

10.6 mybatis中对数据库中数据的查询顺序

(1)二级缓存

(2)一级缓存

(3)数据库

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值