Базовое использование и глубокое понимание фреймворка MyBatis

MyBatis

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

  • Примечание. Источник вывода содержания статьи: Lagou Education Java High-paying Training Camp;

Просмотрите рабочий процесс JDBC

  1. Загрузить драйвер подключения к базе данных
  2. Получить подключение к базе данных через класс управления драйверами
  3. Получить готовые заявления
  4. Задайте параметры подготовленной выписки
  5. Выполнить SQL, обработать результирующий набор
  6. освободить ресурсы
public static void main(String[] args) { 
    Connection connection = null;
    PreparedStatement preparedStatement = null;
    ResultSet resultSet = null;
	try { 
        // 1. 加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver"); 
        // 2. 通过驱动管理类获取数据库连接
        connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf-8", "root", "root"); 
        
        String sql = "select * from user where username = ?";
        // 3. 获取预编译语句
        preparedStatement = connection.prepareStatement(sql); 
        // 4. 设置预编译语句参数 
        preparedStatement.setString(1, "tom");
        // 5. 执行SQL, 处理结果集
        resultSet = preparedStatement.executeQuery();
       
        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String username = resultSet.getString("username");
            
            user.setId(id);
            user.setUsername(username);
        }
        System.out.println(user); 
    } catch (Exception e) { 
        e.printStackTrace();
    } finally { 
        // 6. 释放资源
        if (resultSet != null) { 
            try {
                resultSet.close();
            } catch (SQLException e) { 
                e.printStackTrace(); 
            }
        }
        if (preparedStatement != null) { 
            try {
                preparedStatement.close();
            } catch (SQLException e) { 
                e.printStackTrace();
            } 
        }
        if (connection != null) { 
            try {
                connection.close();
            } catch (SQLException e) { 
                e.printStackTrace();
            }
        }
    }
}

Проблемы с использованием JDBC напрямую:

  1. Соединения с базой данных часто создаются и уничтожаются, что приводит к трате системных ресурсов.
  2. Операторы SQL жестко запрограммированы в коде, и изменения в операторах SQL требуют изменений в коде Java.
  3. Существует жесткое кодирование при передаче параметров в подготовленные заполнители.
  4. Существует жесткое кодирование (имя столбца запроса) для синтаксического анализа набора результатов, и систему нелегко поддерживать.

идеи решения проблем

  1. База данных часто создает соединения и освобождает ресурсы ⇒ пул соединений с базой данных
  2. Операторы и параметры SQL жестко запрограммированы ⇒ файл конфигурации
  3. Вручную анализировать набор результатов возврата пакета ⇒ отражение, самоанализ

Индивидуальный дизайн рамы

Используйте сторону:

Предоставление основных файлов конфигурации

/**
*	sqlMapConfig.xml:存放数据源信息,引入mapper.xml
*	Mapper.xml:SQL语句的配置文件信息
*/

Сторона рамы:

  1. прочитать файл конфигурации

    /**
    *	读取完以后以流的形式存在,可创建JavaBean来存储
    */
    public class Configuration {
        // 数据源
        private DataSource dataSource;
        // map集合: key:statementId value:MappedStatement
        private Map<String,MappedStatement> mappedStatementMap = 
            new HashMap<String, MappedStatement>();
    }
    
    public class MappedStatement {
        //id
        private Integer id;
        //sql语句
        private String sql;
        //输入参数
        private Class<?> paramterType;
        //输出参数
        private Class<?> resultType;
    }
    
  2. Разобрать файл конфигурации

    Создайте класс SqlSessionFactoryBuilder.

    Используйте dom4j для анализа файла конфигурации и инкапсуляции проанализированного содержимого в Configuration и MappedStatement.

  3. Создать фабрику SqlSessionFactory

    Создайте класс реализации DefaultSqlSession для SqlSessionFactory и реализуйте метод openSession() для получения объекта экземпляра класса реализации интерфейса sqlSession (передайте объект Configuration)

  4. Создайте интерфейс SqlSession и класс реализации, в основном инкапсулируйте методы CRUD.

    Метод: selectList(String StatementId, Object param) для запроса всех

    selectOne(String StatementId, Object param) запрос одного

    close() освобождает ресурсы

    Конкретная реализация: инкапсулировать JDBC для выполнения операций запросов к таблицам базы данных.

    Класс Executor, полученный из класса Configuration, DataSource, SQL, paramterType, resultType, устанавливает значение заполнителя предварительно скомпилированного оператора посредством отражения, выполняет SQL посредством самоанализа и анализирует результат в объект через соответствие между именами столбцов и атрибутами объекта

Пользовательская оптимизация фреймворка

Проблемы с вышеуказанной пользовательской структурой

  1. В классе реализации dao есть повторяющиеся коды, и весь процесс операции повторяется (создание SqlSession, вызов метода SqlSession, закрытие SqlSession)
  2. В классе реализации dao существует жесткое кодирование, при вызове метода SqlSession жестко закодирован идентификатор параметра Statement.

Решение

Используйте шаблон прокси для создания объектов прокси для интерфейсов

Mybatis быстро использовать

1. Зависимость

<!--mybatis-->
<dependency> 
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
</dependency>
<!--mysql驱动-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.6</version>
    <scope>runtime</scope>
</dependency>

2. Создайте таблицу данных и класс сущностей соответственно.

3. Напишите файл сопоставления UserMapper

<?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="userMapper">
    <select id="findAll" resultType="com.lagou.domain.User">
        select * from User
    </select>
</mapper>

4. Запишите файл ядра MyBatis

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///test"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/lagou/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

5. CRUD

Примечание. Добавления, удаления и изменения требуют фиксации транзакций или настройки автоматической фиксации.

Пример:

InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
// SqlSession sqlSession = sqlSessionFactory.openSession(true);
// 带参数true 为自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession();
// namespace.id
int insert = sqlSession.insert("userMapper.add", user);
System.out.println(insert);
//提交事务
sqlSession.commit();
sqlSession.close();

Иерархия основных файлов конфигурации MyBatis

  • конфигурация конфигурация
    • недвижимость свойство
    • настройки
    • typeAliases Псевдонимы типов
    • обработчики типов typeHandlers
    • Фабрика объектов objectFactory
    • плагины
    • окружающая обстановка
      • переменная среды окружения
        • Тип менеджера транзакций transactionManager: [JDBC, MANAGED]
        • Тип источника данных dataSource: [UNPOOLED, POOLED, JNDI]
    • Идентификатор поставщика базы данных databaseIdProvider
    • картограф

mapper.xml

Оператор динамического SQL

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

Общие теги:

  • <where>

  • <if>

<select id="findByCondition" parameterType="user" resultType="user"> 
    select * from User
    <where>
        <if test="id!=0">
            and id=#{id}
        </if>
        <if test="username!=null">
            and username=#{username}
        </if>
    </where>
</select>
  • <foreach>

    Атрибуты:

    • коллекция: представляет элементы коллекции для обхода
      1. коллекция ⇒ список
      2. массив ⇒ массив
      3. Карта ⇒ ключ, соответствующий коллекции
    • open: представляет начало оператора
    • близко: конец заявления
    • item: представляет каждый элемент коллекции обхода, сгенерированное имя переменной
    • разделитель: разделитель
<select id="findByIds" parameterType="list" resultType="user">
    <include refid="selectUser"></include>
    <where>
        <foreach collection="array" open="id in(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </where>
</select>
<!--
	List ids = new ArrayList();
	ids.add(1);
	ids.add(2);
	Map params = new HashMap();
	params.put("ids", ids);
	params.put("title", "中国");
-->
<select id="dynamicForeach3Test" resultType="Blog">
    select * from t_blog where title like "%"#{title}"%" and id in
    <foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>
  • <sql>

  • <include>

Разработка аннотации Mybatis

Общие примечания

  • @Insert: новый

  • @Обновление: обновить

  • @Удалить: удалить

  • @Select: запрос

  • @Result: реализовать инкапсуляцию набора результатов [, , , ]

  • @Results: может использоваться с @Result для инкапсуляции нескольких наборов результатов

  • @One: реализует инкапсуляцию результатов один к одному.

  • @Many: реализовать инкапсуляцию набора результатов «один ко многим».

    public interface UserMapper { 
        @Select("select * from user") 
        @Results({ 
            @Result(id = true,property = "id",column = "id"),
            @Result(property = "username",column = "username"),
            @Result(property = "password",column = "password"),
            @Result(property = "birthday",column = "birthday"),
            @Result(property = "roleList",column = "id",javaType = List.class,
                    many = @Many(select ="com.lagou.mapper.RoleMapper.findByUid")) })
        List<User> findAllUserAndRole();
    }
    
    public interface RoleMapper {
        @Select("select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=#{uid}")
        List<Role> findByUid(int uid);
    }
    

Тайник Мибатиса

  • Кэш первого уровня — это кеш уровня SqlSession, который хранится структурой данных HashMap в объекте sqlSession.Кэши между разными sqlSessions не влияют друг на друга, а кеш первого уровня включен по умолчанию.

  • Кэш второго уровня — это кеш уровня картографа, а кеш второго уровня нужно открывать вручную.

    Кэш L1

    • Выполнение операции commit() очистит кеш первого уровня под соответствующим sqlSession.

CacheKey на карте

CacheKey cacheKey = new CacheKey(); 
// MappedStatement的id 
// id: namespace + SQLid
cacheKey.update(ms.getId()); 
// offset  0
cacheKey.update(rowBounds.getOffset()); 
// limit就是 Integer.MAXVALUE
cacheKey.update(rowBounds.getLimit()); 
// 具体的SQL语句
cacheKey.update(boundSql.getSql()); 
// SQL中带的参数
cacheKey.update(value); ...
if (configuration.getEnvironment() != null) {
    // environmentId
    cacheKey.update(configuration.getEnvironment().getId());
}

Кэш L2

  • Кэш второго уровня аналогичен процессу кэширования первого уровня, но кэш второго уровня основан на пространстве имен файла сопоставления.

  • Нижний слой кеша второго уровня по-прежнему представляет собой структуру HashMap.

  • Выполнение операции commit() очистит данные кеша L2.

1. Включить кеш L2

  1. Добавьте в глобальный файл конфигурации sqlMapConfig.xml

    <!-- 开启二级缓存 --> 
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. Включить кэширование в Mapper.xml

    <!-- 开启二级缓存 -->
    <!-- 
    	空标签,默认 type=PerpetualCache的相对路径
    	也可以通过实现 Cache 接口来自定义缓存
    -->
    <cache></cache>
    
  3. Класс pojo реализует интерфейс сериализации.

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

Элементы конфигурации userCache и flushCache

  • userCache: укажите, следует ли отключить кеш второго уровня, степень детализации управления — SQL, а значение по умолчанию — true в операторе.
  • flushCache: очистить кеш, чтобы предотвратить грязное чтение, по умолчанию true
  • Использование кеша заключается в том, что если данные запроса в таблице базы данных будут изменены вручную, произойдет грязное чтение.

Интеграция кэша второго уровня с Redis

  • Цель: реализовать распределенное кэширование

1. Зависимость

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-redis</artifactId>
    <version>1.0.0-beta2</version>
</dependency>

2. Файл конфигурации

Mapper.xml

<cache type="org.mybatis.caches.redis.RedisCache" />

3. Файл конфигурации подключения Redis

redis.host=localhost
redis.port=6379
redis.connectionTimeout=5000
redis.password=
redis.database=0

Примечание:

Хэш-структура, используемая mybatis-redis при хранении данных

key: namespace

field: Cachekey

value: result

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

Знакомство с плагином Mybatis

Mybatis — это превосходная широко используемая ORM-инфраструктура, обладающая высокой гибкостью и предоставляющая простой в использовании механизм расширения подключаемых модулей в четырех основных компонентах (Executor, StatementHandler, ParameterHandler и ResultSetHandler). Mybatis работает на уровне персистентности с помощью четырех основных объектов. MyBatis поддерживает использование подключаемых модулей для перехвата четырех основных объектов.Для mybatis подключаемые модули являются перехватчиками, которые используются для расширения функций основных объектов и улучшения функций.По сути, это реализовано с помощью базового динамического прокси.,другими словами,Четыре основных объекта в MyBatis являются прокси-объектами..

Методы, разрешенные MyBatis для перехвата, следующие:

  • Executor Executor [обновление, запрос, фиксация, откат]
  • Построитель синтаксиса SQL StatementHandler [подготовка, параметризация, пакетная обработка, обновление, запрос]
  • Обработчик параметров ParameterHandler[gerParameterObject, метод setParameters]
  • Обработчик набора результатов ResultSetHandler[handleResultSets, handleOutputParameters и т. д.]

пользовательский плагин

  1. Создайте собственный класс подключаемого модуля для реализации интерфейса Interceptor.
  2. Переопределить метод Intercept()
  3. Затем напишите аннотации к плагину, чтобы указать интерфейсы и методы, которые необходимо перехватить.
  4. Настройте класс плагина, записанный в файле конфигурации mybatis.

Процесс выполнения MyBatis

Шаблоны проектирования

Шаблоны проектирования, используемые MyBatis

Шаблоны проектирования Вариант MyBatis
Режим строителя SqlSessionFactoryBuilder, среда
заводской метод SqlSessionFactory, TransactionFactory, LogFactory
одноэлементный шаблон ErrorContext, LogFactory
прокси-режим Ядро реализации Mybatis, такое как MapperProxy, ConnectionLogger, использует динамический прокси jdk, а пакет executor.loader использует cglib или javassist для достижения эффекта отложенной загрузки.
Комбинированный режим SqlNode и различные подклассы ChooseSqlNode и т. д.
Шаблон метода шаблона BaseExecutor и SimpleExecutor, а также BaseTypeHandler и его подклассы, такие как IntegerTypeHandler;
режим адаптера Например, интерфейс Mybatis для Log и его адаптация к таким платформам журналов, как jdbc и log4j.
шаблон декоратора Например, реализация каждого декоратора в подпакете cache.decorators в пакете Cache
шаблон итератора Например, шаблон итератора PropertyTokenizer