Ленивая загрузка MyBatis (ленивая загрузка) введение

MyBatis

введение

В предыдущей статье был представлен многотабличный запрос. В реальном использовании мы часто будем использовать многотабличный совместный запрос, но иногда не все результаты запроса будут использоваться сразу. Позвольте мне привести два примера:

  • Например, запросите информацию о покупке партии ноутбуков вместо прямого отображения подробной информации о конфигурации компьютера или цене, соответствующей каждому столбцу сведений, а затем выполните запрос к одной таблице, когда пользователю необходимо получить подробную информацию. информация, связанная с блокнотом.
  • Для другого примера, в банке у пользователя 50 счетов (например), и тогда мы запрашиваем информацию этого пользователя, подробная информация всех счетов под этим пользователем, очевидно, разумнее запрашивать ее при использовании.

В ответ на такую ​​ситуацию появился механизм ленивой загрузки.Как следует из названия, ленивая загрузка (lazy load) заключается в задержке загрузки определенной информации.Эта технология также помогает нам реализовать механизм "запроса по требованию". Один ко многим или многие ко многим

Теперь, когда упоминается ленивая загрузка, конечно, кстати, немедленная загрузка означает, что независимо от того, нужна она пользователю или нет, после ее вызова она будет немедленно запрошена.Этот метод подходит для многих-к-одному или ситуации один на один.

(1) Необходимые приготовления

Сначала настраиваем основное окружение, а потом сначала подготавливаем две таблицы в БД

Пользовательская таблица

CREATE TABLE USER (
 `id`			INT(11)NOT NULL AUTO_INCREMENT,
 `username` 	VARCHAR(32) NOT NULL COMMENT '用户名',
 `telephone`    VARCHAR(11) NOT NULL COMMENT '手机',
 `birthday`		DATETIME DEFAULT NULL COMMENT '生日',
 `gender`  		CHAR(1) DEFAULT NULL COMMENT '性别',
 `address` 		VARCHAR(256) DEFAULT NULL COMMENT '地址',
  PRIMARY KEY  (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

Таблица счетов

CREATE TABLE `account` (
  `ID` int(11) NOT NULL COMMENT '编号',
  `UID` int(11) default NULL COMMENT '用户编号',
  `MONEY` double default NULL COMMENT '金额',
  PRIMARY KEY  (`ID`),
  KEY `FK_Reference_8` (`UID`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Затем создайте соответствующие классы сущностей соответственно.

Класс пользователя

public class User implements Serializable {
    private Integer id;
    private String username;
    private String telephone;
    private Date birthday;
    private String gender;
    private String address;
    //一对多关系映射,主表实体应该包含从表实体的集合引用
    private List<Account> accounts;
	...... 请补充 get set 和 toString 方法
}

Класс аккаунта

public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //从表实体应该包含一个主表实体的对象引用
    private User user;
    ...... 请补充 get set 和 toString 方法
}

UserMapper.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="cn.ideal.mapper.UserMapper">

    <!-- 定义User的resultMap-->
    <resultMap id="userAccountMap" type="User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="telephone" column="telephone"></result>
        <result property="birthday" column="birthday"></result>
        <result property="gender" column="gender"></result>
        <result property="address" column="address"></result>
        <collection property="accounts" ofType="account">
            <id property="id" column="aid"></id>
            <result property="uid" column="uid"></result>
            <result property="money" column="money"></result>
        </collection>
    </resultMap>
    
    <!-- 查询所有用户 并且显示对应账户信息 -->
    <select id="findAll" resultMap="userAccountMap">
       SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid;
    </select>

    <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultType="User">
        select * from user where id = #{uid}
    </select>
    
</mapper>

Создайте соответствующие методы в двух интерфейсах

public interface AccountMapper {
    /**
     * 查询所有账户
     * @return
     */
    List<Account> findAll();
}
public interface UserMapper {
    /**
     * 查询所有用户信息,同时显示出该用户下的所有账户
     *
     * @return
     */
    List<User> findAll();

    /**
     * 根据id查询用户信息
     * @param userId
     * @return
     */
    User findById(Integer userId);
}

##(1) Реализация кода отложенной загрузки

Прежде всего, позвольте мне показать вам, как мы раньше запрашивали пользователей один на один, и в то же время мы также будем запрашивать всю информацию об учетной записи, соответствующую пользователям.

/**
* 测试查询所有
*/
@Test
public void testFindAll() {
	List<User> users= userMapper.findAll();
    for (User user : users) {
        System.out.println("---------------------");
        System.out.println(user);
        System.out.println(user.getAccounts());
    }
}

Эффект:

Этот метод предназначен для одновременного запроса информации о пользователях и учетных записях с помощью операторов SQL и resultMap.

Так как же реализовать ленивую загрузку, о которой мы упоминали выше?

На этот раз мы решили запросить учетную запись, а затем лениво загрузить информацию о пользователе.

(1) Изменить AccountMapper.xml

Первое, что необходимо изменить, это файл конфигурации сопоставления учетной записи.Вы можете видеть, что когда мы запрашиваем, мы по-прежнему определяем resultMap, который сначала инкапсулирует учетную запись, а затем связывает пользователя через ассоциацию.Среди них выберите и столбец используются для реализации ленивой загрузки информации о пользователе.

  • select используется для указания оператора SQL, который необходимо выполнить для ленивой загрузки, то есть для указания идентификатора пары тегов select в определенном файле сопоставления SQL, здесь мы указываем метод запроса информации по идентификатору в пользовательском
  • Столбец относится к столбцу связанного запроса информации о пользователе, который является первичным ключом связанного пользователя, идентификатор
<mapper namespace="cn.ideal.mapper.AccountMapper">
	<!-- 定义封装 Account和User 的resultMap -->
    <resultMap id="userAccountMap" type="Account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
        <!-- 配置封装 User 的内容
            select:查询用户的唯一标识
            column:用户根据id查询的时候,需要的参数值
        -->
        <association property="user" column="uid" javaType="User" select="cn.ideal.mapper.UserMapper.findById"></association>
    </resultMap>

    <!-- 根据查询所有账户 -->
    <select id="findAll" resultMap="userAccountMap">
        SELECT * FROM account
    </select>
</mapper>

(2) Первый тестовый код

Давайте просто выполним все методы запроса учетной записи и посмотрим, сможем ли мы добиться нашего эффекта.

@Test
public void testFindAll(){
    List<Account> accounts = accountMapper.findAll();
}

(3) Эффект исполнения

Как видите, выполняются все три оператора SQL, почему так?

Это связано с тем, что перед тестированием метода нам нужно включить ленивую загрузку.

(4) Функция задержки загрузки

Можем зайти на официальный сайт, как настроить и включить такую ​​функцию

Изучив документацию, мы знаем, что если мы хотим запустить функцию ленивой загрузки, нам нужно настроить свойство настройки в файле общей конфигурации SqlMapConfig.xml, то есть ленивая загрузкаlazyLoadingEnableПереключатель устанавливается в положение teue, так как он загружается по требованию, также необходимо сменить активную загрузку на пассивную, то есть изменитьaggressiveLazyLoadingизменить на ложь

Конечно, так как версия MyBatis, которую я импортировал сюда, 3.4.5, это значение по умолчанию false.На самом деле его не нужно устанавливать, но мы все равно выписываем его

<settings>
	<setting name="lazyLoadingEnabled" value="true"/>
	 <setting name="aggressiveLazyLoading" value="false"></setting>
</settings>

Примечание. Если вы используете typeAliases для настройки псевдонимов, обязательно поместите тег typeAliases после

(5) Проведите повторный тест

по-прежнему выполнять только метод запроса

@Test
public void testFindAll(){
    List<Account> accounts = accountMapper.findAll();
}

Эффект исполнения

На этот раз была выполнена только одна команда для запроса учетной записи.

Итак, когда пользователи хотят просмотреть пользователей, соответствующих каждой учетной записи? Это также запрос по требованию, вам нужно только добавить соответствующий метод сбора во время тестирования.

@Test
public void testFindAll(){
    List<Account> accounts = accountMapper.findAll();
    for (Account account : accounts){
        System.out.println("----------------------------");
        System.out.println(account);
        System.out.println(account.getUser());
    }
}

сделай это

Как видите, наша цель ленивой загрузки достигнута.

Суммировать

В приведенном выше тесте мы реализовали ленивую загрузку, кратко суммируем шаги:

  • ①: Выполните соответствующий метод сопоставления, то есть выполните соответствующую конфигурацию SQL со значением id findAll в сопоставлении в приведенном выше примере и запросите только информацию об учетной записи.

  • ②: В программе просмотрите запрошенные учетные записи и вызовите метод getUser(), чтобы начать ленивую загрузку.

    • List<Account> accounts = accountMapper.findAll();
  • ③: выполнить ленивую загрузку, вызвать соответствующую конфигурацию SQL со значением id findById в файле сопоставления и получить информацию о соответствующем пользователе.

Как видите, мы можем напрямую запрашивать несколько таблиц, используя такие методы записи SQL, как левое внешнее соединение.

SELECT u.*,a.id as aid,a.uid,a.money FROM user u LEFT OUTER JOIN account a on u.id = a.uid;

Тем не менее, мы можем выполнить наши требования к запросам по запросу с помощью отложенной загрузки.Подводя итог, при использовании сначала выполните простой SQL, а затем загрузите и запросите другую информацию по мере необходимости.

конец

Если в статье есть какие-либо недостатки, пожалуйста, оставьте сообщение для обмена, спасибо за вашу поддержку!

Если это может вам помочь, то следуйте за мной! Если вы предпочитаете читать статьи WeChat, вы можете подписаться на мой публичный аккаунт.

Мы здесь незнакомцы, но мы все усердно работаем для своей мечты ❤

Публичный аккаунт, настаивающий на размещении оригинальных технических статей о разработке: в идеале — более двух дней.