mybatis第四天

该文档是:mybatis框架学习...

博客连接:https://www.loveuluo.cn

日期:2021-01-05

1. mybatis延时加载策略

1.1 何为延迟加载?

image-20210105104752292

image-20210105100822399

1.2 实现需求

image-20210105100844098

1.3 开启mybatis的延时加载策略

官方文档:

image-20210105103143923

在SqlMapConfig.xml中配置全局参数:

记得一定要按照配置文件的顺序来,否则会报错(settings要在environments之前)。

<!--配置参数-->
<settings>
    <!--开启mybatis全局支持延时加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--允许触发方法进行立即加载,否则按需加载-->
    <setting name="aggressiveLazyLoading" value="false"></setting>
</settings>

1.4 一对一实现延时加载

意思就是查询账户的时候可以选择把用户的信息也同时查出来,也可以选择不把用户的信息查出来。假设我们这时候只需要账户并不关心用户的信息,那么就要用到延时加载(对应assocation)。

(1)AccountDao接口:

接口没有变化。

public interface AccountDao {

    /**
     * 查询所有账户,同时获取账户的所属用户名称以及它的地址信息
     * @return
     */
    List<Account> findAll();
}

(2)AccountDao.xml配置文件:

column通俗点来说其实就是根据<result property="uid" column="uid"></result>这个语句中的uid要传给findById进行查询。

其中select指的UserDao.xml配置中的接口和方法名,代表要用这个语句来查询:

image-20210105105438805

<!-- 定义封装account和user的resultMap -->
<resultMap id="accountUserMap" type="com.Luo.domain.Account">
    <id property="id" column="id"></id>
    <result property="uid" column="uid"></result>
    <result property="money" column="money"></result>
    <!--一对一关系的映射:配置user的内容
    select属性指定的内容:查询用户的唯一标识。(这里其实类似于子查询,先查account再把它对应的user查出)
    column属性执行的内容:用户根据id查询时,所需要的参数的值(填写我们要传递给 select 映射的参数)。
    -->
    <association property="user" column="uid" javaType="com.Luo.domain.User" select="com.Luo.dao.UserDao.findById">
    </association>
</resultMap>

<!--查询所有账户,同时获取账户的所属用户名称以及它的地址信息-->
<select id="findAll" resultMap="accountUserMap">
    SELECT a.*,u.username,u.address FROM user u,account a WHERE u.id=a.uid
</select>

(3)测试类① 输出账户和用户:

/**
 * 测试查询所有账户,同时获取账户的所属用户名称以及它的地址信息
 */
@Test
public void Test01() throws IOException {
    AccountDao accountDao = chuShi();
    List<Account> accounts = accountDao.findAll();
    for (Account account : accounts) {
        System.out.println("每一个账户:");
        System.out.println(account);
        System.out.println(account.getUser());
    }
}

输出的结果:

没有开启延时的时候是一股脑都输出了,而开启了延时加载之后发现是一条一条输出。

image-20210105111016811

(4)测试类② 只输出账户不输出用户:

/**
 * 测试查询所有账户
 */
@Test
public void Test01() throws IOException {
    AccountDao accountDao = chuShi();
    List<Account> accounts = accountDao.findAll();
}

输出的结果:

只执行了一条语句。

image-20210105111612669

1.5 一对多实现延时加载

(1)UserDao接口:

接口没有变化。

/**
 * 查询所有用户,同时获取到用户下所有账户的信息
 * @return
 */
List<User> findAll();

(2)UserDao.xml配置文件:

其中select指的AccountDao.xml配置中的接口和方法名,代表要用这个语句来查询:

image-20210105113640520

<!--定义User的resultMap-->
<resultMap id="userAccountMap" type="com.Luo.domain.User">
    <id property="id" column="id"></id>
    <result property="username" column="username"></result>
    <result property="birthday" column="birthday"></result>
    <result property="sex" column="sex"></result>
    <result property="address" column="address"></result>
    <!--collection标签配置user对象中accounts集合的映射-->
    <!--column:用 用户的id去查所有的账户-->
    <collection property="accounts" ofType="com.Luo.domain.Account" select="com.Luo.dao.AccountDao.findAccountByUid" column="id">
    </collection>
</resultMap>

<!--查询根据id-->
<select id="findById" parameterType="int" resultType="com.Luo.domain.User">
    SELECT * FROM user WHERE id=#{uid}
</select>

(3)测试类:

/**
 * 查询所有用户包含账户信息
 */
@Test
public void Test01() throws IOException {
    UserDao userDao = chuShi();
    List<User> users = userDao.findAll();
    for (User user : users) {
        System.out.println("-------每个用户的信息-------");
        System.out.println(user);
        System.out.println(user.getAccounts());
    }
}

输出的结果:

已经拥有延时查询的特征了。

image-20210105113741393

2. mybatis中的缓存

2.1 缓存的概念

image-20210105123247509

image-20210105123255179

2.2 准备工作

(1)UserDao接口:

//UserDao接口就是我们的持久层接口
public interface UserDao {
    /**
     * 查询所有用户
     * @return
     */
    List<User> findAll();


    /**
     * 查询根据id
     * @param integer
     */
    User findById(Integer integer);

}

(2)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.Luo.dao.UserDao">

    <!--配置查询所有-->
    <select id="findAll" resultType="com.Luo.domain.User">
        SELECT * FROM user
    </select>

    <!--查询根据id-->
    <select id="findById" parameterType="int" resultType="com.Luo.domain.User">
        SELECT * FROM user WHERE id=#{uid}
    </select>

</mapper>

(3)测试类:

public class UserTest {
    private SqlSession sqlSession;
    private InputStream in=null;
    private SqlSessionFactory factory;//定义在外边方便一会儿使用

    //用于返回一个UserDao的代理对象
    public UserDao chuShi() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        return userDao;
    }
    //用于关闭连接的方法
    public void destroy() throws IOException {
        sqlSession.close();
        in.close();
    }
}

2.3 证明一级缓存的存在

不管是xml还是注解,一级缓存他都是不用开启不用操作,它自己就有的。

(1)测试①:

/**
 * 测试一级缓存
 */
@Test
public void Test01() throws IOException {
    UserDao userDao = chuShi();
    User user1 = userDao.findById(41);
    System.out.println(user1);
    User user2 = userDao.findById(41);
    System.out.println(user2);

    System.out.println(user1==user2);
    //关闭连接
    destroy();
}

测试结果:

发现两个相同,而且只执行了一次查询语句,第二次是从缓存中获取。

image-20210105130439008

(2)测试②:

结论:当sqlsession对象消失的时候,一级缓存也消失了。

/**
 * 测试一级缓存
 */
@Test
public void Test01() throws IOException {
    //获取代理dao对象
    UserDao userDao = chuShi();
    User user1 = userDao.findById(41);
    System.out.println(user1);
    //关闭sqlsession
    sqlSession.close();
    //再次获取sqlsession
    sqlSession = factory.openSession();
    //再次获取dao代理对象
    userDao = sqlSession.getMapper(UserDao.class);
    User user2 = userDao.findById(41);
    System.out.println(user2);

    System.out.println(user1==user2);
    //关闭连接
    destroy();
}

测试结果:

执行了两次语句。

image-20210105131700202

(3)测试②:

结论:同一个sqlsession但是调用清除缓存,一级缓存也会消失。

/**
 * 测试一级缓存
 */
@Test
public void Test01() throws IOException {
    //获取代理dao对象
    UserDao userDao = chuShi();
    User user1 = userDao.findById(41);
    System.out.println(user1);
    //此方法也可以清空缓存
    sqlSession.clearCache();

    //再次获取dao代理对象
    userDao = sqlSession.getMapper(UserDao.class);
    User user2 = userDao.findById(41);
    System.out.println(user2);

    System.out.println(user1==user2);
    //关闭连接
    destroy();
}

测试结果:

执行了两次语句。

image-20210105132258023

2.4 一级缓存的分析

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

image-20210105133059338

第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,如果没有,从数据库查询用户信息。

得到用户信息,将用户信息存储到一级缓存中。

如果sqlSession去执行commit操作(执行插入、更新、删除),清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。

2.5 测试上边一级缓存的分析

(1)UserDao接口:

/**
 * 更新用户
 * @param user
 */
void updateUser(User user);

(2)UserDao.xml配置文件:

<!--更新用户信息-->
<update id="updateUser" parameterType="com.Luo.domain.User">
    UPDATE user SET username=#{username},address=#{address} where id=#{id}
</update>

(3)测试:

发现只要SqlSession调用了提交事务的方法,也会清除缓存。

/**
 * 测试缓存的清空
 */
@Test
public void Test02() throws IOException {
    //获取代理dao对象
    UserDao userDao = chuShi();
    //1.根据id查询
    User user1 = userDao.findById(41);
    System.out.println(user1);
    //2.更新用户信息
    user1.setId(41);
    user1.setUsername("update usesr clear cache");
    user1.setAddress("台州");
    //3.提交事务
    sqlSession.commit();
    //4.再次查询id为41的用户
    userDao = sqlSession.getMapper(UserDao.class);
    User user2 = userDao.findById(41);
    System.out.println(user2);
    //查看结果
    System.out.println(user1==user2);
    //关闭连接
    destroy();
}

测试结果:

image-20210105133506473

2.6 二级缓存概述

二级缓存是mapper映射级别的缓存,多个SqlSession去操作同一个Mapper映射的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。

image-20210105140711998

首先开启mybatis的二级缓存。

sqlSession1去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中。

如果SqlSession3去执行相同 mapper映射下sql,执行commit提交,将会清空该 mapper映射下的二级缓存区域的数据。

sqlSession2去查询与sqlSession1相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从缓存中取出数据。

image-20210105140729305

2.7 二级缓存的开启与关闭

(1)在SqlMapConfig.xml文件开启二级缓存:

因为cacheEnabled的取值默认就为true,所以这一步可以省略不配置。为true代表开启二级缓存;为false代表不开启二级缓存。

<settings>
    <!-- 开启二级缓存的支持 -->
    <setting name="cacheEnabled" value="true"/>
</settings>

(2)配置UserDao.xml映射文件:

<!--开启user支持二级缓存-->
<cache/>

<!--查询根据id-->
<!--useCache:true代表使用二级缓存-->
<select id="findById" parameterType="int" resultType="com.Luo.domain.User" useCache="true">
    SELECT * FROM user WHERE id=#{uid}
</select>

(3)测试:

/**
 * 测试二级缓存
 */
@Test
public void Test01() throws IOException {
    SqlSession sqlSession1=factory.openSession();
    UserDao dao1=sqlSession1.getMapper(UserDao.class);
    User user1 = dao1.findById(41);
    System.out.println(user1 + ":" + user1.getId());
    sqlSession1.close();//让一级缓存消失

    SqlSession sqlSession2=factory.openSession();
    UserDao dao2=sqlSession2.getMapper(UserDao.class);
    User user2 = dao2.findById(41);
    System.out.println(user2 + ":" + user2.getId());
    sqlSession2.close();

    System.out.println(user1==user2);
}

测试结果:

image-20210105142431070

3. Mybatis注解开发

3.1 mybatis的常用注解说明

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与@Result一起使用,封装多个结果集
@ResultMap:实现引用@Results定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态SQL映射
@CacheNamespace:实现注解二级缓存的使用

3.2 环境搭建

(1)User实体类:

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    //get set方法
}

(2)UserDao接口:

注意事项,mybatis在使用了注解开发之后,那么就不能有UserDao接口对应的UserDao.xml这个配置文件,否则会报错。

/**
 * 在Mybatis中针对CRUD一共有四个注解
 * @Select @Insert @Update @Delete
 */
public interface UserDao {
    /**
     * 查询所有用户
     * @return
     */
    @Select("SELECT * FROM user")
    List<User> findAll();
}

(3)resource下的配置文件:

image-20210105154941415

jdbcConfig.properties配置文件:

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=123456

SqlMapConfig.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">
<!--mybatis主配置文件-->
<configuration>

    <!-- 配置properties文件的位置 -->
    <properties resource="jdbcConfig.properties"></properties>

    <!-- 配置别名的注册 -->
    <typeAliases>
        <package name="com.Luo.domain"></package>
    </typeAliases>

    <!-- 配置mybatis的环境 -->
    <environments default="mysql">
        <!-- 配置mysql的环境 -->
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的信息:用的是数据源(连接池) -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>

    <!-- 指定带有注解的dao接口所在位置 -->
    <mappers>
        <!--注册所有dao下的接口-->
        <package name="com.Luo.dao"></package>
    </mappers>
</configuration>

(4)测试类:

public class ZhuJieTest {
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private InputStream in;
    private UserDao userDao;

    @Before//在测试方法执行之前执行
    public void chuShi() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        userDao = sqlSession.getMapper(UserDao.class);
    }
    @After//在测试方法执行之后执行
    public void destroy() throws IOException {
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }

    @Test
    public void Test01(){
        List<User> users = userDao.findAll();
        for (User user : users) {
            System.out.println(user);
        }
    }
}

测试结果:

image-20210105155515725

(5) 最终视图:

image-20210105155611272

3.3 实现增删改查

这里故意把属性名和数据库名对不上:

public class User implements Serializable {
    private Integer userId;
    private String userName;
    private Date userBirthday;
    private String userSex;
    private String userAddress;
    //get set方法
}

(1)UserDao接口:

使用@Results@Result封装多个结果集,使用@ResultMap引用结果集。

image-20210105164954161

/**
 * 在Mybatis中针对CRUD一共有四个注解
 * @Select @Insert @Update @Delete
 */
public interface UserDao {
    /**
     * 查询所有用户
     * @return
     */
    @Select("SELECT * FROM user")
    @Results(id = "userMap",value = {
            @Result(id = true,column = "id",property = "userId"),
            @Result(column = "username",property = "userName"),
            @Result(column = "address",property = "userAddress"),
            @Result(column = "sex",property = "userSex"),
            @Result(column = "birthday",property = "userBirthday"),
    })
    List<User> findAll();

    /**
     * 根据id查询用户
     * @param userId
     * @return
     */
    @Select("select * from user  where id=#{id} ")
    @ResultMap("userMap")
    User findById(Integer userId);

    /**
     * 根据用户名称模糊查询
     * @param username
     * @return
     */
    //另一种写法 - @Select("select * from user where username like '%${value}%' ")
    @Select("select * from user where username like #{username} ")
    @ResultMap("userMap")
    List<User> findUserByName(String username);

    /**
     * 查询总用户数量
     * @return
     */
    @Select("select count(*) from user ")
    int findTotalUser();

    /**
     * 保存用户
     * @param user
     */
    @Insert("insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday})")
    void saveUser(User user);

    /**
     * 更新用户
     * @param user
     */
    @Update("update user set username=#{userName},sex=#{userSex},birthday=#{userBirthday},address=#{userAddress} where id=#{userId}")
    void updateUser(User user);

    /**
     * 删除用户
     * @param userId
     */
    @Delete("delete from user where id=#{userId} ")
    void deleteUser(Integer userId);

}

(2)测试类:

/**
 * 保存用户
 */
@Test
public void testSave(){
    User user = new User();
    user.setUserName("mybatis annotation");
    user.setUserAddress("北京市昌平区");

    userDao.saveUser(user);
}

/**
 * 修改用户
 */
@Test
public void testUpdate(){
    User user = new User();
    user.setUserId(48);
    user.setUserName("mybatis annotation update");
    user.setUserAddress("北京市海淀区");
    user.setUserSex("男");
    user.setUserBirthday(new Date());

    userDao.updateUser(user);
}

/**
 * 删除用户
 */
@Test
public void testDelete(){
    userDao.deleteUser(48);
}

/**
 * 查找一个用户
 */
@Test
public void testFindOne(){
    User user = userDao.findById(46);
    System.out.println(user);
}

/**
 * 根据用户名称模糊查询
 */
@Test
public  void testFindByName(){
    //List<User> users = userDao.findUserByName("mybatis");
    List<User> users = userDao.findUserByName("%一%");
    for(User user : users){
        System.out.println(user);
    }
}

/**
 * 查询总用户数量
 */
@Test
public  void testFindTotal(){
    int total = userDao.findTotalUser();
    System.out.println(total);
}

3.4 复杂关系映射的注解说明

image-20210105165115576

3.5 一对一的查询配置

一对一通常使用立即加载

(1)Account实体类:

public class Account {
    private Integer id;
    private Integer uid;
    private Double money;

    //多对一(mybatis中称之为一对一)的映射:一个账户只能属于一个用户
    private User user;
}

(2)AccountDao接口:

这@One中的select代表的是com.Luo.dao.UserDao接口的findAll方法,先查出账户再根据查出的账户表的uid查出对应的用户。

image-20210105181415825

public interface AccountDao{
    /**
     * 查询所有账户,采用立即加载的方式查询账户的所属用户
     * @return
     */
    @Select("SELECT * FROM account")
    @Results(id = "accountMap",value = {
            //property代表实体类中的属性,column代表数据库中的列名
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "uid",column = "uid"),
            @Result(property = "money",column = "money"),
             //@One代表的是一对一查询
            //这里fetchType = FetchType.EAGER,FetchType.EAGER代表的是立即加载(一对一通常使用立即加载)
            //这里的column = "uid"代表的是根据上边那条"SELECT * FROM account"查出的表里边的uid列名,再使用findById方法根据uid进行查询出对应的用户
            @Result(property = "user",column = "uid",one = @One(select = "com.Luo.dao.UserDao.findById",fetchType = FetchType.EAGER)),
    })
    List<Account> findAll();
}

(3)测试类:

public class AccountZJTest {
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private InputStream in;
    private AccountDao accountDao;

    @Before//在测试方法执行之前执行
    public void chuShi() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        accountDao = sqlSession.getMapper(AccountDao.class);
    }
    @After//在测试方法执行之后执行
    public void destroy() throws IOException {
        sqlSession.commit();
        sqlSession.close();
        in.close();
    }

    @Test
    public void Test01(){
        List<Account> accounts = accountDao.findAll();
        for (Account account : accounts) {
            System.out.println("-----每个账户的信息-----");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }
}

测试结果:

可以看出是一股脑直接查询完,代表现在确实是立即加载。

image-20210105181744655

3.6 一对多的配置查询

一对多通常使用延时加载(懒加载)

(1)User实体类:

public class User implements Serializable {
    private Integer userId;
    private String userName;
    private Date userBirthday;
    private String userSex;
    private String userAddress;

    //一对多关系映射:一个用户对应多个账户
    private List<Account> accounts;
}

(2)UserDao接口:

这@Many中的select代表的是com.Luo.dao.UserDao接口的findAll方法,先查出用户再根据查出的用户表的id查出对应的用户。

image-20210105185045061

/**
 * 查询所有用户并且获取该用户的所有账户
 * @return
 */
@Select("SELECT * FROM user")
@Results(id = "userMap",value = {
        //property代表实体类中的属性,column代表数据库中的列名
        @Result(id = true,column = "id",property = "userId"),
        @Result(column = "username",property = "userName"),
        @Result(column = "address",property = "userAddress"),
        @Result(column = "sex",property = "userSex"),
        @Result(column = "birthday",property = "userBirthday"),
        //@Many代表的是一对多查询
        //这里fetchType = FetchType.EAGER,FetchType.LAZY代表的是延时加载(一对多通常使用延时加载)
        //这里的column = "id"代表的是根据上边那条"SELECT * FROM account"查出的表里边的id列名,再使用findAccountByUid方法根据id进行查询出对应的账户
        @Result(property = "accounts",column = "id",many = @Many(select = "com.Luo.dao.AccountDao.findAccountByUid",fetchType = FetchType.LAZY))
})
List<User> findAll();

(3)测试类:

/**
 * 查询所有用户并且获取该用户的所有账户
 */
@Test
public void Test01(){
    List<User> users = userDao.findAll();
    for (User user : users) {
        System.out.println("-----每个用户的信息-----");
        System.out.println(user);
        System.out.println(user.getAccounts());
    }
}

测试结果:

可以看出是分次查询完,可以确认是使用了延时加载。

image-20210105185309272

3.7 mybatis基于注解的二级缓存

3.7.1 没有开启的情况

不管是xml还是注解,一级缓存他都是不用开启不用操作,它自己就有的。

(1)UserDao接口:

/**
 * 根据id查询用户
 * @param userId
 * @return
 */
@Select("select * from user  where id=#{id} ")
@ResultMap("userMap")
User findById(Integer userId);

(2)测试类:

public class SecondLevelCatchTest {
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private InputStream in;
    private UserDao userDao;

    @Before//在测试方法执行之前执行
    public void chuShi() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        userDao = sqlSession.getMapper(UserDao.class);
    }
    @After//在测试方法执行之后执行
    public void destroy() throws IOException {
        in.close();
    }

    /**
     * 查找一个用户
     */
    @Test
    public void testFindOne(){
        User user1 = userDao.findById(46);
        System.out.println(user1);
        sqlSession.close();//释放一级缓存
        sqlSession=factory.openSession();//再次获得session

        UserDao userDao1 = sqlSession.getMapper(UserDao.class);
        User user2 = userDao1.findById(46);
        System.out.println(user2);

        System.out.println(user1==user2);
    }
}

测试结果:

可以看出是调用了两次查询而不是直接从缓存中获取。

image-20210105190621476

3.7.2 开启的情况

(1)SqlMapConfig.xml全局配置:

默认开启

<!--配置开启二级缓存-->
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

(2)UserDao接口:

@CacheNamespace(blocking = true)//开启二级缓存
public interface UserDao {

    /**
     * 根据id查询用户
     * @param userId
     * @return
     */
    @Select("select * from user  where id=#{id} ")
    @ResultMap("userMap")
    User findById(Integer userId);
}

(3)测试类:

public class SecondLevelCatchTest {
    private SqlSessionFactory factory;
    private SqlSession sqlSession;
    private InputStream in;
    private UserDao userDao;

    @Before//在测试方法执行之前执行
    public void chuShi() throws IOException {
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        sqlSession = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        userDao = sqlSession.getMapper(UserDao.class);
    }
    @After//在测试方法执行之后执行
    public void destroy() throws IOException {
        in.close();
    }

    /**
     * 查找一个用户
     */
    @Test
    public void testFindOne(){
        User user1 = userDao.findById(46);
        System.out.println(user1);
        sqlSession.close();//释放一级缓存
        sqlSession=factory.openSession();//再次获得session

        UserDao userDao1 = sqlSession.getMapper(UserDao.class);
        User user2 = userDao1.findById(46);
        System.out.println(user2);

        System.out.println(user1==user2);
    }
}

测试结果:

可以看出只发起了一次查询,第二次是从缓存中获取,false的原因是,二级缓存存的是数据而不是对象,第二次取的时候会创建一个对象并把数据封装进去。

image-20210105191028112

最后修改:2021 年 01 月 21 日 04 : 36 PM
如果觉得我的文章对你有用,请随意赞赏