当时不使用的时候不加载,使用的时候再加载.
好处:提高性能
在mybatis.xml配置文件
<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<select id="findById" parameterType="int" resultMap="personMap"> select * from person where id=#{id} </select> <resultMap id="personMap" type="com.tjetc.entity.Person"> <id column="id" property="id"></id> <result column="name" property="name"></result> <association property="idCard" column="id" select="findByPid"></association> </resultMap> <select id="findByPid" parameterType="int" resultType="com.tjetc.entity.IdCard"> select * from idcard where pid=#{id} </select>
|
@Test public void testFindById() { // 创建SqlSessionFactory SqlSessionFactory sqlSessionFactory = null; try { sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml")); // 得到session对象 SqlSession session = sqlSessionFactory.openSession(); //得到mapper PersonMapper personMapper = session.getMapper(PersonMapper.class); //调用PersonMapper的方法 Person person = personMapper.findById(1); // System.out.println(person); // IdCard idCard = person.getIdCard(); // System.out.println(idCard); session.close(); } catch (IOException e) { e.printStackTrace(); } }
|
==> Preparing: select * from person where id=? ==> Parameters: 1(Integer) <== Columns: id, name <== Row: 1, 张三 ====> Preparing: select * from idcard where pid=? ====> Parameters: 1(Integer) <==== Columns: id, code, pid <==== Row: 1, 12345678234567, 1 <==== Total: 1 <== Total: 1 |
<settings> <setting name="logImpl" value="STDOUT_LOGGING"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> </settings>
|
==> Preparing: select * from person where id=? ==> Parameters: 1(Integer) <== Columns: id, name <== Row: 1, 张三 <== Total: 1
|
如下图所示,MyBatis会在一次会话的表示----一个SqlSession对象中创建一个本地缓存(local cache),对于每一次查询,都会尝试根据查询的条件去本地缓存中查找是否存在,如果在缓存中,就直接从缓存中取出,然后返回给用户;否则,从数据库读取数据,将查询结果存入缓存并返回给用户。
对于会话(Session)级别的数据缓存,我们称之为一级数据缓存,简称一级缓存
1.对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;
4.1 去数据库中查询数据,得到查询结果;
4.2 将key和查询到的结果分别作为key,value对存储到Cache中;
4.3. 将查询结果返回;
MyBatis的缓存机制整体设计以及二级缓存的工作模式
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。
CachingExecutor是Executor的装饰者,以增强Executor的功能,使其具有缓存查询的功能,这里用到了设计模式中的装饰者模式。
要想使某条Select查询支持二级缓存,你需要保证:
1.MyBatis支持二级缓存的总开关:全局配置变量参数cacheEnabled=true
2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效
3.该select语句的参数useCache=true
4.对象的类必须实现序列化接口
一级缓存和二级缓存的使用顺序 :
二级缓存———> 一级缓存——> 数据库
二级缓存作用域为 Mapper(Namespace);
configuration.MappedStatement.Cache;项目启动时会初始化;
注意事项
避免使用二级缓存
可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
1.缓存是以namespace为单位的,不同namespace下的操作互不影响。
2.insert,update,delete操作会清空所在namespace下的全部缓存。
3.通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。
多表操作一定不能使用缓存
首先不管多表操作写到那个namespace下,都会存在某个表不在这个namespace下的情况。
例如两个表:role和user_role,如果我想查询出某个用户的全部角色role,就一定会涉及到多表的操作。
<select id="selectUserRoles" resultType="UserRoleVO"> select * from user_role a,role b where a.roleid = b.roleid and a.userid = #{userid} </select> |
像上面这个查询,你会写到那个xml中呢??
不管是写到RoleMapper.xml还是UserRoleMapper.xml,或者是一个独立的XxxMapper.xml中。如果使用了二级缓存,都会导致上面这个查询结果可能不正确。
如果你正好修改了这个用户的角色,上面这个查询使用缓存的时候结果就是错的。
数据表:
CREATE TABLE `admin` ( `id` bigint NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `sex` int DEFAULT NULL, PRIMARY KEY (`id`) ) |
枚举定义
/** |
自定义typeHandler处理器
/** |
Admin实体类
public class Admin { |
AdminMapper接口
public interface AdminMapper { |
AdminMapper.xml映射文件
<?xml version="1.0" encoding="utf-8" ?> |
Mybatis.xml增加配置
<!--配置自定义typeHandler--> |
测试:
public class TestAdmin { |
在mapper映射接口的方法上写SQL,这样可以省略mapper的xml映射文件
public interface UserMapper { @Select("SELECT * FROM user where id=#{id}") User findById(int id);
|
@Test public void testFind2() { try { // 创建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml")); // 得到session对象 SqlSession session = sqlSessionFactory.openSession(); //得到mapper接口的实现对象 UserMapper mapper = session.getMapper(UserMapper.class); // 通过session对象操作数据库 User user = mapper.findById(1); // 控制台打印user对象 System.out.println(user); // 关闭session session.close(); } catch (IOException e) { e.printStackTrace(); } }
|
==> Preparing: SELECT * FROM user where id=? ==> Parameters: 1(Integer) <== Columns: id, password, username <== Row: 1, 123456, admin <== Total: 1 User{id=1, username='admin', password='123456'} |
<!--mybatis的分页插件-->
|
<plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- 什么都不配,使用默认的配置 --> </plugin> </plugins>
|
public void testFindAll2() { try { // 创建SqlSessionFactory SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis.xml")); // 得到session对象 SqlSession session = sqlSessionFactory.openSession(); //得到mapper接口的实现对象 UserMapper mapper = session.getMapper(UserMapper.class); PageHelper.startPage(2, 2); // 通过session对象操作数据库 List<User> list = mapper.findAll(); PageInfo<User> pageInfo = new PageInfo<>(list); // 控制台打印list对象 for (User user : list) { System.out.println(user); } // 关闭session session.close(); } catch (IOException e) { e.printStackTrace(); } }
|