思路1MP提供了大量单表查询的方法,但是没有多表的 *** 作,所以涉及到多表的查询时,需要我们自己实现
因为MP是基于MyBatis实现,我们可以使用MyBatis的结果映射来做,下面是一个官网的例子
结果映射https://mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps
select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio, A.favourite_section as author_favourite_section, P.id as post_id, P.blog_id as post_blog_id, P.author_id as post_author_id, P.created_on as post_created_on, P.section as post_section, P.subject as post_subject, P.draft as draft, P.body as post_body, C.id as comment_id, C.post_id as comment_post_id, C.name as comment_name, C.comment as comment_text, T.id as tag_id, T.name as tag_name from Blog B left outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_id left outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.id left outer join Tag T on PT.tag_id = T.id where B.id = #{id}
这个对象表示了一篇博客,它由某位作者所写,有很多的博文,每篇博文有零或多条的评论和标签。 我们先来看看下面这个完整的例子,它是一个非常复杂的结果映射(假设作者,博客,博文,评论和标签都是类型别名)
resultMap 元素有很多子元素和一个值得深入探讨的结构。 下面是resultMap 元素的概念视图。
查询的结果,会通过上面的结果映射,映射为下面这个类的实例
Blog.java
@Data public class Blog { private int id; private String title; private Author author; private List多表关联查询posts; } @Data class Post{ private int id; private String subject; private Author author; private List comments; private List tags; } @Data class Author{ private int id; private String username; private String password; private String email; private String bio; private String favourite_section; } @Data class Comment{ private int id; } @Data class Tag{ private int id; }
数据库准备:
内联查询多表关联查询常用的有:
● 内联查询
● 左联查询
● 右联查询
● 全联查询
inner join 为默认连接,join如果不带有其他标识,则默认是内联,即join=inner join
SELECT * FROM pri_class p INNER JOIN student s ON p.class_id = s.student_id;
内联查询数据集的来源
第一步 左表的记录和右表的记录逐一匹配;
第二步 左表没有匹配到右表的记录,这一行废弃;
第三步 右表没有匹配到左表的记录,这一行废弃;
左联查询这里的左表、右边的叫法指的是inner join的左边和右边
左联查询的数据集来源分析
第一步 左表的记录和右表的记录逐一匹配;
第二步 左表的数据全部保留;
第三步 右表的数据如果匹配到左表、那么保留右表的数据;
第四步 右表的数据如果没有匹配到左表、那么保留左表数据,右表记录为空;
左联查询和内联查询的区别
左联查询的结果比内联多出了一部分,多出的部分是没有匹配到右表的左表记录。
右联查询的数据集来源分析
第一步 右表的记录和左表的记录逐一匹配;
第二步 右表的数据全部保留 ;
第三步 左表的数据如果匹配到右表、那么保留左表的数据;
第四步 左表的数据如果没有匹配到右表、那么保留右表数据,左表记录为空;
右联查询和内联查询的区别
右联查询的结果比内联多出了一部分,多出的部分是没有匹配到左表的右表记录。
将来左联和右联的结果做一次UNIOn,求并集再去重;
示例工程目录,基于MP自动生成的代码
CodeGenerator.java
public class CodeGenerator { public static void main(String[] args) { //配置 GlobalConfig GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java"); globalConfig.setAuthor("blazar"); globalConfig.setOpen(false); //设置主键策略 globalConfig.setIdType(IdType.ASSIGN_ID); globalConfig.setFileOverride(true); globalConfig.setActiveRecord(true); globalConfig.setEnableCache(false); //配置 DataSourceConfig DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setUrl("jdbc:mysql://xx.xx.xx.xx:3306/primary_school?useSSL=true&useUnicode=true&characterEncoding=UTF-8"); dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver"); dataSourceConfig.setUsername("root"); dataSourceConfig.setPassword("123456"); //包配置 PackageConfig packageConfig = new PackageConfig(); packageConfig.setParent("com.example.primarySchool") .setMapper("mapper"); //策略配置 StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setCapitalMode(true).setNaming(NamingStrategy.underline_to_camel); //配置代码生成器 AutoGenerator mpg = new AutoGenerator(); mpg.setGlobalConfig(globalConfig); mpg.setDataSource(dataSourceConfig); mpg.setPackageInfo(packageConfig); mpg.setStrategy(strategyConfig); //指定自定义模板路径, 位置:/resources/templates/entity2.java.ftl(或者是.vm) //注意不要带上.ftl(或者是.vm), 会根据使用的模板引擎自动识别 TemplateConfig templateConfig = new TemplateConfig(); //配置自定义模板 mpg.setTemplate(templateConfig); //执行 mpg.execute(); } }
然后手动添加红色框中的类
ClassDetail.java
@Data public class ClassDetail { @TableId(value = "class_id", type = IdType.ASSIGN_ID) private Long classId; private String nickname; private Liststudents; }
然后,依次完成下列步骤:
在PriClassMapper中添加方法
public interface PriClassMapper extends baseMapper{ ClassDetail getDetailById(Serializable id); }
然后在XML文件中写SQL和映射
SELECT p.class_id AS class_id, p.nickname AS cname, s.student_id AS student_id, s.nickname AS sname FROM pri_class p JOIN student s ON p.class_id = s.class_id WHERe p.class_id = #{id}
再在service层中调用mapper中自定义的方法,通过getbaseMapper()来获取mapper的实例
public interface IPriClassService extends IService{ ClassDetail getDetailById(Serializable id); }
@Service public class PriClassServiceImpl extends ServiceImplimplements IPriClassService { @Override public ClassDetail getDetailById(Serializable id) { return getbaseMapper().getDetailById(id); } }
最后,在Controller层中,写WebAPI接口
@RestController @RequestMapping("/priClass") public class PriClassController { @Autowired IPriClassService iPriClassService; @RequestMapping("/getDetailById/{id}") public String getDetailById(@PathVariable("id") Long id){ return JSON.toJSONString(iPriClassService.getDetailById(id)); } }
测试
注意:需要在配置文件中配置一下xml的路径,否则会报错Invalid bound statement (not found)
还可以单独做mapper、service、controller,这样就和用MyBatis一样;
public interface ClassDetailMapper { ClassDetail getDetailById(Serializable id); }
public interface IClassDetailService { ClassDetail getDetailById(Serializable id); }
@Service public class ClassDetailServiceImpl implements IClassDetailService { @Autowired ClassDetailMapper classDetailMapper; @Override public ClassDetail getDetailById(Serializable id) { return classDetailMapper.getDetailById(id); } }
然后在Controller调用Service的方法就可以了;
思路2使用单表查询的结果拼接成多表查询的结果,示例如下
@RestController @RequestMapping("/priClass") public class PriClassController { @Autowired IPriClassService iPriClassService; @Autowired IStudentService iStudentService; @Autowired ClassAllInfo classAllInfo; @RequestMapping("/getAllById/{id}") public String getAllById(@PathVariable("id") Long id){ PriClass priClass = iPriClassService.getById(id); classAllInfo.setClassId(priClass.getClassId()); classAllInfo.setNickname(priClass.getNickname()); //条件查询 Mapmap = new HashMap<>(); map.put("class_id", id); List studentList = iStudentService.listByMap(map); classAllInfo.setStudentList(studentList); return JSON.toJSONString(classAllInfo); } }
数据库如下:
这种做法只需要新添加一个ClassAllInfo类,其他的拼接逻辑在controller层或者service层完成都可以:
@Data @Component public class ClassAllInfo { @TableId(value = "class_id", type = IdType.ASSIGN_ID) private Long classId; private String nickname; private ListstudentList; }
这种做法的好处是可以利用到MP自动生成的各种单表 *** 作,不用手动写各种SQL,但是缺点就是不够灵活,如果查询的条件更加复杂的话,采用Wrapper的方式来描述查询条件可能也没有SQL直观;另一方面,把本来属于一次查询的任务,分成了多次来做,也不利于查询优化;
PriClass.java
@Data public class PriClass extends Model{ @TableId(value = "class_id", type = IdType.ASSIGN_ID) private Long classId; private String nickname; }
Student.java
@Data public class Student extends Model{ @TableId(value = "student_id", type = IdType.ASSIGN_ID) private Long studentId; private String nickname; private Long classId; }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)