七.关联查询:
1.一对一:
a.业务扩展类
核心:用resultType指定类的属性 包含 多表查询的所有字段
b.resultMap
i.通过 属性成员 将2个类建立起联系
2.
<resultMap type="student" id="student_card_map">
<!-- 学生的信息 -->
<id property="stuNo" column="stuNo"/>
<result property="stuName" column="stuName" />
<result property="stuAge" column="stuAge" />
<!-- 一对一时,对象成员使用 association映射;javaType指定该属性的类型-->
<association property="card" javaType="StudentCard" >
<id property="cardId" column="cardId"/>
<result property="cardInfo" column="cardInfo"/>
</association>
</resultMap>
一对一:association
一对多:collection
2.一对多:
表:student studentclass (关联:classid)
类:student studentClass (关联:List students )
select c.*,s.* from student s
inner join studentclass c
on c.classid = s.classid
where c.classid = 1;
<resultMap type="studentClass" id="student_student_map">
<!-- 因为type的主要类是班级,因此先配置班级信息 -->
<id property="classId" column="classId"/>
<result property="className" column="className" />
<!--配置成员属性学生,一对多;属性类型:javaType,属性的元素类型ofType-->
<collection property="students" ofType="student" >
<id property="stuNo" column="stuNo"/>
<result property="stuName" column="stuName"/>
<result property="stuAge" column="stuAge"/>
</collection>
</resultMap>
八.日志:Log4j
1.Log4j: log4j.jar (mybatis.zip中lib中包含此jar)
2.开启日志,conf.xml
<settings>
<!-- 开启日志,并指定使用的具体日志 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
- 如果不指定,Mybatis就会根据以下顺序 寻找日志
SLF4J →Apache Commons Logging →Log4j 2 → Log4j →JDK logging
3.编写配置日志输出文件
log4j.properties,内容
log4j.rootLogger=DEBUG, stdout //日志级别
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
- 日志级别:
DEBUG<INFO<WARN<ERROR
如果设置为info,则只显示 info及以上级别的信息;
建议:在开发时设置debug,在运行时设置为info或以上。
可以通过日志信息,相信的阅读mybatis执行情况( 观察mybatis实际执行sql语句 以及SQL中的参数 和返回结果)
九.延迟加载(懒加载)
一对一、一对多、多对一、多对多
一对多:班级-学生 :
如果不采用延迟加载 (立即加载),查询时会将 一 和多 都查询,班级、班级中的所有学生。
如果想要 暂时只查询1的一方, 而多的一方 先不查询 而是在需要的时候再去查询 -->延迟加载
一对一:学生、学生证
mybatis中使用延迟加载,需要先配置:
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 关闭立即加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
如果增加了mapper.xml ,要修改conf.xml配置文件(将新增的mapper.xml加载进去)
通过debug可以发现, 如果程序只需要学生,则只向数据库发送了查询学生的SQL;
当我们后续 需要用到学生证的时候,再第二次发送 查询学生证的SQL。
一对多:和一对一的延迟加载配置方法相同
延迟加载的步骤:先查班级,按需查询学生
1.开启延迟加载conf.xml配置settings
2.配置mapper.xml
写2个Mapper:
班级mapper.xml
<select id="queryClassAndStudents" resultMap="class_student_lazyLoad_map">
select c.* from studentclass c
</select>
<resultMap type="studentClass" id="class_student_lazyLoad_map">
<!-- 因为 type的主类是班级,因此先配置班级的信息-->
<id property="classId" column="classId"/>
<result property="className" column="className"/>
<!-- 配置成员属性学生,一对多;属性类型:javaType,属性的元素类型ofType -->
<!-- 2222222再查班级对应的学生 -->
<collection property="students" ofType="student" select="org.lanqiao.mapper.StudentMapper.queryStudentsByClassId" column="classid">
</collection>
</resultMap>
即查询 学生的sql是通过 select属性指定,并且通过column指定外键
学生mapper.xml
<!-- 一对多,延迟加载需要的: 查询班级中的所有学生 -->
<select id="queryStudentsByClassId" parameterType="int" resultType="student">
select * from student where classId = #{classId}
</select>
十.查询缓存
10.1 一级缓存 :同一个SqlSession对象
MyBatis默认开启一级缓存,如果用同样的SqlSession对象查询相同的数据,
则只会在第一次 查询时 向数据库发送SQL语句,并将查询的结果 放入到SQLSESSION中(作为缓存在);
后续再次查询该同样的对象时,
则直接从缓存中查询该对象即可(即省略了数据库的访问)
10.2 二级缓存
1.MyBatis默认情况没有开启二级缓存,需要手工打开。
(1).conf.xml
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
(2).在具体的mapper.xml中声明开启(studentMapper.xml中)
<mapper namespace="org.lanqiao.mapper.StudentMapper">
<!-- 声明次namespace开启二级缓存 -->
<cache/>
</mapper>
根据异常提示:NotSerializableException(未序列化异常)可知,MyBatis的二级缓存 是将对象 放入硬盘文件中
序列化:内存->硬盘
反序列化:硬盘->内存
准备缓存的对象,必须实现了序列化接口 (如果开启的缓存Namespace="org.lanqiao.mapper.StudentMapper"),
可知序列化对象为Student,因此需要将Student序列化 (序列化Student类,以及Student的级联属性、和父类)
触发将对象写入二级缓存的时机:SqlSession对象的close()方法。
Mybatis自带二级缓存:【同一个namespace】生成的mapper对象
回顾:namespace的值 就是 接口的全类名(包名.类名), 通过接口可以产生代理对象(studentMapper对象)
- namespace决定了studentMapper对象的产生
结论:只要产生的xxxMapper对象 来自于同一个namespace,则 这些对象 共享二级缓存。
注意:二级缓存 的范围是同一个namespace, 如果有多个xxMapper.xml的namespace值相同,则通过这些xxxMapper.xml产生的xxMapper对象 仍然共享二级缓存。
2.禁用 :select标签中useCache="false"
3.清理:
(1).与清理一级缓存的方法相同
- commit(); (一般执行增删改时 会清理掉缓存;设计的原因 是为了防止脏数据)
在二级缓存中,commit()不能是查询自身的commit。 - commit会清理一级和二级缓存;但是 清理二级缓存时,不能是查询自身的commit;
(2). 在select标签中 增加属性 flushCache=“true”
4.三方提供的二级缓存:
ehcache、memcache
要想整合三方提供的二级缓存 (或者自定义二级缓存),必须实现org.apache.ibatis.cache.Cache接口,该接口的默认实现类是PerpetualCache
5.整合ehcache二级缓存:
(1).
ehcache-core.jar
mybatis-Ehcache.jar
slf4j-api.jar
(2).编写ehcache配置文件 Ehcache.xml
(3).开启EhCache二级缓存
在xxxMapper.xml中开启
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!-- 通过property覆盖Ehcache.xml中的值 -->
<property name="maxElementsInMemory" value="2000"/>
<property name="maxElementsOnDisk" value="3000"/>
</cache>
十一.逆向工程
表、类、接口、mapper.xml四者密切相关,因此 当知道一个的时候 其他三个应该可以自动生成。
表->其他三个
实现步骤:
(1). mybatis-generator-core.jar、mybatis.jar、ojdbc.jar
(2). 逆向工程的配置文件generator.xml (直接网上copy)
(3). 执行