resultType:默认的映射,字段名要与属性名一致
当数据库中字段名为xx_xx 实体类中属性名为xx_Xx
这时候因为数据库有自己命名规范 实体类属性有自己的命名规范,导致字段对应不上
就可以采取以下措施
获取员工以及所对应的部门信息
Emp xxx(@Param(“empId”) Integer empId)
查询时 select 字段(数据库字段都带上)
或者在mybatis-config.xml中配置settings 可以自动将下划线映射为驼峰
//value可以取true/false 默认是falseresultMap:设置自定义的映射关系
id:唯一标识
type:处理映射关系的实体类的类型
常用的标签:
id:处理主键和实体类中属性的映射关系
result:处理普通字段和实体类中属性的映射关系
column:设置映射关系中的字段名,必须是sql查询出的某个字段
property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名
表对应的是实体类,字段对应的是当前属性 表里的一条数据对应的是一个实体类对象
对一对应的就是一个对象 对多就对应的是一个集合
多对一映射关系
表结构为一个部门里有多个员工一对多
select t_emp.,t_dept. from t_emp left join t_dept on t_emp.dept_id = t_dept.dept_id where t_emp.emp.id = #{empId}
1-使用级联处理多对一的映射关系 最简单的解决方法
select t_emp.,t_dept. from t_emp left join t_dept on t_emp.dept_id = t_dept.dept_id where t_emp.emp.id = #{empId}
<resultMap id=“xxx”,type=“Emp”> //type的值填 要查询的结果跟谁映射不了就填哪一个 Emp 因为Emp中有dept的属性映射不了
我们查询出来的dept_id与dept_name肯定不是与dept进行映射,应该是与dept对象下面的属性dept.deptId和dept.deptName属性映射
2-association:专门处理多对一的映射关系(处理实体类类型的属性)
property:设置需要处理映射关系的属性的属性名
javaType:设置要处理的属性的类型
<resultMap id=“xxx”,type=“Emp”>
//javaType 中填写字段的类型,设置了别名,在mybatis范围之内都可以用别名表示具体类型
3-分步查询
一步一步查询信息 现在要查的是员工信息与员工部门的信息
先把员工查出来,把员工所对应的部门的id作为条件,在部门表里查询,就可以查询出所对应的部门了
通过分布查询查询员工以及对应的部门信息的第一步
Emp xxx(方法名) (@Param(“empId”) Integer empId);
在映射文件中
<resultMap id=“xxx”,type=“Emp”>
select * from t_emp where emp_id=#{empId}
association.select对应的是第二条执行的sql语句的唯一标识(设置分步查询的SQL的唯一标识)
column是指第一条sql语句执行完的条件(将查询出的某一个字段作为分步查询的SQL的条件)
需要两个sql来查询
那就编写另一个SQL语句 接口编写
通过分步查询查询员工以及所对应的部门信息的第二步
Dept getEmpAndDeptByStepTwo(@Param(“deptId”)Integer deptId)
在映射文件中编写
select * from t_dept where dept_id=#{deptId}
分步查询的优点:可以实现延迟加载
但是必须在核心配置文件中配置全局配置信息
(开启延迟加载)lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载
(按需加载)aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性都会按需加载
此时就可以实现按需加载,获取数据是什么,就只会执行相应的SQL。此时可通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType=“lazy(延迟加载)|eager(立即加载)”
一对多的映射关系
查询部门以及部门中员工信息
Dept xxx(方法名) (@Param(“deptId”) Integer deptId);
1-通过collection处理 collection处理一对多的映射关系(处理集合类型的属性)
//ofType设置集合类型的属性中存储的数据的类型
select t_dept.,t_emp. from t_dept left jon t_emp on t_dept.dept_id=t_emp.dept_id where t_dept.dept_id=#{deptId}
2-通过分步查询
//通过分步查询查询部门以及部门中的员工信息的第一步
Dept xxx(方法名) (@Param(“deptId”) Integer deptId);
select * from t_dept where dept_id = #{deptId}
//通过分步查询查询部门以及部门中的员工信息的第二步
List xxx方法名(@Param(“deptId”) Integer deptId);
select * from t_emp where dept_id=#{deptId}
动态SQL
mybatis框架的动态技术是一种根据特定条件动态拼接SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题
1-if
if标签可通过test属性的表达式进行判断,若表达式的结果为true,则标签中的内容会执行;反之标签中的内容不会执行
(if,通过test属性中的表达式判断标签中的内容是否有效(是否拼接到SQL中))
select * from t_emp where
emp_name=#{empName}
and age = #{age}
当上面代码中if判断都不成立,那么查询语句就会多出一个where报错
以及第一个if不成立 where后面拼接一个and 也会报错
解决方案:
1-在where后面加上恒成立条件 1=1(不会影响查询结果) 这个数字任意但是两边要相等
select * from t_emp where 1=1
emp_name=#{empName}
and age = #{age}
2-where标签
如果where有条件成立,那么where标签会自动生成where关键字
它可以将我们标签里的where标签的内容前面多余and去掉,其中内容后多余的and无法去除
如果where标签中没有任何条件成立,那么该where标签无效
select * from t_emp
emp_name=#{empName}
and age = #{age}
3-trim
-suffix -prefix 在标签中内容前面或后面添加指定内容
-suffixOverrides -prefoxOverriders 在标签中内容前面或者后面去掉指定内容
4-choose,when,otherwise
相当于Java中的if。。。else if…else
when至少设置一个,otherwise最多设置一个
select * from t_emp
emp_name = #{empName}
age=#{age}
5-foreach(批量添加,批量删除之类的)
collection:设置要循环的数组或集合
item:用于一个字符串表示数组或集合中的每一个数据
separator:设置每次循环的数据之间的分隔符
open:循环的所有内容以什么结束
。。。
void xxx方法名(@Param(“emps”) List emps);
keyProperty useGeneratedKeys 自增主键id
insert into t_emp values
(null,#{emp.empName},#{emp.age},#{emp.gender},null)
new 实例化对象
Arrays.asList对象转为List
批量删除通过数组
void xxx方法名(@Param(“empIds”) Integer[] empIds);
delete from t_emp where emp_id in
#{empId}
foreach -index当前循环的索引 -open 设置当前循环内容以什么开始 -close。。。结束
delete from t_emp where emp_id=#{empId}动态SQL标签 sql片段, 可以记录以一段SQL,在需要用的地方使用include标签进行引用
emp_id,emp_name,age,gender,dept_id
mybatis的缓存
mybatis一级缓存
一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
使一级缓存失效的四种情况
1)不同的SqlSession对应不同的一级缓存
2)同一个SqlSession但是查询条件不同
3)同一个SqlSession两次查询期间执行了任何一次增删改查操作
4)同一个SqlSession两次查询期间手动清空了缓存
mybatis默认开启一级缓存的
mybatis的二级缓存
二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取
二级缓存开启条件:
a-在核心配置文件中,设置全局配置属性cacheEnalbed=“true”,默认为true,不需要设置
b-在映射文件中设置标签
c-二级缓存必须在SqlSession关闭或提交之后有效//我们所查询的数据默认保存在一级缓存中
d-查询的数据所转化的实体类类型必须实现序列化接口
二级缓存失效的情况
两次查询之间执行了任意增删改,会使一级和二级缓存同时失效(一级缓存的手动清空并不会导致二级缓存失效)
二级缓存的相关配置
在mapper配置文件中添加的cache标签可以设置一些属性:
1-eviction属性:缓存回收策略,默认是LRU
LRU(Least Recently Used) -最近最少使用的:移除最长时间不被使用的对象
FIFO(First in First out) -先进先出:按对象进入缓存的顺序来移除它们
SOFT-软引用:移除基于垃圾回收器状态和软应用规则的对象
WEAK-弱引用:更积极地移除基于垃圾回收器状态和弱引用规则的对象
2-flushinterval属性:刷新间隔,单位毫秒
默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
3-size属性:引用数目,正整数
代表缓存最多可以存储多少个对象,太大容易导致内存溢出
4-readOnly属性:只读,true/false
true:只读缓存,会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势
false:读写缓存,会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
mybatis缓存查询的顺序
先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
如果二级缓存没有命中,再查一级缓存
如果一级缓存没有命中,则查询数据库
SqlSession关闭之后,一级缓存中数据写入二级缓存中
整合第三方缓存EHCache
pom.xml
mybatis-ehcache mybatisheEHCache的整合包
logback-classic 支持SLF4j门面接口的一个具体实现
ehcache EHCache核心包
slf4j-api SLF4j日志门面包
创建ehcache.xml配置文件
设置二级缓存的类型
加入logback日志
第三方缓存是二级缓存的基础上进行的第三方缓存,功能是没有变化的,实现过程不同
mybatis的逆向工程
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的
逆向工程:先创建数据库表,又框架负责根据数据库表,反向生成如下资源:
1-Java实体类
2-Mapper接口
3-Mapper映射文件
要导入逆向工程的插件 mybatis-generator-maven-plugin
依赖于mybatis-generator-core mysql驱动
逆向工程配置文件generatorConfig.xml
在maven中找到我们项目再进入Plugins就可以看到mybatis-generator插件
双击这个插件即可会返回 BUILD SUCCESS 成功
生成五个方法增删改查 -根据主键删除 -添加 -根据主键来查询 -查询所有 -根据主键来修改
以上逆向生成的是清新简洁版 targetRuntime=“MyBatis3Simple”
以下是奢华尊享版 TargetRuntime=“MyBatis3” 带条件的crud
分页插件
limit index pageSize
index:当前页的起始索引 index=(pageNum-1)*pageSize
pageSize:每页显示的条数
pageNum:当前页的页码
count:总记录数
totalPage:总页数
totalPage: count/pageSize
if(count%pageSize!=0){
totalPage+=1;
}
pageSize=4 pageNum=1 index=0 limit 0,4
pageSize=4 pageNum=3 index=8 limit 8,4
pageSize=4 pageNum=6 index=20 limit 8,4
首页 上一页 2 3 4 5 6 下一页 末页
分页插件的使用步骤
1-添加依赖pagehelper
2-配置分页插件
在mybatis的核心配置文件中配置插件
分页插件的使用
a-在查询功能之前使用PageHelper.startPage(int pageNum,int PageSize)开启分页功能
pageNum:当前页的页码 pageSize:每页显示的条数
通过分页插件获取分页相关数据
查询功能之前开启分页功能
Page page=PageHelper.startPage(1,4);
List list = mapper.selectByExample(null);
查询功能之后可以获取分页相关的所有数据
PageInfo pageInfo = new PageInfo<>(list,5);//5为导航分页的页码数
PageInfo{
pageNum=1,pageSize=4,size=4,
startRow=1,endRow,total=30,pages=8,list=Page{count=true,pageNum=1,pageSize=4,startRow=0,endRow=4,total=30,pages=8,reasonable=false,pageSizeZero=false}[查询出来的数据]…
prepage=0 nextPage=2 isFirstPage=true,
isLastPage=false,hasPreviousPage=false,
hasNextPage=true,navigatePages=5,
navigateFirstPage=1,navigateLastPage=5,navigatepageNums=[1,2,3,4,5]}