Что делать, если компания запрещает запрос JOIN?

Java

Сцены

Многие компании (особенно компании электронной коммерции) на самом деле не разрешают запросы на сопоставление нескольких таблиц или строго контролируют количество связанных таблиц, например, максимум 2 или 3 таблицы. Что делать, если определенное требование действительно требует выполнения связанного запроса?

Например, в интерфейсе есть страница:

id product_name price user_name user_age
10086 iphone 12 pro 6666 zhangsan 18

Очевидно, что это поле страницы происходит из двух таблиц:

  • 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;

Но, как упоминалось выше, запрос не может быть связан.

решение

Как вариант, можно сначала найти 10 кусков данных из таблицы t_product в память (t_product используется как основная таблица), потом вынуть uid 10 кусков данных, а потом вызвать UserService#listUser(uids) чтобы получить соответствующий список пользователей. В настоящее время в памяти имеется 10 продуктов и 10 пользователей, и комбинация может быть сопоставлена.

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

    // 组合并返回数据
    List<ProductExtendsTO> 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<ProductExtendsTO> getList(Integer page, Integer pageSize) {
    // 1.查询Product
    List<Product> productList = listProduct(page, pageSize);
    // 2.取出里面的所有uid
    List<Long> uids = productList.stream()
            .map(Product::getUid)
            .collect(Collectors.toList());
    // 3.查出userList
    List<User> userList = listUser(uids);
    // 4.把List转成Map(优化了这里)
    Map<Long, User> userMap = userList.stream()
            .collect(Collectors.toMap(User::getId(), user->user));

    // 组合并返回数据
    List<ProductExtendsTO> 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 to Map — очень распространенное требование, Stream API на самом деле немного многословен (код слишком длинный), поэтому мы можем попытаться его инкапсулировать:

public final class ConvertUtil {

    private ConvertUtil() {
    }

    /**
     * 将List转为Map
     *
     * @param list         原数据
     * @param keyExtractor Key的抽取规则
     * @param <K>          Key
     * @param <V>          Value
     * @return
     */
    public static <K, V> Map<K, V> listToMap(List<V> list, 
                                             Function<V, K> keyExtractor) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }
        
        Map<K, V> 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 to Map, также очень распространена необходимость извлечения определенных полей из List, например, приведенный выше код:

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

Средство для извлечения uid из productList. Для повторного использования мы также инкапсулируем:

public class ConvertUtil {

    private ConvertUtil() {
    }

    /**
     * 将List映射为List,比如List<Person> personList转为List<String> nameList
     *
     * @param originList 原数据
     * @param mapper     映射规则
     * @param <T>        原数据的元素类型
     * @param <R>        新数据的元素类型
     * @return
     */
    public static <T, R> List<R> resultToList(List<T> originList, 
                                              Function<T, R> mapper) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<R> newList = new ArrayList<>(originList.size());
        for (T originElement : originList) {
            R newElement = mapper.apply(originElement);
            if (newElement == null) {
                continue;
            }
            newList.add(newElement);
        }
        
        return newList;
    }
    
    /**
     * 将List转为Map
     *
     * @param list         原数据
     * @param keyExtractor Key的抽取规则
     * @param <K>          Key
     * @param <V>          Value
     * @return
     */
    public static <K, V> Map<K, V> listToMap(List<V> list, 
                                             Function<V, K> keyExtractor) {
        if (list == null || list.isEmpty()) {
            return new HashMap<>();
        }
        
        Map<K, V> 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 to Map, основное внимание уделяется правилам извлечения ключа во входящей карте, то есть KeyExtractor, который использует функциональный интерфейс
  • Список извлекает FieldList, основное внимание также уделяется определению правил извлечения полей, а также использует функциональный интерфейс

Другие стратегии разрешения

Иногда встречаются сложные статистические отчеты и другие данные, и трудно выполнить требования с помощью вышеуказанного метода «ассоциации памяти».В настоящее время отдел больших данных компании может предоставить интерфейс для получения данных непосредственно из больших данных. Но нам не нужно беспокоиться об этом: для небольших компаний безвредно правильно коррелировать запросы, а в крупных компаниях вообще есть отделы больших данных.

В последний день майских праздников я собрался и приготовился вернуться в Ханчжоу, чтобы перевезти кирпичи.

Я bravo1988, увидимся в следующий раз.

よろしく・つづく

我昨晚梦见你了.gif

Прошлые статьи:

Комикс: От блокировки JVM к распределенной блокировке Redis

Глубокое понимание основ потоковой передачи Java

Подробные аннотации Java

Tomcat Gaiden: Одинокий котенок