1. 模糊查询
在MyBatis中进行模糊查询时,有以下三种常见的实现方式:
1.1. 错误示范
先来个准备操作,并做一个错误示例
根据姓名,模糊查询用户,(x小x)
更新数据表
SQLMapper.java
package com.sakurapaid.mybatis3.select.mapper;
import com.sakurapaid.mybatis3.select.bean.User;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface SQLMapper {
// 根据姓名,模糊查询用户,(x小x)
List<User> findUserByName(@Param("name") String name);
}
SQLMapper.xml、
这是错误示例,我是——like '%#{name}%'
<?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.sakurapaid.mybatis3.select.mapper.SQLMapper">
<!--根据姓名,模糊查询用户,(x小x)-->
<select id="findUserByName" resultType="com.sakurapaid.mybatis3.select.bean.User">
select * from user where name like '%#{name}%'
</select>
</mapper>
测试输出
package com.sakurapaid.mybatis3.select.test;
import com.sakurapaid.mybatis3.select.bean.User;
import com.sakurapaid.mybatis3.select.mapper.SQLMapper;
import com.sakurapaid.mybatis3.select.utils.SqlSessionUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;
import java.util.List;
public class SQLTest {
@Test
public void test(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
List<User> out = mapper.findUserByName("小");
for (User user : out) {
System.out.println(user);
}
}
}
记住我上面的SQL语句,编译时就会报错
在 SQL 查询语句中使用了 MyBatis 的动态参数 #{name},但在对应的 mapper 映射配置中未正确设置该参数,导致在执行 SQL 查询时,JDBC 无法识别并适配这个参数,从而抛出了“Parameter index out of range”的异常。
所以,#{ }虽然常用,但并不是万能的,遇到模糊查询还是要适当调整的,也就引出了下面要讲到的三种在mybatis中模糊查询的方法
1.2. 方式一:使用#{}
占位符
#{ }占位符结合contact函数
<select id="findUserByName" resultType="com.sakurapaid.mybatis3.select.bean.User">
select * from user where name like concat('%',#{name},'%')
</select>
解释:
这里使用了#{}
占位符来传递参数name
。MyBatis会将#{name}
替换为预编译语句中的参数,并自动为其加上单引号。通过concat
函数将通配符%
与参数值拼接成完整的模糊查询条件。这种方式能够防止SQL注入,因为参数值是经过预编译处理的,且无需手动添加单引号。
测试输出:
测试语句还是最上面那个
1.3. 方式二:使用${}
变量替换
直接使用${ },但记得要加引号
<select id="testMohu" resultType="User">
select * from user where name like '%${name}%'
</select>
解释:
这种方式使用${}
变量替换符来嵌入参数name
的值。${name}
会被直接替换为变量的值,不会添加任何额外的引号。因此,如果传入的name
值为小
,生成的SQL语句将是select * from t_user where username like '%小%'
。这种方式虽然简洁,但存在SQL注入的风险,因为变量值未经预编译直接插入到SQL语句中。除非能确保传入值的安全性,否则不建议使用此方式。
测试输出:
测试语句还是最上面那个
1.4. 方式三:手动添加双引号
最推荐的,也是实际开发中最常用的
<select id="testMohu" resultType="User">
select * from user where name like "%"#{name}"%"
</select>
解释:
这种方式结合了#{}
占位符的预编译安全性与手动添加双引号来包裹通配符和参数。虽然看起来与方式一类似,但这里的#{name}
被双引号包围,使得MyBatis在替换参数时,生成的SQL语句中参数值仍被双引号包围,形如select * from user where name like "%'小'%"
。
2. 批量删除
要使用${ },而非#{ },来避免自动添加单引号
定义接口方法
// 批量删除用户
int deleteMore(@Param("ids") String ids);
编写Mapper XML映射文件
看清楚我这个错误示范
<delete id="deleteMore">
delete from user where id in (#{ids})
</delete>
测试输出
@Test
public void test(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
int i = mapper.deleteMore("4,5,6");
System.out.println(i);
}
不能使用#{ },只能使用${ }
<delete id="deleteMore">
delete from user where id in (${ids})
</delete>
受影响行数1,因为我表里的id值只有1-4,就删除了4,
3. 动态设置表名
也要使用${ },而非#{ },来避免自动添加单引号
定义接口方法
/**
* 动态设置表名,查询所有的用户信息
* @param tableName
* @return
*/
List<User> getAllUser(@Param("tableName") String tableName);
编写Mapper XML映射文件
看清楚我这个错误示范
<select id="getAllUser" resultType="com.sakurapaid.mybatis3.select.bean.User">
select * from #{tableName}
</select>
测试输出
@Test
public void test(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
List<User> allUser = mapper.getAllUser("user");
allUser.forEach(System.out::println);
}
不能使用#{ },只能使用${ }
<select id="getAllUser" resultType="com.sakurapaid.mybatis3.select.bean.User">
select * from ${tableName}
</select>
4. 添加功能获取自增的主键
在数据库应用开发中,使用自增主键是一种常见且实用的设计策略。自增主键字段的值会自动递增,每当插入一条新记录时,数据库系统会为其自动分配一个唯一的、递增的整数值作为主键。
场景一:简化数据插入操作
场景描述: 当需要在数据库中创建新的实体记录(如用户、订单、文章等)时,开发者通常需要为这些记录指定一个唯一的标识符。使用自增主键可以免去手动为每条新记录生成唯一ID的复杂性。
使用自增主键: 开发者只需关注其他非主键字段的数据填充,插入操作时无需指定主键值。数据库系统会自动为新插入的记录生成下一个自增主键值。例如,在创建新用户时,只需提供用户名、密码、邮箱等信息,主键ID由数据库自动生成。
场景二:确保数据唯一性
场景描述: 在多用户并发环境下,如果没有有效的机制保证主键的唯一性,可能会出现主键冲突,导致数据插入失败。自增主键能有效防止此类问题。
使用自增主键: 数据库系统内部对自增主键的管理确保了每次插入新记录时主键值的唯一性。即使在高并发场景下,不同用户同时尝试插入记录,也不会产生相同的主键值,从而避免数据冲突。
定义接口方法
// 添加用户
int insertUser(User user);
编写Mapper XML映射文件
useGeneratedKeys="true":指示MyBatis在执行INSERT操作后使用JDBC的getGeneratedKeys()方法获取数据库自动生成的主键值。
keyProperty="id":指定获取到的自增主键值应被赋给传入映射语句的参数对象(如User)的特定属性(如id),实现主键值的自动回填。
两者结合使用,确保在插入新记录后,自动生成的主键能被无缝地赋给对应的Java对象属性,简化了主键管理与后续业务逻辑的处理。
<!--useGeneratedKeys:设置使用自增的主键-->
<!--keyProperty:因为增删改有统一的返回值是受影响的行数,
因此只能将获取的自增的主键放在传输的参数user对象的某个属性中-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
insert into user values (null,#{name},#{age},#{sex});
</insert>
测试输出
@Test
public void test(){
SqlSession sqlSession = SqlSessionUtils.getSqlSession();
SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);
User user = new User(null, "李四", 23, "男");
int i = mapper.insertUser(user);
if (i > 0) {
System.out.println("插入成功");
System.out.println(user);
} else {
System.out.println("插入失败");
}
}