Mybatis之延迟加载与查询缓存

延迟加载

什么是延迟加载

ResultMap可以实现高级映射(使用collection和association),collection和association具有延迟加载的功能。

需求:查询订单并且关联用户信息,如果先查询订单信息可以满足要求,当我们需要使用到 用户信息的时候,再去查询用户信息。把 用户信息 按需 查询就是延迟加载。

延迟加载:先从单表查询,需要的时候,再去关联的表查询,大大提升了数据库的性能,因为单表查询肯定比关联查询更快。

案例如下:

案例所需的数据

一:先修改配置Mybatis的配置文件,添加以下设置

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

二:Mapper接口

package com.hyx3.lazy.mapper;

import com.hyx3.lazy.pojo.OrderCustomer;
import com.hyx3.lazy.pojo.Orders;
import com.hyx3.lazy.pojo.User;

import java.util.List;

public interface OrderMapper {
  
    //根据用户id找到订单
    public List<Orders> findUserOrdersResultMap();
   
}

三: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">
<mapper namespace="com.hyx3.lazy.mapper.OrderMapper">

    <resultMap id="orderUserMap" type="orders">
        <id column="id" property="id"></id>
        <result column="user_id" property="user_id"></result>
        <result column="number" property="number"></result>
        <result column="note" property="note"></result>

        <association property="user" javaType="User" select="findUserById" column="user_id">
        </association>

    </resultMap>

    <select id="findUserOrdersResultMap" resultMap="orderUserMap">
        select * from orders;

    </select>

    <select id="findUserById" parameterType="int" resultType="User">
        select * from user where id = #{id};
    </select>

</mapper>

四:测试代码

package com.hyx3.lazy.test;

import com.hyx3.lazy.mapper.OrderMapper;
import com.hyx3.lazy.pojo.OrderCustomer;
import com.hyx3.lazy.pojo.Orders;
import com.hyx3.lazy.pojo.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.Before;
import org.junit.Test;

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

public class Demo01 {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void fun0() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream("lazy_sqlMapconfig.xml");
        //通过配置创建会话工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
    }


    @Test
    public void fun1(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        OrderMapper mapper = sqlSession.getMapper(OrderMapper.class);
        List<Orders> userOrders = mapper.findUserOrdersResultMap();
        for(Orders oc : userOrders){
            System.out.println(oc);
        }
    }
}

 

五:实现效果如下

可以看到,在断点处,此时没有加载用户信息时,sql语句之执行了查询所有订单

点击查询到的userOrders时,会触发查询用户数据

 

查询缓存

为什么要缓存

如果缓存(内存)中有数据,就不需要从数据库中去查询了,而是直接从内存中拿,大大提供系统性能。

查询商品ID为1000的商品

第一次查询时候,去数据库拿,写到内存中、并且返回

第2、3次,直接内存读,然后返回。

什么是查询缓存

Mybatis提供查询,用于减轻数据库的压力,提供数据库的性能。

Mybatis提供一级缓存、和二级缓存

一级缓存是SQLSession级别的缓存

在操作数据库是需要构建SQLSession对象,在对象有有一个数据接口(hashMap)用于存储缓存数据,不同的SQLSession之间缓存数据区域(hashMap)是互补影响。

二级缓存是Mapper基本的缓存

多个SQLSession去操作同一个Mapper的SQL语句,多个SQLSession可以共用二级缓存,二级缓存是跨SQLSession的。

一级缓存

原理

案例实现,查找一个用户根据id

User.class

package com.hyx3.cach.pojo;

import java.util.Date;

public class User {
    private Integer id;
    private String username;// 用户姓名
    private String sex;// 性别
    private Date birthday;// 生日
    private String address;// 地址

    public User() {
    }

    public User(String username, String sex, Date birthday, String address) {
        this.username = username;
        this.sex = sex;
        this.birthday = birthday;
        this.address = address;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" + "id=" + id + ", username='" + username + '\'' + ", sex='" + sex + '\'' + ", birthday=" + birthday + ", address='" + address + '\'' + '}';
    }
}

UserMapper.interface

package com.hyx3.cach.mapper;

import com.hyx3.cach.pojo.User;

public interface UserMapper {
    /**
     * 找到用户通过id
     */
    public User findUserById(Integer id);
}

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">
<mapper namespace="com.hyx3.cach.mapper.UserMapper">

<select id="findUserById" parameterType="int" resultType="user">
        select  * from user where id = #{id}
    </select>

</mapper>

测试代码

package com.hyx3.cach.test;

import com.hyx3.cach.mapper.UserMapper;
import com.hyx3.cach.pojo.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.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class Dmo01 {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void fun0() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream( "cach_sqlMapconfig.xml" );
        //通过配置创建会话工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
    }

    @Test
    public void fun(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.findUserById(1);
        System.out.println(userById);
        User userById1 = mapper.findUserById(1);
        System.out.println(userById1);
    }
}

执行测试代码可以看到如下效果,sql语句只执行了一次,但是在方法中调用了两次方法

 对UserMapper.interface与UserMapper.xml进行如下修改:

package com.hyx3.cach.mapper;

import com.hyx3.cach.pojo.User;

public interface UserMapper {
    /**
     * 找到用户通过id
     */
    public User findUserById(Integer id);

    /**
     * 删除用户通过id
     * @param id
     */
    public void deleteUserById(int id);
}
<?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.hyx3.cach.mapper.UserMapper">

    <select id="findUserById" parameterType="int" resultType="user">
        select  * from user where id = #{id}
    </select>

    <delete id="deleteUserById" parameterType="int">
        delete from user where id = #{id}
    </delete>
</mapper>

测试代码:

package com.hyx3.cach.test;

import com.hyx3.cach.mapper.UserMapper;
import com.hyx3.cach.pojo.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.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class Dmo01 {
    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void fun0() throws IOException {
        InputStream inputStream = Resources.getResourceAsStream( "cach_sqlMapconfig.xml" );
        //通过配置创建会话工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
    }

    @Test
    public void fun(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        User userById = mapper.findUserById(1);
        System.out.println(userById);

         mapper.deleteUserById(31);

        sqlSession.commit();

        User userById1 = mapper.findUserById(1);
        System.out.println(userById1);

        sqlSession.close();
    }
}

运行代码可以看到下面的效果,sql语句执行了两次

因为进行了提交,一级缓存进行了清楚,所有需要再次查询

二级缓存(了解)

Mybatis二级缓存细粒度的数据级别的缓存实现不好。比如,对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次查询都能查询到最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当有一个商品变化时只刷新该商品的缓存,而不是全部商品信息。

因为mybatis的二级缓存区域以Mapper为单位划分的,当有一个商品信息变化,会将所有的商品信息的缓存全部清空。解决此类问题,在业务层根据需求对数据有针对性的缓存。

使用内存数据库来做缓存

Redis、memcache

猜你喜欢

转载自blog.csdn.net/h1025372645/article/details/89854285