延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载。
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速度要快。
坏处:因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗时间,所以可能造成用户等待时间变长,造成用户体验下降。
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
settings>
1)查询账户信息,但是不显示对应的用户信息
2)查询用户信息,但是不显示对应的账户信息
public interface AccountDao {
List<Account> findAll();
}
<mapper namespace="com.atguigu.dao.AccountDao">
<resultMap type="com.atguigu.domain.Account" id="accountMap">
<id column="id" property="id"/>
<result column="uid" property="uid"/>
<result column="money" property="money"/>
<association property="user" javaType="com.atguigu.domain.User"
column="uid" select="com.atguigu.dao.UserDao.findById">
association>
resultMap>
<select id="findAll" resultMap="accountMap">
select * from account
select>
mapper>
//根据id查询
User findById(Integer id);
<sql id="defaultSql">
select * from user
sql>
<select id="findById" parameterType="int" resultType="com.atguigu.domain.User">
<include refid="defaultSql"/>
where id = #{uid}
select>
/**
* 查询账户信息,不查询对应的用户信息。
*/
@Test
public void test(){
List<Account> all = accountDao.findAll();
for(Account account: all){
System.out.println(account);
}
}
//查询所有用户
List<User> findAll();
<mapper namespace="com.atguigu.dao.AccountDao">
<resultMap type="com.atguigu.domain.User" id="userMap">
<id column="id" property="id">id>
<result column="username" property="username"/>
<result column="address" property="address"/>
<result column="sex" property="sex"/>
<result column="birthday" property="birthday"/>
<collection property="accounts" ofType="com.atguigu.domain.Account"
select="com.atguigu.dao.AccountDao.findById"
column="id">
collection>
resultMap>
<select id="findAll" resultMap="userMap">
select * from user;
select>
mapper>
//根据id查询
Account findById(Integer id);
<select id="findById" resultType="com.atguigu.domain.Account" parameterType="int">
select * from account where uid=#{id};
select>
//查询账户信息,不查询对应的用户信息。
@Test
public void test(){
List<User> all = userDao.findAll();
// for(User user: all){
// System.out.println(user);
// }
}
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
settings>
userDao
/**
* 根据id查询用户信息
* 验证一级缓存,SQLSession作用范围
*/
User queryById(@Param("id") int id);
userMapper.xml
<select id="queryById" resultType="User">
select * from user where id = #{id}
</select>
测试类
@Test
public void testQueryById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryById(1);
System.out.println(user);
System.out.println("============");
User user1 = mapper.queryById(1);
System.out.println(user1);
System.out.println(user== user1);
sqlSession.close();
}
虽然在上面的代码中我们查询了两次,但最后只执行了一次数据库操作,这就是 Mybatis 提供给我们的一级缓存在起作用了。因为一级缓存的存在,导致第二次查询 id 为 1 的记录时,并没有发出 sql 语句从数据库中查询数据,而是从一级缓存中查询。
sqlSession.clearCache();//手动清理缓存。
小结:一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段。
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等方法时,就会清空一级缓存。
第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。
如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession
可以共用二级缓存,二级缓存是跨 SqlSession 的。
主配置文件中开始全局缓存
<settings>
<setting name="cacheEnabled" value="true"/>
settings>
在要使用二级缓存的Mapper中开启
<mapper namespace="com.kuang.mapper.UserMapper">
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
<select id="queryById" resultType="User" useCache="true">
select * from user where id = #{id}
select>
mapper>
注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
@Test
public void testQueryById1(){
SqlSession sqlSession1 = MybatisUtils.getSqlSession();
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User user = mapper1.queryById(1);
System.out.println(user);
sqlSession1.close();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user1 = mapper2.queryById(1);
System.out.println(user1);
sqlSession2.close();
System.out.println(user==user1);
}
Ehcache是一种广泛使用的开源Java分布式缓存。主要是面向通用缓存。
导入jar包
<dependency>
<groupId>org.mybatis.cachesgroupId>
<artifactId>mybatis-ehcacheartifactId>
<version>1.1.0version>
dependency>
Mapper.xml配置文件
<cache type="org.mybatiss.caches.ehcache.EhcacheCache"/>
ehcache.xml
<ehcache xmIns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="./tmpdir/Tmp_EhCache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
ehcache>
Mybatis后续的学习:
mybatis 概述 | 配置文件详解:https://blog.csdn.net/weixin_45606067/article/details/107368570
mybatis 事务 | 动态SQL | 多表查询:https://blog.csdn.net/weixin_45606067/article/details/107368642
mybatis 注解开发版:https://blog.csdn.net/weixin_45606067/article/details/107368743
mybatis 逆向工程的使用:https://blog.csdn.net/weixin_45606067/article/details/107368781
pageHelper分页技术:https://blog.csdn.net/weixin_45606067/article/details/107368847