фон
Springboot сделал его одной из самых основных фреймворков веб-разработки Java сегодня, потому что он предоставляет различные плагины из коробки. Mybatis-это очень легкая и простая в использовании ORM Framework. Redis сегодня очень основная база данных распределенной клавиш. В веб -разработке мы часто используем его для результатов запроса базы данных кэша.
Этот блог представит, как быстро создать веб -приложение с помощью Springboot и использовать Mybatis в качестве нашего ORM Framework. Чтобы повысить производительность, мы используем Redis в качестве кэша второго уровня для Mybatis. Чтобы проверить наш код, мы написали модульные тесты и использовали базу данных H2 в памяти для генерации наших тестовых данных. В рамках этого проекта мы надеемся, что читатели смогут быстро овладеть навыками и лучшими практиками современной веб -разработки Java.
Пример кода для этой статьи можно загрузить в GitHub: https://github.com/lovelcp/spring-boot-mybatis-with-redis/tree/master
среда
Среда развития: MAC 10.11
IDE: IntelliJ 2017.1
JDK: 1,8
Спринг-бот: 1.5.3.
Redis: 3.2.9
MySQL: 5.7
Весна
Создать новый проект
Во-первых, нам нужно инициализировать наш проект Spring-Boot. Благодаря весенним инициализаторам Intellij очень легко создать новый проект Spring-Boot. Во -первых, мы выбираем новый проект в IntelliJ:
Затем в интерфейсе, чтобы выбрать зависимости, проверить Web, Mybatis, Redis, MySQL, H2:
После того, как новый проект будет успешным, мы можем увидеть начальную структуру проекта, как показано на рисунке ниже:
Spring Initializer помог нам автоматически генерировать класс запуска - Springbootmybatiswithredisapplication. Код этого класса очень прост:
@Springbootapplicationpublic class springbootmybatiswithredisapplication {public static void main (string [] args) {springapplication.run (Springbootmybatiswithredisapplication.class, args); }}@Springbootapplication аннотация означает включение функции автоматической конфигурации Spring Boot. Хорошо, наш скелет проекта был успешно построен, чтобы заинтересованные читатели могли начать результаты через IntelliJ.
Создать новый интерфейс API
Далее мы напишем веб -API. Предположим, что наша веб -инженерия отвечает за обработку продуктов продавца (продукт). Нам нужно предоставить интерфейс GET, который возвращает информацию о продукте на основе идентификатора продукта, и интерфейс PUT, который обновляет информацию о продукте. Сначала мы определяем класс продукта, который включает в себя идентификатор продукта, название продукта и цену:
Продукт открытого класса реализует сериализуемые {частный статический конечный длинный серийный сериал = 14355159952762555188L; частный длинный идентификатор; Приватное название строки; частная длинная цена; // Getters Setters}Тогда нам нужно определить класс контроллера. Поскольку Spring Boot использует Spring MVC в качестве своего веб -компонента внутри, мы можем быстро разработать наш класс интерфейса посредством аннотации:
@Restcontroller @requestmapping ("/product") product productcontroller {@getmapping ("/{id}") public product getProductInfo (@pathvariable ("id") long product) {// todo return null; } @Putmapping ("/{id}") public product updateProductInfo (@pathvariable ("id") long productId, @Requestbody Product NewProduct) {// todo return null; }}Давайте кратко представим функции аннотаций, используемых в приведенном выше коде:
@RestController: означает, что класс является контроллером и обеспечивает интерфейс покоя, то есть значения всех интерфейсов возвращаются в формате JSON. Эта аннотация на самом деле представляет собой комбинированную аннотацию @Controller и @Responsebody, которая облегчает нам разработку API REST.
@Requestmapping, @getMapping, @putmapping: представляет URL -адрес интерфейса. Аннотация @Requestmapping, аннотированная на классе, означает, что URL -адреса всех интерфейсов под классом начинаются с /продуктом. @Getmapping означает, что это интерфейс GET HTTP, @putmapping означает, что это интерфейс http.
@Pathvariable, @Requestbody: представляет соотношение параметров параметров. Предполагая, что доступ к запросу GET /Product /123, запрос будет обрабатываться методом GetProductInfo, где 123 в URL будет сопоставлен с ProductId. Аналогичным образом, если это запрос на то, что запрашиваемое тело будет сопоставлено в объект NewProduct.
Здесь мы только определяем интерфейс, и фактическая логика обработки еще не была завершена, потому что информация продукта присутствует в базе данных. Затем мы будем интегрировать Mybatis в проект и взаимодействовать с базой данных.
Интеграция Mybatis
Настройте источник данных
Сначала нам нужно настроить наш источник данных в файле конфигурации. Мы используем MySQL в качестве нашей базы данных. Здесь мы используем YAML в качестве формата нашего файла конфигурации. Мы создаем новый файл Application.yml в каталоге ресурсов:
Spring:# DataSource: url: jdbc: mysql: // {your_host}/{your_db} username: {your_username} пароль: {your_password}-class-name: org.gjt.mm.mysql.driverПоскольку Spring Boot имеет функцию автоматической конфигурации, нам не нужно создавать новый класс конфигурации данных. Spring Boot автоматически загружает файл конфигурации и установит пул соединений базы данных на основе информации о файле конфигурации, что очень удобно.
Автор рекомендует использовать YAML в качестве формата файла конфигурации. XML выглядит длинным, а свойства не имеют иерархической структуры. Ямл просто компенсирует недостатки обоих. Это также причина, по которой Spring Boot поддерживает формат YAML по умолчанию.
Настройте mybatis
Мы представили библиотеку Mybatis-Spring-Boot-Boot-Starte в pom.xml через Spring Pinitiazer, которая автоматически поможет нам инициализировать Mybatis. Во -первых, мы заполняем соответствующую конфигурацию mybatis в Application.yml:
# mybatis configure mybatis: # Настройте имя пакета, где класс отображения находится
Затем определите класс ProductMapper в коде:
@Mapperpublic interface productmapper {product select (@param ("id") long id); void обновление (продукт продукта);}Здесь, пока мы добавим аннотацию @mapper, Spring Boot автоматически загружает класс Mapper при инициализации Mybatis.
Самая большая причина, по которой Spring Boot настолько популярен, - это функция автоматической конфигурации. Разработчики должны только обращать внимание на конфигурацию компонентов (например, информацию об подключении к базе данных), не заботясь о том, как инициализация отдельных компонентов, что позволяет нам сосредоточиться на реализации бизнеса и упростить процесс разработки.
Доступ к базе данных
После завершения конфигурации Mybatis мы можем получить доступ к базе данных в нашем интерфейсе. Мы вводим класс Mapper через @Autowired в ProductController и вызовываем соответствующий метод для реализации операций запроса и обновления в продукте. Здесь мы принимаем интерфейс запроса в качестве примера:
@Restcontroller @requestmapping ("/product") product class productcontroller {@autowired productmapper productmapper; @Getmapping ("/{id}") открытый продукт getProductInfo (@pathvariable ("id") long product) {return productmapper.select (productId); } // Избегайте слишком долго и опускайте код updateProductInfo}Затем вставьте несколько информации о продукте в свой MySQL, и вы можете запустить проект, чтобы увидеть, успешно ли запрос.
До сих пор мы успешно интегрировали Mybatis в наш проект, добавив возможность взаимодействовать с базой данных. Но этого недостаточно. Современный веб -проект определенно ускорит наш запрос базы данных на кэше. Далее мы представим, как научно интегрировать Redis в вторичный кэш Mybatis, чтобы реализовать автоматический кэш запросов базы данных.
Интегрированные Redis
Настройка Redis
Подобно доступу к базе данных, нам нужно настроить информацию о подключении Redis. Добавьте следующую конфигурацию в файл Application.yml:
Spring: Redis: # Redis Database Index (по умолчанию 0). Мы используем базу данных с Index 3, чтобы избежать конфликтов с другими базами данных: 3 # Redis Server Adder (по умолчанию IS Localhost) Хост: Localhost # Redis Port (по умолчанию 6379) Порт: 6379 # Redis Access Password (по умолчанию null) Пароль: # Redis Timeout (единица является Milliseconds). Отрицательные числа представляют бесконечные) максимально-активные: 8 # Максимальное количество подключений на холостом ходу (по умолчанию 8, отрицательные числа представляют собой бесконечный) максимальный IDLE: 8 # Минимальное количество соединений на холостом ходу (по умолчанию это 0, это значение только эффективно) Min-IDLE: 0 # Получите максимальное время ожидания соединения из пула соединений (по умолчанию -1, единица является Milliseconds, негативные числа указывают инцидент).
Все перечисленные выше являются обычно используемыми конфигурациями, и читатели могут понять конкретную роль каждого элемента конфигурации посредством информации о комментариях. Поскольку мы представили библиотеку Spring-Boot-Starter-DATA-REDIS в pom.xml, Spring Boot поможет нам автоматически загружать Redis подключения и конкретные классы конфигурации
org.springframework.boot.autoconfigure.data.redis.redisautoconfiguration. Через этот класс конфигурации мы можем обнаружить, что базовый уровень по умолчанию использует библиотеку Jedis и предоставляет Redistemplate и StringTemplate из коробки.
Используйте Redis в качестве кэша уровня 2
Принцип вторичного кэширования Mybatis не будет описан в этой статье. Читатели должны только знать, что вторичное кеширование Mybatis может автоматически кэшировать запросы базы данных и может автоматически обновлять кэш при обновлении данных.
Реализация вторичного кэширования Mybatis очень проста. Вам нужно только создать новый класс для реализации интерфейса org.apache.ibatis.cache.cache.
Есть пять методов для этого интерфейса:
String getId (): идентификатор объекта операции MyBatis Cache. Карточка соответствует объекту операции Mybatis Cache.
void putobject (ключ объекта, значение объекта): заполните результаты запроса в кэш.
Object getObject (ключ объекта): получить результат кэшированного запроса из кеша.
Object RemoveObject (клавиша объекта): удалите соответствующую клавишу и значение из кэша. Стрелял только при перевороте назад. Как правило, нам не нужно его реализовать. Для конкретных методов использования, пожалуйста, см.
void clear (): очистить кэш при обновлении.
int getSize (): необязательная реализация. Возвращает количество кэшей.
ReadWritelock getReadWriteLock (): необязательная реализация. Используется для реализации операций атомного кеша.
Далее мы создаем новый класс Reviscache для реализации интерфейса кэша:
открытый класс rediscache реализует Cache {private Static Final Logger logger = loggerFactory.getLogger (rediscache.class); Private Final ReadWritelock ReadWritelock = new ReenterTreadWriteLock (); Частный финальный идентификатор строки; // идентификатор экземпляра кэша частного Redistemplate Redistemplate; Частная статическая конечная длинная срок действия истечения_time_in_minutes = 30; // Redis Time Time Public resiscache (String Id) {if (id == null) {бросить новый allosalArgumentException ("экземпляры кэша требуют идентификатора"); } this.id = id; } @Override public String getId () {return id; } / ** * Поместите результат запроса Redis * * @param key * @param value * / @override @suppresswarnings ("uncecked") public void putobject (ключ объекта, значение объекта) {redistemplate redistemplate = getredistemplate (); ValueOperations opsforvalue = Redistemplate.OpsForValue (); opsforvalue.set (ключ, значение, истечение срокатиза_ина_minutes, timeUnit.minutes); logger.debug («Поместить результат запроса в Redis»); } / ** * Получить результат кэшированного запроса от Redis * * @param key * @return * / @override public object getObject (объект Key) {redistemplate redistemplate = getRedistemplate (); ValueOperations opsforvalue = Redistemplate.OpsForValue (); logger.debug («Получить кэшированный результат запроса от Redis»); return opsforvalue.get (key); } / ** * Удалить результат кэшированного запроса из redis * * @param key * @return * / @override @suppresswarnings ("uncecked") public overse removeObject (объект Key) {redistemplate redistemplate = getRedistemplate (); Redistemplate.delete (Key); logger.debug ("удалить кэшированный запрос результат из Redis"); вернуть ноль; } / ** * очищает этот экземпляр кэша * / @Override public void clear () {redistemplate redistemplate = getRedistemplate (); redistemplate.execute ((rediscallback) connection -> {connection.flushdb (); return null;}); logger.debug («Очистить все кэшированные результаты запроса от Redis»); } @Override public int getSize () {return 0; } @Override public readWritelock getReadWriteLock () {return ReadWritelock; } private redistemplate getRedistemplate () {if (redistemplate == null) {redistemplate = ApplicationContextholder.getbean ("Redistemplate"); } return redistemplate; }}Позвольте мне объяснить несколько ключевых моментов в приведенном выше коде:
Кэш второго уровня, который вы реализуете, должен иметь конструктор с идентификатором, в противном случае будет сообщена ошибка.
Мы используем пружинный инкапсулированный Redistemplate для эксплуатации Redis. Все статьи в Интернете, которые вводят Redis со вторичным кэшем уровня 2, используют библиотеку Jedis напрямую, но автор считает, что этого недостаточно весеннего стиля. Более того, Redistemplate инкапсулирует основную реализацию. Если в будущем мы не будем использовать Jedis, мы можем напрямую заменить базовую библиотеку, не изменяя верхний код. Что более удобно, так это то, что использование Redistemplate, нам не нужно заботиться об выпуске Redis Connections, в противном случае новичкам будет легко забыть выпустить соединение и привести к застенчивому приложению.
Следует отметить, что Redistemplate не может быть упомянут через Autowire, потому что RESISCACHESE не является бобовым в пружинном контейнере. Таким образом, нам нужно вручную позвонить в метод контейнера GetBean, чтобы получить этот боб. Для конкретных методов реализации, пожалуйста, обратитесь к коду в GitHub.
Метод сериализации Redis, который мы используем, является сериализацией JDK по умолчанию. Следовательно, объект запроса базы данных (например, класс продукта) должен реализовать сериализуемый интерфейс.
Таким образом, мы внедряем элегантный, научный класс и кеш Redis с весенним стилем.
Включите кеш 2 -го уровня
Далее нам нужно включить кеш 2 -го уровня в productmapper.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.org/dtd/mybatis-3-mapper.dtd"> mapper. namespace="com.wooyoo.learning.dao.mapper.ProductMapper"> <!-- Enable redis-based secondary cache--> <cache type="com.wooyoo.learning.util.RedisCache"/> <select id="select" resultType="Product"> SELECT * FROM products WHERE id = #{id} LIMIT 1 </select> <update id="update" ParameterType = "Product" flushCache = "true"> Обновление продуктов SET NAME = #{name}, price = #{цена} где id = #{id} Limit 1 </update> </mapper><cache type = "com.wooyoo.learning.util.rediscache"/> означает включение вторичного кэша на основе Redis, а в операторе обновления мы устанавливаем FlushCache на true, чтобы при обновлении информации о продукте кэш может быть автоматически недействительным (по сути, называется прозрачный метод).
тест
Настройка базы данных памяти H2
На этом этапе мы завершили всю разработку кода, а затем нам нужно написать код испытаний модуля, чтобы проверить качество нашего кода. В процессе разработки мы использовали базу данных MySQL, и, как правило, мы часто использовали базы данных в памяти во время тестирования. Здесь мы используем H2 в качестве базы данных, используемой в нашем тестовом сценарии.
Также очень просто использовать H2, вам просто нужно настроить его при использовании MySQL. В файле Application.yml:
--- пружина: Профили: тест # Настройка конфигурации базы данных: URL: JDBC: H2: MEM: Test Имя пользователя: Корневой пароль: 123456 Класс-класс: org.h2.driver схема: classpath: schema.sql Данные: classpath: data.sql
Чтобы избежать конфликтов с конфигурацией по умолчанию, мы используем-чтобы запустить новый абзац и использовать профили: тест, чтобы указать, что это конфигурация в тестовой среде. Затем просто добавьте аннотацию @activeProfiles (Profiles = "Test") в наш тестовый класс, чтобы включить конфигурацию в тестовой среде, чтобы вы могли переключаться из базы данных MySQL в базу данных H2 с одним щелчком.
В приведенной выше конфигурации Schema.SQL используется для хранения нашего оператора создания таблицы, а Data.SQL используется для хранения вставки данных. Таким образом, когда мы тестируем, H2 будет читать эти два файла, инициализировать структуру таблицы и данные, которые нам нужны, а затем уничтожат его в конце теста, что не окажет никакого влияния на нашу базу данных MySQL. Это преимущество в базах данных в памяти. Кроме того, не забудьте установить сферу зависимости H2 для тестирования в pom.xml.
Использование Spring Boot так просто, вы можете легко переключать базы данных в разных средах без изменения какого -либо кода.
Написание тестового кода
Поскольку мы инициализируются через пружинный инициализатор, у нас уже есть тестовый класс - SpringbootmybatiswithredisApplicationTests.
Spring Boot предоставляет некоторые классы инструментов, которые облегчают нам проведение тестирования веб -интерфейса, например TestRestTemplate. Затем в файле конфигурации мы настраиваем уровень журнала для отладки, чтобы облегчить наблюдение за журналами отладки. Конкретный тестовый код заключается в следующем:
@Runwith (springrunner.class) @springboottest (webenvironment = springboottest.webenvironment.random_port) @activeprofiles (profiles = "test") public class springbootmybatiswithredisapplicationtests {@localserport private int port; @Autowired private testresttemplate resttemplate; @Test public void test () {long productId = 1; Продукт продукта = RESTTEMPLATE.GETFOROBJECT ("http: // localhost:" + port + "/product/" + productId, product.class); AssertThat (product.getPrice ()). Isequalto (200); Продукт NewProduct = новый продукт (); long newprice = new random (). nextlong (); newProduct.setName ("Новое имя"); NewProduct.SetPrice (NewPrice); resttemplate.put ("http: // localhost:" + port + "/product/" + productId, newProduct); Продукт TestProduct = RESTTEMPLATE.GETFOROBJECT ("http: // localhost:" + port + "/product/" + productId, product.class); AssertThat (testProduct.getPrice ()). Isequalto (NewPrice); }}В приведенном выше коде теста:
Сначала мы называем интерфейс GET и используем оператор ASSERT, чтобы определить, был ли ожидаемый объект. В настоящее время объект продукта будет храниться в Redis.
Затем мы называем интерфейс PUT, чтобы обновить объект продукта, и кэш Redis будет недействительным.
Наконец, мы снова называем интерфейс GET, чтобы определить, получили ли мы новый объект продукта. Если старый объект получен, это означает, что неверный код кэша не выполнил, и в коде есть ошибка, в противном случае это означает, что наш код в порядке.
Письменное блюдо - это хорошая привычка программирования. Хотя для вас займет определенное количество времени, когда вам нужно будет выполнять какую -то рефакторирующую работу в будущем, вы будете благодарны вам, кто писал модульные тесты в прошлом.
Просмотреть результаты теста
Мы нажимаем, чтобы выполнить тестовый пример в IntelliJ, и результаты теста следующие:
Зеленый отображается, что указывает на то, что тестовый пример был успешно выполнен.
Суммировать
В этой статье представлено, как быстро создать современный веб -проект с помощью Spring Boot, Mybatis и Redis, а также представляет, как изящно писать модульные тесты под Spring Boot, чтобы обеспечить качество нашего кода. Конечно, есть еще одна проблема с этим проектом, то есть кэш Mybatis уровня 2 может быть кэширован только путем промывки всего БД. В настоящее время некоторые кэши, которые не должны быть признаны недействительными, также могут быть признаны недействительными, поэтому они имеют определенные ограничения.