Быстрая обработка mybatis может сэкономить много времени на ручном кодировании в простом CRUD, но даже сложные запросы легко обрабатываются без каких-либо проблем. В этой статье мы продемонстрируем следующие возможности:
- В подзапросе
column IN (select column from ... )
- СУЩЕСТВУЕТ подзапрос
EXISTS (select 1 from .... )
- запрос JOIN (включая INNER JOINm, LEFT JOIN, RIGHT JOIN)
select ... from table1 a join table2 b on a.xxx = b.xxx where ...;
select ... from table1 a left join table2 b on a.xxx = b.xxx where ...;
select ... from table1 a right join table2 b on a.xxx = b.xxx where ...;
Не только поддерживает связанный запрос двух таблиц, но также поддерживает любую таблицу JOIN.
- ПРИСОЕДИНЯЙТЕСЬ, И, ИЛИ большую рукопашную
настройки сцены
Чтобы облегчить объяснение этих сложных функций запросов беглого mybatis, мы создаем 3 таблицы: информационная таблица студента, административная область и стенограмма студента.
CREATE TABLE student
(
id bigint(21) unsigned auto_increment primary key COMMENT '主键id',
age int DEFAULT NULL COMMENT '年龄',
grade int DEFAULT NULL COMMENT '年级',
user_name varchar(45) DEFAULT NULL COMMENT '名字',
gender_man tinyint(2) DEFAULT 0 COMMENT '性别, 0:女; 1:男',
birthday datetime DEFAULT NULL COMMENT '生日',
phone varchar(20) DEFAULT NULL COMMENT '电话',
bonus_points bigint(21) DEFAULT 0 COMMENT '积分',
status varchar(32) DEFAULT NULL COMMENT '状态(字典)',
home_county_id bigint(21) DEFAULT NULL COMMENT '家庭所在区县',
address varchar(200) DEFAULT NULL COMMENT '家庭详细住址',
gmt_created datetime DEFAULT NULL COMMENT '创建时间',
gmt_modified datetime DEFAULT NULL COMMENT '更新时间',
is_deleted tinyint(2) DEFAULT 0 COMMENT '是否逻辑删除'
) ENGINE = InnoDB CHARACTER SET = utf8 COMMENT = '学生信息表';
CREATE TABLE county_division
(
id bigint(21) unsigned auto_increment primary key COMMENT '主键id',
province varchar(50) DEFAULT NULL COMMENT '省份',
city varchar(50) DEFAULT NULL COMMENT '城市',
county varchar(50) DEFAULT NULL COMMENT '区县',
gmt_created datetime DEFAULT NULL COMMENT '创建时间',
gmt_modified datetime DEFAULT NULL COMMENT '更新时间',
is_deleted tinyint(2) DEFAULT 0 COMMENT '是否逻辑删除'
) ENGINE = InnoDB CHARACTER SET = utf8 COMMENT = '区县';
create table `student_score`
(
id bigint auto_increment primary key COMMENT '主键ID',
student_id bigint NOT NULL COMMENT '学号',
school_term int NULL COMMENT '学期',
subject varchar(30) NULL COMMENT '学科',
score int NULL COMMENT '成绩',
gmt_create datetime NOT NULL COMMENT '记录创建时间',
gmt_modified datetime NOT NULL COMMENT '记录最后修改时间',
is_deleted tinyint(2) default 0 NOT NULL COMMENT '逻辑删除标识'
) engine = InnoDB default charset = utf8 COMMENT = '学生成绩';
Демонстрация присоединения в статье основана на свободном использовании mybatis версии 1.8.7.
<dependencies>
<!-- fluent mybatis依赖-->
<dependency>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis-processor</artifactId>
<version>1.8.7</version>
<scope>provided</scope>
</dependency>
</dependencies>
В подзапросе
- сценарий спроса
Найти все студенты 4 класса в Ханчжоу, провинция Чжэцзян
- Сценарий SQL
selct * from student
where grade = 4
and is_deleted = 0
and home_county_id in
(select id from county_division
where is_deleted = 0
and province = '浙江省'
and city = '杭州市')
- Реализация FluentMybatis
@RunWith(SpringRunner.class)
@SpringBootTest(classes = QuickStartApplication.class)
public class InSelectDemo {
@Autowired
private StudentMapper mapper;
@Test
public void test_in_select() {
StudentQuery query = new StudentQuery()
.where.isDeleted().isFalse()
.and.grade().eq(4)
.and.homeCountyId().in(new CountyDivisionQuery()
.selectId()
.where.isDeleted().isFalse()
.and.province().eq("浙江省")
.and.city().eq("杭州市")
.end()
).end();
List<StudentEntity> students = mapper.listEntity(query);
}
}
- Проверьте вывод журнала консоли
DEBUG - ==> Preparing: SELECT id, gmt_modified, is_deleted, address, age, birthday, bonus_points, gender_man, gmt_created, grade, home_county_id, phone, status, user_name
FROM student WHERE is_deleted = ? AND grade = ?
AND home_county_id IN (SELECT id FROM county_division
WHERE is_deleted = ? AND province = ? AND city = ?)
DEBUG - ==> Parameters: false(Boolean), 4(Integer), false(Boolean), 浙江省(String), 杭州市(String)
DEBUG - <== Total: 0
СУЩЕСТВУЕТ подзапрос
- сценарий спроса
Запросите список студентов, которые не сдали экзамены по китайскому языку или математике в семестре 2019 года.
- Реализация SQL
select * from student
where is_deleted = 0
and exists (select 1 from student_score
where is_deleted = 0
and score < 60
and school_term = 2019
and subject in ('语文', '数学')
and student_id = student.id
)
- свободная реализация mybatis
@SpringBootTest(classes = QuickStartApplication.class)
public class InSelectDemo {
@Autowired
private StudentMapper mapper;
@Test
public void test_exists() {
StudentQuery query = new StudentQuery()
.where.isDeleted().isFalse()
.and.exists(new StudentScoreQuery()
.selectId()
.where.isDeleted().isFalse()
.and.schoolTerm().eq(2019)
.and.score().lt(60)
.and.subject().in(new String[]{"语文", "数学"})
.and.studentId().apply("= student.id")
.end()
).end();
List<StudentEntity> students = mapper.listEntity(query);
}
}
- Проверьте вывод журнала консоли
DEBUG - ==> Preparing: SELECT id, gmt_modified, is_deleted, address, age, birthday, bonus_points, gender_man, gmt_created, grade, home_county_id, phone, status, user_name FROM student
WHERE is_deleted = ?
AND EXISTS (SELECT id FROM student_score
WHERE is_deleted = ?
AND school_term = ?
AND score < ?
AND subject IN (?, ?)
AND student_id =student.id
)
DEBUG - ==> Parameters: false(Boolean), false(Boolean), 2019(Integer), 60(Integer), 语文(String), 数学(String)
DEBUG - <== Total: 0
ВНУТРЕННЕЕ СОЕДИНЕНИЕ запрос
- Требования к сценарию
Семья оказалась студентом мужского пола из города Ханчжоу, провинция Чжэцзян. Имя, возраст и район/округ, где он живет.
- Реализация SQL
select a.user_name, a.age, a.gender_man, b.province, b.city, b.county
from student a join county_division b
on a.home_county_id = b.id
where a.is_deleted = 0
and a.gender_man = 1
and b.is_deleted = 0
and b.province = '浙江省'
and b.city = '杭州市'
- Свободный синтаксис соединения Mybatis
Основной синтаксис запроса на соединение выглядит следующим образом:
Parameters parameters = new Parameters();
IQuery query = JoinBuilder
.from(new 左表Query("别名").where(设置左表查询条件).end())
.join(new 右表1Query("别名").where(设置右表1查询条件).end())
.on(l->{左表on字段}, r->{右表1on字段})
.join(new 右表2Query("别名").where(设置右表2查询条件).end())
.on(l->{左表on字段}, r->{右表2on字段})
.builder();
- свободная реализация mybatis
public class JoinSelectDemo {
@Autowired
private StudentMapper mapper;
@Test
public void test_join_student_county() {
IQuery query = JoinBuilder
.<StudentQuery>from(new StudentQuery("t1")
.select.userName().age().genderMan().end()
.where.isDeleted().isFalse()
.and.genderMan().eq(1).end())
.join(new CountyDivisionQuery("t2")
.select.province().city().county().end()
.where.isDeleted().isFalse()
.and.province().eq("浙江省")
.and.city().eq("杭州市").end())
.on(l -> l.where.homeCountyId(), r -> r.where.id()).endJoin()
.build();
mapper.listMaps(query);
}
}
- Проверьте вывод журнала консоли
DEBUG - ==> Preparing: SELECT t1.user_name, t1.age, t1.gender_man, t2.province, t2.city, t2.county
FROM student t1
JOIN county_division t2
ON t1.home_county_id = t2.id
WHERE t1.is_deleted = ?
AND t1.gender_man = ?
AND t2.is_deleted = ?
AND t2.province = ?
AND t2.city = ?
DEBUG - ==> Parameters: false(Boolean), 1(Integer), false(Boolean), 浙江省(String), 杭州市(String)
DEBUG - <== Total: 0
Мы видим, что fluent mybatis автоматически собирает запрос соединения в соответствии с настройками, устанавливает условие on и устанавливает псевдоним для таблицы запросов, а также устанавливает условие в соответствии с псевдонимом.
LEFT JOIN & RIGHT JOIN запрос
Запрос LEFT JOIN & RIGHT JOIN аналогичен запросу JOIN, просто поместите
JoinBuilder
.from(new StudentQuery("t1").where("条件设置").end())
.join(new CountyDivisionQuery("t2").where("条件设置").end())
.on(l->l.where.左表字段(), r->r.where.右表字段()).endJoin()
заменить на соответствующий
JoinBuilder
.from(new StudentQuery("t1").where("条件设置").end())
.leftJoin(new CountyDivisionQuery("t2").where("条件设置").end())
.on(l->l.where.左表字段(), r->r.where.右表字段()).endJoin()
или
JoinBuilder
.from(new StudentQuery("t1").where("条件设置").end())
.rightJoin(new CountyDivisionQuery("t2").where("条件设置").end())
.on(l->l.where.左表字段(), r->r.where.右表字段()).endJoin()
JOIN-запрос из 3 таблиц
В приведенном выше примере показана связанная операция запроса между двумя таблицами.Что делать, если с запросом связано более двух таблиц? Связанный запрос нескольких таблиц также довольно прост для беглого mybatis, просто установите еще одну операцию соединения.
В реальном бизнесе старайтесь избегать операций сопоставления нескольких таблиц.
- сценарий спроса
Актуальный запрос для получения информации о студентах с баллом 90 и выше по китайскому языку или математике в Ханчжоу, провинция Чжэцзян, в семестре 2019 года.
- Реализация SQL
select a.user_name, c.subject, c.score
from student a
join county_division b on a.home_county_id = b.id
join student_score c on a.id = c.student_id
where a.is_deleted = 0
and b.is_deleted = 0
and b.province = '浙江省'
and b.city = '杭州市'
and c.is_deleted = 0
and c.school_term = 2019
and c.subject in ('语文', '数学')
and c.score >=90
- свободная реализация mybatis
@RunWith(SpringRunner.class)
@SpringBootTest(classes = QuickStartApplication.class)
public class JoinSelectDemo {
@Autowired
private StudentMapper mapper;
@Test
public void test_3_table_join() {
IQuery query = JoinBuilder
.from(new StudentQuery("t1")
.select.userName().end()
.where.isDeleted().isFalse().end())
.join(new CountyDivisionQuery("t2")
.where.isDeleted().isFalse()
.and.province().eq("浙江省")
.and.city().eq("杭州市").end())
.on(l -> l.where.homeCountyId(), r -> r.where.id()).endJoin()
.join(new StudentScoreQuery("t3")
.select.subject().score().end()
.where.isDeleted().isFalse()
.and.schoolTerm().eq(2019)
.and.subject().in(new String[]{"语文", "数学"})
.and.score().ge(90).end())
.on(l -> l.where.id(), r -> r.where.studentId()).endJoin()
.build();
mapper.listMaps(query);
}
}
- Проверить журнал вывода консоли
DEBUG - ==> Preparing: SELECT t1.user_name, t3.subject, t3.score
FROM student t1
JOIN county_division t2 ON t1.home_county_id = t2.id
JOIN student_score t3 ON t1.id = t3.student_id
WHERE t1.is_deleted = ?
AND t2.is_deleted = ? AND t2.province = ? AND t2.city = ?
AND t3.is_deleted = ? AND t3.school_term = ? AND t3.subject IN (?, ?) AND t3.score >= ?
DEBUG - ==> Parameters: false(Boolean), false(Boolean), 浙江省(String), 杭州市(String), false(Boolean), 2019(Integer), 语文(String), 数学(String), 90(Integer)
DEBUG - <== Total: 0
Мы видим, что fluent mybatis устанавливает 2 операции соединения и настройки условий, а также устанавливает псевдонимы для каждой таблицы соединения. Условия where трех таблиц также устанавливаются в соответствии с псевдонимами.
ПРИСОЕДИНЯЙТЕСЬ, И, ИЛИ большую рукопашную
Fluent mybatis поддерживает запросы AND, IN (подзапрос), EXISTS (подзапрос), JOIN. В то же время вы также можете использовать И (множественные условия ИЛИ) и ИЛИ (несколько условий И), чтобы комбинировать сложные условия по мере необходимости. Например, для вышеуказанного языка или математики мы заменяем операцию IN на условие OR для простой демонстрации.
- И (Условие 1 ИЛИ Условие 2) свободная реализация mybatis
@RunWith(SpringRunner.class)
@SpringBootTest(classes = QuickStartApplication.class)
public class AndOrDemo {
@Autowired
private StudentMapper mapper;
@Test
public void test_and_or() {
IQuery query = JoinBuilder
.from(new StudentQuery("t1")
.select.userName().end()
.where.isDeleted().isFalse().end())
.join(new CountyDivisionQuery("t2")
.where.isDeleted().isFalse()
.and.province().eq("浙江省")
.and.city().eq("杭州市").end())
.on(l -> l.where.homeCountyId(), r -> r.where.id()).endJoin()
.join(new StudentScoreQuery("t3")
.select.subject().score().end()
.where.isDeleted().isFalse()
.and.schoolTerm().eq(2019)
.and(iq -> iq
.where.subject().eq("语文")
.or.subject().eq("数学").end())
.and.score().ge(90).end())
.on(l -> l.where.id(), r -> r.where.studentId()).endJoin()
.build();
mapper.listMaps(query);
}
}
- Проверьте вывод журнала консоли
DEBUG - ==> Preparing: SELECT t1.user_name, t3.subject, t3.score
FROM student t1
JOIN county_division t2 ON t1.home_county_id = t2.id
JOIN student_score t3 ON t1.id = t3.student_id
WHERE t1.is_deleted = ?
AND t2.is_deleted = ? AND t2.province = ? AND t2.city = ?
AND t3.is_deleted = ? AND t3.school_term = ?
AND ( subject = ? OR subject = ? )
AND t3.score >= ?
DEBUG - ==> Parameters: false(Boolean), false(Boolean), 浙江省(String), 杭州市(String), false(Boolean), 2019(Integer), 语文(String), 数学(String), 90(Integer)
Мы заметили, что вывод оператора в журнале содержитAND ( subject = ? OR subject = ? )
Суммировать
Для сложных запросов Fluent mybatis также обеспечивает нулевое кодирование xml и mapper, отсутствие кодирования волшебных строк и плавную работу в стиле API.Вы думаете, Fluent mybatis является артефактом Java-формы? Если вы считаете, что беглый mybatis — это неплохо, помогите поставить лайк и переслать статью.
Сравнение функций Fluent Mybatis, родного Mybatis и Mybatis Plus