Mybatis中使用association及collection进行自关联示例(含XML版与注解版)
XML版本:
实体类:
@Data
@ToString
@NoArgsConstructor
public class Dept {
private Integer id;
private String name;
private List<Dept> children = new ArrayList<Dept>();
private Dept parent; public Dept(Integer id) {
this.id = id;
} public Dept(String name) {
this.name = name;
} public Dept(String name, Integer parentId) {
this.name = name;
this.parent = new Dept(parentId);
} public String toLazyString() {
return "Dept:{id: " + this.id + " ; name: " + this.name + "}";
}
}
Mapper接口:
public interface DeptMapper {
public Dept selectById(Integer id);
public int insertDept(Dept dept);
public int updateDept(Dept dept);
public int deleteDept(Dept dept);
public List<Dept> selectByParentId(Integer parentId);
}
Mapper映射文件:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.sunwii.mybatis.mapper.DeptMapper">
<resultMap type="Dept" id="DeptMap_basic">
<id property="id" column="did" />
<result property="name" column="name" />
</resultMap>
<resultMap type="Dept" id="DeptMap" extends="DeptMap_basic">
<!-- 多对一关联:使用select引用方式 。association配置先于collection-->
<association property="parent" column="parent_id" javaType="Dept" select="selectById"></association> <!-- 一对多关联:使用select引用方式 -->
<collection property="children" column="did" ofType="Dept" select="selectByParentId" fetchType="lazy">
</collection> </resultMap> <select id="selectById" parameterType="Integer"
resultMap="DeptMap">
select id as did, name,parent_id from t_dept d where d.id=#{id}
</select>
<select id="selectByParentId" parameterType="Integer"
resultMap="DeptMap">
select id as did, name,parent_id from t_dept d where d.parent_id=#{parentId}
</select> <insert id="insertDept" parameterType="Dept" keyColumn="id"
keyProperty="id" useGeneratedKeys="true">
insert into t_dept(name,parent_id)
values(#{name},
<if test="parent==null">
0
</if>
<if test="parent!=null">
#{parent.id}
</if>
)
</insert> <update id="updateDept" parameterType="Dept">
update t_dept set
name=#{name},parent_id=
<if test="parent==null">
0
</if>
<if test="parent!=null">
#{parent.id}
</if>
where id=#{id}
</update> <delete id="deleteDept" parameterType="Dept">
delete from t_dept
where
id=#{id}
</delete>
</mapper>
Service实现类:
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper; @Override
public Dept getDept(Integer id) {
return deptMapper.selectById(id);
} @Override
public List<Dept> getDeptByParentId(Integer parentId) {
return deptMapper.selectByParentId(parentId);
} @Override
@Transactional
public void insertDept(Dept dept) {
deptMapper.insertDept(dept);
} @Override
@Transactional
public void updateDept(Dept dept) {
deptMapper.updateDept(dept);
} @Override
@Transactional
public void deleteDept(Dept dept) {
List<Dept> children = this.getDeptByParentId(dept.getId());
if(children!=null && children.size()>0) {
for(Dept d : children) {
//删除所有下级
deleteDept(d);
}
}
deptMapper.deleteDept(dept); //测试事务回滚
//new Integer(0/0);
} }
测试类:
public class TestSelf2Self {
private ApplicationContext context = SpringUtil.getContext();
private DeptService deptService = (DeptService) context.getBean(DeptService.class);
/**
* -添加部门
*/
@Test
public void testInsert() {
deptService.insertDept(new Dept("dept-6"));
}
/**
* -添加部门
*/
@Test
public void testInsert2() {
deptService.insertDept(new Dept("dept-7", 2));
}
/**
* -查询指定部门
*/
@Test
public void testSelect() {
int id = 1;
Dept dept = deptService.getDept(id);
String trees = dept.getName() + "(" + (dept.getParent() == null ? 0 : dept.getParent().getId()) + "-"
+ dept.getId() + ")";
List<Dept> children = dept.getChildren();
trees += "\n" + treeLevel(children, "\t");
System.out.println(trees);
/*
//结果:
部门-1(0-1)
部门-2(1-2)
部门-3(1-3)
部门-4(3-4)
部门-5(4-5)
*/
}
// 子树
private String treeLevel(List<Dept> children, String levelChar) {
String trees = "";
for (Dept dept : children) {
trees += levelChar + dept.getName() + "(" + (dept.getParent() == null ? 0 : dept.getParent().getId()) + "-"
+ dept.getId() + ")\n";
List<Dept> subChildren = dept.getChildren();
if (subChildren != null && subChildren.size() > 0) {
levelChar = "\t" + levelChar;
trees = trees + treeLevel(subChildren, levelChar);
}
}
return trees;
}
/**
* 查询所有下级部门(由于已经配置了一对多的关联,并且有延迟加载方案,其实没有必要再进行下级部门查询,直接用getChildren()就可以的啦,会自动进行查询)
*/
@Test
public void testSelectByParent() {
int parentId = 1;
//List<Dept> children = deptService.getDeptByParentId(parentId);
Dept dept = deptService.getDept(parentId); //实际中,要查询下级的当前部门是已经存在的,只是由于延迟加载,没有加载子级
List<Dept> children = dept.getChildren(); //触发加载,执行SQL
String trees = treeLevel(children, "\t");
System.out.println(trees);
/*
//结果:
部门-2(1-2)
部门-3(1-3)
部门-4(3-4)
部门-5(4-5)
*/
}
/**
* 查询所有上级部门(由于已经配置了一对多的关联(可能设置有延迟加载),其实没有必要再进行上级部门的查询,直接用getParent()就可以的啦,会自动进行查询)
*/
@Test
public void testSelectParents() {
int id = 4;
Dept dept = deptService.getDept(id);
List<Dept> parents = new ArrayList<Dept>();
parents.add(dept);
while (dept.getParent() != null && dept.getParent().getId() > 0) {
parents.add(dept.getParent());
dept = dept.getParent();
}
String trees = "";
String LevelChar = "\t";
for (int i = parents.size() - 1; i >= 0; i--) {
trees += LevelChar + parents.get(i).getName() + "(" + parents.get(i).getId() + ")" + "\n";
LevelChar += "\t";
}
System.out.println(trees);
//结果:
/*
部门-1(1)
部门-3(3)
部门-4(4)
*/
}
/**
* 更新部门
*/
@Test
public void testUpdate() {
int id = 6;
Dept dept = deptService.getDept(id);
dept.setName("dept-six");
dept.setParent(new Dept(3));
deptService.updateDept(dept);
}
/**
* 删除部门(级联删除所有下级部门)
*/
@Test
public void testDelete() {
int id = 3;
deptService.deleteDept(new Dept(3));
}
}
注解版:
注解版本只是将Mapper映射文件去掉,将映射注解到Mapper接口中(并使用了动态sql提供器),其它东西不变。
Mapper接口(注解版):
public interface DeptMapper {
@Select("select id as did, name, parent_id from t_dept d where d.id=#{id}")
@Results(id="DeptMap", value= {
@Result(property = "id", column = "did"),
@Result(property = "name", column = "name"),
@Result(property = "parent", column = "parent_id", one=@One(
select = "selectById",
fetchType = FetchType.LAZY
)),
@Result(property = "children", column = "did", many=@Many(
select = "selectByParentId",
fetchType = FetchType.LAZY
))
})
public Dept selectById(Integer id);
@InsertProvider(type = DeptProvider.class, method = "insert")
@Options(keyColumn = "id", keyProperty = "id", useGeneratedKeys = true)
public int insertDept(Dept dept);
@UpdateProvider(type = DeptProvider.class, method = "update")
public int updateDept(Dept dept);
@Delete("delete from t_dept where id=#{id}")
public int deleteDept(Dept dept);
@Select("select id as did, name, parent_id from t_dept d where d.parent_id=#{parentId}")
@ResultMap("DeptMap")
public List<Dept> selectByParentId(Integer parentId);
}
动态SQL提供器:
public class DeptProvider {
public String insert(Dept dept) {
return new SQL() {
{
INSERT_INTO("t_dept");
VALUES("name", "#{name}");
if (dept.getParent() != null) {
VALUES("parent_id", "#{parent.id}");
} else {
VALUES("parent_id", "0");
}
}
}.toString();
}
public String update(Dept dept) {
return new SQL() {
{
UPDATE("t_dept");
SET("name=#{name}");
if (dept.getParent() != null) {
SET("parent_id=#{parent.id}");
} else {
SET("parent_id=0");
}
WHERE("id=#{id}");
}
}.toString();
}
}
Mybatis中使用association及collection进行自关联示例(含XML版与注解版)的更多相关文章
- Mybatis中使用association及collection进行一对多双向关联示例(含XML版与注解版)
XML版本: 实体类: package com.sunwii.mybatis.bean; import java.util.ArrayList; import java.util.List; impo ...
- Mybatis中使用collection进行多对多双向关联示例(含XML版与注解版)
Mybatis中使用collection进行多对多双向关联示例(含XML版与注解版) XML版本: 实体类: @Data @NoArgsConstructor public class Course ...
- Mybatis中使用association进行关联的几种方式
这里以一对一单向关联为例.对使用或不使用association的配置进行举例. 实体类: @Data @ToString @NoArgsConstructor public class IdCard ...
- Mybatis中的association用法
这篇文章我们将来学习一些 association 用法 表结构 DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(1 ...
- MyBatis对象关联关系---- association与collection
Mybatis处理“一对多”的关系时,需要用到associasion元素.处理”多对一“用collection元素来实现(这两个元素在之前mapper文件中提到过). 本例子中,假设一名User可以有 ...
- mybatis中一对多查询collection关联不执行
今天遇到的原因是因为下面红底id没有,导致关联查询没有条件(id字段没传),所以一直没有执行. <?xml version="1.0" encoding="UTF- ...
- MyBatis中出现Mapped Statements collection does not contain value
引用csdn上一大神的解决方法: 经过排查,解决上述异常的过程如下: 1.确定xml文件中<mapper namespace=""/>中的namespace是否路径正确 ...
- Mybatis中的N+1问题与延迟加载
0.什么是N+1问题? 在查询中一下子取出所有属性,就会使数据库多执行几条毫无意义的SQL .实际中不需要把所有信息都加载进来,因为有些信息并不常用,加载它们会多执行几条毫无用处的 SQL,导致数据库 ...
- MyBatis学习总结(三)——多表关联查询与动态SQL
在上一章中我们学习了<MyBatis学习总结(二)——MyBatis核心配置文件与输入输出映射>,这一章主要是介绍一对一关联查询.一对多关联查询与动态SQL等内容. 一.多表关联查询 表与 ...
随机推荐
- [Gamma阶段]第九次Scrum Meeting
Scrum Meeting博客目录 [Gamma阶段]第九次Scrum Meeting 基本信息 名称 时间 地点 时长 第九次Scrum Meeting 19/06/05 大运村寝室6楼 20min ...
- leetcode 688. “马”在棋盘上的概率
题目描述: 已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始.即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1). 现有一个 “马”(也译作 “骑士”)位于 ( ...
- 【转】聊聊并发(一)——深入分析Volatile的实现原理
即两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序,称为竞争条件(race condition). 引言 在多线程并发编程中synchronized和Volatile都扮演着重要的 ...
- .Net Core3 新特性整理
.net core 3实现了.net 标准2.1. 1.生成可执行文件 以前版本需要dotnet run运行项目,.net core 3支持直接生成目标平台的可执行文件.比如windows就是exe了 ...
- Redis 键的过期删除策略及缓存淘汰策略
前言 Redis缓存淘汰策略与Redis键的过期删除策略并不完全相同,前者是在Redis内存使用超过一定值的时候(一般这个值可以配置)使用的淘汰策略:而后者是通过定期删除+惰性删除两者结合的方式进行内 ...
- postgre with递归查询组织路径
with递归查询组织路径 SELECT r.id, (array_to_string( array( select name from ( with recursive rec as( select ...
- 增量ETL (长周期指标) 优化方案
在日常数据处理过程中避免不了要计算跨长周期数据指标统计需求,类似于如下: 1. 统计每个城市(过去30天)用户浏览次数: 统计每个城市(本年)用户浏览次数: 统计每个城市(历史至今)用户浏览次数: ...
- iredmail开源邮件系统部署
Iredmail 安装前注意事项: 通过官网了解iRedMail: 2. 选择相应的linux发行版(我选的是64位的CentOS6.4,iRedMail-0.8.6.tar.bz2) ired ...
- EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器解决方案之Windows服务安装
背景说明 EasyDSS流媒体解决方案是由安徽旭帆信息科技有限公司自主研发的一套集流媒体点播.转码.管理.直播.录像.检索.时移回看于一体的一套完整的商用流媒体解决方案.EasyDSS软件以压缩包的形 ...
- EasyNVR摄像机网页无插件直播方案H5前端构建之:bootstrap弹窗功能的实现方案与代码
前言介绍 在web前端的网页设计中,为了展示出简洁的网页风格和美观的效果,往往会使用弹窗效果在EasyNVR前端页面录像检索功能时,必然会播放录像,如果单独为播放录像文件排一个界面,用户在使用上会更加 ...