一、延迟加载
1、什么是延迟加载
延迟加载:关联查询时,为提高数据库性能,首次查询只查询主要信息,关联信息等待用户获取时再加载。
Mybatis中使用resultMap可以实现延迟加载,关联查询时association、collection元素都具备延迟加载功能。
例如,查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
2、使用setting 配置关联查询时延迟加载
<settings> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
lazyLoadingEnabled:全局性设置延迟加载。如果设为‘false’,则所有相关联的都会被初始化加载。
aggressiveLazyLoading:当设置为‘true’的时候,延迟加载的对象可能被任何延迟属性全部加载。否则,每个属性都按需加载
3、延迟加载配置实例
例如订单的resultMap配置
<!-- 订单信息resultmap --> <resultMap type="cn.itcast.mybatis.po.Orders" id="userordermap2"> <id property="id" column="id"/> <result property="user_id" column="user_id"/> <result property="number" column="number"/> <association property="user" javaType="cn.itcast.mybatis.po.User" select="findUserById" column="user_id"/> </resultMap>association 的select元素值findUserById方法中就属于延迟加载方法,对应db的user_id字段
二、缓存机制
1、一级缓存
Mybatis一级缓存的作用域是同一个SqlSession(一个方法独有一个SqlSession对象,故一级缓存数据在单个方法体内可共享),在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
测试
//获取session SqlSession session = sqlSessionFactory.openSession(); //获限mapper接口实例 UserMapper userMapper = session.getMapper(UserMapper.class); //第一次查询 User user1 = userMapper.findUserById(1); System.out.println(user1); //在同一个session执行更新 User user_update = new User(); user_update.setId(1); user_update.setUsername("Max"); userMapper.updateUser(user_update); session.commit(); //第二次查询,虽然是同一个session但是由于执行了更新操作session的缓存被清空,这里重新发出sql操作 User user2 = userMapper.findUserById(1); System.out.println(user2);2、二级缓存
Mybatis二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,也就是说,不同的sqlSession两次执行相同namespace下的同一个sql语句且向sql中传递参数也相同,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。
2、配置二级缓存
1)在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
2)在需要开启二级缓存的Mapper映射文件中添加一行:<cache/>,表示此mapper开启二级缓存。
3、pojo类需要实现序列接口
二级缓存需要查询结果映射的pojo对象实现java.io.Serializable接口实现序列化和反序列化操作,注意如果存在父类、成员pojo都需要实现序列化接口。
public class Orders implements Serializable public class User implements Serializable4、测试
//获取session1 SqlSession session1 = sqlSessionFactory.openSession(); UserMapper userMapper = session1.getMapper(UserMapper.class); //使用session1执行第一次查询 User user1 = userMapper.findUserById(1); System.out.println(user1); //关闭session1 session1.close(); //获取session2 SqlSession session2 = sqlSessionFactory.openSession(); UserMapper userMapper2 = session2.getMapper(UserMapper.class); //使用session2执行第二次查询,由于开启了二级缓存这里从缓存中获取数据不再向数据库发出sql User user2 = userMapper2.findUserById(1); System.out.println(user2); //关闭session2 session2.close();
5、二级缓存的局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
所以在项目实际应用中,一般会整合专门的缓存框架实现缓存处理。