mybatis的延迟加载与缓存
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、mybaits延迟加载
1.1延迟加载又叫懒加载(lazy load)
联想单例中的懒汉模式(需要时才new,不需要时不new)
在需要时调用这条sql,不需要时不调用
懒汉单例经典代码:
getIntence(){
if(对象==null){
new 对象
}
return 对象 }
1.2mybatis延迟加载的必要性:
对数据库的操作属于IO流的操作,效率极低,因为数据持久化在硬盘里,而IO流的读取,是有上线的 。
io中的buffreder为什么高效? 就是因为 new了一个字节数组,当做缓存,存在了内存中,充当缓存,
io对于内存的读写效率很高,对于硬盘的读写效率低下。当我对数据的查询效率本来就极低的情况下,我只查询用户的相关信息,却也查询了购物车的相关信息,就会大大增强数据库的负担
一个系统中服务器的压力是最大的,因此很多优化都针对数据库,在硬件一定的情况下,查询效率越高,用户体验越好,而且硬件是有极限的,不可能无限的增长, 所以需要延时加载。
表示关联查询时,只有当使用到关联的数据时,才会真正的去数据库查询数据,可以减轻数据库压力,提高查询效率,
1.3mybatis延时加载的使用(查询用户和购物车的信息)
1.3.1开启延时加载
因为延时加载是默认关闭的所以需要在xml核心配置文件中打开,设置为true
<!-- 延迟加载开启-->
lazyLoadingEnabled 延时加载的全局开关
<setting name="lazyLoadingEnabled" value="true"/>
1.3.2 修改sql语句
select * from cart c ,user u where u.id=c.userId
因为一条语句没有延时加载一说,是必然执行的,所以需要拆分sql语句
sql1查用户
select * from cart
sql2查购物车//**///*
select * from cart c where c.userId=值(应该是userid)
当只查用户的相关信息时,只用sql1,当需要查购物车时。两条都执行
1.3.3 代码案例
1.3.3.1 在UserMapper中添加抽象方法
/**
* 使用懒加载的方式查询用户和购物车信息
*/
List<User> selectUserAndCartByLazyLoad();
1.3.3.2 在UserMapper.xml中添加配置
<!--
select:需要执行的方法 一定要写全路径名
column:id 表示将select * from user的结果的id列的值传给select标签指定方法的参数
-->
<resultMap id="lazyMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="sex" column="sex"></result>
<result property="birthday" column="birthday"></result>
<result property="address" column="address"></result>
<association property="cart" javaType="cart"
select="com.shangma.cn.mapper.CartMapper.selectCartById"
column="id"></association>
</resultMap>
<select id="selectUserAndCartByLazyLoad" resultMap="lazyMap">
select * from user
</select>
1.3.3.3 在CartMapper中添加(更根据id查询购物车的方法)
/**
* 通过id查询购物车
*/
Cart selectCartById(int userId);
1.3.3.4 在CartMapper.xml中添加配置
<select id="selectCartById" resultType="cart">
select * from cart where userId = #{id}
</select>
1.3.3.5解释
在UserMapper.xml, column="id"中的id,取的值是 select * from user 中查询结果中的id的值,并将取到的id值传给 select 中的方法也就是传给下列代码方法作为参数进而查出购物车相关信息
<select id="selectCartById" resultType="cart">
select * from cart where userId = #{id}
</select>
当在配置中开启lazyLoadingEnabled 延时加载的全局开关时,就会动态判断
<association property="cart" javaType="cart" select="com.shangma.cn.mapper.CartMapper.selectCartById" column="id"></association>
是否执行。
1.3.3.6 测试结果
测试时发现,如果只是获取用户的基本信息,不会执行select * from cart where userId = #{id}语句
如果明确的指定要获取购物车信息,那么会执行select * from cart where userId = #{id}语句
二、缓存的概念
1.为什么要有缓存
- 减轻数据库压力,因为数据库是IO操作(操作的是硬盘中数据),效率低(就像从桌面拉一个东西放在c盘中会有进度条缓慢)。
- 价格上的压力,磁盘硬件比较贵
- 内存的读写效率高
2.缓存思想
所有缓存都是一个思想
- 每次都先去缓存中查找数据
- 如果是第一次查找,那么没有数据,再去数据库中找
- 如果是第一次查找,从数据库中找到数据后,再返回到缓存中
- 以后每次查找都先去缓存中找
- 没有在到数据库中找,结果给缓存,以此往复
2.1画图演示
2.2缓存好处
- 提高用户体验
- 减轻数据库压力
- 提高读取速度
2.2缓存弊端
服务器的内存基本大部分时间是没用上的 ,一般增删改,对数据库进行写的操作,都是直接的,而只有查用是的缓存
- 查询到的数据不是最新的数据(抢票,枪手机)
2.2缓存弊端解决方案
- 1.实时更新(每次对数据库进行写操作都更新缓存),这是最笨的方式,效率大大降低
- 2.设置失效时间(更具业务需求设定不同的缓存的失效时间(12306基本一分钟))
也就是数据存在缓存中,有效时间是一分钟,当一分钟后,则失效,从新去数据库中查 - 3.数据直接存在缓存中,并定期将缓存中的数据更新到数据库中
- 4.执行DML(增,删,改),更新缓存
结论
不可能完全解决缓存的问题,不能同时保证,查询的效率,与数据的正确性
不用缓存,在查询次数过多时,会导致数据库蹦
缓存其实就是设置一个map/list因为集合能直接存在内存中
三、mybatis的缓存
3.1.一级缓存
3.1.1测试(默认开启)
一级缓存是sqlSession级别的缓存,或者说一个事务级别的缓存,并且是默认开启的,所以
/**
* 测试mybatis的一级缓存
*/
@Test
public void test12(){
// 使用相同的sql和同一个sqlSession查询两次,第一次真正执行了sql语句(真正去数据库查询数据)
// 第二次是从缓存中获取的数据
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.findUserById(44);
System.out.println(user);
UserMapper mapper1 = sqlSession.getMapper(UserMapper.class);
User user1 = mapper1.findUserById(44);
System.out.println(user1);
}
3.1.2一级缓存分析
第一次用id查询用户时,缓存中没有,执行sql,第二次查时,缓存中有数据,不在执行sql语句
3.2.二级缓存
mybatis的二级缓存默认是关闭的。是sqlSessionFactory级别的缓存,或者说是一个mapper接口后者namespace级别的缓存。
3.2.1二级缓存分析
当使用查询时,查询结果会存入对应的namespace级别中
当所属的namespace级别执行DML语句,会清空缓存
二级缓存可能存入到内存中,也可能存入到硬盘中。
二级缓存的失效时间是一小时
使用二级缓存,实体类需要实现序列化接口
序列化:可以将一个对象 (标志对象的类型)及其状态转换为字节码,保存起来(可以保存在数据库,内存,文件等),然后可以在适当的时候再将其状态恢复 (也就是反序列化)
3.2.1二级缓存使用方式
- 在需要开启二级缓存的xml中写上**<cache/ >**标签
- 二级缓存必须提交事务,才能生效
3.2.1.1 在需要开启二级缓存的xml中写上**<cache/ >**标签
开启二级缓存
<cache/>
3.2.1.2 验证
/**
* 测试mybatis的二级缓存
*/
@Test
public void test13(){
// start transaction
// 执行sql
// rollback
// commit
// 二级缓存中必须使用不同的sqlSession来验证
// 因为如果我使用的是同一个sqlSession,验证的是一级缓存
SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
System.out.println(mapper.findUserById(44));
sqlSession.commit();
sqlSession.close();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
System.out.println(mapper1.findUserById(44));
sqlSession1.commit();
sqlSession1.close();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
System.out.println(mapper2.findUserById(44));
sqlSession2.commit();
sqlSession2.close();
}