Mybatis的使用(详细)

Mybatis的使用

1、MVC三层架构的问题

在这里插入图片描述

2、mybatis是什么

mybatis本身就是一个数据里访问的这样一个框架 
mybatis就跟我们的Hibernate  JDBC   dbutils   JdbcTemplate这一连串的东西是一样的 都是为了来实现数据库的增删改查的

3、mybatis能干什么

数据库的CRUD  你们肯定有疑问就是学习了JDBC之后 为什么我们还要学习 mybatis呢?

说到这里还需要说道另外的一个框架  Hibernate(也是为了实现数据库的CRUD的)

在这三个中 Hibernate使用起来 是最简单的  SQl语句都不用编写 直接使用 
他里面有个东西 叫做 HQL(Hibernate Query lauguage) 这个是我们在开发的时候要编写的 

这三个中 代码最复杂的是 JDBC  代码最简单的是 Hibernate
这三个中  程序效率最高的是 JDBC  效率最低的是Hibernate

也就是说 你可以认为  mybatis是属于  JDBC和Hibernate之间的一个中间产物
效率是位于 JDBC和Hibernate之间
代码的复杂度也是位于 JDBC和Hibernate之间

4、mybatis的第一个helloworld程序

4.1、导包

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <!--第一步:导包-->
        <!--下面就是iBatis的相关的包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>


        <!--mysql的驱动 导入自己对应的版本-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

        <!--下面是日志的包-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.16</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-core -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
            <scope>test</scope>
        </dependency>


        <!--导入源码之后 这两个包 是需要手动导入的-->
        <dependency>
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.27.0-GA</version>
        </dependency>

        <dependency>
            <groupId>ognl</groupId>
            <artifactId>ognl</artifactId>
            <version>3.2.18</version>
        </dependency>


        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.2.4</version>
        </dependency>

        <!--在这里导入缓存的这个包-->
        <!-- ehcache核心jar包 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.11</version>
        </dependency>
        <!-- MyBatis与ehcache整合jar包 -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>

4.2、编写po实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
}
4.3、编写mybatis.xml
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--这个文件中主要用来配置我们数据库的连接信息
     	数据库连接的四要素:
       default:表示的是你要使用哪一个环境
                default的值 实际上就是下面其中的一个id值
       environment:表示配置的是数据库连接的信息
                    id:这个是可以随便写的 主要是见名之意
    -->

    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <!--下面就是数据库连接的四要素-->
                <property name="driver" value="com.mysql.jdbc.Driver"></property>
                <property name="url" value="jdbc:mysql:///数据库名字?useUnicode=true&amp;characterEncoding=UTF-8"></property>
                <property name="username" value="xxx"></property>
                <property name="password" value="xxx"></property>
            </dataSource>
        </environment>
    </environments>

    <!--这里需要引入mapper.xml文件-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"></mapper>
    </mappers>

</configuration>
4.4、编写UserMapper.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">
<!--
    nameSpace命名空间 这个是可以随便写的的 但是一般见名之意  还要唯一
-->
<mapper namespace="UserMapper">
    <select id="selectList" resultType="对应自己的pojo路径">
        select * from t_user
    </select>
</mapper>
4.5、编写 测试类
    /**
     * 第一个程序
     */
    @Test
    public void testHelloWorld() throws Exception {
        //首先引入配置文件
        Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsReader);
        //打开会话
        SqlSession sqlSession = build.openSession();
        //执行查询
        List<Object> objects = sqlSession.selectList("UserMapper.selectList");
        System.out.println("查询到的数据是:"+objects);
        sqlSession.commit();
        sqlSession.close();
    }

5、mybatis中的基本的增删改查的编写

ibatis和mybatis是个啥关系呀?
 ibatis是以前的名字  mybatis  是现在的名字
 说白了 一个是以前的名字  一个是现在的名字
5.1、编写SQL描述文件mapper.xml
  <!--下面玩一个增删改查-->
    <insert id="add">
        insert into t_user(username,password) values ('111','123111')
     </insert>

    <delete id="delete">
        delete from t_user where id=3
     </delete>

    <insert id="update">
        update t_user set username='xxxx' where id=5
     </insert>

    <select id="selectOne" resultType="xx.xx.pojo.User">
        select * from t_user where id=6
     </select>
5.2、编写测试文件
package com.xx.mybatis.crud;

public class Test001 {
    /**
     * 向数据库添加数据
     */
    @Test
    public void testAdd() throws IOException {
        //这里为啥出来是一个字符流呢? 方便解析配置文件的时候 一行一行的读取这个内容
        Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
        //工厂的设计模式:工厂的作用是创建对象的 SqlSession对象的
        // 以后 只要看到....builder 那么这里使用的就是 构建者的设计模式
        // 构建者设计模式 说白了 就有点类似咋们的工厂  根据传入的条件 构建不同的这个对象
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsReader);

        //打开了我们的会话  操作数据库
        SqlSession sqlSession = build.openSession();
        sqlSession.insert("UserMapper.add");
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 删除数据
     */
    @Test
    public void testDelete() throws IOException {
        Reader resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
        SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsReader);
        SqlSession sqlSession = build.openSession();

        //这里增删改的方法是可以混用的 不存在问题
        sqlSession.delete("UserMapper.delete");
        sqlSession.commit();
        sqlSession.close();
    }
}

6、mybatis下的工具类的编写

6.1、编写我们的工具类
package com.xx.mybatis.utils;
/**
 * @description: 这个就是咋们的这个mybatis的工具类
 * 异常分成两类:
 *    编译时异常 和 运行时异常 那么这两种异常有什么区别呢?
 *    编译时异常 需要异常申明
 *    运行时异常是不需要 异常申明的
 */
public class MyBatisUtils {
    private static  Reader resourceAsReader;
    private static SqlSessionFactory build;

    private static  ThreadLocal<SqlSession> sqlSessionThreadLocal;
    static {
        try {
            resourceAsReader = Resources.getResourceAsReader("mybatis.xml");
            build = new SqlSessionFactoryBuilder().build(resourceAsReader);
            sqlSessionThreadLocal=new ThreadLocal<SqlSession>();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 按照我们的想法应该这么写
     * @return
     * @throws IOException
     */
    public static SqlSession getSqlSession() throws IOException {
        SqlSession sqlSession1 = sqlSessionThreadLocal.get();
        if(null!=sqlSession1){
            return sqlSession1;
        }
        //程序执行到这里 说明不是一个sqlsession对象
        //打开了我们的会话  操作数据库
        SqlSession sqlSession = build.openSession();
        sqlSessionThreadLocal.set(sqlSession);
        return sqlSession;
    }

    /**
     * 关闭资源?
     */
    public static void  close(){
        SqlSession sqlSession = sqlSessionThreadLocal.get();
        if(null!=sqlSession){
            sqlSession.commit();
            sqlSession.close();
            sqlSessionThreadLocal.remove();
        }
    }
}
6.2、编写测试类
    /**
     * 向数据库添加数据
     */
    @Test
    public void testDelete() throws IOException {
        //打开了我们的会话  操作数据库
        SqlSession sqlSession = getSqlSession();
        System.out.println("---------------:"+sqlSession);
        sqlSession.insert("UserMapper.add");
        close();
    }

7、传入参数的问题

7.1、传入一个简单参数
7.1.1、编写SQL描述
    
    <select id="selectById" parameterType="int" resultType="com.qfedu.mybatis.pojo.User">
        select * from t_user where id=#{value }
    </select>

7.1.2、编写测试类
  @Test
    public void testA() throws IOException {
        SqlSession sqlSession = getSqlSession();
        Object o = sqlSession.selectOne("UserMapper1.selectById", 2);
        System.out.println("查询到 的数据是:"+o);
        close();
    }
7.2、传入对象参数
7.2.1、SQL描述
<!--向数据库插入数据
        传入的是对象 那么就写 对象的全路径
        传入的对象的占位符中 就不能乱写了 要写对象对应的属性的名字
    -->
    
    <insert id="add1" parameterType="com.qfedu.mybatis.pojo.User">
        insert into t_user(username,password) values(#{username},#{password})
    </insert>
7.2.2、测试
    @Test
    public void testAdd1() throws IOException {
        SqlSession sqlSession = getSqlSession();
        User user = new User();
        user.setUsername("小波波");
        user.setPassword("110");
        Object o = sqlSession.insert("UserMapper1.add1", user);
        System.out.println("影响的行数是:"+o);
        close();
    }
7.3、传入map类型的参数
7.3.1、SQL描述
   <!--传入map类型的参数
         如果传入的是 map类型的数据 那么占位符中的值就要写 map中对应的key的名字
    -->
    <select id="findUserByCondition" parameterType="map" resultType="com.qfedu.mybatis.pojo.User">
        select * from t_user where username=#{username} and password=#{password}
    </select>

7.3.2、编写测试
    @Test
    public void testSelectByCondition() throws IOException {
        SqlSession sqlSession = getSqlSession();

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("password","110");

        Object o = sqlSession.selectList("UserMapper1.findUserByCondition",map);
        System.out.println("影响的行数是:"+o);
        close();
    }

8、返回参数的问题

8.1、传出简单参数
    <!--返回单个值 通过id找用户名-->
    <select id="findUserNameById" parameterType="int" resultType="string">
        select username from t_user where id=#{value }
    </select>

8.2、传出一个对象参数
 <!--通过id找用户-->
    <select id="selectUserById" parameterType="int" resultType="user">
        select * from t_user where id=#{value }
    </select>
8.3、传出集合类型的参数
  <!--返回类型的数据
        如果返回的是集合类型的话 那么resultType后面写 集合中 泛型的数据类型
        List<User>
    -->
    <select id="selectList1" resultType="user">
        select * from t_user
    </select>

9、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命名空间 这个是可以随便写的的 但是一般见名之意  还要唯一
-->
<mapper namespace="UserMapper2">
    <!--这里面专门玩 动态SQL-->

    <!--先玩一个条件组合查询的例子
        现在情况是秦端可能传递  username  也有可能传递  id   还有可能传递 password
        也可以是这其中两两组合  也可以是这三个的组合
        具体有多少值我们是不知道的
          select * from t_user where id=? and username=? and password=?
    -->
    
    <select id="findUserByCondition" parameterType="user" resultType="user">
        select * from t_user where 1=1
        <if test="username!=null and username!=''">
            and username=#{username}
        </if>
        <if test="id!=null">
            and id=#{id}
        </if>
        <if test="password!=null and password!=''">
            and password=#{password}
        </if>
    </select>

    <!--下面玩下第二种写法-->
    <select id="findUserByCondition1" parameterType="user" resultType="user">
        select * from t_user
        <where>
            <if test="username!=null and username!=''">
                and username=#{username}
            </if>
            <if test="id!=null">
                and id=#{id}
            </if>
            <if test="password!=null and password!=''">
                and password=#{password}
            </if>
        </where>
    </select>


    <!--下面玩下第三种写法
         prefixOverrides:去掉条件成立的第一个前面的某一个标签
         suffixOverrides:去掉SQL语句末尾的一个什么东西
         prefix="":在下面的SQL语句之前添加什么东西
         suffix="":在SQL语句的后面添加什么东西
    -->
    <select id="findUserByCondition3" parameterType="usercondition" resultType="user">
        select * from t_user
           <if test="user!=null">
                where
                   <trim prefixOverrides="and" >
                       <if test="user.username!=null and user.username!=''">
                           and username=#{user.username}
                       </if>
                       <if test="user.id!=null">
                           and id=#{user.id}
                       </if>
                       <if test="user.password!=null and user.password!=''">
                           and password=#{user.password}
                       </if>
                   </trim>
           </if>
    </select>
</mapper>

10、mybatis下的动态sql的问题(下)

10.1、就是编写SQL描述

    <!--第二个案例:
        查询用户 这些用户id是指定id的这些用户
        我可以传递一个id  也可以传递多个id  或者传递 n个id
        这个案例主要的功能:传递集合  传递数组
        SELECT * FROM t_user WHERE id IN(1,3,5,7)
        collection:表示的是遍历的集合是啥?List集合的话 那么这里直接写 list
        item :每一次遍历出来的数据是啥
        open:以什么开始
        close:以什么结束
        separator:数据之间使用什么进行分割
    -->
    <select id="findUserByIds" parameterType="list" resultType="user">
        select * from t_user
        <foreach collection="list" item="id" open="WHERE id IN(" close=")" separator=",">
            #{id}
        </foreach>
    </select>


    <!--下面玩的是传递数组
         无论是传递集合 还是传递数组  parameterType的类型都是 list
         如果传输的是数组 那么 collection 后面的名字 写 array
    -->
    <select id="findUserByIds1" parameterType="list" resultType="user">
        select * from t_user
        <foreach collection="array" item="id" open="WHERE id IN(" close=")" separator=",">
            #{id}
        </foreach>
    </select>
10.2、编写测试
 @Test
    public void testfindUserByIds() throws IOException {
         SqlSession sqlSession = getSqlSession();
//        List<Integer> ids=new ArrayList<Integer>();
        ids.add(1);
        ids.add(3);
        ids.add(5);

        Integer[] ids={
          1,3,5
        };

        Object o = sqlSession.selectList("UserMapper2.findUserByIds1",ids);
        System.out.println("查询到 的数据是:"+o);
        close();
    }

11、mybatis下引入接口的问题

  1:为什么要引入接口
     1、面向接口编程
     2、异常可以前扬?
     3、实现了代码和Mapper.xml文件之间的解耦
  
11.1、编写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">

<!--这个主要玩的是引入接口之后的玩法
    1:命名空间不能乱写 只能是 接口的全路径
-->
<mapper namespace="com.qfedu.mybatis.mapper.UserMapper">

    <!--进行方法的描述
        id不能乱写了 只能是接口中对应方法的名字
        输入参数 要和接口中保持一致
        输出参数也要和接口中方法保持一致
    -->
    <select id="selectList" resultType="user">
        select * from t_user
    </select>
</mapper>
11.2、编写Mapper接口
public interface UserMapper {
    /**
     * 查询所有的用户
     * @return
     */
    List<User>  selectList();
}
11.3、编写测试
package com.qfedu.mybatis.mapper;
public class Test001 {
    /**
     * 测试
     */
    @Test
    public void testA() throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //第三步:直接开始调用
        List<User> users = userMapper.selectList();
        System.out.println("查询出来的数据是:"+users);
        MyBatisUtils.close();
    }
}

12、取别名的两种方式

12.1、第一种方式
  <typeAliases>
        <!--给单个类取别名-->
        <typeAlias type="com.qfedu.mybatis.pojo.User" alias="user"></typeAlias>
    </typeAliases>
12.2、第二种方式
    <typeAliases>
        <!--给单个类取别名-->
        <!--<typeAlias type="com.qfedu.mybatis.pojo.User" alias="user"></typeAlias>-->
        <!--下面这个表示 给这个包里面所有的类 直接取别名
            那么这个别名是啥呢? 类名的所有字母小写
        -->
        <package name="com.qfedu.mybatis.pojo"></package>
    </typeAliases>

13、一对一的映射

人和身份证之间是一个一对一?
部门和员工之间是一个一对多?

我们以后在说 一对一 还是  一对多的时候 一定是在 某种业务场景下 去说 才有意义。
我说一个人只有 一个身份证  一个身份证也唯一的对应了一个人 那么人和身份证之间 就是一个一对一?
  我说一个人拥有多个身份证  一盒身份证唯一的对应一个人   人和身份证之间就是一个一对多?

一个人---一个身份证   一个身份证----一个人   人和身份证之前 就是一个 一对一的关系
13.1、编写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">

<!--这个主要玩的是引入接口之后的玩法
    1:命名空间不能乱写 只能是 接口的全路径
-->
<mapper namespace="com.qfedu.mybatis.one2one.PeopleMapper">

    <!--这里对查询出来的数据做结果集的映射-->
    <resultMap id="findByIdResultMap" type="people">
        <!--映射主键
            property:java对象中属性的名字
            column:这个代表的是 对应的查询出来的列的名字
        -->
        <id property="pId" column="pId"></id>
        <!--映射其他的字段-->
        <result property="name" column="name"></result>
        <result property="age" column="age"></result>
        <result property="number" column="number"></result>
        <!--还有一字段没有映射-->
        <association property="idCard" javaType="com.qfedu.mybatis.pojo.IdCard">
            <!--映射这个Java对象-->
            <id property="number" column="number"></id>
            <!--其他字段映射-->
            <result property="startTime" column="startTime"></result>
            <result property="endTime" column="endTime"></result>
        </association>
    </resultMap>
    
    <!--希望的是 查询这个人的时候 需要将身份证 都查询出来
       resultMap:他的意思是将结果集做一个映射
    -->
     <select id="findById" parameterType="int" resultMap="findByIdResultMap">
         select * from t_people t1 join t_idcard t2 on t1.number=t2.number
     </select>
</mapper>
13.2、编写People实体
@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
    private Integer pId;
    private String name;
    private Integer age;
    private String number;  //身份证号码
    private IdCard idCard;   //一个人有一个身份证
}
13.3、编写IdCard实体

@Data
@AllArgsConstructor
@NoArgsConstructor
public class IdCard {
    private String number;
    private Date startTime;
    private Date endTime;
}
13.4、编写测试
public class Test001 {
    /**
     * 测试
     */
    @Test
    public void testA() throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        PeopleMapper mapper = sqlSession.getMapper(PeopleMapper.class);
        //第三步:直接开始调用
        People people = mapper.findById(1);
        MyBatisUtils.close();
    }
}
13.5、编写Mapper接口
public interface PeopleMapper {
    People findById(Integer pId);
}

14、一对多的映射

业务场景:
  就是一个部门拥有多个员工  一个员工 只是属于一个部门的话 那么 部门和员工之间 就是一个一对多的关联关系
14.1、编写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">

<!--这个主要玩的是引入接口之后的玩法
    1:命名空间不能乱写 只能是 接口的全路径
-->
<mapper namespace="com.qfedu.mybatis.one2many.DeptMapper">

    
    <!--定义一个结果映射集-->
    
    <resultMap id="findDeptByIdResultMap" type="com.qfedu.mybatis.pojo.Dept">
        <!--映射主键-->
         <id property="deptId" column="deptId"></id>
        <!--映射普通字段-->
        <result property="deptName" column="deptName"></result>
        <result property="deptDes"  column="deptDes"></result>
        <!--映射集合字段-->
        <collection property="emps" ofType="com.qfedu.mybatis.pojo.Emp">
            <!--映射主键-->
            <id property="empId" column="empId"></id>
            <!--映射其他字段-->
            <result property="empName" column="empName"></result>
            <result property="empAddress" column="empAddress"></result>
        </collection>

    </resultMap>
    
    
    <select id="findDeptById" parameterType="int" resultMap="findDeptByIdResultMap">
        SELECT *
        FROM t_dept t1 JOIN t_emp t2 ON t1.deptId=t2.deptId
        WHERE t1.deptId=#{value };
    </select>
</mapper>
14.2、编写Dept对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Dept {
    private Integer deptId;
    private String deptName;
    private String deptDes;
    //一个部门有多个员工?
    private List<Emp> emps;
}
14.3、编写Emp对象
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Integer empId;
    private String empName;
    private String empAddress;
    private Integer deptId;
}

14.4、编写DeptMapper

public interface DeptMapper {

    /**
     * 通过id查询部门
     */
    Dept findDeptById(Integer deptId);

}
14.5、编写测试类
public class Test001 {
    /**
     * 测试
     */
    @Test
    public void testA() throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        //第三步:直接开始调用
        Dept deptById = mapper.findDeptById(1);
        MyBatisUtils.close();
    }
}

15、懒加载的使用

前面的一对一 和 一对多 都有一个共同的问题 
这个问题是啥?
就是 不管你用不用咋们的这个身份证的信息 或者 用户不用我们的员工信息  这个信息都要被查询出来 显然是有问题的

这个时候 懒加载 就应运而生了

简单的说就是使用的时候 才加载  不使用的时候 是不得加载的

你查询部门的时候 如果你不使用员工信息 那么不得发送SQL语句查询员工信息  你使用People数据的时候 主要你不使用 IdCard那么都不得查询

XMLConfigBuilder(参考配置在这个类里面)
15.1、首先设置支持懒加载
   <!--在这里进行全局配置
          打开懒加载  关闭 积极的加载
       -->
    <settings>
        <!--打开懒加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--关闭积极的加载-->
        <setting name="aggressiveLazyLoading" value="false"></setting>
    </settings>
15.2、编写部门的Mapper
   /**
     * 这个是为了测试懒加载
     * @param deptId
     * @return
     */
    Dept findDeptById11(Integer deptId);
15.3、编写员工的Mapper
   /**
     * 通过部门id查询员工信息
     * @param deptId
     * @return
     */
   List<Emp> findEmpByDeptId(Integer deptId);
15.4、编写部门Mapper.xml

    <!--这里玩的是 通过部门id查询部门信息  懒加载的玩法-->

    <select id="findDeptById11" parameterType="int" resultMap="findDeptByIdResultMap11">
        SELECT * FROM t_dept t1 WHERE t1.deptId=#{value };
    </select>


    <resultMap id="findDeptByIdResultMap11" type="com.qfedu.mybatis.pojo.Dept">
        <!--映射主键-->
        <id property="deptId" column="deptId"></id>
        <!--映射普通字段-->
        <result property="deptName" column="deptName"></result>
        <result property="deptDes"  column="deptDes"></result>
        <!--
           column:表示的是调用其他的Mapper.xml文件 要传递的参数  这个参数只能在上面的参数中出现过才能写
           否则是不能写的
           select:这个表示的是要调用的是 那个namespace中的那个方法....
        -->
        <collection property="emps" ofType="com.qfedu.mybatis.pojo.Emp" column="deptId" select="com.qfedu.mybatis.one2many.EmpMapper.findEmpByDeptId"></collection>
    </resultMap>
15.5、编写员工的Mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--这个主要玩的是引入接口之后的玩法
    1:命名空间不能乱写 只能是 接口的全路径
-->
<mapper namespace="com.qfedu.mybatis.one2many.EmpMapper">

    <!--通过部门id查询员工信息-->
    <select id="findEmpByDeptId" parameterType="int" resultType="emp">
        select * from t_emp where deptId=#{value }
    </select>
</mapper>
15.6、测试
    /**
     * 测试
     */
    @Test
    public void testLazy() throws IOException {
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        //第三步:直接开始调用
        Dept dept = mapper.findDeptById11(1);
        dept.getEmps();
        MyBatisUtils.close();
    }

16、一级缓存(没用)

一级缓存 还有一个名字 叫做Session缓存  顾名思义:整个缓存的生命周期  都受Session的管理 不能跨域Session

没用

17、二级缓存

这个就有用的了 这个二级缓存是可以跨越Session来实现的

我们一般做开发的时候 使用  Ehcache来做这个缓存
17.1、导包
 <!--在这里导入缓存的这个包-->
        <!-- ehcache核心jar包 -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.11</version>
        </dependency>
        <!-- MyBatis与ehcache整合jar包 -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.1.0</version>
        </dependency>
17.2、编写ehcache.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache updateCheck="false">

    <!--
     diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
     user.home – 用户主目录
     user.dir  – 用户当前工作目录
     java.io.tmpdir – 默认临时文件路径
   -->
    <!--这个是我们的数据在硬盘上的存储位置-->
    <diskStore path="G:\\mytemp"/>
    <!--
     name:缓存名称。
     maxElementsInMemory:缓存最大数目
     maxElementsOnDisk:硬盘最大缓存个数。
     eternal:对象是否永久有效,一但设置了,timeout将不起作用。
     overflowToDisk:是否保存到磁盘,当系统当机时
     timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
     timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
     diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
     diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
     diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
     memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
     clearOnFlush:内存数量最大时是否清除。
     memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
     FIFO,first in first out,这个是大家最熟的,先进先出。
     LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
     LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
  -->

    <!-- 数据过期策略 -->
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="true"
    />
</ehcache>
17.3、配置支持二级缓存
  <!--设置打开二级缓存-->
        <setting name="cacheEnabled" value="true"></setting>
17.4、在需要缓存的mapper.xml中设置缓存
  <cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
17.5、测试
@Test
    public void testLazy() throws IOException {

        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
        //第三步:直接开始调用
        Dept dept = mapper.findDeptById11(1);
        MyBatisUtils.close();


        SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        DeptMapper mapper1 = sqlSession1.getMapper(DeptMapper.class);
        //第三步:直接开始调用
        Dept dept1 = mapper1.findDeptById11(1);
        MyBatisUtils.close();


        SqlSession sqlSession2 = MyBatisUtils.getSqlSession();
        //第二步骤:获取调用类对象
        DeptMapper mapper2 = sqlSession2.getMapper(DeptMapper.class);
        //第三步:直接开始调用
        Dept dept2 = mapper2.findDeptById11(1);
        MyBatisUtils.close();
    }

18、当数据库的字段和Java实体不对应的时候的解决方案

18.1、第一种方案就是取别名
  <!--下面研究的是 Java实体的字段和数据库字段不一致的时候的解决方案-->
    <select id="selectList" resultType="user">
       SELECT userId AS id,NAME AS username,pwd AS PASSWORD FROM t_user
    </select>
18.2、定义结果集的映射关系

    <!--定义一个结果集的映射关系-->
    <resultMap id="selectList2ResultMap" type="user">
        <id property="id" column="userId"></id>
        <result property="username" column="name"></result>
        <result property="password" column="pwd"></result>
    </resultMap>

    <!--下面研究的是 Java实体的字段和数据库字段不一致的时候的解决方案-->
    <select id="selectList2" resultMap="selectList2ResultMap">
       SELECT * FROM t_user
    </select>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值