【Mybatis】Mybatis实战2(一对一、一对多、多对多的设计及实现,高级特性及二级缓存)

6).多表查询-“一对多”(表设计、实体设计、DAO(mapper)设计)

(1)关联关系操作(一对多)
	①表设计:以员工和部门表为例
思想:  1个员工对应1个部门,1个部门对应多个员工
添加数据原则:先添加没有外键的数据(部门信息),再添加存在外键的数据(员工信息)
注意:将外键添加在n的一方
部门表:
    create table t_dept(id varchar2(36) primary key,name varchar2(50));
员工表:
create table t_emp(
    id varchar2(36) primary key,
    name varchar2(50),
    age number(3),
    salary number(10,2),
    dept_id references t_dept(id));
②实体设计
a. 在实体中添加关系属性,来表示实体之间的关系(对应表数据的关系)
b. 在N的一方添加1的一个关系属性。
c. 在1的一方添加N的一个List的关系属性
 
DAO:(MyBatis如何查询两张表信息)
需求1:查询员工信息(工号,名字,年龄 , 薪资,所属部门的编号和名称)根据员工工号?
DAO接口方法:public Emp selectById(String id);
Mapper文件:
①SQL:
select e.id,e.name,e.age,e.salary,d.id,d.name from t_emp e left join t_dept d on e.dept_id = d.id where e.id = '5';
② 参数
③ 将查询结果映射成一个实体对象
特点: 如果关系属性是”1” ,使用 <association></association>
 
需求2:根据id查询部门信息,及其内部的所有员工信息?
DAO接口方法:public Dept selectById(String id);
Mapper文件中
①SQL:
	select d.id,d.name,e.id as eid,e.name as ename,e.age as eage,e.salary as salary from t_dept d left join t_emp e on d.id = e.dept_id
where d.id = ?;
②参数绑定
③结果映射:ReusultMap映射集合关系属性
特点: 关系属性是”n”个的集合 ,使用 <collection></ collection >

7).多表查询-“一对一”(表设计、实体设计、DAO(mapper)设计)

关联关系操作(一对一)
例如:需求: 学生电脑管理系统
①库表设计
表示1对1的关系
a. 添加外键(那张表添加都可以)
    ① 从业务的角度分析,后添加的数据对应的表。
    ② 该表叫做副表(子表),添加外键。
b. 外键列约束  unique  唯一,不能重复
 
②实体设计
互相保留彼此的一个关系属性
 
③DAO设计
需求: 根据学生id查看学生信息(名字,年龄,手机号,使用的电脑编号,电脑名称)?
DAO接口设计:
public interface StudentDAO{
    public Student selectById(String id);}
Mapper文件:
a. sql语句  b. 参数  c. 映射结果集(Student)

8).多表查询-“多对多”(表设计、实体设计、DAO(mapper)设计)

需求:学生选课系统(学生信息表、课程信息表)
①库表设计
设计原则: n对n的关系建表,要创建第三个关系表
例:学生表:create table t_student(
       id varchar2(36) primary key,
       name varchar2(50),
       age number(3),
       mobile varchar2(11));
课程表:create table t_course(
       id varchar2(36) primary key,
       name varchar2(50));
选课表:create table t_stu_course(
     sid references t_student(id),
     cid references t_course(id),
     primary key(sid,cid) ); --联合sid和cid作为主键,非空 联合唯一。如果产品需求中要求一个学生,选择一个课程,只能选择一次。
 
②实体设计
设计原则:互相保留对方的一个集合属性即可。
 
③DAO设计
需求:根据id查询学生学号,姓名,年龄,手机号,课程编号,课程名称?
    本质: 1对n
DAO接口:public interface StudentDAO{
				public Student selectById(String id);
}
Mapper文件:
<resultMap>
		主属性 id标签
		一般属性 result标签
		关系属性(list集合关系属性) collection标签。
</resultMap>
<select>
		sql: 以学生表为主,关联关系表和课程表
</select>
	  通过id查询课程被那些学生选了的信息,与上同理

9).MyBatis高级特性:动态sql(复用sql、简化查询、修改、删除、以及通用)

(1)动态sql:复用sql语句
案例: 复用sql的列名:
①定义sql片段:	<sql id="Xxx_column">被复用sql片段</sql>
②引用sql片段:	<include refid="Xxx_column"></include>
优点:简化sql书写、提高sql的可维护性
 
(2)动态sql:简化sql查询
①封装查询参数:
package com.baizhi.demo2;
public class PersonQuery {
	private String id;
	private String school;
	private String professional;
	private Integer status;
}
②DAO的简化
将页面所有可能的查询参数, 封装成XxxQuery对象。
public interface PersonDAO {
	List<Person> selectperson(PersonQuery query);
}
Mapper的selectwhere条件设计:  利用where标签 + if标签
核心:调用dao方法传入的参数不同,决定了sql的条件不同
动态sql:一个sql标签,由于传入参数不同,实际执行的sql语句也不同。
 
调用DAO:
① 将查询条件放入XxxQuery对象中
② dao.selectxxx(query);
 
(3)update+if 动态修改
set标签:	① 替代set关键字   ② 自动忽略修改的列后面多余的 逗号。
if标签:	test="dao方法的参数属性是否有值"
语法:<if test="参数的属性名 != null">...修改sql 	</if> 
(4)动态sql删除
DAO接口的方法:void delete(@Param("ids")String[] ids);
Mapper文件:
 
(5)补充trim [了解]
作用:①可以替代任何任何关键字(where set) ②可以忽略任何特殊字符(and ,)
 

10).MyBatis缓存、Ehcache缓存整合使用

现实现象:
①数据库的数据,来源于数据库的物理硬盘(150M/s~450M/s),速度慢 ②数据获取,每次都要经过DB-->Tomcat的网络传输。网络传输IO,降低速度
解决思路:
①内存,读取速度(10000M/s),速度快于物理硬盘 ②将数据临时存放在tomcat本地,再次获取数据,无需通过网络从DB传输给java
缓存:
概念:数据的临时存放空间。
特点:数据会被临时存放在内存中。(内存)
	①可以将查询结果临时存放在缓存中。
	②数据获取,从第二次开始,从缓存中获取。
	③服务器内部缓存(JVM内部),每次获得数据,无需通过网络传输。
作用:
	①提高查询效率
	②降低的数据库的访问压力
		数据库的硬件配置固定,大量查询,会侵占数据库的资源(CPU 内存)
		数据库的可同时提供的连接数有限,大量查询,会侵占数据库的连接资源.
(1)MyBatis缓存
一级缓存:
概念: SqlSession级别的缓存
特点:
①每个sqlSession会有独立的缓存空间。
②SqlSession查询数据,默认放入缓存中。
③第二次查询,sqlSession直接从缓存中获得数据,不会发送sql语句。
④生命周期: 一个事务过程。【sqlSession.commit().一级缓存就会被清空】
二级缓存:
概念:全局缓存、SqlSessionFactory级别缓存、多个SqlSession可以共享的
工作机制:
①第一次查询,数据会从数据库(物理硬盘)获得数据,并且,通过网络传输给java。
②将第一次的查询结果,放入全局缓存[二级缓存]。
③第2+次以后,每次查询都从缓存获取。[从tomcat的jvm的内存中获得数据,避免从DB网络传输数据。]
 
二级缓存的使用步骤:
①二级缓存MyBatis默认自动开启了
<settings>
		<setting name="cacheEnabled" value="true"/>
</settings>
②被缓存的数据对象类型要可序列化
③在使用二级缓存的查询sql所在的Mapper中添加
<mapper>
		<cache></cache>
</mapper>
作用: 当前mapper文件下所有的select标签,查询结果都会默认自动放入到缓存中。
④缓存的使用
a. 每次查询先从缓存中获得数据,如果获得,直接返回,不会发送sql,
b. 如果没有从缓存获得需要的数据,再发送sql,从数据库获得数据,会将查询结果放入缓存中。
深入二级缓存:
特点:
①开启了二级缓存的mapper文件中的select标签语句默认会使用缓存。(先从缓存中获取,获得到,返回,获得不到,从db获得,放入缓存)。 先从select语句所对应的namespace的缓存空间中,获得数据,如果获得,返回,如果没有,则发送sql查询数据,并将查询结果放入sql所对应的namespace的缓存空间。
②mapper文件中的 DML标签insert update delete ,会默认清空缓存。[为了保证缓存中数据一致性]
		清空dml语句所在mapper文件,对应的namespace的缓存空间。
③session.commit();当前session查询结果,才会放入二级缓存中。[空一级缓存]
缓存实现原理(源码)
①MyBatis二级缓存,是以(Mapper的)namespace进行划分。SQL标签 (select)操作的是sql所在的mapper文件
的namespace对应的缓存空间。
②MyBatis缓存的源码实现
   	  mybaits的namesopace的缓存实现,本质HashMap
      select语句的查询结果,是如果放入缓存
   			key: "namespaceid:执行的sql语句:实际传入的查询参数"
   			value: 查询结果的返回值。
缓存的应用场景:该数据的查询次数远远多于修改的次数
注意:MyBatis二级缓存属于服务器内部缓存。如果缓存数据过多,会挤占tomcat服务器内部(JVM)内部代码运行本
身需要的内存空间,导致代码运行异常。

(2)Ehcache缓存整合[重点]
简介:Ehcache 专职负责实现缓存、Ehcache 分布式缓存、Ehcache支持将数据序列化硬盘上(支持,不太可靠)
服务器内部缓存(jvm进程内缓存)
Ehcache集成MyBatis(替换mybatis自带的缓存):
①导入Ehcache的jar,导入ehcache集成MyBatis的jar
	ehcache-core-2.6.5.jar
	mybatis-ehcache-1.0.2.jar
②在mapper中使用缓存是,指定使用Ehcache的缓存实现类
	<cache type="Ehcache实现类的全类名"></cache>
③配置文件
    <defaultCache
            maxElementsInMemory="10000"  
            eternal="false"  
            overflowToDisk="true"
            maxElementsOnDisk="10000000"  
            memoryStoreEvictionPolicy="LRU"  
    />
说明:	maxElementsInMemory:缓存最大的对象个数。  
       	eternal:对象是否永久有效,一但设置了,timeout将不起作用。  
       	overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。  
       	maxElementsOnDisk:硬盘最大缓存个数。  
       	memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略
去清理内存(默认策略是LRU(last resently used 最近最少使用)、FIFO(first in first out先进先出)、LFU(least requently used 较少使用))
原文地址:https://www.cnblogs.com/jwnming/p/13635059.html