Усовершенствования, облегчающие разработку Mybatis — Ourbatis

задняя часть база данных GitHub MyBatis

1. Недостатки Mybatis

Mybatis — это превосходная и гибкая структура уровня сохраняемости, которая обеспечивает базовый ввод операций с данными для уровня службы посредством конфигурации XML и сопоставления с интерфейсом Mapper.

Такой хороший фреймворк, но есть еще недостатки?

Как говорится, никто не идеален, потому что Mybatis настолько гибок, что каждый интерфейс Mapper должен настраивать соответствующий XML, поэтому это вызовет некоторые проблемы.

Проблема 1: много файлов конфигурации

Если система включает 100 таблиц БД, нам нужно написать100Интерфейс маппера, не доделан, самое страшное, надо100Каждый интерфейс Mapper настраивает соответствующий100Набор XML. И каждый Mapper должен добавлять, удалять, изменять и проверять функции, поэтому нам нужно написать100Как благородный инженер-разработчик Java, я не могу этого допустить, поэтомуMybatis Generatorродился, возникает еще один вопрос!

Проблема 2: Сложность обслуживания

Мы используемMybatis GeneratorРешил первую проблему, сколько бы файлов не генерировалось, просто и грубо, вроде решает все проблемы, Mybatis идеален!

Не радуйтесь, когда система только установлена, мы используемMybatis GeneratorСгенерировал кучу XML, продукт внезапно повысил новый спрос в процессе разработки, и менеджер проекта увеличился или изменил поле в кусок в соответствии с этим спросом. В это время я думаю, что ваша операция это:

  • 1. Найдите XML соответствующей таблицы
  • 2. Скопируйте пользовательский тег в XML и сохраните его локально.
  • 3. ИспользуйтеMybatis GeneratorРегенерировать XML для таблицы
  • 4. Перезаписать текущий XML
  • 5. Вставьте пользовательский тег в новый XML

В этом процессе, если мы пропустим часть этикетки на шаге 2, после того, как вся операция будет завершена, это будет другое ощущение ~

Вопрос третий: трудности с написанием XML

Если печень хорошая, проблема также в небольшом случае, тогда проблема приходит, как мы пишем и изменим наш XML в растущем XML.

Когда мы открываем XML для редактирования, мы видим более 1000 строк XML, из которых 900 строк являются общими операциями добавления, удаления и модификации.Чтобы добавить тег, нам нужно потянуть в конец файла, чтобы написать новый операция с данными. Чтобы обновить метку, нам нужно передатьCtrl + FГлядя на дальнейшее изменение этикетки.

Как избежать этих проблем?

Как сделать Mybatis более универсальным, не теряя гибкости?

2. Используйте нашу помощь, чтобы помочь MyBatis

Ourbatis — это небольшой и лаконичный инструмент для улучшения разработки Mybatis, адрес проекта:

характеристика:

  • 1, Краткий и удобный, Mybatis может развиваться без XML.
  • 2, элегантная развязка, общие и пользовательские теги SQL полностью изолированы, что упрощает обслуживание.
  • 3, Неинвазивный, Mybatis и Ourbatis можно использовать одновременно, а конфигурация проста.
  • 4, Гибкие и управляемые общие шаблоны можно настраивать и расширять.
  • 5, развертывание выполняется быстро, требуется только одна зависимость и две конфигурации, и его можно запустить напрямую.
  • 6, несколько источников данных, а также может использоваться, как обычно, в среде с несколькими источниками данных.

Небольшая демонстрация, используемая Ourbatis

окрестности:

  • Spring Boot 2.0.5.RELEASE
  • Ourbatis 1.0.5
  • JAVA 8
  • Mysql

отSpring Boot 2.0.5.RELEASEВозьмите версию в проекте, который можно использовать MyBatis обычно,pom.xmlДобавьте следующие зависимости:

   <dependency>
       	<groupId>com.smallnico</groupId>
       	<artifactId>ourbatis-spring-boot-starter</artifactId>
       	<version>1.0.5</version>
   </dependency>

Добавьте следующую конфигурацию в файл конфигурации:

ourbatis.domain-locations=实体类所在包名

Далее, интерфейсу Mapper нужно только наследоватьSimpleMapperПросто:

import org.nico.ourbatis.domain.User;
public interface UserMapper extends SimpleMapper<User, Integer>{
}

На данный момент развернуто простое приложение, использующее Ourbatis.После этого вы можете использовать некоторые общие методы работы Ourbatis по умолчанию:

	public T selectById(K key);
	
	public T selectEntity(T condition);
	
	public List<T> selectList(T condition);
	
	public long selectCount(Object condition);
	
	public List<T> selectPage(Page<Object> page);
	
	default PageResult<T> selectPageResult(Page<Object> page){
		long total = selectCount(page.getEntity());
		List<T> results = null;
		if(total > 0) {
			results = selectPage(page);
		}
		return new PageResult<>(total, results);
	}
	
	public K selectId(T condition);
	
	public List<K> selectIds(T condition);
	
	public int insert(T entity);
	
	public int insertSelective(T entity);
	
	public int insertBatch(List<T> list);
	
	public int update(T entity);
	
	public int updateSelective(T entity);
	
	public int updateBatch(List<T> list);
	
	public int delete(T condition);
	
	public int deleteById(K key);
	
	public int deleteBatch(List<K> list);

Пользовательский метод сопоставления

Во многих сценах мы используем более общий метод, который далек от удовлетворения наших собственных потребностей, нам часто требуется дополнительное расширение новых методов Mapper, XML-тегов, как достичь Ourbatis после его использования?

Сначала посмотрите на наши требования, в приведенной выше демонстрации мы добавляем метод в UserMapper.selectNameById:

import org.nico.ourbatis.domain.User;
public interface UserMapper extends SimpleMapper<User, Integer>{
    public String selectNameById(Integer userId);
}

Как Mybatis, это должно бытьresourcesСоздайте новую папку в каталоге ресурсовourbatis-mappers, а затем создайте в нем новый файл XML с правилами именования:

DomainClassSimpleName + Mapper.xml

вDomainClassSimpleNameэто имя класса нашего класса сущностей, вотUserЗатем назвал новый XMLUserMapper.xml.

src/main/resources
 - ourbatis-mappers
   - UserMapper.xml

После этого откройтеUserMapper.xml, начните писать MapperselectNameByIdМетка, соответствующая методу:

<select id="selectNameById" resultType="java.lang.String">
    select name from user where id = #{userId}
</select>

Обратите внимание, что писать теги нужно только во весь файл, больше ничего не нужно, зачем? После того, как вы углубитесь, вы поймете, что вы скажете это первым!

Далее рядом нет, вы можете использовать его напрямуюselectNameByIdметод.

Узнайте больше об Урбатисе

ourbatis 流程图

При запуске службы Ourbatis сначала сканируетourbatis.domain-locationsНастройте все классы сущностей в пакете и сопоставьте их с соответствующими данными структуры таблицы:

ourbatis Mapping

затем пройтиourbatis.xmlРендеринг, создание одного или другого XML-файла и, наконец, пересборка в контейнеры mybatis!

Весь процесс делится на два основных момента:

  • 1. Сопоставление классов сущностей в виде метаданных
  • 2. Используйтеourbatis.xmlОтображать метаданные в виде XML-файла

Я буду представлять их одну за другой~

Сопоставление классов сущностей в качестве метаданных

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

public interface Wrapper<T> {
	public String wrapping(T value);
}

Для полей, которые необходимо сопоставить, напримерИмя таблицыиимя поля таблицы, все они будут проходить через цепочку упаковщиков, прежде чем будут помещены вourbatis.xmlСделайте рендеринг, чтобы мы могли настроить формат поля упаковки для замены карты, конкретный метод можно найти в официальной Wiki:Обертка

использоватьourbatis.xmlОтображать метаданные в виде XML-файла

Во втором ключевом моменте Ourbatis использует пользовательские теги для рендеринга шаблонов.Сначала мы можем посмотреть на официальные теги по умолчанию.ourbatis.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="@{mapperClassName}">
	<resultMap id="BaseResultMap" type="@{domainClassName}">
		<ourbatis:foreach list="primaryColumns" var="elem">
			<id column="@{elem.jdbcName}" property="@{elem.javaName}" />
		</ourbatis:foreach>
		<ourbatis:foreach list="normalColumns" var="elem">
			<result column="@{elem.jdbcName}" property="@{elem.javaName}" />
		</ourbatis:foreach>
	</resultMap>

	<sql id="Base_Column_List">
		<ourbatis:foreach list="allColumns" var="elem"
			split=",">
			`@{elem.jdbcName}`
		</ourbatis:foreach>
	</sql>

	<select id="selectById" parameterType="java.lang.Object"
		resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from @{tableName}
		where 1 = 1
		<ourbatis:foreach list="primaryColumns" var="elem">
			and `@{elem.jdbcName}` = #{@{elem.javaName}}
		</ourbatis:foreach>
	</select>

	<select id="selectEntity" parameterType="@{domainClassName}"
		resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from @{tableName}
		where 1 = 1
		<ourbatis:foreach list="allColumns" var="elem">
			<if test="@{elem.javaName} != null">
				and `@{elem.jdbcName}` = #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
		limit 1
	</select>

	<select id="selectCount" parameterType="@{domainClassName}"
		resultType="long">
		select count(0)
		from @{tableName}
		where 1 = 1
		<ourbatis:foreach list="allColumns" var="elem">
			<if test="@{elem.javaName} != null">
				and `@{elem.jdbcName}` = #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
		limit 1
	</select>

	<select id="selectPage"
		parameterType="org.nico.ourbatis.entity.Page"
		resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from @{tableName}
		where 1 = 1
		<if test="entity != null">
			<ourbatis:foreach list="allColumns" var="elem">
				<if test="entity.@{elem.javaName} != null">
					and `@{elem.jdbcName}` = #{entity.@{elem.javaName}}
				</if>
			</ourbatis:foreach>
		</if>
		<if test="orderBy != null">
			order by ${orderBy}
		</if>
		<if test="start != null and end != null">
			limit ${start},${end}
		</if>
	</select>

	<select id="selectList" parameterType="@{domainClassName}"
		resultMap="BaseResultMap">
		select
		<include refid="Base_Column_List" />
		from @{tableName}
		where 1 = 1
		<ourbatis:foreach list="allColumns" var="elem">
			<if test="@{elem.javaName} != null">
				and `@{elem.jdbcName}` = #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
	</select>

	<select id="selectId" parameterType="@{domainClassName}"
		resultType="java.lang.Object">
		select
		<ourbatis:foreach list="primaryColumns" var="elem"
			split=",">
			`@{elem.jdbcName}`
		</ourbatis:foreach>
		from @{tableName}
		where 1 = 1
		<ourbatis:foreach list="allColumns" var="elem">
			<if test="@{elem.javaName} != null">
				and `@{elem.jdbcName}` = #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
		limit 1
	</select>

	<select id="selectIds" parameterType="@{domainClassName}"
		resultType="java.lang.Object">
		select
		<ourbatis:foreach list="primaryColumns" var="elem"
			split=",">
			`@{elem.jdbcName}`
		</ourbatis:foreach>
		from @{tableName}
		where 1 = 1
		<ourbatis:foreach list="normalColumns" var="elem">
			<if test="@{elem.javaName} != null">
				and `@{elem.jdbcName}` = #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
	</select>

	<delete id="deleteById" parameterType="java.lang.Object">
		delete
		from @{tableName}
		where 1=1
		<ourbatis:foreach list="primaryColumns" var="elem">
			and `@{elem.jdbcName}` = #{@{elem.javaName}}
		</ourbatis:foreach>
	</delete>

	<insert id="insert" keyProperty="@{primaryColumns.0.jdbcName}"
		useGeneratedKeys="true" parameterType="@{domainClassName}">
		insert into @{tableName}
		(
		<include refid="Base_Column_List" />
		)
		values (
		<ourbatis:foreach list="allColumns" var="elem"
			split=",">
			#{@{elem.javaName}}
		</ourbatis:foreach>
		)
	</insert>

	<insert id="insertSelective"
		keyProperty="@{primaryColumns.0.jdbcName}" useGeneratedKeys="true"
		parameterType="@{domainClassName}">
		insert into @{tableName}
		(
		<ourbatis:foreach list="primaryColumns" var="elem"
			split=",">
			`@{elem.jdbcName}`
		</ourbatis:foreach>
		<ourbatis:foreach list="normalColumns" var="elem">
			<if test="@{elem.javaName} != null">
				,`@{elem.jdbcName}`
			</if>
		</ourbatis:foreach>
		)
		values (
		<ourbatis:foreach list="primaryColumns" var="elem">
			#{@{elem.javaName}}
		</ourbatis:foreach>
		<ourbatis:foreach list="normalColumns" var="elem">
			<if test="@{elem.javaName} != null">
				, #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
		)
	</insert>

	<insert id="insertBatch"
		keyProperty="@{primaryColumns.0.jdbcName}" useGeneratedKeys="true"
		parameterType="java.util.List">
		insert into @{tableName}
		(
		<include refid="Base_Column_List" />
		)
		values
		<foreach collection="list" index="index" item="item"
			separator=",">
			(
			<ourbatis:foreach list="allColumns" var="elem"
				split=",">
				#{item.@{elem.javaName}}
			</ourbatis:foreach>
			)
		</foreach>
	</insert>

	<update id="update" parameterType="@{domainClassName}">
		update @{tableName}
		<set>
			<ourbatis:foreach list="normalColumns" var="elem"
				split=",">
				`@{elem.jdbcName}` = #{@{elem.javaName}}
			</ourbatis:foreach>
		</set>
		where 1=1
		<ourbatis:foreach list="primaryColumns" var="elem">
			and `@{elem.jdbcName}` = #{@{elem.javaName}}
		</ourbatis:foreach>
	</update>

	<update id="updateSelective" parameterType="@{domainClassName}">
		update @{tableName}
		<set>
			<ourbatis:foreach list="primaryColumns" var="elem"
				split=",">
				`@{elem.jdbcName}` = #{@{elem.javaName}}
			</ourbatis:foreach>
			<ourbatis:foreach list="normalColumns" var="elem">
				<if test="@{elem.javaName} != null">
					,`@{elem.jdbcName}` = #{@{elem.javaName}}
				</if>
			</ourbatis:foreach>
		</set>
		where 1=1
		<ourbatis:foreach list="primaryColumns" var="elem">
			and `@{elem.jdbcName}` = #{@{elem.javaName}}
		</ourbatis:foreach>
	</update>

	<update id="updateBatch" parameterType="java.util.List">
		<foreach collection="list" index="index" item="item"
			separator=";">
			update @{tableName}
			<set>
				<ourbatis:foreach list="normalColumns" var="elem"
					split=",">
					`@{elem.jdbcName}` = #{item.@{elem.javaName}}
				</ourbatis:foreach>
			</set>
			where 1=1
			<ourbatis:foreach list="primaryColumns" var="elem">
				and `@{elem.jdbcName}` = #{item.@{elem.javaName}}
			</ourbatis:foreach>
		</foreach>
	</update>

	<delete id="deleteBatch" parameterType="java.util.List">
		delete from @{tableName} where @{primaryColumns.0.jdbcName} in
		<foreach close=")" collection="list" index="index" item="item"
			open="(" separator=",">
			#{item}
		</foreach>
	</delete>

	<delete id="delete" parameterType="@{domainClassName}">
		delete from @{tableName} where 1 = 1
		<ourbatis:foreach list="allColumns" var="elem">
			<if test="@{elem.javaName} != null">
				and `@{elem.jdbcName}` = #{@{elem.javaName}}
			</if>
		</ourbatis:foreach>
	</delete>

	<ourbatis:ref path="classpath:ourbatis-mappers/@{domainSimpleClassName}Mapper.xml" />
</mapper>

Видно, что,ourbatis.xmlСодержимое похоже на исходный XML Mybatis, разница в том, что есть два незнакомых тега:

  • ourbatis: цикл foreach, отображающий список в метаданных
  • ourbatis:ref Внедрить содержимое внешнего файла

Это уникальная метка в Ourbatis, и Ourbatis также предоставляет нам соответствующую запись для настройки метки:

Class: org.nico.ourbatis.Ourbatis
Field: 
public static final Map<String, AssistAdapter> ASSIST_ADAPTERS = new HashMap<String, AssistAdapter>(){
		private static final long serialVersionUID = 1L;
		{
			put("ourbatis:foreach", new ForeachAdapter());
			put("ourbatis:ref", new RefAdapter());
		}
	};

мы можем изменитьorg.nico.ourbatis.Ourbatisстатические параметры в классеASSIST_ADAPTERSДля удаления, обновления и добавления пользовательских тегов необходимо реализовать адаптер тегов, мы можем рассмотреть самый простойRefAdapterРеализация адаптера:

public class RefAdapter extends AssistAdapter{
	@Override
	public String adapter(Map<String, Object> datas, NoelRender render, Document document) {
		String path = render.rending(datas, document.getParameter("path"), "domainSimpleClassName");
		String result =  StreamUtils.convertToString(path.replaceAll("classpath:", ""));
		return result == null ? "" : result.trim();
	}
}

В Ourbatis определены только два вышеуказанных пользовательских тега, которых достаточно для удовлетворения потребностей.foreachмаркировать, просматривать и визуализировать коллекцию в метаданных с помощьюrefМетка вводит внешние ресурсы, которые, как мы уже говорили, являются расширением методов интерфейса Mapper!

<ourbatis:ref path="classpath:ourbatis-mappers/@{domainSimpleClassName}Mapper.xml" />

Путь — это относительный путь текущего пути к классам проекта, и@{domainSimpleClassName}Он представляет собой имя класса сущности. Дополнительные системные параметры см. в Wiki:сопоставление метаданных

Благодаря этому механизму рендеринга шаблонов, Ourbatis достаточно гибок, мы можем не только расширять, вводя внешние файлы, когда нам нужно добавить или изменить общие методы, мы можем настроитьourbatis.xmlсодержание, как это сделать? Просто сделайте копию и поместите ее в каталог ресурсов!

Увидев это, я полагаю, что все уже знают основные принципы Урбатиса и то, как они используются, поэтому я не буду много говорить. Для более подробной информации вы можете перейти на официальную Вики, чтобы прочитать:Ourbtis Wiki