MySQL使用GROUP_CONTACT和JSON_OBJECT代替烦人的子查询

假设一个场景:一个用户可以有多个角色,用户列表需要显示用户所有的角色名称,如下表

ID名称角色
1张三管理员、审核员
2李四普通员工

那么我们可以设计三个表:user(用户表) role(角色表) user_role(用户角色表)

第一种方法就是使用mybatis的association标签关联,但这个方法,有多少条用户记录,就要多少次的子查询来关联角色信息,所以不推荐使用

第二种方法,使用GROUP_CONTACT和JSON_OBJECT把角色列表的数据封装成一个json数组,再使用TypeHandler解析成一个List

Mapper.xml如下:

<?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.example.system.mapper.SysUserMapper">

    <resultMap type="SysUser" id="SysUserWithJsonResult">
        <id property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="nickName" column="nick_name"/>
        <result property="email" column="email"/>
        <result property="phonenumber" column="phonenumber"/>
        <result property="password" column="password"/>
        <result property="status" column="status"/>
        <result property="delFlag" column="del_flag"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time"/>
        <result property="updateBy" column="update_by"/>
        <result property="updateTime" column="update_time"/>
        <result property="roles" column="roles" javaType="SysRole" typeHandler="com.example.common.mybatis.handler.JsonTypeHandler" />

    </resultMap>


    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserWithJsonResult">
        select DISTINCT
        u.id,u.user_name,u.nick_name,u.email,u.phonenumber,u.status,u.create_time,
        CASE WHEN max(r.id) is not null THEN CONCAT('[',GROUP_CONCAT(JSON_OBJECT('id',r.id,'roleName',r.role_name)),']') END roles
        from sys_user u
        left join sys_user_role ur on u.id = ur.user_id
        left join sys_role r on ur.role_id = r.id
        where u.del_flag = '0'
        <if test="id != null and id != 0">
            AND u.id = #{id}
        </if>
        <if test="userName != null and userName != ''">
            AND u.user_name like concat('%', #{userName}, '%')
        </if>
        <if test="status != null and status != ''">
            AND u.status = #{status}
        </if>
        <if test="phonenumber != null and phonenumber != ''">
            AND u.phonenumber like concat('%', #{phonenumber}, '%')
        </if>
      
        group by u.id
    </select>
    

</mapper> 

其中,关键的语句是:

CASE WHEN max(r.id) is not null THEN CONCAT('[',GROUP_CONCAT(JSON_OBJECT('id',r.id,'roleName',r.role_name)),']') END roles

result中的javaType也不能少

TypeHandler如下:

package com.exapmle.common.mybatis.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JsonTypeHandler<T> implements TypeHandler<T> {
    private Class<T> type;

    public JsonTypeHandler(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Type argument cannot be null");
        }
        // 拿到xml中配置的javaType
        this.type = type;
    }

    @Override
    public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parseJsonString(parameter));
    }

    @Override
    public T getResult(ResultSet rs, String columnName) throws SQLException {
        return parseJavaObject(rs.getString(columnName));
    }

    @Override
    public T getResult(ResultSet rs, int columnIndex) throws SQLException {
        return parseJavaObject(rs.getString(columnIndex));
    }

    @Override
    public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return parseJavaObject(cs.getString(columnIndex));
    }

    private String parseJsonString(T parameter) {
        if (parameter == null) {
            return null;
        }
       
        return JSON.toJSONString(parameter, SerializerFeature.WriteClassName,SerializerFeature.NotWriteRootClassName);
    }

    @SuppressWarnings("unchecked")
    private T parseJavaObject(String parameter) {
        if (parameter == null) {
            return null;
        }
        if (parameter.startsWith("[")) {
            return (T) JSON.parseArray(parameter, this.type);
        }
        return JSON.parseObject(parameter, this.type);
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值