MyBatis嵌套查询、加载策略-延迟加载(懒加载)、一级二级缓存

嵌套查询

为了解决查询时候带来的问题

#多表查询
SELECT * FROM tbl_user tu
LEFT JOIN tbl_account ta ON ta.uid=tu.id
#内连接 外连接 子查询 : 嵌套查询其实跟子查询差不多
#得到用户信息
SELECT * FROM tbl_user;
#还希望得到账户信息
SELECT * FROM tbl_account WHERE uid = 2;
#嵌套查询其实就是将sql语句分开成两条sql语句执行即可

一对一嵌套查询

查询账户 将与之相关的用户信息查询

环境搭建

接口
在这里插入图片描述
映射文件
AccountDao.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.llz.dao.AccountDao">
        <!--
                <association 一对一配置 property=""></association>
                        property="" 实体类中的属性名称
                        javaType="" 全限定类名 只不过我们此处用的是别名
                        select="" 表示 调用哪段配置 定位到 我们需要执行的sql位置 namespace+id
                        column="" 数据库的列名 此处指的其实就是外键
        -->

        <!--对账户信息的配置描述-->
        <resultMap id="baseAccountUser" type="account">
                <!--主键-->
                <id column="id" property="id"></id>
                <!--普通配置-->
                <result column="money" property="money"></result>
                <result column="address" property="address"></result>
                <result column="aname" property="aname"></result>
                <result column="uid" property="uid"></result>
                <!--一对一:外键  根据uid 查询用户的信息-->
                <association property="user" javaType="user"
                 select="com.llz.dao.UserDao.findByUid" column="uid"></association>
        </resultMap>
        <!--
        //查询所有的账户信息
    public List<Account> findAllAccount();
    resultType="account" 自动封装 -> 手动封装
        -->
        <select id="findAllAccount" resultMap="baseAccountUser" >
                select * from tbl_account
        </select>
</mapper>

UserDao.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.llz.dao.UserDao">
        <!--
        //根据uid 查询用户的信息
    public User findByUid(Integer uid);
        -->
        <select id="findByUid" parameterType="int" resultType="user">
                select * from tbl_user where id = #{id}
        <lect>
</mapper>

测试类:

public class TestDemo {
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    @Before //在执行测试类方法之前执行
    public void before(){
        //获得工厂对象
        sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
        //获得sqlSession
        sqlSession = sqlSessionFactory.openSession();

    }

    /**
     * 查询所有的账户信息
     * 查询出账户信息的同时 希望得到每一个账户对应的用户信息
     * 1.查询出账户信息
     * 一对一:在账户中进行特殊配置 表示 查询账户的时候 同时查询用户信息
     */
    @Test
    public void testFindAllAccount(){
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        List<Account> accountList = accountDao.findAllAccount();
        for (Account account : accountList) {
            System.out.println(account);
            //得到uid 如果不使用嵌套查询,就必须先查account表再查user表,效率较低
            //当我们使用association 做了一对一嵌套查询后边的代码可注释掉
            // Integer uid = account.getUid();
            // User user = userDao.findByUid(uid);
            //account.setUser( user );
        }
    }

    @After //在执行测试类方法之后执行
    public void after(){
        MyBatisUtils.commitAndClose(sqlSession);
    }
}

一对多嵌套查询

查询用户 将与之相关的账户信息查询

环境搭建

接口
在这里插入图片描述
映射文件
UserDao.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.llz.dao.UserDao">

    <!--
        type="user"  v表示当前sql语句执行的最后返回结果
        <collection property=""></collection> 一对多配置
        property="" 封装到实体类中的属性名称
        javaType="" 集合的类型
        ofType=""集合中的泛型类型 全限定类名
        select="" 执行另外一条sql语句 namespace+id
        column="" 传递的参数
    -->
    <resultMap id="baseUseAccount" type="user">
        <!--主键-->
        <id column="id" property="id"></id>
        <!--其他字段配置-->
        <result column="username" property="username"></result>
        <result column="password" property="password"></result>
        <result column="gender" property="gender"></result>
        <result column="email" property="email"></result>
        <result column="telephone" property="telephone"></result>
        <!--配置外键 查询另一个表的数据即可-->
        <collection property="accounts" javaType="list" ofType="account"
        select="com.llz.dao.AccountDao.findById" column="id"></collection>
    </resultMap>
    <!--
            //查询所有的用户信息
            public List<User> findAll();
    -->
    <select id="findAll" resultMap="baseUseAccount">
        select * from tbl_user
    </select>
</mapper>

AccountDao.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.llz.dao.AccountDao">
    <!--
        //根据用户的id 查询用户下对应的账户信息
        public List<Account> findById(Integer uid);
    -->
    <select id="findById" parameterType="int" resultType="account">
        select * from tbl_account where uid = #{uid}
    </select>
</mapper>

测试类:

public class TestDemo {
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession sqlSession;
    @Before //在执行测试类方法之前执行
    public void before(){
        //获得工厂对象
        sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
        //获得sqlSession
        sqlSession = sqlSessionFactory.openSession();

    }

    /**
     *  案例效果:一对多: 查询用户信息 同时 得到用户下所有的账户信息
     *  1.查询用户信息\
     *  一对多的目标查询的是用户信息
     */
    @Test
    public void testFindAllUser(){
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.findAll();
        for (User user : userList) {
            System.out.println(user);
            //List<Account> list = accountDao.findByUid(user.getId());
            //user.setAccounts(list);
        }
    }

    @After //在执行测试类方法之后执行
    public void after(){
        MyBatisUtils.commitAndClose(sqlSession);
    }
}

加载策略-延迟加载

在嵌套查询的基础上 做优化
查询用户数据 将 账户数据一并查询出来了 但是我们的需求只需要用户数据 还查询账户信息的话 影响效率
嵌套查询一共有两条sql
懒加载:(延迟加载,按需加载) : 加载主要对象的时候 是否需要将与之相关的对象查询出来
是: 立即加载 (不管要不要第二张表信息 , 都查询出来)
否: 懒加载(不查询第二张表信息, 什么时候使用到第二张表信息的时候 就查询 )
懒加载的加载时机 : 什么时候使用 什么时候查询 , 只要是涉及到第二张表的任意字段都会查询

主配置文件打开延迟加载策略-全局配置

在这里插入图片描述

在主配置文件中打开,默认懒加载配置是关闭的
全局配置:一对一有效一对多也有效

<!--全局的配置信息-->
  <settings>
    <!--懒加载的配置打开-->
    <setting name="lazyLoadingEnabled" value="true"/>
  </settings>

局部配置-覆盖全局(某些特殊的sql特殊设置)

开发中:一般情况配置懒加载即可(全局配置够用了)
查询账户的时候 马上查询用户信息(特殊情况) : 查询的账户信息 对应的就只有一个用户 最多内存中多存入一个对象(可配置也可以不配置)
但是, 如果是一对多的情况, 查询一个用户, 例如订单-购买历史记录…(必须使用懒加载)

<!--对账户信息的配置描述-->
        <resultMap id="baseAccountUser" type="account">
                <!--主键-->
                <id column="id" property="id"></id>
                <!--普通配置-->
                <result column="money" property="money"></result>
                <result column="address" property="address"></result>
                <result column="aname" property="aname"></result>
                <result column="uid" property="uid"></result>
                <!--一对一:外键-->
                <association property="user" javaType="user"
                 select="com.llz.dao.UserDao.findByUid" column="uid" fetchType="eager"></association>
        </resultMap>
fetch抓取Type类型 : 
eager: 立即加载
lazy: 懒加载
一对多和一对一的配置 , 只要有局部配置(单独的位置覆盖) 会覆盖全局配置

缓存配置

嵌套查询 加载策略 优化
缓存:优化 查询 速度快
数据库的数据存储的位置
数据是保存在本地磁盘(硬盘)
需要读取数据 必然要经过磁盘的IO
目标 减少磁盘的IO 查询效率更高
数据不要保存在硬盘上 保存在内存中即可
缓存:不需要经理磁盘IO ,查询速度高,
缺点:数据保存在缓存中 不持久
缓存主要用于存储查询数据
mybatis分为一级缓存和二级缓存
在这里插入图片描述

一级缓存

cache:缓存
默认的不用管,自己进行操作(已经经过了一定的优化)存储,默认就有。
一级缓存存储的位置sqlSession
在这里插入图片描述
测试类:

   /**
     * 查询账户信息
     */
    @Test
    public void testFindByUid(){
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        List<Account> accountList1 = accountDao.findById(1);
        System.out.println("第一次查询:"+accountList1); //同一个AccountDao  同一个sqlSession产生的
        List<Account> accountList2 = accountDao.findById(1);
        System.out.println("第二次查询:"+accountList2);//同一个AccountDao  同一个sqlSession产生的
        AccountDao accountDao2 = sqlSession.getMapper(AccountDao.class);
        List<Account> accountList3 = accountDao2.findById(1); //不同的AccountDao 但是 是由同一个sqlSession产生的
        System.out.println("第三次查询:"+accountList3);
        //另外一个sqlSession
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        AccountDao acocuntDao3 = sqlSession2.getMapper(AccountDao.class);
        List<Account> accountLis4= acocuntDao3.findById(1);// 不同的AccountDao    不同的sqlSession  但是同一个 sqlSessionFactory
        System.out.println("第四次查询:"+accountLis4);
    }

二级缓存

比一级缓存更高级: 存储的范围更广(很少用)
麻烦,复杂,效率不怎样 , 存储的位置 sqlSessionFactory 需要手动配置
可配置缓存(开发中不用) , 后续我们会学习专门的缓存技术

手动配置很麻烦

  • 程序必须支持二级缓存 官网找配置 默认二级缓存是开启的 cacheEnabled=true 还是配置一下
  • 指明哪些配置需要使用二级缓存 找到映射xml文件配置使用二级缓存即可
<!--当前配置文件需要使用二级缓存-->
<cache></cache>
配置会报错
NotSerializableException: com.llz.domain.Account   account对象没有实现序列化接口
  • 只要想要二级缓存的对象 必须实现序列化接口 -> 将原本的一级缓存数据 转移到二级缓存的位置上 还是sqlSession级别的缓存
  • 指明哪一条sql语句需要使用二级缓存
<!--
        //根据用户的id 查询用户下对应的账户信息
        public List<Account> findById(Integer uid);
         useCache="true"> 当前配置使用二级缓存
    -->
    <select id="findById" parameterType="int" resultType="account" useCache="true">
        select * from tbl_account where uid = #{uid}
    </select>
  • 二级缓存不是自动存储的 必须得手动的往二级缓存中加入数据 否则 只使用一级缓存
    1. 至少有一次查询数据的时候 将数据结果 commit即可
      序列化接口的目的: 1.持久化(序列化) 将数据保存到文件中(本地) 2.数据传输(多个项目之间进行数据交互的方式).

properties

当主配置文件写完后 尽量可以使用copy而不做修改更好 而数据源的部分我们是需要发生改变的 数据源值部分需要修改, 如果不修改配置文件 也能够达到替换xml值部分 , 将一部分内容抽取出去

<dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///day07_02"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
      <dataSource type="POOLED">
        <property name="driver" value="变量"/>
        <property name="url" value="变量"/>
        <property name="username" value="变量"/>
        <property name="password" value="变量"/>
      </dataSource>

图示:
在这里插入图片描述

typeAlias

<typeAlias type="com.llz.domain.User" alias="user"/>  单独定义
<!-- 指定实体类 别名扫描包,别名不区分大小写 只不过习惯要求 首字母小写 -->
<package name="com.llz.domain"/> 批量定义

setting

在这里插入图片描述

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

mappers

配置到xml
<mapper resource="com/llz/dao/UserDao.xml"/>
配置到dao接口(没用过)  注意事项:此方式要求映射文件和接口文件要在同一个包下,并且名字要一样
<mapper class="com.llz.dao.UserDao"/>
配置到包下 : 基于第二种的基础上   注意事项:此方式要求映射文件和接口文件要在同一个包下,并且名字要一样
<package name="com.llz.Dao"/>

transactionManager

transactionMananger:事务管理

<transactionManager type="JDBC"/>  使用jdbc的事务操作

//SqlSession sqlSession = sqlSessionFactory.openSession();  connection.setAutoCommit(false)
 //connection.setAutoCommit(true) 自动事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);

dataSource

在这里插入图片描述

 <!--
        type="POOLED" : 使用mybatis的默认数据源
        type="UNPOOLED"  : 不使用数据源
        type="JNDI" : 使用服务数据源  服务器内部统一指定api规则
      -->
      <dataSource type="POOLED">
        <property name="driver" value="${mybatis.driver}"/>
        <property name="url" value="${mybatis.url}"/>
        <property name="username" value="${mybatis.username}"/>
        <property name="password" value="${mybatis.password}"/>
      </dataSource>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值