Начало работы с Fluent MyBatis

Java

введение

Наиболее часто используемыми фреймворками ORM в Java являются mybatis, hibernate, JPA и другие фреймворки. В Китае широко используется Mybatis.На основе расширенного фреймворка mybatis существуют также mybatis plus и TK mybatis. Сегодня мы представляем новую платформу улучшения mybatis — Fluent mybatis, Поскольку JDBC --> Mybatis или Mybatis Plus несомненно упрощает работу разработчика, о какой роли Fluent MyBatis мы сегодня говорим?

Сравнение функций Fluent Mybatis, родного Mybatis и Mybatis Plus

Принцип FluentMybatis

Первое знакомство с Fluent MyBatis

Fluent MyBatis — это инструмент расширения для MyBatis, который выполняет только синтаксическую инкапсуляцию сахара mybatis без каких-либо модификаций mybatis. С помощью компиляции предоставляется ряд вспомогательных классов, которые помогают упростить разработку и повысить эффективность.

Начиная

Создайте образец таблицы базы данных

DROP TABLE IF EXISTS `your_table`;
create table `your_table`
(
    id bigint auto_increment comment '主键ID' primary key,
    name varchar(30) charset utf8 null comment '姓名',
    age int null comment '年龄',
    email varchar(50) charset utf8 null comment '邮箱',
    gmt_create datetime null comment '记录创建时间',
    gmt_modified datetime null comment '记录最后修改时间',
    is_deleted tinyint(2) default 0 null comment '逻辑删除标识'
);

Инициализировать проект SpringBoot

  • Установить зависимости проекта
  1. весенняя загрузка: на основе весенней загрузки, это определенно необходимо
  2. lombok: артефакт, который пропускает коды get, set, toString, лично мне он нравится; вы также можете сгенерировать методы get set вручную
  3. mysql-connector-java: драйвер базы данных
  4. fluent-mybatis: зависимость времени выполнения fluent-mybatis
  5. fluent-mybatis-processor: генерация кода fluent-mybatis и зависимости времени компиляции
  6. Тестовые зависимые пакеты jar: spring-test, junit

Конкретная конфигурация maven pom

  • Настроить информацию о базе данных
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.url=jdbc:mysql://localhost:3306/fluent_mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

конкретная конфигурация свойств

  • Создать класс сущности

Классы сущностей можно создавать вручную или создавать классы сущностей любым способом, а затем аннотировать.

  1. Добавьте аннотацию @FluentMybatis в класс Entity.
  2. Аннотируйте поле первичного ключа с помощью @TableId
  3. Добавьте аннотацию @TableField к общим полям

Здесь код генерируется напрямую с помощью класса инструмента, предоставленного fluent mybatis.

public class AppEntityGenerator {
    static final String url = "jdbc:mysql://localhost:3306/fluent_mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8";

    public static void main(String[] args) {
        FileGenerator.build(Abc.class);
    }

    @Tables(
        /** 数据库连接信息 **/
        url = url, username = "root", password = "password",
        /** Entity类parent package路径 **/
        basePack = "cn.org.fluent.mybatis.springboot.demo",
        /** Entity代码源目录 **/
        srcDir = "spring-boot-demo/src/main/java",
        /** Dao代码源目录 **/
        daoDir = "spring-boot-demo/src/main/java",
        /** 如果表定义记录创建,记录修改,逻辑删除字段 **/
        gmtCreated = "gmt_create", gmtModified = "gmt_modified", logicDeleted = "is_deleted",
        /** 需要生成文件的表 **/
        tables = @Table(value = {"your_table"})
    )
    static class Abc {
    }
}

специальный код

Здесь есть 3 специальных поля

  1. gmt_create, время создания записи, установит значение по умолчанию для вставки записи, соответствующее аннотации в сгенерированном поле Entity @TableField(insert="now()")
  2. gmt_modified, время последнего обновления записи, установит значение по умолчанию для вставки и обновления записи, соответствующее аннотации в поле Entity сгенерированного кода @TableField(insert="now()", update="now() ")
  3. is_deleted, идентификатор логического удаления записи, тип поля — Boolean, установлено значение по умолчанию вставки записи, соответствующее аннотации @TableField(insert="0")

Выполнить основную функцию сгенерированного кода и сгенерировать файлы Entity, DaoIntf, DaoImpl в каталоге проекта main/src/java; Соблюдайте аннотации полей идентификатора первичного ключа YourEntity, gmt_create, gmt_modified, is_deleted.

@Data
@Accessors(chain = true)
@FluentMybatis(table = "your_table")
public class YourEntity extends RichEntity{
    private static final long serialVersionUID = 1L;

    @TableId(value = "id")
    private Long id;

    @TableField(value = "gmt_create", insert = "now()")
    private Date gmtCreate;

    @TableField(value = "gmt_modified", insert = "now()", update = "now()")
    private Date gmtModified;

    @TableField(value = "is_deleted", insert = "0")
    private Boolean isDeleted;

    @TableField(value = "age")
    private Integer age;

    @TableField(value = "email")
    private String email;
 
    @TableField(value = "name")
    private String name;

    @Override
    public final Class entityClass() {
      return YourEntity.class;
    }
}

Сгенерированный файл Dao относится к классу YourTableBaseDao.Этот класс необходимо скомпилировать и сгенерировать в соответствии с классом Entity.Перед компиляцией будут ошибки компиляции, поэтому после генерации кода его необходимо пересобрать.

@Repository
public class YourDaoImpl extends YourBaseDao implements YourDao {
    // 在这里添加你自己的业务逻辑代码
}

-w100

После Rebuild в целевом каталоге будет еще несколько файлов.Обновите проект и добавьте target/generated-sources в исходный каталог.

Эти файлы генерируются в target/generated-sources, и на них можно напрямую ссылаться и упаковывать в коде. Их не нужно копировать в каталог src, и их не нужно поддерживать. перекомпилирован и упакован.

image.png

  • Запустите тест SpringBoot, чтобы проверить эффект

В настоящее время проект уже имеет мощную функцию добавления, удаления, модификации и запроса fluent mybatis. Давайте создадим тестовый класс для проверки, внедрим YourMapper в тестовый класс и продемонстрируем здесь метод запроса, поэтому мы используем listEntity, параметр которого является объектом Query.

@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void contextLoads() {
        List<YourEntity> list = yourMapper.listEntity(yourMapper.query());
        for (YourEntity entity : list) {
            System.out.println(entity);
        }
    }
}

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

Методы манипулирования данными, предоставляемые Mapper, соответствующие Entity

Ниже мы представляем методы вставки, выбора, обновления и удаления, предоставляемые FluentMybatis соответственно. Введение контента в основном анализируется в 4 частях.

  1. Mapper определение метода (Скомпилируйте сгенерированный код)
  2. Соответствующая динамическая сборка SQL Mapper SQLProvider (Скомпилируйте сгенерированный код)
  3. Пример проверочного теста
  4. В соответствии с оператором SQL и информационным выводом, напечатанным в примере, сравните и просмотрите

Метод вставки, предоставляемый FluentMybatis

insert

одиночная операция вставки

  • Метод сопоставления
public interface YourMapper extends IEntityMapper<YourEntity> {
  /**
   * 插入一条记录
   *
   * @param entity
   * @return
   */
  @Override
  @InsertProvider(
      type = YourSqlProvider.class,
      method = "insert"
  )
  @Options(
      useGeneratedKeys = true,
      keyProperty = "id",
      keyColumn = "id"
  )
  int insert(YourEntity entity);
}
  • Динамическая сборка SQL
public class YourSqlProvider {
    public String insert(YourEntity entity) {
        assertNotNull("entity", entity);
        MapperSql sql = new MapperSql();
        sql.INSERT_INTO("your_table");
        List<String> columns = new ArrayList<>();
        List<String> values = new ArrayList<>();
        if (entity.getId() != null) {
            columns.add("id");
            values.add("#{id}");
        }
        columns.add("gmt_create");
        if (entity.getGmtCreate() != null) {
            values.add("#{gmtCreate}");
        } else {
            values.add("now()");
        }
        columns.add("gmt_modified");
        if (entity.getGmtModified() != null) {
            values.add("#{gmtModified}");
        } else {
            values.add("now()");
        }
        columns.add("is_deleted");
        if (entity.getIsDeleted() != null) {
            values.add("#{isDeleted}");
        } else {
            values.add("0");
        }
        if (entity.getAge() != null) {
            columns.add("age");
            values.add("#{age}");
        }
        if (entity.getEmail() != null) {
            columns.add("email");
            values.add("#{email}");
        }
        if (entity.getName() != null) {
            columns.add("name");
            values.add("#{name}");
        }
        sql.INSERT_COLUMNS(columns);
        sql.VALUES();
        sql.INSERT_VALUES(values);
        return sql.toString();
    }
}

В процессе сборки были сделаны специальные выводы по трем полям, соответствующим @TableField(insert="значение по умолчанию"): gmt_crate, gmt_modified, is_deleted.

  • Напишите тест вставки для проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void insert() {
        // 构造一个对象
        YourEntity entity = new YourEntity();
        entity.setName("Fluent Mybatis");
        entity.setAge(1);
        entity.setEmail("darui.wu@163.com");
        entity.setIsDeleted(false);
        // 插入操作
        int count = yourMapper.insert(entity);
        System.out.println("count:" + count);
        System.out.println("entity:" + entity);
    }
}
  • Выполните метод проверки вставки и просмотрите информацию журнала выходных данных консоли.
DEBUG - ==>  Preparing: INSERT INTO your_table(gmt_create, gmt_modified, is_deleted, age, email, name) VALUES (now(), now(), ?, ?, ?, ?)  
DEBUG - ==> Parameters: false(Boolean), 1(Integer), darui.wu@163.com(String), Fluent Mybatis(String) 
DEBUG - <==    Updates: 1 
count:1
entity:YourEntity(id=18, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis)
  • Вот несколько замечаний
  1. Автоинкремент и обратная запись значения первичного ключа Entity

В соответствии с выводом консоли вы можете видеть, что атрибут id объекта был записан обратно в соответствии с автоматически увеличивающимся значением первичного ключа базы данных. Настройка автоматического увеличения первичного ключа осуществляется с помощью аннотации @TableId, а значением по умолчанию его метода свойства auto() является true. 2. Аннотация @Options для класса Mapper, сгенерированная Fluent mybatis на основе аннотации @TableId, выглядит следующим образом:

@Options(
  useGeneratedKeys = true,
  keyProperty = "id",
  keyColumn = "id"
)
  1. gmt_created, gmt_modified, is_deleted обработка вставки значения по умолчанию

Давайте взглянем на аннотации @TableField этих трех полей в Entity. Все они определяют метод вставки свойства, который устанавливает значение вставки по умолчанию (то есть, когда программа кодирует вставку, если поле не установлено, значение по умолчанию используется значение)

    @TableField(value = "gmt_create", insert = "now()")
    private Date gmtCreate;

    @TableField(value = "gmt_modified", insert = "now()", update = "now()")
    private Date gmtModified;

    @TableField(value = "is_deleted", insert = "0")
    private Boolean isDeleted;

В тестовом примере gmt_created и gmt_modified не устанавливали никакого значения при инициализации Entity, is_deleted устанавливало значение false. При построении sql, gmt_created, gmt_modified используют значение по умолчанию "now()" напрямую, is_deleted использует настройку предварительно скомпилированной переменной (?) (фактическое значение false).

INSERT INTO your_table
(gmt_create, gmt_modified, is_deleted, age, email, name) 
VALUES 
(now(), now(), ?, ?, ?, ?)

Давайте посмотрим на структуру SQL соответствующего SQLProvider, мы рассмотрим только структуру 3 полей.

public class YourSqlProvider {
    public String insert(YourEntity entity) {
        List<String> columns = new ArrayList<>();
        List<String> values = new ArrayList<>();
        // 省略 ... ...
        columns.add("gmt_create");
        if (entity.getGmtCreate() != null) {
            values.add("#{gmtCreate}");
        } else {
            values.add("now()");
        }
        columns.add("gmt_modified");
        if (entity.getGmtModified() != null) {
            values.add("#{gmtModified}");
        } else {
            values.add("now()");
        }
        columns.add("is_deleted");
        if (entity.getIsDeleted() != null) {
            values.add("#{isDeleted}");
        } else {
            values.add("0");
        }
        if (entity.getAge() != null) {
            columns.add("age");
            values.add("#{age}");
        }
        // 省略... ...
        return sql.toString();
    }
}

Мы видим, что для полей без атрибута вставки, только если он пуст; для полей с атрибутом вставки, если сущность не пуста, оператору sql присваивается значение по умолчанию.

insertBatch

  • Для пакетной вставки проверьте динамическую структуру SQL insertBatch в SqlProvider, соответствующую Mapper.
public class YourSqlProvider {
    public String insertBatch(Map map) {
        assertNotEmpty("map", map);
        MapperSql sql = new MapperSql();
        List<YourEntity> entities = getParas(map, "list");
        sql.INSERT_INTO("your_table");
        sql.INSERT_COLUMNS(ALL_ENTITY_FIELDS);
        sql.VALUES();
        for (int index = 0; index < entities.size(); index++) {
            if (index > 0) {
                sql.APPEND(", ");
            }
            sql.INSERT_VALUES(
                "#{list[" + index + "].id}",
                entities.get(index).getGmtCreate() == null ? "now()" : "#{list[" + index + "].gmtCreate}",
                entities.get(index).getGmtModified() == null ? "now()" : "#{list[" + index + "].gmtModified}",
                entities.get(index).getIsDeleted() == null ? "0" : "#{list[" + index + "].isDeleted}",
                "#{list[" + index + "].age}",
                "#{list[" + index + "].email}",
                "#{list[" + index + "].name}"
            );
        }
        return sql.toString();
    }
}

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

INSERT INTO your_table ('Entity对应的字段列表') VALUES ('实例1值'), ('实例2值')
  • Напишите тест, чтобы увидеть конкретный эффект
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;
    
    void insertBatch(){
        List<YourEntity> entities = new ArrayList<>();
        entities.add(new YourEntity().setName("Fluent Mybatis").setEmail("darui.wu@163.com"));
        entities.add(new YourEntity().setName("Fluent Mybatis Demo").setEmail("darui.wu@163.com"));
        entities.add(new YourEntity().setName("Test4J").setEmail("darui.wu@163.com"));
        int count = yourMapper.insertBatch(entities);
        System.out.println("count:" + count);
        System.out.println("entity:" + entities);
    }
}
  • Выполните тест и посмотрите вывод консоли
DEBUG - ==>  Preparing: INSERT INTO your_table(id, gmt_create, gmt_modified, is_deleted, age, email, name) VALUES (?, now(), now(), 0, ?, ?, ?) , (?, now(), now(), 0, ?, ?, ?) , (?, now(), now(), 0, ?, ?, ?)  
DEBUG - ==> Parameters: null, null, darui.wu@163.com(String), Fluent Mybatis(String), null, null, darui.wu@163.com(String), Fluent Mybatis Demo(String), null, null, darui.wu@163.com(String), Test4J(String) 
DEBUG - <==    Updates: 3 
count:3
entity:[YourEntity(id=null, gmtCreate=null, gmtModified=null, isDeleted=null, age=null, email=darui.wu@163.com, name=Fluent Mybatis), YourEntity(id=null, gmtCreate=null, gmtModified=null, isDeleted=null, age=null, email=darui.wu@163.com, name=Fluent Mybatis Demo), YourEntity(id=null, gmtCreate=null, gmtModified=null, isDeleted=null, age=null, email=darui.wu@163.com, name=Test4J)]

Метод запроса select, предоставляемый FluentMybatis

findById

Найти один фрагмент данных по идентификатору

  • Определение метода Mapper, сгенерированного системой
public interface YourMapper extends IEntityMapper<YourEntity> {
    String ResultMap = "YourEntityResultMap";

    @SelectProvider(
        type = YourSqlProvider.class,
        method = "findById"
    )
    @Results(
        id = ResultMap,
        value = {
            @Result(column = "id", property = "id", javaType = Long.class, id = true),
            @Result(column = "gmt_create", property = "gmtCreate", javaType = Date.class),
            @Result(column = "gmt_modified", property = "gmtModified", javaType = Date.class),
            @Result(column = "is_deleted", property = "isDeleted", javaType = Boolean.class),
            @Result(column = "age", property = "age", javaType = Integer.class),
            @Result(column = "email", property = "email", javaType = String.class),
            @Result(column = "name", property = "name", javaType = String.class)
        }
    )
    YourEntity findById(Serializable id);
}

В findById в дополнение к определению классов и методов SQLProvider, предоставляющих динамические операторы SQL, также определяется отношение сопоставления данных @Results. Это сопоставление ResultMap является общим для одного Mapper, а также используется, когда другие методы запроса возвращают объекты Entity.

  • Генерируемый системой динамический метод построения sql
public class YourSqlProvider {
    public String findById(Serializable id) {
        assertNotNull("id", id);
        MapperSql sql = new MapperSql();
        sql.SELECT("your_table", ALL_ENTITY_FIELDS);
        sql.WHERE("id = #{id}");
        return sql.toString();
    } 
}

Это объединение SQL относительно просто

  1. Список полей запроса склеен в соответствии с полем Entity
  2. установить идентификатор = # {id}
  • Напишите тест и используйте его
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void findById(){
        YourEntity entity = yourMapper.findById(8L);
        System.out.println(entity);
    }
}
  • Просмотр журнала вывода консоли
DEBUG - ==>  Preparing: SELECT id, gmt_create, gmt_modified, is_deleted, age, email, name FROM your_table WHERE id = ?  
DEBUG - ==> Parameters: 8(Long) 
DEBUG - <==      Total: 1 
YourEntity(id=8, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis)

listByIds

Экземпляры пакетного запроса на основе списка идентификаторов

  • Определение картографа
public interface YourMapper extends IEntityMapper<YourEntity> {
    String ResultMap = "YourEntityResultMap";

    @Override
    @SelectProvider(
        type = YourSqlProvider.class,
        method = "listByIds"
    )
    @ResultMap(ResultMap)
    List<YourEntity> listByIds(@Param(Param_Coll) Collection ids);
}

Входные данные представляют собой набор списков идентификаторов, возвращаемые значения представляют собой список сущностей, а сопоставление данных повторно использует ResultMap, определенный в findById.

  • Метод динамического поставщика SQL
public class YourSqlProvider {
    public String listByIds(Map map) {
        Collection ids = getParas(map, "coll");
        MapperSql sql = new MapperSql();
        sql.SELECT("your_table", ALL_ENTITY_FIELDS);
        sql.WHERE_PK_IN("id", ids.size());
        return sql.toString();
    }
}
  1. Список полей запроса склеен в соответствии с полем Entity
  2. В соответствии с количеством переданных идентификаторов (размер), установите идентификатор IN (#{coll[0]}, ..., #{coll[size - 1]})
  • Напишите тест для проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void listByIds() {
        List<YourEntity> entities = yourMapper.listByIds(Arrays.asList(8L, 9L));
        System.out.println(entities);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: SELECT id, gmt_create, gmt_modified, is_deleted, age, email, name FROM your_table WHERE id IN (?, ?)  
DEBUG - ==> Parameters: 8(Long), 9(Long) 
DEBUG - <==      Total: 2 
[YourEntity(id=8, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis), 
 YourEntity(id=9, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis)]

findOne

Запрос одной записи на основе настраиваемых критериев

  • Определение метода сопоставления
public interface YourMapper extends IEntityMapper<YourEntity> {
    @SelectProvider(
        type = YourSqlProvider.class,
        method = "findOne"
    )
    @ResultMap(ResultMap)
    YourEntity findOne(@Param(Param_EW) IQuery query);
}
  • динамическая сборка sql
public class YourSqlProvider {
    public String findOne(Map map) {
        WrapperData data = getWrapperData(map, "ew");
        MapperSql sql = new MapperSql();
        sql.SELECT("your_table", data, ALL_ENTITY_FIELDS);
        sql.WHERE_GROUP_ORDER_BY(data);
        return byPaged(DbType.MYSQL, data, sql.toString());
    }
}

Динамическая сборка SQL делает несколько вещей:

  1. В зависимости от того, задано ли поле запроса явно в запросе, установите список полей выбора.Если он не задан, возьмите сборку по умолчанию для всех полей Entity.
  2. Установите условия запроса в зависимости от того, где, сгруппировать, иметь и упорядочить в запросе: sql.WHERE_GROUP_ORDER_BY(данные)
  3. В зависимости от того, установлены ли информация о подкачке и тип базы данных, соберите синтаксис запроса на подкачку: byPaged(DbType.MYSQL, data, sql.toString())
  • Напишите тест для проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void findOne() {
        YourEntity entity = yourMapper.findOne(new YourQuery()
            .where.id().eq(4L).end()
        );
    }
}

Посмотрите вывод консоли:

DEBUG - ==>  Preparing: SELECT id, gmt_create, gmt_modified, is_deleted, age, email, name FROM your_table WHERE id = ?  
DEBUG - ==> Parameters: 4(Long) 
DEBUG - <==      Total: 1 
YourEntity(id=4, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis)

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

  • Если findOne, подходящих данных больше 2
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void findOne2() {
        YourEntity entity = yourMapper.findOne(new YourQuery()
            .where.name().eq("Fluent Mybatis").end()
        );
        System.out.println(entity);
    }
}

Поскольку в базе данных есть несколько фрагментов данных с name='Fluent Mybatis', вызов этого метода вызовет исключение.

DEBUG - ==>  Preparing: SELECT id, gmt_create, gmt_modified, is_deleted, age, email, name FROM your_table WHERE name = ?  
DEBUG - ==> Parameters: Fluent Mybatis(String) 
DEBUG - <==      Total: 14 

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions
.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), 
but found: 14

listByMap

  • Определение метода сопоставления
public interface YourMapper extends IEntityMapper<YourEntity> {
    String ResultMap = "YourEntityResultMap";
    @SelectProvider(
        type = YourSqlProvider.class,
        method = "listByMap"
    )
    @ResultMap(ResultMap)
    List<YourEntity> listByMap(@Param(Param_CM) Map<String, Object> columnMap);
}

Входной параметр Map используется для указания условий запроса данных. Конкретным условием является отношение И ключ = значение.

  • Динамическое сплайсинг SQL
public class YourSqlProvider {
    public String listByMap(Map map) {
        Map<String, Object> where = getParas(map, "cm");
        MapperSql sql = new MapperSql();
        sql.SELECT("your_table", ALL_ENTITY_FIELDS);
        sql.WHERE("cm", where);
        return sql.toString();
    }
}
  1. Запросить все поля Entity
  2. Соберите условие карты, (ключ1 = значение1) И (ключ2 = значение2)
  • Напишите тестовую демонстрацию для проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;
    @Test
    void listByMap() {
        List<YourEntity> entities = yourMapper.listByMap(new HashMap<String, Object>() {
            {
                this.put("name", "Fluent Mybatis");
                this.put("is_deleted", false);
            }
        });
        System.out.println(entities);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: SELECT id, gmt_create, gmt_modified, is_deleted, age, email, name FROM your_table WHERE is_deleted = ? AND name = ?  
DEBUG - ==> Parameters: false(Boolean), Fluent Mybatis(String) 
DEBUG - <==      Total: 5 
[YourEntity(id=4, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis), 
 YourEntity(id=5, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis), 
 YourEntity(id=6, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis), 
 YourEntity(id=7, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis), 
 YourEntity(id=8, gmtCreate=null, gmtModified=null, isDeleted=false, age=1, email=darui.wu@163.com, name=Fluent Mybatis)]

listEntity

Запросить данные в соответствии с пользовательскими условиями и сопоставить данные с соответствующим классом Entity.

  • Определение метода сопоставления
public interface YourMapper extends IEntityMapper<YourEntity> {
    @SelectProvider(
        type = YourSqlProvider.class,
        method = "listEntity"
    )
    @ResultMap(ResultMap)
    List<YourEntity> listEntity(@Param(Param_EW) IQuery query);
}
  • Динамическая сборка SQL
public class YourSqlProvider {
    public String listEntity(Map map) {
        WrapperData data = getWrapperData(map, "ew");
        MapperSql sql = new MapperSql();
        sql.SELECT("your_table", data, ALL_ENTITY_FIELDS);
        sql.WHERE_GROUP_ORDER_BY(data);
        return byPaged(DbType.MYSQL, data, sql.toString());
    }
}

С помощью метода findOne динамическая сборка SQL делает следующее:

  1. В зависимости от того, задано ли поле запроса явно в запросе, установите список полей выбора.Если он не задан, возьмите сборку по умолчанию для всех полей Entity.
  2. Установите условия запроса в зависимости от того, где, сгруппировать, иметь и упорядочить в запросе: sql.WHERE_GROUP_ORDER_BY(данные)
  3. В зависимости от того, установлены ли информация о подкачке и тип базы данных, соберите синтаксис запроса на подкачку: byPaged(DbType.MYSQL, data, sql.toString())
  • Напишите тест, чтобы увидеть эффект
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void listEntity() {
        List<YourEntity> entities = yourMapper.listEntity(new YourQuery()
            .select.name().age().email().end()
            .where.id().lt(6L)
            .and.name().like("Fluent").end()
            .orderBy.id().desc().end()
        );
        System.out.println(entities);
    }
}
  • Просмотр журнала консоли
DEBUG - ==>  Preparing: SELECT name, age, email FROM your_table WHERE id < ? AND name LIKE ? ORDER BY id DESC  
DEBUG - ==> Parameters: 6(Long), %Fluent%(String) 
DEBUG - <==      Total: 2 
[YourEntity(id=null, gmtCreate=null, gmtModified=null, isDeleted=null, age=1, email=darui.wu@163.com, name=Fluent Mybatis),
 YourEntity(id=null, gmtCreate=null, gmtModified=null, isDeleted=null, age=1, email=darui.wu@163.com, name=Fluent Mybatis)]

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

  1. Поля для запроса: имя, возраст, электронная почта3 поля
  2. Определены конкретные условия: id
  3. Определяется в обратном порядке по идентификатору

listMaps

Структура параметра listMaps такая же, как и у listEntity.Если она отличается, то при возврате она не сопоставляется с Entity, а сопоставляется с объектом Map.

  • Напишите тест для проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void listMaps() {
        List<Map<String,Object>> maps = yourMapper.listMaps(new YourQuery()
            .select.name().age().email().end()
            .where.id().lt(6L)
            .and.name().like("Fluent").end()
            .orderBy.id().desc().end()
        );
        System.out.println(maps);
    }
}
  • Просмотр выходной информации консоли
DEBUG - ==>  Preparing: SELECT name, age, email AS EMail FROM your_table WHERE id < ? AND name LIKE ? ORDER BY id DESC  
DEBUG - ==> Parameters: 6(Long), %Fluent%(String) 
DEBUG - <==      Total: 2 
[{name=Fluent Mybatis, EMail=darui.wu@163.com}, 
 {name=Fluent Mybatis, EMail=darui.wu@163.com}]

listObjs

Структура параметра запроса listObjs такая же, как у listEntity и listMaps, но возвращается только первый столбец объекта запроса, а остальные столбцы отбрасываются.

  • Пример проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void listObjs() {
        List<String> ids = yourMapper.listObjs(new YourQuery()
            .select.name().age().email().end()
            .where.id().lt(6L)
            .and.name().like("Fluent").end()
            .orderBy.id().desc().end()
        );
        System.out.println(ids);
    }
}
  • Просмотр выходной информации консоли
DEBUG - ==>  Preparing: SELECT name, age, email AS EMail FROM your_table WHERE id < ? AND name LIKE ? ORDER BY id DESC  
DEBUG - ==> Parameters: 6(Long), %Fluent%(String) 
DEBUG - <==      Total: 2 
[Fluent Mybatis, Fluent Mybatis]

Мы видим, что консоль выводит только название первого столбца поля запроса: [Fluent Mybatis, Fluent Mybatis]

count

count, возвращает количество записей, соответствующих условию

  • Определение картографа
public interface YourMapper extends IEntityMapper<YourEntity> {
  @SelectProvider(
      type = YourSqlProvider.class,
      method = "count"
  )
  Integer count(@Param(Param_EW) IQuery query);
}
  • Пример проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void count() {
        int count = yourMapper.count(new YourQuery()
            .where.id().lt(1000L)
            .and.name().like("Fluent").end()
            .limit(0, 10)
        );
        System.out.println(count);
    }
}
  • Просмотр выходной информации консоли
DEBUG - ==>  Preparing: SELECT COUNT(*) FROM your_table WHERE id < ? AND name LIKE ? LIMIT ?, ?  
DEBUG - ==> Parameters: 1000(Long), %Fluent%(String), 0(Integer), 10(Integer) 
DEBUG - <==      Total: 1 
5

countNoLimit

Метод использования такой же, как и у count, за исключением того, что часть оператора SQL отбрасывает параметр ограничения (если вы его установили).

  • Пример проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void countNoLimit() {
        int count = yourMapper.countNoLimit(new YourQuery()
            .where.id().lt(1000L)
            .and.name().like("Fluent").end()
            .limit(0, 10)
        );
        System.out.println(count);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: SELECT COUNT(*) FROM your_table WHERE id < ? AND name LIKE ?  
DEBUG - ==> Parameters: 1000(Long), %Fluent%(String) 
DEBUG - <==      Total: 1 
5

Мы видим, что в распечатанном операторе SQL отсутствует предельная часть по сравнению с методом подсчета.

Метод обновления обновления, предоставляемый FluentMybatis.

updateById

updateById В соответствии со значением идентификатора сущности обновить непустые свойства в сущности

  • Определение картографа
public interface YourMapper extends IEntityMapper<YourEntity> {
  @UpdateProvider(
      type = YourSqlProvider.class,
      method = "updateById"
  )
  int updateById(@Param(Param_ET) YourEntity entity);
}

Входным параметром является объект Entity, а выходным параметром является количество обновленных записей, возвращаемое значение здесь может быть только 0: id записи нет, обновление не выполнено, 1: id запись успешно обновлена.

  • Динамическая сборка SQL
public class YourSqlProvider {
    public String updateById(Map<String, Object> map) {
        YourEntity entity = getParas(map, "et");
        MapperSql sql = new MapperSql();
        sql.UPDATE("your_table");
        List<String> sets = new ArrayList<>();
        if (entity.getGmtCreate() != null) {
            sets.add("gmt_create = #{et.gmtCreate}");
        }
        if (entity.getGmtModified() != null) {
            sets.add("gmt_modified = #{et.gmtModified}");
        } else {
            sets.add("gmt_modified = now()");
        }
        if (entity.getIsDeleted() != null) {
            sets.add("is_deleted = #{et.isDeleted}");
        }
        if (entity.getAge() != null) {
            sets.add("age = #{et.age}");
        }
        if (entity.getEmail() != null) {
            sets.add("email = #{et.email}");
        }
        if (entity.getName() != null) {
            sets.add("name = #{et.name}");
        }
        sql.SET(sets);
        sql.WHERE("id = #{et.id}");
        return sql.toString();
    }
}

Мы видим, что при установке набора он будет определять, является ли объект сущности нулевым; но если @TableField(update = 'обновить значение по умолчанию') установлен для объекта сущности, Если атрибут сущности пуст, вместо него будет использоваться значение по умолчанию, например атрибут gmtModified выше.

if (entity.getGmtModified() != null) {
    sets.add("gmt_modified = #{et.gmtModified}");
} else {
    sets.add("gmt_modified = now()");
}

Часть условия where относительно проста: id = #{et.id}

  • Демонстрационный пример проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;
    
    @Test
    void updateById() {
        int count = yourMapper.updateById(new YourEntity()
            .setId(2L)
            .setName("Powerful Fluent Mybatis")
        );
        System.out.println(count);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: UPDATE your_table SET gmt_modified = now(), name = ? WHERE id = ?  
DEBUG - ==> Parameters: Powerful Fluent Mybatis(String), 2(Long) 
DEBUG - <==    Updates: 1 
1

Мы видим часть набора обновлений, помимо установки name=?, также устанавливаем gmt_modified = now()

updateBy

updateBy, в соответствии с оператором пользовательского набора, условие where выполняет операцию обновления

  • Определение картографа
public interface YourMapper extends IEntityMapper<YourEntity> {
  @UpdateProvider(
      type = YourSqlProvider.class,
      method = "updateBy"
  )
  int updateBy(@Param(Param_EW) IUpdate update);
}

Входной параметр — это объект IUpdate, а выходной параметр — количество успешно обновленных записей.

  • Динамические конструкции SQL
public class YourSqlProvider {
    public String updateBy(Map<String, Object> map) {
        WrapperData data = getWrapperData(map, "ew");
        MapperSql sql = new MapperSql();
        Map<String, String> updates = data.getUpdates();
        assertNotEmpty("updates", updates);
        sql.UPDATE("your_table");
        List<String> sets = new ArrayList<>();
        if (!updates.containsKey("gmtModified")) {
            sets.add("gmt_modified = now()");
        }
        sets.add(data.getUpdateStr());
        sql.SET(sets);
        sql.WHERE_GROUP_ORDER_BY(data);
        sql.LIMIT(data, true);
        return sql.toString();
    }
}

В операторе динамического построения поле @TableField(update = 'обновить значение по умолчанию') (здесь gmtModified) оценивается отдельно, Если gmtModified не включен в условие, добавляется обновление значения по умолчанию.

  • Напишите пример для проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void updateBy() {
        int count = yourMapper.updateBy(new YourUpdate()
            .set.name().is("Powerful Fluent mybatis")
            .set.email().is("darui.wu@163.com")
            .set.age().is(1).end()
            .where.id().eq(2).end()
        );
        System.out.println(count);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: UPDATE your_table SET gmt_modified = now(), name = ?, email = ?, age = ? WHERE id = ?  
DEBUG - ==> Parameters: Powerful Fluent mybatis(String), darui.wu@163.com(String), 1(Integer), 2(Integer) 
DEBUG - <==    Updates: 1 
1

Обратите внимание на раздел gmt_modified = now() для обновления значений по умолчанию.

Метод удаления, предоставляемый FluentMybatis

deleteById

Физически удалять записи на основе идентификатора первичного ключа

  • Просмотрите метод построения оператора SqlProvider, соответствующий deleteById.
public class YourSqlProvider {
    public String deleteById(Serializable id) {
        MapperSql sql = new MapperSql();
        sql.DELETE_FROM("your_table");
        sql.WHERE("id = #{id}");
        return sql.toString();
    }
}
  • SQL-структура deleteById относительно проста, давайте посмотрим непосредственно на тестовый демонстрационный пример.
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void deleteById(){
        int count = yourMapper.deleteById(3L);
        System.out.println("count:" + count);
    }
}
  • Проверьте журнал вывода консоли:
DEBUG - ==>  Preparing: DELETE FROM your_table WHERE id = ?  
DEBUG - ==> Parameters: 3(Long) 
DEBUG - <==    Updates: 1 
count:1

deleteByIds

Пакетное удаление по списку идентификаторов, использование такое же, как и для удаленияById

  • Напишите тест напрямую, чтобы проверить
@Test
void deleteByIds() {
    int count = yourMapper.deleteByIds(Arrays.asList(1L, 2L, 3L));
    System.out.println("count:" + count);
}
  • консольный вывод
DEBUG - ==>  Preparing: DELETE FROM your_table WHERE id IN (?, ?, ?)  
DEBUG - ==> Parameters: 1(Long), 2(Long), 3(Long) 

delete

удалять, удалять записи в соответствии с пользовательскими условиями запроса

  • Определение картографа
public interface YourMapper extends IEntityMapper<YourEntity> {
    @DeleteProvider(
        type = YourSqlProvider.class,
        method = "delete"
    )
    int delete(@Param(Param_EW) IQuery wrapper);
}

Входным параметром является объект IQuery, а выходным параметром — количество удаленных записей.

  • Пример проверки
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void delete() {
        int count = yourMapper.delete(new YourQuery()
            .where.id().in(new int[]{1, 2, 3}).end()
        );
        System.out.println("count:" + count);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: DELETE FROM your_table WHERE id IN (?, ?, ?)  
DEBUG - ==> Parameters: 1(Integer), 2(Integer), 3(Integer) 
DEBUG - <==    Updates: 3 
count:3

deleteByMap

deleteByMap: Обновить записи в соответствии с условием ключ=значение, установленным на карте.

  • Определение картографа
public interface YourMapper extends IEntityMapper<YourEntity> {
    @DeleteProvider(
        type = YourSqlProvider.class,
        method = "deleteByMap"
    )
    int deleteByMap(@Param(Param_CM) Map<String, Object> cm);
}
  • тестовый демонстрационный пример
@SpringBootTest(classes = QuickStartApplication.class)
public class FluentMybatisApplicationTest {
    @Autowired
    private YourMapper yourMapper;

    @Test
    void deleteByMap() {
        int count = yourMapper.deleteByMap(new HashMap<String, Object>() {
            {
                this.put("name", "Fluent Mybatis");
                this.put("email", "darui.wu@163.com");
            }
        });
        System.out.println("count:" + count);
    }
}
  • Просмотр вывода консоли
DEBUG - ==>  Preparing: DELETE FROM your_table WHERE name = ? AND email = ?  
DEBUG - ==> Parameters: Fluent Mybatis(String), darui.wu@163.com(String) 
DEBUG - <==    Updates: 2 
count:2

Суммировать

После того, как в этой статье будет представлен встроенный метод Mapper, предоставляемый FluentMuybatis, мы познакомимся с тем, как определять мощные динамические операторы SQL с помощью IQuery и IUpdate. В статье упоминается, что пример примера проверки можно найти вНайдено в документации FluentMybatis gitee

Свободно вводная серия Mybatis

Свободная документация и примеры Mybatis

Свободный исходный код Mybatis, github