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

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

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

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

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

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

Mapper.xml如下:





    
        
        
        
        
        
        
        
        
        
        
        
        
        

    


    
    

 

其中,关键的语句是:

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 implements TypeHandler {
    private Class type;

    public JsonTypeHandler(Class 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);
    }

}

你可能感兴趣的:(springboot,mysql,json,mybatis)