Mybatis的一对多操作以及缓存

149 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1.Mybatis中的的延迟加载、缓存和注解开发

解决:

  • 延迟加载:在真正使用数据时才发起查询,不用的时候不查询,按需加载
  • 立即加载:不管用不用,只要一调用方法,马上发起查询

在对应的四种表关系中:一对多,多对一,多对多

  • 一对多,多对多:通常情况下我们都是采用延迟加载
  • 多对一,一对一:通常情况请下我们采用立即加载 我们在查询mybatis的官方文档时,lazyLoadingEnable就是延迟加载全局开关,以及aggressiveLazyLoading调用加载该对象的属性

2.一对多的方式

Account与User实现类都不变,与上面的一致 改变的为IAccountDao接口

package com.mybatisD.dao;

import com.mybatisD.domain.Account;
import com.mybatisD.domain.AccountUser;

import java.util.List;

public interface IAccountDao {
    //查询所有账户
    List<Account> findAll();
    //查询账户,并且带有用户名称和地址信息
    List<AccountUser> findAllAccount();
    //加入
    List<Account> findAccountByUid(Integer uid);
}

IAccountDao.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.mybatisD.dao.IAccountDao">
    <!--定义封装account的resultMap-->
    <resultMap id="accountUserMap" type="com.mybatisD.domain.Account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!--一对一的关系映射,配置封装user内容
        select属性指定的内容:查询用户的唯一标识
        column属性指定的内容:用户根据id查询时,所需要的参数的值
        -->
        <association property="user"   column="uid" javaType="com.mybatisD.domain.User" select="com.mybatisD.dao.IUserDao.findById"></association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap" >
        select * from account
    </select>
    <!--配置用户id查询所有账户列表-->
    <select id="findAccountByUid" resultType="com.mybatisD.domain.Account">
       select * from account where uid=#{uid}
    </select>
</mapper>

IUserDao.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.mybatisD.dao.IUserDao">
    <!--定义user的resultMap-->
    <resultMap id="userMap" type="com.mybatisD.domain.User">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></result>
        <!--配置user对象中accounts集合的映射-->
        <collection property="account" ofType="com.mybatisD.domain.Account" select="com.mybatisD.dao.IAccountDao.findAccountByUid" column="id">
        </collection>
    </resultMap>
    <!--配置查询所有-->
    <select id="findAll" resultMap="userMap">
       select * from user
    </select>
    <!--根据ID查询用户-->
    <select id="findById" parameterType="INT" resultType="com.mybatisD.domain.User">
        select * from user where id=#{userid}
    </select>
</mapper>

测试类

package com.mybatisJ.test;

import com.mybatisD.dao.IAccountDao;
import com.mybatisD.dao.IUserDao;
import com.mybatisD.domain.Account;
import com.mybatisD.domain.AccountUser;
import com.mybatisD.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-22 16:07
 */
public class userTest {
    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws  Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }
    @After//用于在测试方法之后执行
    public void destory() throws Exception{
        //添加提交事物,不添加无法提交
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
    //查询连接方法其中包括用户的一些信息
    @Test
    public  void testFindAll() throws  Exception{
        List<User> users = userDao.findAll();
        for (User user: users) {
            System.out.println(user);
            System.out.println(user.getAccount());
        }
        }

}

结果,延迟加载就是在用到这个信息才会加载

image.png

2.mybatis中的缓存

1.缓存的概念

什么是缓存:存在于内存中的临时数据 为什么使用缓存:减少和数据库的交互次数,提高执行效率 什么样的数据能使用缓存:经常查询并且不经常改变的、数据的正确与否对最终的结果影响不大 不能使用缓存:经常改变的数据,数据的正确与否对最终的结果影响很大如:商品的库存,银行的汇率

2.Mybatis中的一级缓存和二级缓存

一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit()提交,close()等方法时,就会清空一级缓存

  • 一级缓存

它指的是Mybatis中SqlSession对象的缓存,当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供一块区域中,该区域的结构是一个Map,当我们再次查询同样的数据,Mybatis会先去SqlSession中查询是否有,有的话直接用,当SqlSession对象消失后,Mybatis的 一级缓存也就消失了

image.png

代码: 配置IUserDao.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.mybatisD.dao.IUserDao">
    <!--定义user的resultMap-->
    <!--配置查询所有-->
    <select id="findAll" resultType="com.mybatisD.domain.User">
       select * from user
    </select>
</mapper>`

测试中最主要的

  @Test
    public  void testFirstLevelchatch() throws  Exception{
      User user1 = userDao.findById(2);
        System.out.println("第一次查询"+user1);
        sqlSession.close();//是为了清除缓存
        //再次获取SqlSession
        //sqlSession.clearcache();  也是可以清空缓存
        sqlSession =factory.openSession();
        userDao = sqlSession.getMapper(IUserDao.class);
      User user2 = userDao.findById(2);
        System.out.println("第二次查询"+ user2);
        System.out.println(user1=user2);
        }

测试类

package com.mybatisJ.test;

import com.mybatisD.dao.IAccountDao;
import com.mybatisD.dao.IUserDao;
import com.mybatisD.domain.Account;
import com.mybatisD.domain.AccountUser;
import com.mybatisD.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * @author :程序员徐大大
 * @description:TODO
 * @date :2022-01-22 16:07
 */
public class userTest {
    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private IUserDao userDao;

    @Before//用于在测试方法执行之前执行
    public void init()throws  Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        userDao = sqlSession.getMapper(IUserDao.class);
    }
    @After//用于在测试方法之后执行
    public void destory() throws Exception{
        //添加提交事物,不添加无法提交
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }
    //一级缓存
    @Test
    public  void testFirstLevelchatch() throws  Exception{
      User user1 = userDao.findById(2);
        System.out.println("第一次查询"+user1);
        sqlSession.close();//是为了清除缓存
        //再次获取SqlSession
        //sqlSession.clearcache();  也是可以清空缓存
        sqlSession =factory.openSession();
        userDao = sqlSession.getMapper(IUserDao.class);
      User user2 = userDao.findById(2);
        System.out.println("第二次查询"+ user2);
        System.out.println(user1=user2);
        }

}

两次查询地址不一样,使用两次Connection第二次为缓存

image.png

当使用update更新用户信息,一级缓存和数据库不一致了怎么办 他会再次向数据库进行查询,不会再缓存里面查询 一级缓存是SqlSession范围的缓存,当调用SqlSession的修改,添加,删除,commit()提交,close()等方法时,就会清空一级缓存