MyBatis-Plus 自定义 SQL 和复杂查询详解
MyBatis-Plus 是 MyBatis 的增强版,提供了许多开箱即用的 CRUD 操作。然而,在实际项目中,开发者常常需要编写自定义 SQL 以处理更复杂的查询需求。MyBatis-Plus 提供了灵活的机制,允许开发者通过注解或 XML 自定义 SQL,同时也能支持复杂查询、动态 SQL 等高级操作。
1. 自定义 SQL 的两种方式
MyBatis-Plus 支持两种自定义 SQL 的方式:
- 注解方式 :直接在
Mapper
接口上通过注解编写 SQL 语句。 - XML 方式 :通过
Mapper
配置文件的方式编写自定义 SQL。
2. 通过注解编写自定义 SQL
MyBatis-Plus 支持在 Mapper
接口方法上直接使用注解编写 SQL 语句。常见的注解包括:
@Select
:用于查询。@Insert
:用于插入。@Update
:用于更新。@Delete
:用于删除。
2.1 查询示例
假设有一个 User
表,包含 id
、username
和 email
字段。通过注解编写自定义 SQL 查询用户信息:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 根据用户名查询用户
@Select("SELECT * FROM user WHERE username = #{username}")
User findByUsername(String username);
// 查询所有用户
@Select("SELECT * FROM user")
List<User> findAll();
}
2.2 插入示例
通过注解实现插入用户记录:
import org.apache.ibatis.annotations.Insert;
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Insert("INSERT INTO user (username, email) VALUES (#{username}, #{email})")
void insertUser(User user);
}
2.3 动态 SQL
MyBatis-Plus 还支持通过 @SelectProvider
、@UpdateProvider
等注解来实现动态 SQL。以下是通过 @SelectProvider
动态生成查询 SQL 的示例:
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.builder.annotation.ProviderContext;
import java.util.Map;
@Mapper
public interface UserMapper extends BaseMapper<User> {
@SelectProvider(type = SqlProvider.class, method = "findByCondition")
List<User> findByCondition(Map<String, Object> conditions);
class SqlProvider {
public String findByCondition(Map<String, Object> params, ProviderContext context) {
StringBuilder sql = new StringBuilder("SELECT * FROM user WHERE 1=1");
if (params.get("username") != null) {
sql.append(" AND username = #{username}");
}
if (params.get("email") != null) {
sql.append(" AND email = #{email}");
}
return sql.toString();
}
}
}
在此示例中,通过 @SelectProvider
动态生成 SQL,根据传入的条件查询用户。
3. 通过 XML 编写自定义 SQL
除了注解方式,MyBatis-Plus 还支持通过 XML 文件编写自定义 SQL。XML 配置的方式可以编写更复杂、灵活的查询和动态 SQL。
3.1 XML 配置基本结构
首先,在 resources/mapper/
目录下创建 UserMapper.xml
,并通过 namespace
绑定 UserMapper
接口。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<!-- 查询所有用户 -->
<select id="findAll" resultType="com.example.demo.model.User">
SELECT * FROM user
</select>
<!-- 根据用户名查询用户 -->
<select id="findByUsername" resultType="com.example.demo.model.User">
SELECT * FROM user WHERE username = #{username}
</select>
<!-- 插入用户 -->
<insert id="insertUser">
INSERT INTO user (username, email) VALUES (#{username}, #{email})
</insert>
</mapper>
3.2 XML 动态 SQL 示例
MyBatis 的动态 SQL 标签可以用于构建灵活的 SQL 语句,常见的动态 SQL 标签有:
<if>
:根据条件拼接 SQL。<choose>
:类似于switch-case
。<where>
:智能拼接条件。<foreach>
:用于处理集合(如IN
查询)。
以下示例展示如何使用动态 SQL 实现根据条件查询用户:
<select id="findByCondition" resultType="com.example.demo.model.User">
SELECT * FROM user
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>
4. 复杂查询的实现
在实际开发中,复杂查询经常涉及多表关联查询、分页、动态条件查询等。MyBatis-Plus 提供了良好的支持,结合 SQL 注解、XML 和查询构造器等机制,可以实现灵活的复杂查询。
4.1 多表关联查询
MyBatis-Plus 支持通过自定义 SQL 实现多表关联查询(如 JOIN
查询)。
<select id="findUserWithRole" resultType="com.example.demo.model.User">
SELECT u.id, u.username, r.role_name
FROM user u
LEFT JOIN role r ON u.role_id = r.id
WHERE u.id = #{id}
</select>
在此示例中,user
表通过 role_id
关联 role
表,查询用户的角色信息。
4.2 动态分页查询
结合 MyBatis-Plus 提供的分页插件和动态 SQL,可以实现复杂的分页查询。首先,需要引入分页插件:
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyBatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
然后在 UserMapper.xml
中实现分页查询:
<select id="findByCondition" resultType="com.example.demo.model.User">
SELECT * FROM user
<where>
<if test="username != null">
AND username = #{username}
</if>
<if test="email != null">
AND email = #{email}
</if>
</where>
</select>
在服务层调用时使用分页功能:
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Page<User> findUsersByCondition(Page<User> page, Map<String, Object> conditions) {
return userMapper.findByCondition(page, conditions);
}
}
5. 使用查询构造器进行复杂查询
MyBatis-Plus 提供了一个查询构造器 Wrapper
,用于简化条件查询。常见的查询构造器有:
QueryWrapper
:用于构建查询条件。UpdateWrapper
:用于构建更新条件。
5.1 使用 QueryWrapper
进行复杂查询
QueryWrapper
是 MyBatis-Plus 提供的条件构造器,允许开发者使用链式语法构建查询条件。
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.mapper.UserMapper;
import com.example.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public List<User> findUsersByCondition(String username, String email) {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq(username != null, "username", username)
.like(email != null, "email", email);
return userMapper.selectList(queryWrapper);
}
}
在此示例中,QueryWrapper
用于根据条件动态构建 SQL 查询,eq
和 like
方法会根据传入的参数生成相应的 SQL 语句。
5.2 使用 UpdateWrapper
进行复杂更新
类似于查询,UpdateWrapper
用于构建更新条件。
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
public
void updateUserEmail(Integer id, String email) {
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("id", id).set("email", email);
userMapper.update(null, updateWrapper);
}
6. 总结
MyBatis-Plus 提供了灵活的自定义 SQL 和复杂查询机制,支持通过注解、XML 和查询构造器实现灵活的数据库操作。
- 注解方式:简单、直观,适合快速开发常见的 SQL 操作。
- XML 方式:适用于复杂 SQL 和动态 SQL,通过 MyBatis 提供的标签,可以灵活地编写条件查询、多表关联查询等。
- 查询构造器 :通过
QueryWrapper
和UpdateWrapper
,开发者可以以链式语法构建复杂查询条件。