栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 前沿技术 > 大数据 > 大数据系统

公司禁止JOIN查询怎么办?

公司禁止JOIN查询怎么办?

场景

很多公司(特别是做电商的)其实都是不允许多表关联查询的,或者严格控制关联的表数量,比如最多关联2、3张表。此时,如果某个需求又确实需要进行关联查询怎么办呢?

比如前端有个页面:

很明显,这个页面字段来自两张表:

  • t_product
  • t_user

正常来说,直接这样写SQL即可:

SELECt p.id, p.product_name, p.price, u.user_name, u.user_age
FROM t_product p 
LEFT JOIN t_user u ON p.user_id=u.id;

但上面说了,不能关联查询。

解决方案

作为替代方案,可以先从t_product表查出10条数据到内存(t_product作为主表),然后取出10条数据的uid,再调用UserService#listUser(uids),得到对应的userList。此时内存中有10条product,也有10条user,匹配组合即可。

public List getList(Integer page, Integer pageSize) {
    // 1.查询Product
    List productList = listProduct(page, pageSize);
    // 2.取出里面的所有uid
    List uids = productList.stream()
            .map(Product::getUid)
            .collect(Collectors.toList());
    // 3.查出userList
    List userList = listUser(uids);
    // 4.把List转成Map
    Map userMap = new HashMap();
    for(userList : user){
        userMap.put(user.getId(), user);
    }

    // 组合并返回数据
    List result = new ArrayList<>();
    productList.foreach(product->{
        ProductExtendsTO productExtends = new ProductExtendsTO();
        BeanUtils.copyProperties(product, productExtends);
        // 根据product的uid从userMap获取user(此处省略user null判断)
        User user = userMap.get(product.getUid());
        productExtends.setUserAge(user.getUserAge());
        productExtends.setUserName(user.getUserName());
        result.add(productExtends);
    });

    return result;
}

上面的代码可以优化为(主要第4点):

public List getList(Integer page, Integer pageSize) {
    // 1.查询Product
    List productList = listProduct(page, pageSize);
    // 2.取出里面的所有uid
    List uids = productList.stream()
            .map(Product::getUid)
            .collect(Collectors.toList());
    // 3.查出userList
    List userList = listUser(uids);
    // 4.把List转成Map(优化了这里)
    Map userMap = userList.stream()
            .collect(Collectors.toMap(User::getId(), user->user));

    // 组合并返回数据
    List result = new ArrayList<>();
    productList.foreach(product->{
        ProductExtendsTO productExtends = new ProductExtendsTO();
        BeanUtils.copyProperties(product, productExtends);
        // 根据product的uid从userMap获取user(此处省略user null判断)
        User user = userMap.get(product.getUid());
        productExtends.setUserAge(user.getUserAge());
        productExtends.setUserName(user.getUserName());
        result.add(productExtends);
    })

    return result;
}

代码优化:封装ConvertUtil

List转Map是非常普遍的需求,Stream API其实还是有点啰嗦(代码太长了),所以我们可以试着封装一下:

public final class ConvertUtil {

    private ConvertUtil() {
    }

    
    public static  Map listToMap(List list, 
                                             Function keyExtractor) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }
        
        Map map = new HashMap<>(list.size());
        for (V element : list) {
            // 利用keyExtractor从对象中抽取Key
            K key = keyExtractor.apply(element);
            // 这里默认key不能为null
            if (key == null) {
                continue;
            }
            map.put(key, element);
        }
        
        return map;
    }
}

除了List转Map,从List中抽取特定字段的需求也是非常普遍的,比如上面代码:

// 2.取出里面的所有uid(省略null判断)
List uids = productList.stream()
                             .map(Product::getUid)
                             .collect(Collectors.toList());

意思是从productList中抽取uids。为了复用,我们也封装一下:

public class ConvertUtil {

    private ConvertUtil() {
    }

    
    public static  List resultToList(List originList, 
                                              Function mapper) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        
        List newList = new ArrayList<>(originList.size());
        for (T originElement : originList) {
            R newElement = mapper.apply(originElement);
            if (newElement == null) {
                continue;
            }
            newList.add(newElement);
        }
        
        return newList;
    }
    
    
    public static  Map listToMap(List list, 
                                             Function keyExtractor) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }
        
        Map map = new HashMap<>(list.size());
        for (V element : list) {
            K key = keyExtractor.apply(element);
            if (key == null) {
                continue;
            }
            map.put(key, element);
        }

        return map;
    }
}

上面权当抛砖引玉,大家可以基于实际需求自行扩展ConvertUtil,让它更好用。

总结:
  • List转Map,重点是传入Map中Key的抽取规则,也就是KeyExtractor,用了函数式接口
  • List抽取FieldList,重点也是定义字段的抽取规则,也用了函数式接口
其他解决策略

有时遇到复杂的统计报表等数据,很难通过上面“内存关联”的方式完成需求,此时可以让公司的大数据部门提供接口,直接从大数据那边获取数据。但这个并不需要我们操心:小公司适当关联查询无伤大雅,大公司一般都有大数据部门。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/671681.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号