观前提示:本篇博客演示使用的 IDEA 版本为2021.3.3版本,使用的是Java8(又名jdk1.8)
前端使用 VSCode(Visual Studio Code1.78.2)
电脑使用的操作系统版本为 Windows 10
目录
Mybatis是什么?
Mybatis 有什么用?
Mybatis 框架交流
Mybatis 项目环境搭建
1. 添加 Mybatis 框架支持
2.设置 Mybatis 配置信息
2.1 建立数据库
2.2 设置数据库连接的相关信息以及 MyBatis 的 xml 保存路径和 xml 命名模式
Mybatis 模式开发
后端开发思路
添加实体类
添加 Mapper 接口
添加 Mapper.xml
添加 Service
添加 Controller
启动项目
单元测试
进入单元测试
Mybatis 动态获取参数
参数占位符 #{} 和 ${}
# 和 $ 的区别
SQL 注入
$ 优点
改、删、增操作
1. 修改密码
2. 删除用户操作
3. 增加用户操作
特别的添加: 返回自增 id
查询操作
1. 模糊查询
2. 多表联查
并发查询
动态 SQL
标签
标签
Mybatis 中多个都是非必传参数的解决方案
解决方案1: 1=1 解决方案
解决方案2: trim 的方式
解决方案3: 标签方式
Mybatis是什么?
MyBatis是一款优秀的Java持久层框架。它通过 XML 或注解的方式将要执行的 SQL 语句映射成为 Java 对象中的方法,然后利用 JDBC 执行 SQL 并将查
询结果映射为 Java 对象返回。MyBatis 的设计思想是将 SQL 语句与 Java 代码分离,通过 XML 或注解来定义 SQL 语句,这样不仅方便了开发人员对 SQL
语句进行管理和维护,而且使得 SQL 语句与 Java 代码解耦,提高了代码的可读性和可维护性。
Mybatis 有什么用?
对于后端开发来说,程序是由以下两个重要的部分组成的:
1. 后端程序
2. 数据库
使用 JDBC ,整个操作⾮常的繁琐,我们不但要拼接每⼀个参数,⽽且还要按照模板代码的⽅式,⼀步步的操作数据库,并且在每次操作完,还要⼿动关
闭连接等,⽽所有的这些操作步骤都需要在每个⽅法中重复书写。
MyBatis 可以帮助我们更⽅便、更快速的操作数据库。
Mybatis 框架交流
MyBatis 是⼀个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在⾯向对象编程语⾔中,将关系型数据库中的数据与对象建⽴起
映射关系,进⽽⾃动的完成数据与对象的互相转换:
1. 将输⼊数据(即传⼊对象)+SQL 映射成原⽣ SQL
2. 将结果集映射为返回对象,即输出对象
ORM 把数据库映射为对象:
数据库表(table)--> 类(class)
记录(record,⾏数据)--> 对象(object)
字段(field) --> 对象的属性(attribute)
⼀般的 ORM 框架,会将数据库模型的每张表都映射为⼀个 Java 类。也就是说使⽤ MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和
数据库表之间的转换。
Mybatis 项目环境搭建
1. 添加 Mybatis 框架支持
还是先创建一个 Spring-Boot项目, 把Spring Boot DevTools, Lombok, Spring Web 勾选上
再找到 SQL, 把MyBatis Framework 和 MySQL Driver 勾选上
到目前为止,一个带有 Mybatis 的 Spring-Boot项目已经创建完成
虽然 MyBatis 项目创建完成了, 但是启动的时候是必然会失败的
原因很简单, 没有连接数据库
2.设置 Mybatis 配置信息
在 application.properties 里面进行连接数据库操作, 在连接之前需要先建立数据库
2.1 建立数据库
-- 创建数据库
drop database if exists bolgtest;
create database bolgtest DEFAULT CHARACTER SET utf8mb4;
-- 使用数据数据
use bolgtest;
-- 创建表[用户表]
drop table if exists userinfo;
create table userinfo(
id int primary key auto_increment,
username varchar(100) not null,
password varchar(32) not null,
photo varchar(500) default '',
createtime timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
`state` int default 1
) default charset 'utf8mb4';
-- 创建文章表
drop table if exists articleinfo;
create table articleinfo(
id int primary key auto_increment,
title varchar(100) not null,
content text not null,
createtime timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
uid int not null,
rcount int not null default 1,
`state` int default 1
)default charset 'utf8mb4';
-- 创建视频表
drop table if exists videoinfo;
create table videoinfo(
vid int primary key,
`title` varchar(250),
`url` varchar(1000),
createtime timestamp default current_timestamp,
updatetime timestamp default current_timestamp,
uid int
)default charset 'utf8mb4';
-- 添加一个用户信息
INSERT INTO `bolgtest`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);
-- 文章添加测试数据
insert into articleinfo(title,content,uid)
values('Java','Java正文',1);
-- 添加视频
insert into videoinfo(vid,title,url,uid) values(1,'java title','http://www.baidu.com',1);
数据库建立成功就会提示 Query OK ,1 row affected
只要最后一行都显示这个,前面就不用看了
2.2 设置数据库连接的相关信息以及 MyBatis 的 xml 保存路径和 xml 命名模式
#1.链接数据库
spring.datasource.url=jdbc:mysql://localhost:3306/bolgtest?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
# 注意!!! password 要写自己本机mysql密码,不是固定的111111
spring.datasource.password=111111
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 2.设置MyBatis
mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml
#打印 mybatis 执行 SQL
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
#配置打印
logging.level.com.example.demo=debug
注意:
Mybatis 模式开发
后端开发思路
下⾯按照后端开发的⼯程思路,也就是下⾯的流程来实现 MyBatis 查询所有⽤户的功能
本篇博客建立分层就是按照上图进行建立, 不过是先建立实体类, 在按照 Mapper -> Servic -> Controller 的顺序建立
添加实体类
在 com.example.demo 建立 Entity, 再在 Entity 里建 UserEntity 类
实体类里面有什么东西, 取决于数据库里面有什么东西
把数据库 userinfo 里面的信息全部录入到 UserEntity 里面, 剩下的 mybatis 自己会解决
package com.example.demo.Entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class UserEntity {
private Integer id;
private String username;
private String password;
private String photo;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private Integer state;
}
添加 Mapper 接口
注意: Mapper 接口是 interface, 让其它层可以注入使用的接口
在 com.example.demo 建立 Mapper, 再在 Mapper 里建 UserMapper 接口
package com.example.demo.Mapper;
import com.example.demo.Entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface UserMapper {
List<UserEntity> getAll()
}
添加 Mapper.xml
注意: 具体实现 sql(它是 interface 的 "实现")
在 resource 里建立 Mybatis, 再在 Mybatis里建 UserMapper.xml
<?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="getAll" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo
</select>
</mapper>
注意:
添加 Service
package com.example.demo.Service;
import com.example.demo.Entity.UserEntity;
import com.example.demo.Mapper.UserMapper;
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<UserEntity> getAll() {
return userMapper.getAll();
}
}
添加 Controller
package com.example.demo.Controller;
import com.example.demo.Entity.UserEntity;
import com.example.demo.Service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getall")
public List<UserEntity> getAll() {
return userService.getAll();
}
}
注意: URL 在写的时候绝对不要出现大写字母, 可以出现 阿拉伯数字甚至汉字
比如.哔哩哔哩的视频 URL 它就是出现阿拉伯数字, 也不会出现大写字母
我拿必应搜索百度, 可以看到他的 URL 出现了汉字在里面, 但是依然没有大写字母
因为: RFC 1738 针对早期的 Web 环境制定了 URL 基本格式的标准。该标准要求 URL 中的字母必须采用 US-ASCII 字符集,并限制所有大写字符转换为相
应的小写字符。而 RFC 3986 则对之前的规范做了更新和扩展,对字符集的要求进行了更加严格的规定,同时保留了大小写敏感的部分。因此,为了遵守
URL 的标准规范,在 URL 中使用大写字母可能会导致 URL 不被正确解析或无法访问。
说白了就是:乌龟的屁股------龟腚
全部分层建立完
启动项目
返回服务器
成功使用带有 MyBatis 的 Spring-Boot 项目通过 URL 进行访问
给数据库在添加一条数据,看看还能不能通过 URL 访问到
-- 添加一个测试信息
INSERT INTO `bolgtest`.`userinfo` (`id`, `username`, `password`, `photo`, `createtime`, `updatetime`, `state`) VALUES
(2, 'zhangsan', 'zhangsan', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);
查询数据库, 发现两条信息
刷新 URL , 这边也可以查询到
单元测试
单元测试的优点
1、可以⾮常简单、直观、快速的测试某⼀个功能是否正确。
2、使⽤单元测试可以帮我们在打包的时候,发现⼀些问题,因为在打包之前,所以的单元测试必须通过,否则不能打包成功。
3、使⽤单元测试,在测试功能的时候,可以不污染连接的数据库,也就是可以不对数据库进⾏任何改变的情况下,测试功能。
4. 可以绕过用户登录验证进行单元测试
进行单元测试需要 在 pom.xml 引入依赖,好消息是不需要管他, 因为他自己已经引入了
每一个 Spring-Boot 的项目都会自带单元测试
junit 和 mockito 都是自带的
进入单元测试
先把测试需要的代码写上
usermapper
package com.example.demo.Mapper;
import com.example.demo.Entity.UserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface UserMapper {
List<UserEntity> getAll();
//根据 id 查询用户对象
UserEntity getUserById(@Param("id") Integer id);
}
// @Param 来自于 ibatis, 是 MyBatis 的前身
// 用于指定 SQL 语句中的参数名称和类型。MyBatis 框架会根据 @Param 注解来映射参数的名称和值,方便实现动态 SQL。
usermapper.xml
<?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="getAll" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo
</select>
<select id="getUserById" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo where id=${id}
</select>
</mapper>
再要测试的类上面右键 Generate 生成
勾选完,他会自动生成类,可以看到他在 Test 里面
只勾选一个
因为 UserEntity 里面有 @Data, 所以可以直接打印
package com.example.demo.Mapper;
import com.example.demo.Entity.UserEntity;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest// 表示当前单元测试的类是运行在 Spring Boot 环境中
class UserMapperTest {
@Autowired
private UserMapper userMapper;
@Test
void getUserById() {
//查询zhangsan,所以里面是放2
UserEntity user = userMapper.getUserById(2);
System.out.println(user);
}
}
运行测试类
上次只测试了 getUserById, 现在测试 getAll, 生成测试的时候会报错,问你是否还在这个测试类里面继续生成新的测试,选 OK
测试代码
@Test
void getAll() {
List<UserEntity> list = userMapper.getAll();
System.out.println(list.size());
}
运行测试类
观察上面两个单元测试会发现, 每次只运行一个,所以里面可以有多个
可以使用断言,但是不常用
Mybatis 动态获取参数
参数占位符 #{} 和 ${}
1. ${paramName} -> 直接替换
2. #{paramName} -> 占位符替换
这三行就可以看出来 $ 和 #
# 和 $ 的区别
先使用 #
mapper
//根据名称查询用户对象
UserEntity getUserByName(@Param("username") String username);
mapper.xml
<select id="getUserByName" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo where username=#{username}
</select>
生成单元测试
@Test
void getUserByName() {
UserEntity user = userMapper.getUserByName("zhangsan");
System.out.println(user);
}
再使用 $
只有 mapper.xml 需要修改
<select id="getUserByName" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo where username=${username}
</select>
重新运行单元测试
抛出异常
使用 $ 会报错,显示找不到 zhangsan Unknown column 'zhangsan' in 'where clause'
$ 是所见即所得,不会进行预处理,加上 ' ' 可以解决问题,但是有 SQL 注入问题
<select id="getUserByName" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo where username='${username}'
</select>
此时进行单元测试,一切正常
SQL 注入
使用最简单的 SQL 注入, 需要先删除一条数据,因为多条数据他有 bug
使用登录来进行 SQL 注入演示
Mapper
//登录
UserEntity login(UserEntity user);
Mapper.xml
<select id="login" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo where username='${username}' and password='${password}'
</select>
单元测试
@Test
void login() {
String username = "admin";
String password = "admin";
UserEntity inputUser = new UserEntity();
inputUser.setUsername(username);
inputUser.setPassword(password);
UserEntity user = userMapper.login(inputUser);
System.out.println(user);
}
现在开始 SQL 注入
@Test
void login() {
String username = "admin";
String password = "' or 1='1";
UserEntity inputUser = new UserEntity();
inputUser.setUsername(username);
inputUser.setPassword(password);
UserEntity user = userMapper.login(inputUser);
System.out.println(user);
}
原因: SQL 注入问题的出现,主要是因为在拼接 SQL 语句时,未对输入数据进行充分的过滤和转义处理。
这条 SQL 语句的条件部分中含有一个逻辑表达式 '1'='1'
,这个表达式的值永远为真。因此,不管数据库中是否存在名为 admin 的用户,这条 SQL 语句
都会返回用户表中的所有记录,甚至可能返回所有表中的记录。这就是 SQL 注入攻击的原理。
解决方法:
使用 #
当有可能存在 SQL 注入攻击时,MyBatis 会自动将参数进行转义处理,从而避免了通过插入恶意代码来实现 SQL 注入攻击的可能性。
<select id="login" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo where username=#{username} and password=#{password}
</select>
$ 优点
Mapper
List<UserEntity> getAllByIdOrder(@Param("ord") String ord);
Mapper.xml
<select id="getAllByIdOrder" resultType="com.example.demo.Entity.UserEntity">
select * from userinfo order by id ${ord}
</select>
单元测试
@Test
void getAllByIdOrder() {
List<UserEntity> list = userMapper.getAllByIdOrder("desc");
System.out.println(list.size());
}
使用 #, 单元测试就会报错
使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时,如果传递的值为 String 则会加单引号,就会导致 sql
错误。
改、删、增操作
1. 修改密码
mapper
//修改密码
int updatePassword(@Param("id") Integer id,
@Param("password") String password,
@Param("newPassword") String newPassword);
mapper.xml
<update id="updatePassword">
update userinfo set password=#{newPassword}
where id=#{id} and password=#{password}
</update>
单元测试
@Transactional
//事务,保证不会污染数据库(代码执行完,rollback 回滚)
//可以加载类上,也可以加载方法上
@Test
void updatePassword() {
int result = userMapper.updatePassword(1, "admin", "123456");
System.out.println("修改: " + result);
}
事务成功回滚
2. 删除用户操作
mapper
//删除用户
int delById (@Param("id")Integer id);
mapper.xml
<delete id="delById">
delete from userinfo where id=#{id}
</delete>
单元测试
@Transactional
@Test
void delById() {
int id = 1;
int result = userMapper.delById(id);
System.out.println("删除结果: " + result);
}
3. 增加用户操作
mapper
//新增用户
int addUser(UserEntity user);
mapper.xml
<insert id="addUser">
insert into userinfo(username,password) values(#{username},#{password})
</insert>
单元测试
@Test
void addUser() {
UserEntity user = new UserEntity();
user.setUsername("zhangsan");
user.setPassword("123456");
int result = userMapper.addUser(user);
System.out.println("添加: " + result);
}
特别的添加: 返回自增 id
mapper
//添加返回影响行数和id
int addUserGetId(UserEntity user);
mapper.xml
<insert id="addUserGetId" useGeneratedKeys="true" keyProperty="id">
<!--useGeneratedKeys 是否自动生成 id, 默认是 false-->
<!--keyProperty 自动生成 分配给 id-->
insert into userinfo(username,password) values(#{username},#{password})
</insert>
单元测试
@Test
void addUserGetId() {
UserEntity user = new UserEntity();
user.setUsername("lisi");
user.setPassword("123456");
int result = userMapper.addUserGetId(user);
System.out.println("添加结果: " + result);
System.out.println("ID: " + user.getId());
}
查询操作
1. 模糊查询
mapper
//根据用户模糊查询
List<UserEntity> getListByName(@Param("username") String username);
mapper.xml
<select id="getListByName" resultType="com.example.demo.Entity.UserEntity">
select id,username,password as pwd from userinfo where username like concat ('%',#{username},'%')
</select>
这个写法,使用了 concat 进行拼接, 组成一个模糊匹配的查询条件,即查询所有用户名中包含指定字符串的用户信息。
单元测试
@Test
void getListByName() {
String username = "zhang";
List<UserEntity> list = userMapper.getListByName(username);
list.stream().forEach(System.out::println);
}
2. 多表联查
新建一个实体类 ArticleInfo
package com.example.demo.Entity;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class ArticleInfo {
private int id;
private String title;
private String content;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private int uid;
private int rcount;
private int state;
}
在entity 建立一个 vo 在新建一个实体类 ArticleInfoVo
package com.example.demo.Entity.vo;
import com.example.demo.Entity.ArticleInfo;
import lombok.Data;
//作者名
@Data
public class ArticleInfoVO extends ArticleInfo {
private String username;
@Override
public String toString() {
return "ArticleInfoVO{" +
"username='" + username + '\'' +
"} " + super.toString();
}
}
mapper
新建一个 ArticleMapper
package com.example.demo.Mapper;
import com.example.demo.Entity.vo.ArticleInfoVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface ArticleMapper {
// 查询文章详情
ArticleInfoVO getDetail(@Param("id") Integer id);
}
mapper.xml
对于的新建一个 ArticleMapper.xml
<?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.ArticleMapper">
<select id="getDetail" resultType="com.example.demo.Entity.vo.ArticleInfoVO">
select a.*,u.username from articleinfo a
left join userinfo u on u.id=a.uid
where a.id=#{id}
</select>
</mapper>
文章表和详情表进行多表联查
单元测试
package com.example.demo.Mapper;
import com.example.demo.Entity.vo.ArticleInfoVO;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class ArticleMapperTest {
@Autowired
private ArticleMapper articleMapper;
@Test
void getDetail() {
ArticleInfoVO articleInfoVO = articleMapper.getDetail(1);
System.out.println(articleInfoVO);
System.out.println("title:" + articleInfoVO.getTitle());
}
}
并发查询
数据库新增文章数据
mapper
//并发查询
List<ArticleInfoVO> getListByUid(@Param("uid")Integer id);
mapper.xml
<select id="getListByUid" resultType="com.example.demo.Entity.vo.ArticleInfoVO">
select a.*,u.username from articleinfo a
left join userinfo u on u.id=a.uid
where a.uid=#{uid}
</select>
单元测试
@Test
void getListByUid() {
Integer uid = 1;
List<ArticleInfoVO> list = articleMapper.getListByUid(uid);
list.stream().parallel().forEach(System.out::println);
}
这是并发
list.stream().forEach(System.out::println);
这是不并发
动态 SQL
动态 SQL 是指在构建 SQL 语句时,根据需要动态地生成 SQL 语句的一种技术。它使用程序的控制流程和条件逻辑来决定 SQL 语句的组成
部分,从而实现更加灵活和可变的数据库操作。
与静态 SQL 相比,动态 SQL 能够根据不同的条件生成不同的 SQL 语句,从而适应更加复杂和多变的业务需求。常见的场景包括根据用
户输入的参数进行数据查询、动态生成复杂的查询条件、动态生成排序规则等。
在 Java 开发中,常用的动态 SQL 技术包括使用 PreparedStatement 对象进行参数化查询、使用 MyBatis 框架的动态 SQL 功能等。这些技
术都可以帮助开发人员灵活地构建 SQL 语句,从而提高代码的灵活性和可维护性。
需要注意的是,动态 SQL 也可能会带来一些性能问题,如在运行时动态生成 SQL 语句可能会影响查询效率。因此,在实际应用中,需要
权衡灵活性和性能之间的关系,并谨慎使用动态 SQL 技术。
<if> 标签
回到 UserMapper
mapper
//动态 SQL
int addUser2(UserEntity user);
mapper.xml
<insert id="addUser2">
insert into userinfo(username,
<if test="photo!=null and photo!='' ">
photo,
</if>
password)values(#{username},
<if test="photo!=null and photo!=''">
#{photo},
</if>
#{password})
</insert>
单元测试
@Transactional
@Test
void addUser2() {
String username = "liliu";
String password = "123456";
UserEntity user = new UserEntity();
user.setUsername(username);
user.setPassword(password);
user.setPhoto("cat.png");
int result = userMapper.addUser2(user);
System.out.println("添加: " + result);
}
<trim> 标签
之前的插⼊用户功能,只是有⼀个 sex 字段可能是选填项,如果所有字段都是⾮必填项,就考虑使用 <trim> 标签结合 <if> 标签,对多个字
段都采取动态生成的⽅式。
<trim>标签中有如下属性:
prefix:表示整个语句块,以prefix的值作为前缀
suffix:表示整个语句块,以suffix的值作为后缀
prefixOverrides:表示整个语句块要去除掉的前缀
suffixOverrides:表示整个语句块要去除掉的后缀
mapper
//trim 演示
int addUser3(UserEntity user);
mapper.xml
<insert id="addUser3">
insert into userinfo
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username!=null and username!='' ">
username,
</if>
<if test="photo!=null and photo!='' ">
photo,
</if>
<if test="password!=null and password!='' ">
password,
</if>
</trim>
values
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username!=null and username!='' ">
#{username},
</if>
<if test="photo!=null and photo!=''">
#{photo},
</if>
<if test="password!=null and password!='' ">
#{password},
</if>
</trim>
</insert>
单元测试
@Transactional
@Test
void addUser3() {
String username = "liliu";
String password = "123456";
UserEntity user = new UserEntity();
user.setUsername(username);
user.setPassword(password);
int result = userMapper.addUser3(user);
System.out.println("添加: " + result);
}
Mybatis 中多个都是非必传参数的解决方案
解决方案1: 1=1 解决方案
mapper
List<ArticleInfoVO> getListByIdOrTitle(@Param("id")Integer id,
@Param("title")String title);
mapper.xml
<select id="getListByIdOrTitle" resultType="com.example.demo.Entity.vo.ArticleInfoVO">
select * from articleinfo
where 1=1
<trim prefixOverrides="and">
<if test="id!=null and id>0">
and id=#{id}
</if>
<if test="title!=null and title!=''">
and title like concat('%',#{title},'%')
</if>
</trim>
</select>
解决方案2: trim 的方式
mapper.xml
<select id="getListByIdOrTitle" resultType="com.example.demo.Entity.vo.ArticleInfoVO">
select * from articleinfo
<trim prefix="where" suffixOverrides="and">
<if test="id!=null and id>0">
id=#{id} and
</if>
<if test="title!=null and title!=''">
title like concat('%',#{title},'%')
</if>
</trim>
</select>
当 trim 中生成代码, 那么才会添加 <trim> 里面的前缀和后缀的, 如果 trim 中没有生成代码, 则前缀和后缀都会省略
单元测试
@Test
void getListByIdOrTitle() {
List<ArticleInfoVO> list = articleMapper.getListByIdOrTitle(null,null);
System.out.println(list.size());
}
解决方案3: <where> 标签方式
mapper.xml
<select id="getListByIdOrTitle" resultType="com.example.demo.Entity.vo.ArticleInfoVO">
select * from articleinfo
<where>
<if test="id!=null and id>0">
id=#{id}
</if>
<if test="title!=null and title!=''">
and title like concat('%',#{title},'%')
</if>
</where>
</select>
单元测试
@Test
void getListByIdOrTitle() {
List<ArticleInfoVO> list = articleMapper.getListByIdOrTitle(1,null);
System.out.println(list.size());
}
本文完,感谢观看,不足之处请在评论区指出 !