Mybatis关联查询和动态SQL
相关面试题
1、Mybatis中#{}和${}的区别 是什么?
2、如何实现模糊查询?like?
3、Mybatis的动态sql有什么用?执行原理?有哪些动态sql?
4、如何实现1对N,N对1的查询 ?举例说明
回顾
问题:mybatis的操作流程?
1、全局配置文件(参考官网)
2、创建dao接口和SQL映射文件,提供实体类
3、注册映射文件
4、加载配置文件,获取SqlSessionFactory,获取SqlSession
5、测试
备注:在idea中 添加模板:配置文件,映射文件的创建:
操作:file-->settings-->File and Code Templates
![d073322f3ce2fb327654c504f38b35ff.png](https://i-blog.csdnimg.cn/blog_migrate/61566768dc6f0b052b2aca55f17f70e1.jpeg)
添加模板
学习目标
1、MyBatis关联查询(1对N,N对1)
2、动态SQL
3、#{}和 ${}的区别?
4、模糊查询
5、调用存储过程
学习内容
1、MyBatis关联查询
1.1 问题1:
如何将查询到的关系数据映射为实体对象?
1、使用别名:让别名和实体的属性名保持一致
实体类:
@Data public class Emp { private int empno; private String empname; private String work; private String gender; }
查询:
select empno, ename empname,job work,sex gender from emp
2、结果映射:resultMap
在映射文件中指定resultMap
可以设置自动映射:
查询命令:
select * from emp
1.2、有关联关系的数据如何查询
比如:部门和员工
![8bd8ff1d9925783a036797dcfc7d8555.png](https://i-blog.csdnimg.cn/blog_migrate/5c40228dd83d0530a70097d88b758fa7.jpeg)
1、嵌套select查询
在执行查询时嵌套select命令进行查询:
1.1 多对一操作:
实体类:
@Data public class Emp { private int empno; private String ename; private String job; private String sex; //引用部门:1 private Dept dept;//对应外键列:deptno }
映射文件 :
select * from dept where deptno=#{deptno} select * from emp
测试:
@Test public void test3(){ SqlSession session= SessionFactory.getSession(); //接口绑定 EmpDao dao= session.getMapper(EmpDao.class); List list=dao.query3(); for (Emp emp : list) { System.out.println("员工:"+emp.getEmpno()+":"+emp.getEname()); System.out.println("部门:"+emp.getDept().getDeptno()+":"+emp.getDept().getDname()); } session.close(); }
引发N+1查询问题:
![753b83fe85a6ebdfe025b31d24648cca.png](https://i-blog.csdnimg.cn/blog_migrate/e5cbf48b0fb0d196e53ad112529690c4.jpeg)
1.2 1对多操作:
实体类:
@Data public class Dept { private int deptno; private String dname; //引用员工的集合:N的一方 private List emps; }
映射文件:
select * from emp where deptno=#{deptno} select * from dept
测试:
@Test public void test4(){ SqlSession session= SessionFactory.getSession(); //接口绑定 DeptDao dao= session.getMapper(DeptDao.class); List list=dao.query1(); for (Dept dept : list) { System.out.println("部门:"+dept.getDeptno()+":"+dept.getDname()); //遍历员工集合 for (Emp emp : dept.getEmps()) { System.out.println("员工:"+emp.getEmpno()+":"+emp.getEname()); } } session.close(); }
如何解决N+1查询问题?
开启懒加载,使用时再查询:
2、嵌套结果查询
在resultMap中嵌套resultMap,查询时使用表连接查询;(推荐使用)
2.1 多对一操作:
实体类同上(略)
映射文件配置:
select * from dept d join emp e on d.deptno=e.deptno
测试过程同上;
2.2 一对多操作:
实体类同上
映射文件配置:
select * from dept d join emp e on d.deptno=e.deptno
测试过程同上;
备注:在实际的项目开发过程中,涉及到多对多关联关系的可以转换为1对多和多对一。
任务:员工(角色集合)和角色(员工集合)查询(三表连接),角色和权限?
备注:实际查询时不能使用select *查询,影响性能。
3、查询返回Map类型
应对:json类型转换时使用;省略实体类,省略resultMap
缺点:不符合面向对象的思想。
dao中:
//返回List List query3();
映射文件:
select * from dept d join emp e on d.deptno=e.deptno
测试:
@Test public void test6(){ SqlSession session= SessionFactory.getSession(); //接口绑定 DeptDao dao= session.getMapper(DeptDao.class); List list= dao.query3(); for (Map map : list) { System.out.println(map); } session.close(); }
2、动态SQL
如何实现多条件查询?
select * from 表 where 1=1 if (条件){ 拼接 } if (条件){ 拼接 }
mybatis提供的对应的标签,实现动态sql
- if
- choose (when, otherwise)
- where set ==trim (where, set)
- foreach
参数传递:
在dao中如何实现传递多个参数:
- 单独传递
- 封装成实体
- 封装成map
1、单独传递:
//@Param("名字"):设定参数的名字,供查询命令使用select List query5(@Param("name") String name);
如果不指定@Param注解报错:
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'name' in 'class java.lang.String'
2、封装成实体:
List query5(Emp emp); select * from emp where 1=1 -- ename:实体中的属性名字 and ename=#{ename}
3、封装成map
List query5(Map emp); select * from emp where 1=1 -- ename:map中的键的名字 and ename=#{ename}
测试:
@Test public void test5(){ String name="小浩"; Map map=new HashMap(); map.put("ename