Mybatis注解
映射器注解
基本注解
@Insert 类似 < insert > 完成新增 修改操作
@Update 类似 < update > 完成修改 删除操作
@Delete 类似 < delete > 完成删除 查询操作
@Select 类似 < select > 完成查询
@Options(useGeneratedKeys = true,keyProperty = " ") 主键回填
@Param("haha") String ssex 起别名 给ssex起别名haha
结果映射注解
@Results结果映射
@Results({ @Result(id = 是否为主键, column = "字段", property = "属性" ) }
一对一映射
学生{...班级{}}
学生和班级通过classid 联系
-
在实体类Student中加入外部属性
-
在班级接口类ClassMapper中写入方法(通过班级id查班级信息)
3. 在学生接口类StudentMapper中写入方法(查询所有学生信息)以及与班级表的映射关系(因为classid映射给了bj,导致查询结果中student的classid=0,所以需要再写一个映射,将student的classid再映射一下)
4. 在测试类中调用方法名即可
一对多映射
班级{....学生{}}
班级和学生通过classid 联系
-
在实体类Class中加入外部属性
-
在班级接口类StudentMapper中写入方法(通过学生班级id查学生信息)
-
在学生接口类ClassMapper中写入方法(查询所有班级信息)以及与学生表的映射关系(因为classid映射给了stu对象列表,导致查询结果中class的classid=0,所以需要再写一个映射,将class的classid再映射一下,此处未写,跟1:1写法一致)
4. 在测试类中调用方法名即可
动态SQL注解
方式一 :脚本sql注解
方式二:动态sql注解
在方法中构建动态sql语句
⭐️⭐️⭐️方式三:构造器注解
生成动态sql语句,将方式二进行封装-- 构造器(须创建内部类)
//内部类
class StudentSql {
//查询
public String getGZQSelectStudentSql (Student s){
return new SQL() {
{
//字段名
SELECT("sid,sname");
SELECT("birthday");
SELECT("ssex,classid");
FROM("student");
if (s.getSsex() != null) {
WHERE("ssex=#{ssex}");
}
if (s.getClassid() != 0) {
WHERE("classid=#{classid}");
}
}
}.toString();
}
//新增
public String getGZQAddStudentSql(Student s){
return new SQL(){
{
INSERT_INTO("student");
if (s.getSname() != null) {
VALUES("sname","#{sname}");
}
if (s.getBirthday() != null) {
VALUES("birthday","#{birthday}");
}
if (s.getClassid() != 0) {
VALUES("classid","#{classid}");
}
if (s.getSsex() != null) {
VALUES("ssex","#{ssex}");
}
}
}.toString();
}
//修改
public String getGZQUpdateStudentSql(Student s){
return new SQL(){
{
UPDATE("student");
if (s.getSname() != null) {
SET("sname=#{sname}");
}
if (s.getBirthday() != null) {
SET("birthday=#{birthday}");
}
if (s.getClassid() != 0) {
SET("classid=#{classid}");
}
if (s.getSsex() != null) {
SET("ssex=#{ssex}");
}
WHERE("sid=#{sid}");
}
}.toString();
}
//删除
public String getGZQDeleteStudentSql(Student s){
return new SQL(){
{
DELETE_FROM("student");
WHERE("sid=#{v}");
}
}.toString();
}
}
}
@Insert ,@Delete,@Update,@Select 注解的功能
• 分别完成新增,删除,修改和查询操作;
@Results 注解和 @ResultMap 注解的功能
• @Results 定义结果映射,@ResultMap 调用对应的结果映射;
动态SQL的注解
@SelectProvider 查询语句的动态SQL,@InsertProvider 新增语句的动态SQL, @DeleteProvider 删除语句的动态SQL,@UpdateProvider 修改语句的动态SQL;
SQL 语句构造器的功能
• 解决 Java 代码中嵌入 SQL 语句,通过简单地创建一个实例来调用方法生成SQL语句;
分页
方式1:物理分页
使用Map集合来保存分页需要数据,来进行分页
方式2: 逻辑分页
使用RowBounds集合来保存分页需要数据,来进行分页
⭐️⭐️⭐️方式3: 分页插件分页
-
引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.3</version>
</dependency>
-
mybatis.xml配置
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
</plugin>
</plugins>
-
mapper接口
-
测试类
Page<Object> pageHeper = PageHelper.startPage(1, 10);
//在查询前面加上PageHeper就可以
List<StudentBean> list = studentMapper.seectAllOneofOne();
//pageinfo更详细的分页信息
PageInfo<StudentBean> studentBeanPageInfo = new PageInfo<>(list);
list.forEach(System.out::println);
//pageHeper分页信息
System.out.println(pageHeper);
System.out.println("------------------------------");
//info详细信息
System.out.println(studentBeanPageInfo);
-
结果
延迟加载和立即加载
mybatis默认的立即加载
立即加载
不管用不用信息,只要调用,马上发起查询并进行加载
通常:当 一对一或者 多对一的时候需要立即加载
延迟加载
在真正使用数据时才发起查询,不用的时候不查询,按需加载(也叫懒加载)
通常: 一对多,或者多对多的是需要使用延迟加载
缓存
⭐️⭐️⭐️一级缓存
⭐️概念
缓存(cache),数据交换的缓冲区,当应用程序需要读取数据时,先从数据库中将数据取出,放置在 缓冲区中,应用程序从缓冲区读取数据。
特点
数据库取出的数据保存在内存中,具备快速读取和使用。
限制
读取时无需再从数据库获取,数据可能不是最新的;
术语
什么是 MyBatis 缓存
通过配置和定制,减少 Java Application 与数 据库的交互次数,从而提升程 序的运行效率。
⭐️⭐️缓存的适用性
-
适合用缓存
-
经常查询并且不经常改变的
-
数据的正确与否对最终结果影响不大的
-
比如:一个公司的介绍,新闻等
-
不适合用缓存:
-
经常改变的数据
-
数据的正确与否对最终结果影响很大
-
比如:商品的库存,股市的牌价等
⭐️⭐️⭐️⭐️缓存分类
一级缓存 (sqlsession缓存)
会话 session 级别的缓存,针对一次会话操作内;
默认开启,一级缓存只是相对同一个 SqlSession 对象而言
二级缓存
映射器级别的缓存,针对不同 Namespace 的映射器;
一个 namespace 下的所有操作语句,都影响着同一个Cache;
自定义缓存
根据各类不同的缓存机制,自定义 缓存的实现方式。
自定义缓存的方式
实现 org. apache. ibatis. cache. Cache 接口自定义缓存;
引入 Redis 等第三方内存库作为 MyBatis 缓存。
知识点
1. 补充一对一、一对多 resultMap的使用
一对多(一个班级对应多个学生)
<collection/>标签完成一对多映射
ofType="" 指定要创建的类型
<resultMap id="class_stu_map" type="Classbean">
<result column="classid" property="classid"/>
<result column="classname" property="classname"/>
<!--
一对多(一个班级对应多个学生)
<collection/>标签完成一对多映射
ofType="" 指定要创建的类型
-->
<collection property="stu" ofType="Student">
<result column="sid" property="sid"/>
<result column="sname" property="sname"/>
<result column="birthday" property="birthday"/>
<result column="ssex" property="ssex"/>
<result column="classid" property="classid"/>
</collection>
</resultMap>
<select id="findClassAndStu" resultMap="class_stu_map">
select * from class
left join student on class.classid = student.classid
</select>
<!-- 一对一 : 查询课程和老师信息-->
<resultMap id="course_tea_map" type="Course">
<result column="cid" property="cid"/>
<result column="cname" property="cname"/>
<result column="tid" property="tid"/>
<association property="teacher" >
<result column="tid" property="tid"/>
<result column="tname" property="tname"/>
<result column="tsex" property="tsex"/>
<result column="tbirthday" property="tbirthday"/>
<result column="taddress" property="taddress"/>
<result column="temail" property="temail"/>
<result column="tmoney" property="tmoney"/>
</association>
</resultMap>
<select id="findCourseAndTeacher" resultMap="course_tea_map">
select * from course
left join teacher on course.tid=teacher.tid
</select>
单表 resultmap可以只写映射不上的
<resultMap type="SMaster" id="sm_map">
<result column="sm_name" property="smname"/>
</resultMap>
<select id="findSmasterAll" resultMap="sm_map">
select * from schoolmaster
</select>
2. 查询多参的方式
//查询 某个班的某个性别的学生 mybatis只能传一个参
//传递多参的方式一: javaBean对象(推荐)
public List<Student> findStudentByclassidAndssex(Student s);
//传递多参的方式二+分页: Map(不推荐,耦合度高)
public List<Student> findStudentByclassidAndssexLimit(Map<String,Object> map);
//传递多参的方式三+分页: param数(数是从1开始 推荐使用)
//按照顺序 和接口输入参数的顺序要保持一致
public List<Student> findStudentByclassidAndssexLimitParam(int classid,String ssex,int ys,int bc);
//传递多参的方式四+分页:arg(数是从0开始 不推荐 )
public List<Student> findStudentByclassidAndssexLimitArg(int classid,String ssex,int ys,int bc);
3. 主键回填
主键回填:新增的时候,mybatis会获取主键的值,传回给Java对象和主键的属性中
useGeneratedKeys="true" 开启主键回填
keyProperty="sid" 回填的主键要给哪个属性
4. choose和set标签
choos标签
相当于java中的 switch 结构
条件有先后顺序,越优先越要写,一旦匹配到了,后面的条件将不会再执行
when是条件,自带break
otherwise是当所有的when都不执行,才会匹配
set标签
1.添加set关键词
2.去掉最后一个逗号
5. 模糊查询
(1)方案一 concat 推荐 select * from where sname like concat('%',#{v},'%') (2)方案二 业务层解决模糊符号 不推荐 select * from student where sname like #{v} (3)方案三 sql语法 select * from student where sname like "%"#{v}"%" (4)方案四 ${} 不推荐 select * from student where sname like '%${v}%' #{} 预处理sql语句 ?占位 preparedstatment 进行防止sql注入 ${} 字符串的替换 不能防止sql注入 (5)方案五 bind标签 用来定义变量 <bind name="keyn" value="'%'+_parameter+'%'"/> select * from student where sname like #{keyn}
6. 二级缓存为什么用不了?
虽然实现了缓存数据的共享,但是在分布式环境(数据部署在多台服务器中)下会导致数据不一致。
7. 缓存失效
同一个SqlSession两次查询期间手动clearcaChe(清空缓存)
同一个SqlSession两次查询期间执行了任何一次增删改操作
不使用同一个sqlSeession进行查询
同一个sqlsession查询条件不同