введение
Наиболее часто используемыми фреймворками 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
- Установить зависимости проекта
- весенняя загрузка: на основе весенней загрузки, это определенно необходимо
- lombok: артефакт, который пропускает коды get, set, toString, лично мне он нравится; вы также можете сгенерировать методы get set вручную
- mysql-connector-java: драйвер базы данных
- fluent-mybatis: зависимость времени выполнения fluent-mybatis
- fluent-mybatis-processor: генерация кода fluent-mybatis и зависимости времени компиляции
- Тестовые зависимые пакеты 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
конкретная конфигурация свойств
- Создать класс сущности
Классы сущностей можно создавать вручную или создавать классы сущностей любым способом, а затем аннотировать.
- Добавьте аннотацию @FluentMybatis в класс Entity.
- Аннотируйте поле первичного ключа с помощью @TableId
- Добавьте аннотацию @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 специальных поля
- gmt_create, время создания записи, установит значение по умолчанию для вставки записи, соответствующее аннотации в сгенерированном поле Entity @TableField(insert="now()")
- gmt_modified, время последнего обновления записи, установит значение по умолчанию для вставки и обновления записи, соответствующее аннотации в поле Entity сгенерированного кода @TableField(insert="now()", update="now() ")
- 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 {
// 在这里添加你自己的业务逻辑代码
}
После Rebuild в целевом каталоге будет еще несколько файлов.Обновите проект и добавьте target/generated-sources в исходный каталог.
Эти файлы генерируются в target/generated-sources, и на них можно напрямую ссылаться и упаковывать в коде. Их не нужно копировать в каталог src, и их не нужно поддерживать. перекомпилирован и упакован.
- Запустите тест 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 частях.
- Mapper определение метода (Скомпилируйте сгенерированный код)
- Соответствующая динамическая сборка SQL Mapper SQLProvider (Скомпилируйте сгенерированный код)
- Пример проверочного теста
- В соответствии с оператором 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)
- Вот несколько замечаний
- Автоинкремент и обратная запись значения первичного ключа Entity
В соответствии с выводом консоли вы можете видеть, что атрибут id объекта был записан обратно в соответствии с автоматически увеличивающимся значением первичного ключа базы данных. Настройка автоматического увеличения первичного ключа осуществляется с помощью аннотации @TableId, а значением по умолчанию его метода свойства auto() является true. 2. Аннотация @Options для класса Mapper, сгенерированная Fluent mybatis на основе аннотации @TableId, выглядит следующим образом:
@Options(
useGeneratedKeys = true,
keyProperty = "id",
keyColumn = "id"
)
- 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 относительно просто
- Список полей запроса склеен в соответствии с полем Entity
- установить идентификатор = # {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();
}
}
- Список полей запроса склеен в соответствии с полем Entity
- В соответствии с количеством переданных идентификаторов (размер), установите идентификатор 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 делает несколько вещей:
- В зависимости от того, задано ли поле запроса явно в запросе, установите список полей выбора.Если он не задан, возьмите сборку по умолчанию для всех полей Entity.
- Установите условия запроса в зависимости от того, где, сгруппировать, иметь и упорядочить в запросе: sql.WHERE_GROUP_ORDER_BY(данные)
- В зависимости от того, установлены ли информация о подкачке и тип базы данных, соберите синтаксис запроса на подкачку: 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();
}
}
- Запросить все поля Entity
- Соберите условие карты, (ключ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 делает следующее:
- В зависимости от того, задано ли поле запроса явно в запросе, установите список полей выбора.Если он не задан, возьмите сборку по умолчанию для всех полей Entity.
- Установите условия запроса в зависимости от того, где, сгруппировать, иметь и упорядочить в запросе: sql.WHERE_GROUP_ORDER_BY(данные)
- В зависимости от того, установлены ли информация о подкачке и тип базы данных, соберите синтаксис запроса на подкачку: 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)]
Пользовательский запрос определяет
- Поля для запроса: имя, возраст, электронная почта3 поля
- Определены конкретные условия: id
- Определяется в обратном порядке по идентификатору
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