MyBatis-plus

MyBatis-Plus

MyBatis-Plus作为一个强大的ORM(对象关系映射)框架,为Java开发人员提供了在数据库操作中更高效的工具和方法。

数据库查询在许多应用程序中起着至关重要的作用,因此优化查询效率对于提高应用程序性能至关重要。MyBatis-Plus的Wrapper提供了一种强大的工具,可以帮助我们以更直观、更灵活的方式构建复杂的SQL查询,而无需编写繁琐的SQL语句。

MyBatis-Plus相比MyBatis的优势

MyBatis-Plus(简称MP)是MyBatis的增强工具,它在MyBatis的基础上进行了扩展,提供了更多的便利功能,以简化开发工作和提高开发效率。以下是MyBatis-Plus相比MyBatis的一些主要优势:

  1. 简化开发:MyBatis-Plus提供了内置的CRUD操作,开发者无需编写大量的SQL映射文件,可以快速实现单表的大部分CRUD操作。
  2. 性能优化:MyBatis-Plus对性能进行了优化,支持批量插入、查询缓存等特性,提高了应用的性能和效率。
  3. 易于扩展:MyBatis-Plus的设计使其易于扩展和定制化,开发者可以根据自己的需求添加新的功能或插件。
  4. 代码生成器:MyBatis-Plus内置了代码生成器,可以快速生成Mapper、Model、Service、Controller层代码,减少了开发者的开发量。
  5. 分页插件:MyBatis-Plus提供了分页插件,开发者无需关心具体操作,配置好插件之后,写分页等同于普通List查询。
  6. Lambda表达式支持:Lambda 表达式的优势在于它提供了一种类型安全的方式来编写查询条件,使得代码更加简洁和易于维护。它也减少了因为字段名错误而导致的运行时错误。此外,Lambda 表达式支持链式调用。
  7. 全局方法注入:支持全局通用方法注入,可以减少重复的代码编写。
  8. 关键词自动转义:支持数据库关键词自动转义,还可自定义关键词。
  9. 全局拦截插件:提供全表delete、update操作智能分析阻断,也可自定义拦截规则,预防误操作。

LambdaQueryWrapper

在MyBatis-Plus中,Lambda表达式的重要性体现在构建查询条件时。它们提供了一种更加类型安全和直观的方式来构建数据库查询条件,而不需要硬编码SQL语句。通过使用Lambda表达式,你可以创建查询条件的对象,而不是手动编写字符串,这有助于减少SQL注入的风险,提高了代码的可维护性。

下面是一个示例,演示如何使用Lambda表达式来表示查询条件:

假设你有一个实体类User,它代表了数据库中的用户表,包含idnameage字段。你想要查询年龄大于等于30岁的用户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
public class LambdaExpressionExample {
public static void main(String[] args) {
// 使用Lambda表达式创建查询条件
QueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
.ge(User::getAge, 30);

// 执行查询
List<User> userList = userDao.selectList(queryWrapper);

// 输出查询结果
for (User user : userList) {
System.out.println(user);
}
}
}

在这个示例中,我们使用了Wrappers.lambdaQuery()来创建一个Lambda查询包装器,然后使用.ge(User::getAge, 30)来表示年龄大于等于30岁的条件。这种方式更加直观和类型安全,不需要编写原始的SQL语句,提高了代码的可读性和可维护性。

总之,Lambda表达式在MyBatis-Plus中的重要性在于它们提供了一种更加直观和类型安全的方式来构建数据库查询条件,从而简化了代码并降低了错误的风险。

QueryWrapper与LambdaQueryWrapper区别

QueryWrapperLambdaQueryWrapper都是MyBatis-Plus中用于构建查询条件的工具,但它们之间存在一些重要的区别:

构建方式:

  • QueryWrapper:使用字符串表示列名,通过字符串拼接的方式构建查询条件,类似于传统的SQL查询。这种方式灵活但不够类型安全。
  • LambdaQueryWrapper:使用Lambda表达式表示列名,通过Lambda表达式的方式构建查询条件。这种方式更加类型安全,可以在编译时捕获拼写错误。

类型安全:

  • QueryWrapper:由于使用字符串表示列名,编译器无法检查列名的正确性,因此存在拼写错误或不合法列名的风险。
  • LambdaQueryWrapper:使用Lambda表达式,可以在编译时捕获属性和字段名的拼写错误,提高了类型安全性。

可读性:

  • QueryWrapper:由于使用字符串,查询条件的构建可能不够清晰和直观,可能需要更多的注释来解释查询条件的含义。
  • LambdaQueryWrapper:Lambda表达式更加直观和清晰,使代码更易于理解,通常不需要额外的注释。

智能提示:

  • QueryWrapper:不同于一些集成开发环境(IDE)提供的智能提示,因为列名是字符串,难以提供准确的自动完成和错误检查。
  • LambdaQueryWrapper:常见的IDE通常能够提供Lambda表达式的智能提示,帮助您更快地编写查询条件。

链式操作:

  • QueryWrapperLambdaQueryWrapper都支持链式操作,使得构建复杂的查询条件变得更加清晰。

总的来说,**LambdaQueryWrapper相对于QueryWrapper更加类型安全、清晰易读,因此在实际开发中,特别是需要在编译时捕获错误和提高代码可维护性的情况下,更常用。**但如果您对查询条件的灵活性有更高的要求,QueryWrapper仍然是一个有效的选择,因为它允许您以字符串的形式构建复杂的查询条件。

LambdaQueryWrapper的高级用法

LambdaQueryWrapper是MyBatis-Plus中用于构建复杂查询条件的强大工具。它允许你使用Lambda表达式来创建查询条件,包括条件构建和多表关联查询。下面将深入讨论LambdaQueryWrapper的高级用法,并演示如何使用Lambda表达式生成查询条件。

1. 基本条件构建:

首先,让我们看看如何使用LambdaQueryWrapper构建基本查询条件。假设我们有一个名为User的实体类,并且我们想要查询年龄大于30岁且名字包含”John”的用户:

1
2
3
4
LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
.ge(User::getAge, 30)
.like(User::getName, "John");
List<User> userList = userDao.selectList(queryWrapper);

在这个示例中,我们使用.ge(User::getAge, 30)表示大于等于30岁的条件,使用.like(User::getName, "John")表示名字包含”John”的条件。

2. 多表关联查询:

LambdaQueryWrapper还支持多表关联查询。假设我们有一个名为Order的实体类,表示用户的订单,其中包含了用户的userId字段,我们想要查询年龄大于30岁的用户以及他们的订单信息:

1
2
3
4
5
LambdaQueryWrapper<User> userWrapper = Wrappers.<User>lambdaQuery()
.ge(User::getAge, 30);
LambdaQueryWrapper<Order> orderWrapper = Wrappers.<Order>lambdaQuery()
.inSql(Order::getUserId, "SELECT id FROM user", userWrapper);
List<Order> orderList = orderDao.selectList(orderWrapper);

在这个示例中,我们首先创建了一个用于用户表的LambdaQueryWrapper,然后创建了一个用于订单表的LambdaQueryWrapper。在订单表的条件中,我们使用了.inSql()方法,允许我们在子查询中使用另一个LambdaQueryWrapper来构建条件,从而实现多表关联查询。

3. 动态条件构建:

LambdaQueryWrapper也支持动态条件构建,你可以根据实际情况添加或删除条件。例如,如果你有一个搜索页面,用户可以选择性地输入查询条件,你可以像这样动态构建查询条件:

1
2
3
4
5
6
7
8
9
10
11
LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery();
if (StringUtils.isNotBlank(username)) {
queryWrapper.like(User::getUsername, username);
}
if (minAge != null) {
queryWrapper.ge(User::getAge, minAge);
}
if (maxAge != null) {
queryWrapper.le(User::getAge, maxAge);
}
List<User> userList = userDao.selectList(queryWrapper);

在这个示例中,根据用户输入的条件,我们动态地添加了.like().ge().le()等条件,从而构建了查询条件。

总之,LambdaQueryWrapper是一个强大的工具,允许你使用Lambda表达式来构建复杂的查询条件,包括基本条件构建、多表关联查询和动态条件构建。这种方式使得查询条件的构建更加直观和灵活,提高了代码的可读性和可维护性。

4.mysql函数嵌入

假设你有一个实体类User,其中包含了一个日期字段birthDate,你想要查询生日在特定月份的用户,并将生日格式化为”yyyy-MM-dd”格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import java.time.format.DateTimeFormatter;
public class LambdaQueryWrapperWithMySQLFunction {
public static void main(String[] args) {
// 选择要查询的月份,这里假设选择1月
int selectedMonth = 1;
LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
.apply("MONTH(birth_date) = {0}", selectedMonth)
.select(User::getId, User::getName, User::getBirthDate);
List<User> userList = userDao.selectList(queryWrapper);

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
for (User user : userList) {
String formattedBirthDate = user.getBirthDate().format(formatter);
System.out.println("User ID: " + user.getId() + ", Name: " + user.getName() + ", Formatted Birth Date: " + formattedBirthDate);
}
}
}

在这个示例中,我们使用.apply()方法来嵌入MySQL的MONTH()函数,以检查生日的月份是否与selectedMonth匹配。同时,我们使用.select()方法选择要查询的字段,然后在结果中格式化日期字段为”yyyy-MM-dd”格式。

这样,你就可以在LambdaQueryWrapper中使用MySQL的函数来构建查询条件,满足不同的查询需求。根据需要,你可以嵌入其他MySQL函数来执行各种数据库操作。

MyBatis-Plus会有sql注入风险吗

MyBatis-Plus 在设计时已经考虑到了 SQL 注入的风险,并且采取了一些措施来减轻这种风险。使用 QueryWrapperLambdaQueryWrapper 时,MyBatis-Plus 会进行参数绑定,这有助于防止 SQL 注入攻击。

参数绑定

当使用 QueryWrapperLambdaQueryWrapper 构建查询条件时,所有的参数值都会被当作参数绑定到 SQL 语句中,而不是直接拼接到 SQL 字符串中。这意味着参数值会被数据库驱动处理,从而避免了 SQL 注入的风险。

例如,使用 eqlikege 等方法时,传入的参数值会被自动处理为参数绑定:

java

1
queryWrapper.eq("name", "John Doe");

在这个例子中,"John Doe" 会被当作参数绑定,而不是直接拼接到 SQL 语句中。

动态 SQL

在构建动态 SQL 时,如果使用 apply 方法,需要特别注意 SQL 注入的风险。因为 apply 方法允许你直接写入 SQL 片段,如果不正确地使用,可能会导致 SQL 注入:

java

1
queryWrapper.apply("name = '{0}'", "John Doe");

在这个例子中,如果不正确地使用 apply 方法,可能会导致 SQL 注入。因此,在使用 apply 方法时,应该确保传入的参数值是受控的,并且不包含恶意的 SQL 代码。

最佳实践

为了确保安全,建议遵循以下最佳实践:

  1. 避免直接使用 apply 方法:尽量避免使用 apply 方法直接拼接 SQL 片段,除非完全必要,并且你完全理解可能带来的风险。
  2. 使用参数绑定:尽量使用 QueryWrapperLambdaQueryWrapper 提供的条件构造方法,如 eqlikege 等,这些方法会自动处理参数绑定。
  3. 验证和清理输入:在将用户输入用于查询之前,进行验证和清理,确保输入符合预期的格式。
  4. 使用 ORM 的安全特性:充分利用 MyBatis-Plus 提供的安全特性,如自动参数绑定和条件构造器。

MyBatis-plus
http://example.com/2024/01/09/Spring+MyBatis/MyBatis-plus/
作者
PALE13
发布于
2024年1月9日
许可协议