mybatis对树进行增删改查

理解重点:
select的含义是想给children赋值可以调用一个方法,并把这个方法执行结果赋值给children。
column的含义是:其引用的值作为当前select方法执行的参数,让select执行他调用的方法,并且把结果赋值给引用的collection的children

一.数据库

先来看看我们的数据库
在这里插入图片描述

在这里插入图片描述
注意:

1.我们的数据库是一张三级联动的表,类似于省市县的写法
2.我们的depPath是用部门的id一个一个往后拼接起来的。
3.每一列的depPath的最后一个数字就是我们当前列的部门的id,depPath的倒数第二个数字就是我们当前列部门的父部门的id

二.业务需求

当前的业务需求是对此表进行查询,查询出整个部门树的结构,并在任意一个子节点可以进行增删操作。

三.查询出整个部门树

怎么查询一个树?

1.首先一定是从头到位把这一个树给查询出来,即从最开始的那一列,id=1 ,parentId=-1的那一列开始进行查询。
2.从数据图中我们不难分析出两点:关键点一:子部门的parentId =父部门的id ,
关键点二:depPath的最后一个数字=当前列的id
3.由关键点一,我们就有了头绪,通过 父部门parentId =子部门 id 进行递归查询我们能够查询出来这个树,如果要递归查询查询的话我们包装一个与Department类一模一样的子类DepartmentChildrenVO来进行递归查询是不是十分合适。
4.但是如何去利用mybatis在mapper.xml进行递归查询。

3.1 包装类

@Data
public class DepartmentChildrenVO extends  Department{
    List <Department> children;
}

3.2 controller,service,mapper简写

controller层
  @GetMapping("/")
    public List<DepartmentChildrenVO> getAllDepts (){
        return departmentService.getAllDepts();
    }
    
    
service层
 List<DepartmentChildrenVO> getAllDepts();


serviceImpl接口实现类
    @Override
    public List<DepartmentChildrenVO> getAllDepts() {
        return departmentMapper.getAllDepts(-1);
    }


mapper层
 List<DepartmentChildrenVO> getAllDepts(int pid);

3.3 关键—mapper.xml

1.映射的实体类还是DepartMent
2.定义了包装类,作为部门树的子部门,
3.ofType指定的是 映射到list集合属性中pojo的类型
4.在里面引入了一个参数select,指定了引入一个mapper的语句getAllDepts,也就是
我们这里的查询语句,进行递归查询,从头查询到尾部。select的含义是想给children赋值可以调用一个方法,并把这个方法执行结果赋值给children是,column的含义是:其引用的值作为当前children方法执行的参数,让select执行他调用的方法,并且把结果赋值给引用的collection的children
5.id这个id是当前部门的id,也是我们通过getAllDepts传入parentId查询到的当前部门的id,
把他当做下一个查询的pid丢进来进行查询,实现递归查询

<mapper namespace="com.huang.vhr.framework.web.mapper.DepartmentMapper">
   <!--这里正常的把DepartMent映射进来,说到底包装类DepartmentChildrenVO 
   的数据还是DepartMent里的数据 -->
    <resultMap id="BaseDepartMents" type="com.huang.vhr.framework.web.entity.Department">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="enabled" column="enabled"/>
        <result property="depPath" column="depPath"/>
        <result property="isParent" column="isParent"/>
        <result property="parentId" column="parentId"/>
    </resultMap>

<!--
定义一个可以迭代的映射,给他取名为DepartMentChildren,类型一定是DepartmentChildrenVO
这个名为DepartMentChildren的映射一定是继承DepartMent的
说到底是用到DepartMent里面的数据进行递归查询 
-->
    <resultMap id="DepartMentChildren"type="com.huang.vhr.framework.web.entity.DepartmentChildrenVO"
      extends="BaseDepartMents">
<!--关键点来了:
1.定义了包装类,作为部门树的子部门,
2.ofType指定的是 映射到list集合属性中pojo的类型 
3.在里面引入了一个参数select,指定了引入一个mapper的语句getAllDepts,也就是
我们这里的查询语句,进行递归查询,从头查询到尾部。
4.id这个id是当前部门的id,也是我们通过getAllDepts传入parentId查询到的当前部门的id,
把他当做下一个查询的pid丢进来进行查询,实现递归查询
 -->
        <collection property="children" ofType="com.huang.vhr.framework.web.entity.Department"
                 select="com.huang.vhr.framework.web.mapper.DepartmentMapper.getAllDepts"
                    column="id">
        </collection>
    </resultMap>

    <select id="getAllDepts" resultMap="DepartMentChildren">
        select *
        from department
        WHERE parentId = #{pid}
    </select>
</mapper>

四.部门树增加节点

4.1 存储过程实现

编写存储方法的过程,数据库中编写


# 修改数据库中命令的结束符号
DELIMITER $$

USE `vhr`$$

DROP PROCEDURE IF EXISTS `addDep`$$
# 五个参数 in 表示这是一个输入参数,out 表示这是一个输出参数
CREATE DEFINER=`root`@`localhost` PROCEDURE `addDep`(in depName varchar(32),in parentId int,in enabled boolean,out result int,out result2 int)
# 开始存储过程的定义
begin
  # 声明一个变量
  declare did int;
  declare pDepPath varchar(64);
  # 执行插入操作
  insert into department set name=depName,parentId=parentId,enabled=enabled;
  # 查询受影响的行数,并将查询结果赋值给 result 变量
  select ROW_COUNT() into result;
  # 查询刚刚插入记录的 id 并将查询结果赋值给 did 变量
  select LAST_INSERT_ID() into did;
  set result2=did;
  # 查询父部门的 depPath,并将查询结果赋值给 pDepPath 这个变量
  select depPath into pDepPath from department where id=parentId;
  # 更新刚刚插入记录的 depPath,concat 是一个字符串拼接函数
  update department set depPath=CONCAT(pDepPath,'.',did) where id=did;
  # 修改父部门的 isParent 属性
  update department set isParent=true where id=parentId;
  
# 存储过程定义结束
end$$

DELIMITER ;

4.1.1 定义实体类AddDepartmentVO

@Data
public class AddDepartmentVO extends Department{
    private Integer result;
}

4.1.2 controller,service,mapper写法


controller层
/**存储过程写法
     *
     * @param department
     * @return
     */
    @PostMapping("/add")
    public ResponseCode addDepartment(@RequestBody AddDepartmentVO department) {
        return departmentService.addDepartment(department);
    }


service层
 List<DepartmentChildrenVO> getAllDepts();
 
service的接口实现类
    @Override
    public ResponseCode addDepartment(AddDepartmentVO department) {
        department.setEnabled(true);
        department.setIsParent(false);
        departmentMapper.addDepartment(department);
        if (department.getResult() == 1) {
            return ResponseCode.ok("添加成功", department);
        }
        return ResponseCode.error("添加失败");
    }
    
 mapper层
  void addDepartment(AddDepartmentVO department);

4.1.3 mappe.xml

  <insert id="addDepartment" statementType="CALLABLE">
        call addDep(#{name,jdbcType=VARCHAR,mode=IN}, #{parentId,jdbcType=INTEGER,mode=IN},
                    #{enabled,jdbcType=BOOLEAN,mode=IN}, #{result,jdbcType=INTEGER,mode=OUT},
                    #{id,jdbcType=INTEGER,mode=OUT})
    </insert>

4.2 业务进行实现

思想:

业务写法,从前端拿到父部门的id,就是我们的parentId
1.通过parentId找到副部们的depPath,
2.加上我们的id,id自增长,(同时插入用户名,得到我们的这一条数据,再查询到这个id
3.再更新我们的depPath就是我们的

1.查询要插入用户是否存在,
2.通过parentId查找父部门Dep
3.插入用户,除去dep和id其他四个插入,其他四个中,有 parentId和name我们知道的
4.查询插入的用户,获取返回的id
5.id+父dep = 现在的dep
6.插入dep

业务实现的步骤思想也就是我们存储过程的思想

4.2.1 controller,service,mapper

	controller层
    @PostMapping("/add1")
    public  ResponseCode addDepartment1(@RequestBody Department department){
            return  departmentService.addDepartment1(department);
    }

	service层
	 ResponseCode addDepartment1(Department department);
	serviceImp

	serviceImpl 接口的实现类
	  @Override
    public ResponseCode addDepartment1(Department department) {


        department.setEnabled(true);
        department.setIsParent(false);
        //先查询要插入的用户是否存在
        if (departmentMapper.selectDptByPidAndName(department.getParentId(),department.getName())!=null){
            return ResponseCode.error("插入失败,用户存在");
        }
        //查询父部门的depPath
        Department fatherDpt = departmentMapper.selectFatherDptByPid(department.getParentId());
        if (fatherDpt==null){
            return ResponseCode.error("父用户不存在,查询失败");
        }
        if (departmentMapper.insertDepartment(department)!=1){
            return ResponseCode.error("获取id的插入失败");
        }
        //获取id
        int id =departmentMapper.selectDptId(department.getParentId(),department.getName());
        String nowDepPath = fatherDpt.getDepPath()+'.'+id ;

        if (departmentMapper.updateDptDepPath(nowDepPath,id)==1){
            return ResponseCode.ok("成功");
        }
        return ResponseCode.ok("增加失败");
    }


mapper用到的方法
	 void addDepartment(AddDepartmentVO department);

    Department selectDptByPid(@Param("parentId") Integer parentId);

    Integer selectDptId(@Param("parentId")Integer parentId,@Param("name")String name);

    Department selectDptByPidAndName(@Param("parentId")Integer parentId,@Param("name") String name);

    int insertDepartment(Department department);

    Department selectFatherDptByPid(Integer parentId);

    int updateDptDepPath(@Param("DepPath") String DepPath,@Param("id") int id);





mapper.xml用到的方法
    <select id="selectDptByPid" resultType="com.huang.vhr.framework.web.entity.Department">
        select *
        from department where parentId=#{parentId};
    </select>

    <insert id="insertDepartment">
        insert into department ( name, parentid, enabled, isparent) values (#{name,jdbcType=VARCHAR},#{parentId},#{enabled,jdbcType=BOOLEAN},#{isParent})
    </insert>

    <select id="selectFatherDptByPid" resultType="com.huang.vhr.framework.web.entity.Department">
        select * from  department where id =#{parentId}
    </select>

    <update id="updateDptDepPath">
        update department set DepPath = #{DepPath} where  id =#{id};
    </update>

    <select id="selectDptByPidAndName" resultMap="BaseDepartMents">
        select * from department where  parentId =#{parentId} and name =#{name};
    </select>

    <select id="selectDptId" resultType="java.lang.Integer">
        select  id from  department where parentId =#{parentId} and  name=#{name}
    </select>

五.部门树删除节点

删除的思想:

1.传入id,查询有没有子部门
2.有子部门无法删除
3.无子部门可以删除
4.再去查询当前部门的父部门还有无子部门
5.无,父部门的isParent改成1
6.有,直接结束

5.1 存储过程实现

DELIMITER $$

USE `vhr`$$

DROP PROCEDURE IF EXISTS `deleteDep`$$


#实际要编写的步骤
 
# in did int 输入参数为int类型,你要删除的部门的id  ,  out result int输出参数为int类型,你要删除的部门的结果
CREATE DEFINER=`root`@`localhost` PROCEDURE `deleteDep`(in did int,out result int)
begin
# ecount保存部门下的员工数量
  declare ecount int;
# 要删除部门的父部门的id  
  declare pid int;
# 要删除的部门下的子部门的数量
  declare pcount int;
# 
  declare a int;
# 满足条件id=did 且  isParent=false 的部门的数量赋值给 a,即如果你的传入id为did的时候你的要删除部门isParent为false(其下无子部门),
#这时候的查询结果如果不是1,即上面两个条件不满足,(-2,表示当前部门不存在,或者说)
#或者统计到的a!=1(查询结果赋值给了a),即当前部门不满足上面两个条件,就自动的判定为false就说明当前部门无法删除
  select count(*) into a from department where id=did and isParent=false;
  
  if a=0 then set result=-2;
  else
#查询要删除的部门下的员工数量,有员工则不能够删除
  select count(*) into ecount from employee where departmentId=did;
#-1表示部门下有员工,删除失败
  if ecount>0 then set result=-1;
  else
#查询要删除部门的父部门id,并将结果赋值给pid 
  select parentId into pid from department where id=did;
#执行删除操作  
  delete from department where id=did and isParent=false;
#查询手影响的行数  
  select row_count() into result;
#查询被删除部门的父部门下的子部门的数量  
  select count(*) into pcount from department where parentId=pid;
#将父部门的IsParent设置为 false  
  if pcount=0 then update department set isParent=false where id=pid;
  end if;
  end if;
  end if;
  
  
  
  
end$$

DELIMITER ;

5.2 controller,service,mapper

controller 层
@DeleteMapping("/{id}")
    public ResponseCode deleteDepartmentById(@PathVariable Integer id) {
        return departmentService.deleteDepartmentById(id);
    }

service层
ResponseCode deleteDepartmentById(Integer id);


serviceImpl接口的实现类
 @Override
    public ResponseCode deleteDepartmentById(Integer id) {
        AddDepartmentVO addDepartmentVO = new AddDepartmentVO();
        addDepartmentVO.setId(id);
        departmentMapper.deleteDepartmentById(addDepartmentVO);
        if (addDepartmentVO.getResult() == -2) {
            return ResponseCode.error("该部门下有子部门或者该部门不存在,删除失败");
        } else if (addDepartmentVO.getResult() == -1) {
            return ResponseCode.error("该部门下有员工,删除失败");
        } else if (addDepartmentVO.getResult() == 1) {
            return ResponseCode.ok("删除成功");
        }
        return ResponseCode.error("删除失败");
    }


mapper层
void deleteDepartmentById(AddDepartmentVO addDepartmentVO);

5.3 mapper.xml

 	 <select statementType="CALLABLE" id="deleteDepartmentById">
 <!--依次填充入我们存储过程中的语句-->
        call deleteDep(#{id,jdbcType=INTEGER,mode=IN},#				 {result,jdbcType=INTEGER,mode=OUT})
    </select>

5.4 业务实现

具体业务步骤:
1.通过传入的id查询当前部门的isParent,为0则继续下面,为1则说明其下还有子部门结束业务
2.通过传入的id找到parentId
3.通过parentId找到parnetId的总数
4.parentId总数>1 ,可以删除,且不用改父部门的isParent,直接删除
5.parentId总数=1 ,可以删除,要把父部门的isParent改成false
6.通过parentId找到父部门的id
7.再通过id去修改父部门的IsParent

黄黄这里就不写了,跟上面没啥差别的

六. 存储过程的具体解释

存储过程细节讲解

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值