日升时奋斗,日落时自省
目录
1、MyBatis
1.1、Mybatis配置
1.2、添加MyBatis框架支持
1.3、配置连接字符串和MyBatis
1.3.1、配置连接字符串
1.3.2、配置MyBatis中XML路径
2、业务代码
2.1、添加实体类
2.2、添加mapper接口
2.3、添加.xml文件
3、单元测试
3.1、单元测试优势
3.2、Spring Boot单元测试使用
4、MyBatis操作数据库
4.1、查询操作(单表)
4.1.1、有参查询
4.1.2、${}诱发SQL注入(传对象举例)
4.1.3、#{}解决${}带来的SQL注入(传对象举例)
4.1.4、like模糊查询
4.1.5、#{}和${}的区别
4.2、数据修改(单表)
4.3、数据删除(单表)
4.4、数据插入(单表)
4.4.1、插入操作(普通插入)
4.4.2、插入操作(设置主键)
4.5、多表查询
5、动态SQL使用
5.1、if标签
5.2、trim标签
5.3、where标签
5.4、set标签
5.5、foreach标签
如果是一路平缓的学习,那一定了解过JDBC,以及JDBC如何连接数据库,但是那时学习的数据库连接操作代码冗余太多,操作也比较复杂。
注:本篇内容有点长(选取自己需要的即可)
此处MyBatis查询数据库与Spring系列连起来,前面学习内容都不能进行保存,除了日志记录是保存文件中的,其他数据存储都是保存子内存中的,当下就通过MyBatis来连接数据库
MyBatis是一个优秀的基于Java的持久层框架,它支持定制化SQL、存储过程以及高级映射。 Mybatis通过XML或注解方式将要执行的各种statement(statement、preparedStatment、callableStatment)配置起来,并通过java对象和statement中的sql进行映射生成最终的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回
<1>自定义SQL:指开发者可以手动编写SQL语句并通过MyBatis框架执行的方式进行数据操作
<2>存储过程:预先保存在数据库中的一段程序,可以被多次调用,通常用于执行特定的复杂业务逻辑或数据操作
<3>高级映射:在SQL查询语句中加入关联查询的语句,并通过ResultMap将查询结果映射成Java对象
Mybatis去除了JDBC繁琐的代码(获取参数结果集等),Mybatis通过简单的XML文件或者注解来配置和映射原始类型,接口和java对象
配置Mybatis开发环境
使用Mybatis模式和语法操作数据库
MyBatis也是ORM框架,ORM(Object Relational Mapping)即位对象关系映射,在面向对象语言的编程中,将关系来型数据与对象建立起映射关系,进而自动的完成数据域对象的互相转换:
<1>将输入数据(即传入对象)+SQL映射成原生SQL
<2>将结果集映射为返回对象,即输出对象
ORM把数据库映射为对象(规定性映射):
数据库表(table)--->类(class)
记录(record,行数据)--->对象(object)
字段(field)--->对象的属性(attribute)
添加MyBatis框架支持分为两种情况:
<1>一种情况是对自己之前的Spring项目进行升级
<2>另一种情况是创建一个全新的MyBatis和Spring Boot的项目
下面开始创建一个项目并且开始附带上Mybatis需要的依赖:
创建Spring Boot项目 这里只展示引入依赖部分
后面的操作部分和Spring Boot项目创建操作相同
Spring Boot配置文件相关
此步骤需要进行两项设置,数据库连接字符串设置和MyBatis的XML文件设置
这里给友友们提供数据库和其中表(但是没有数据,可以自己加两条)
我们这里使用.yml配置文件进行配置设置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
注:这里的数据库连接自己的数据库,因为我这里的数据库名称叫做 mycnblog ;
友友们填写的自己的数据库就可以了
driver-class-name配置项:设置驱动程序的名称(是固定的,直接复制就行我们这里使用的是mysql的)
注:mysql的版本是有一定规定的,mysql5.x版本之前的使用“com.mysql.jdbc.Driver”这个配置
如果是高于5.x版本的使用“com.mysql.cj.jdbc.Driver”
MyBatis的XML中保存是查询数据库的具体操作SQL,配置如下:
这里还会设置到 日志的打印级别,因为日志级别的Mybatis打印的日志级别是Debug级别的,但是Spring Boot 默认的打印级别是INFO,所以这里也会将日志级别设置较低
mybatis:
mapper-locations: classpath:mybatis/*Mapper.xml
# 设置 Mybatis 的 xml 保存路径
configuration: # 配置打印 MyBatis 执行的 SQL
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 配置打印 MyBatis 执行的 SQL
logging:
level:
com:
example:
demo: debug
注意几个点:
添加业务代码,有这么一系列流程来实现MyBatis查询用户功能,当前先走第一步写一个实体类
这个实体类也不是随便加的,因为我们想用MyBatis,所以要遵循规定,MyBatis的映射关系
以下是我想要映射的数据库表单,所以java对象的实体类要与之一样
这里创建entity层,该层存放实体类,
@Data
public class UserEntity {
private Integer id;
private String username;
private Integer password;
private String photo;
private LocalDateTime createtime;
private LocalDateTime updatetime;
private Integer state;
}
这里我们定义一个mapper层,用来写mapper接口(一定注意这里创建的是一个接口)
@Mapper
public interface UserMapper {
List getAll();
}
getAll()就是我们写的方法用来操控数据库的,但是暂时还没有写sql代码
注:mapper接口,上一定要写@Mapper注解
@Mapper:MyBatis会自动扫描所有的接口,然后根据接口定义创建相应的代理对象。这样我们就可以直接使用该接口来操作数据库,而无需手动编写SQL语句的实现
数据持久层现,MyBatis的固定xml格式:
此处就要开始写sql语句了,在mapper标签内写sql操作语句
id:写的是映射java接口路径下对应的方法名
resultType:指定查询结果集中每行数据的映射类型的属性,这里我们操作是UserEntity实体类,就写该类的路径就行
接下来我们来写controller层操控数据库,前提需要调用service层的接口,所以还需要写一下service的接口
Service层:
@Service //类注解 一定要记得 即是区分 也 是将注入spring容器
public class UserService {
//将数据库类 进行注入
@Autowired
private UserMapper userMapper;
public List getAll(){
return userMapper.getAll();
}
}
controller层:
@Controller //设置类注解
@RequestMapping("/user") //设置路由
public class UserController {
//service层对象注入
@Autowired
private UserService userService;
//设置方法对应的路由
@RequestMapping("/sayhi")
public void sayhi(){
userService.getAll();
}
}
访问路由结果:
现在开始就需要进行测试我们的代码成功了没有,但是直接写操作数据库的代码就很不方便,如果这里不是查询,是添加,修改,友友们是不是还得去数据库改回来,无意义的操作,所以针对这点产生了单元测试操作,避免对数据库的污染(就是不修改数据的同时也能知道,操作数据库的代码对不对)
单元测试:用于测试程序中的最小可测试单元(代码中的一个函数或方法)。可以帮助开发人员及时打掉代码中的bug,提高代码质量,并减少在后期集成测试和系统测试中的错误
编写一小段代码,用于检测被测试代码的一个很小的,很明确(代码)功能是否正确,执行单元测试证明某段代码的执行结果是否符合我们的预期。通过则满足,不同过不满足
<1>简单、直观、快速的测试某个功能是否正确
<2>使用单元测试可以帮我们打包的时候,发现问题,在打包之前就会告诉我们,所以单元测试就是必须的,否则打包不成功
<3>使用单元测试,在测试功能的时候,可以不污染连接的数据库,操作可以进行回滚
Spring Boot针对单元测试有常用的框架如下:
JUnit:JUnit是一个Java语言的单元测试框架,提供了一些用于编写测试用例的注解和断言工具,可以方便地创建测试用例并运行测试。
Mockito:Mockito是一个用于Java的mock框架,用于模拟对象和行为,使得单元测试更加简单和可靠。
Hamcrest:Hamcrest是一个Java语言的匹配器库,它提供了一些强大的断言语法,可以更加灵活地对测试结果进行检查。
AssertJ:AssertJ是一个Java语言的断言库,提供了一些流畅的API,使得编写测试用例更加简单和易读。
TestNG:TestNG是一个基于JUnit的测试框架,提供了一些更加高级和灵活的测试功能,例如测试套件、测试参数化等
在Spring boot项目的目录中是有对应的jar包的
剩下就开始操作,如何使用单元测试在
在mapper层写一个接口处理一个实体类(表)的sql操作进行测试
测试选择项,这里当前只需要你勾选测试方法,其他的不要动,因为不需要用,点击OK就可以了
测试代码:
@SpringBootTest //这个注解不能忘了, 他是连接Spring boot的 用于测试使用,要不直接启动这里的 测试类直接就结束了
class UserMapperTest {
//2、需要进行对象注入 为什么接口可以实例化???
@Autowired
private UserMapper userMapper;
//1、生成代码如下
@Test
void getAll() {
//3、测试打印该查询sql能不能顺利进行
List lists=userMapper.getAll();
System.out.println(lists);
}
}
该方法左边有一个绿色的三角,点击这里进行启动
注:这里不需要页面的访问,什么也不需要,就能看见操作数据库代码是否正确
当然了如果需要严谨一点的话,可以加上断言
断言:用于判断测试结果是否符合预期的方法
此处做以了解即可(大部分情况不用,以下是相关方法)
这里说单元测试,为了我们后面的操作都使用单元测试来完成操作
在操作之前,我们这里给友友们提供一个比较好用的插件,为了方便我们写sql代码
FIle->Settings->plugins
没有安装的友友们, 点击install即可,这里的效果下面在查询操作就给友友们展示
这里涉及到一个注解@Param注解(该注解也能修改名称,也就是取别名),可以不使用注解直接传参但是不太稳妥,总是可能出问题的
原因:IDEA编译时采取了强制保持方法参数变量名
这就是但是即便是以上情况也要满足jdk使用8版本以上的或者jdk8,所以友友们还是加上注解
Java接口内写sql操作方法:
@Mapper
public interface UserMapper {
List getAll();
//注解@Param 接收的名称为uid
UserEntity getUserId(@Param("uid") Integer id);
}
.xml文件中写sql语句 id 就是我们要操作Java接口 中对应的的方法
注意传参这里使用的是${} 这种形势,遵守规定即可,还有另外一种传参方式#{} ,这两个有所区别,后面给友友们介绍
代码都写好了,现在开始单元测试:(还是原来的操作,除了选择的方法不同以外其他没有什么区别)
在我们写操作数据库方法的Java接口处 单击右键 generate ->Test
还是在刚刚创建测试类中 (一起都沿用之前有的,对象注入也适用刚刚写过的):
@Test
void getUserId() {
UserEntity user=userMapper.getUserId(1);
System.out.println(user);
}
运行结果:
注:红色框框中显示的是我们写的sql语句,蓝色框框就是传参过程中,我们拿到值
使用${}是很不安全的,容易叫人进行恶意拿取数据
SQL注入:是一种攻击技术,攻击者利用输入验证不严格的网站或应用程序中的漏洞将恶意SQL代码插入到查询中,从而绕过身份验证和控制访问数据的机制
这里给友友们演示一下:${}带来的问题
还是写一个login操作 登录需要涉及用户名和密码(还是在原来的UserMapper接口中写):
UserEntity login(UserEntity user);
注:此时传递的是一个对象
对象映射到.xml文件中,属性怎么设置,Spring boot 已经给我们封装好了,直接使用属性就传参就行了
.xml文件 sql 语句 :
同样的操作,创建单元测试对应的方法来测试(这里就不在演示添加过程,有参查询中有详细过程):
注意:这里传参都是字符串(问题就在这里)
@Test
void login() {
String username="admin";
String password="admin";
UserEntity user=new UserEntity();
user.setUsername(username);
user.setPassword(password);
UserEntity user1=userMapper.login(user);
System.out.println(user1);
}
运行结果:
这里不能看出字符串少了引号,所以sql语句错了,那们就给给他添加上引号
给sql语句添加上 单引号:
这次就不会报错了:
正是因为这样,字符串的拼接带来了SQL注入的问题,当前是没有拿到信息的,total是:0,这才是正确的,数据不对不应该拿到信息
以下是我数据库中的用户和密码:
这里就开始展现SQL注入如何获取信息(只修改了密码输入)
运行结果:
解决${}的方法就是使用#{} ,一旦使用${}就需要格外注意SQL注入
把原来的$换成# 直接运行单元测试:
另一种方式就需要在接收数据时,需要处理部分特殊情况,防止诱发SQL注入
当然了${} 也不是没有什么用处,#{}传递的是属性,不能传递sql中的关键字,${}能(凡是存在必有道理),这里试问:什么情况会涉及到传sql关键字呀,感觉基本没有什么情况是吧
上事例:
如果需要设置升降序
java接口内操作sql的方法:
//sql 关键字 传递
List getUserByUserOrder(@Param("ord") String ord);
.xml文件sql语句(这里只能使用${} ,#{}会报错):
添加单元测试 进行测试(传参直接传 sql 关键字 desc 倒序方便看到效果):
@Test
void getUserByUserName() {
List lists=userMapper.getUserByUserOrder("desc");
for (UserEntity list:lists) {
System.out.println(list);
}
}
单元测试结果(是可以做到,但是做到是做到了,但是还是要注意SQL注入,可以使用传一个值来判定升降即可,尽可能避免掉SQL注入):
注:后面的操作都会使用#{} 来接收属性值
Java接口内操作sql方法:
模糊查询直接 需要 %字符串% 这个确实使用#{}是输入不出来的,虽然${}是可以进行字符串拼接操作的,但是还是不得不提防SQL注入:
所以这里就给友友们推荐一个方法 concat
concat:有多少参数都可以进行拼接 ,下面开始操作一下:
Java接口内操作sql的方法:
List getListByName(@Param("username")String username);
.xml文件中的sql语句(以下是${}版的,不安全):
.xml文件中的sql语句(以下是concat方法版的,比${}安全):
单元测试(因为这里是模糊查找所以只需要输入一部分即可):
@Test
void getListByName() {
String username="无";
List list=userMapper.getListByName(username);
//list.stream().forEach(System.out::println); //stream是正则表达式的封装,可以进行直接打印
//如果没有了解过stream 的 直接使用for循环即可
for(int i=0;i
运行结果:
<1>功能不同:${}
是直接替换,而 #{}
是占位符;
<2>使用场景不同:普通参数使用 #{}
,如果传递的是 SQL 命令或 SQL 关键字,需要使用 ${}
,但在使用前一定要做好安全验证;
<3>安全性:使用 ${}
存在安全问题,如 SQL 注入,而 #{}
则不存在安全问题。
修改数据就没有那么那么复杂了,但是这里会新认识一个相关单元测试的注解@Transactional
Java接口内 sql 方法代码:
//修改密码
int updatePassword(@Param("uid") Integer id,
@Param("password") String password,
@Param("newpassword") String newpassword);
.xml文件sql语句 :
update userinfo set password=#{newpassword}
where id=#{uid} and password=#{password}
单元测试:
@Test
void updatePassword() {
int result=userMapper.updatePassword(1,"123456","admin");
System.out.println("修改行数:"+result);
}
运行结果:
此时要想不污染数据库需要添加一个注解@Transactional,才能进行回滚不影响数据库数据
因为修改和删除简单,所以先举例,容易接收,有了前面的地基,其实操作也很类似
这里就直接写一个删除的例子友友们就基本了解了:
Java接口内 代码:
//删除用户信息
int deleteById(@Param("uid") Integer id);
.xml文件sql 语句:
delete from userinfo where id=#{uid}
单元测试:
@Transactional //该注解 会让操作的数据 进行回滚
@Test
void deleteById() {
int result=userMapper.deleteById(6);
System.out.println("删除影响的行数:"+result);
}
运行结果(前面已经介绍了 回滚的注解,介绍就用起来):
普通的插入操作和前面的 删除和修改操作 很类似
Java接口内操作sql的方法:
//添加用户
int addUser(UserEntity user);
.xml文件sql语句:
insert into userinfo(username,password) values(#{username},#{password})
单元测试(此处使用注解 进行回滚操作了):
@Transactional
@Test
void addUser() {
String username="黑无常";
String password="123456";
UserEntity input=new UserEntity();
input.setUsername(username);
input.setPassword(password);
int result=userMapper.addUser(input);
System.out.println("添加影响的行数:"+result);
}
数据插入就与前面有所不同了,设置自动生成主键等操作
看代码来理解
Java接口内写一个添加操作的方法:
//插入操作 主键设置
int addUserGetId(UserEntity user);
.xml文件中写插入的sql语句:
insert into userinfo(username,password) values(#{username},#{password});
注:涉及到两个新的参数一个是:useGeneratedKeys,另一个是keyProperty
useGeneratedKeys:是一个可选的配置属性,可以用于指示 MyBatis 是否应该使用数据库自动生成的主键。当 useGeneratedKeys 设置为 true 时,MyBatis 将使用 JDBC 的 getGeneratedKeys 方法来获取自动生成的主键(前提是你数据库创建表已经设置里主键),并将其设置回实体对象中
keyProperty:对应数据库主键字段
单元测试:
@Test
void addUserGetId() {
String username="白无常";
String password="123456";
UserEntity input=new UserEntity();
//设置新的 用户名和 密码
input.setUsername(username);
input.setPassword(password);
//传递对象直接传, Spring boot中的映射会进行获取其中属性 对应到xml文件中写sql语句
int result=userMapper.addUserGetId(input);
System.out.println("添加行数:"+result);
}
这里就先不加@Transactional注解了,为了方便友友观察到
单元测试启动:然后看一下数据库,是否有新增 :
这里我们就尝试操作多个表,这里创建一个文章表,但是我们还想知道这个文章对应的是哪个用户的
扩展的实体类:用户的名字字段
文章表的实体类:文章表字段信息
文章实体类:
@Data
public class ArticleInfo {
private Integer id;
private String title;
private String content;
private String createtime;
private String updatetime;
private Integer uid;
private Integer rcount;
private Integer state;
}
扩展表的需要的名称:
@Data
public class AritcleInfoVo extends ArticleInfo {
//Data注解来自于 Lombok是不能直接 提供父类的toString
//所以这里就需要 自己进行generate 快捷一个toString
@Override
public String toString() {
return "AritcleInfoVo{" +
"username='" + username + '\'' +
"} " + super.toString();
}
private String username;
}
注:类虽然有继承父类,但是Lombok提供的注解不行,所以我们需要自己来写已给toString
这里toString怎么来的,给友友们简要操作一下:
这里创建操作和原来的无异(接下来就以操作文章表进行):
注:蓝鸟写 Java接口内操作sql的方法 ; 红鸟:.xml文件写sql语句
前置操作已经做完了,下面开始多表查询:
Java接口内 操作sql 的方法(通过id获取多表查询信息):
@Mapper
public interface AritcleMapper {
List getAll(@Param("uid")Integer uid);
}
.xml文件中的sql语句:
单元测试(获得uid = 1,也就是用户编号为1的文章 ):
@SpringBootTest
class AritcleMapperTest {
@Autowired
private AritcleMapper aritcleMapper;
//测试多表查询
@Test
void getAll() {
int uid=1;
List lists=aritcleMapper.getAll(uid);
for(int i=0;i
运行结果:
注:为什么这里只说到多表的查询,是因为其他的多表操作的基本不太敢用,多表删除一条数据回影响很多条数据,修改也是类似;
为啥有个动态SQL呢,我们不是所有选择都是一定的
举个例子:就像我们去填写信息的时候(注册csdn账号),注册只填写部分必要信息,还有一些是可写可不写的,这部分怎么写入数据库,个数少了还好说,没种情况我都写一个方法来操作数据存入,个数多了咋办,像填写简历的信息的时候,那么多信息可选可不选,所有情况都要写吗??
答案:不需要
这里使用
我们这里使用userinfo用户表,用户和密码总是要传的嘛,头像可以不传
Java接口内 sql 操作方法:
//if 标签
int addUser2(UserEntity user);
.xml文件sql语句:
insert into userinfo(username,
photo,
password)
values(#{username},
#{photo},
#{password});
使用特点:
单元测试(添加了@Transactional注解,不会污染数据库):
@Transactional
@Test
void addUser2() {
String username="白无常";
String password="123456";
UserEntity input=new UserEntity();
input.setUsername(username);
input.setPassword(password);
int result=userMapper.addUser2(input);
System.out.println("插入:"+result+"条");
}
运行结果:
这里我们更换以下顺序,为了突显效果像这样传参 username,password,photo
trim标签又是干什么的,if标签是让sql成为了动态的,但是不代表if标签一个人就能完成无错操作,
注意细节的友友们,会看到写if标签中除了password字段后面还跟了一个“逗号”,如果这个逗号
举个例子:
如果 username,password,photo 就以这个顺序为例,假如这三个属性都是可选可不选的,那要是photo没有传的话,就根据上面if标签来写
产生结果: usernam,password, 这样的sql能运行吗???我相信肯定是不能的
trim标签能去掉没有用的后缀或者前缀,所以这时在if标签外面写一个trim标签来控制后缀多余的“逗号”就可以解决问题(不要觉得这个问题是特殊问题,很常见)
trim标签有四个参数:
<1>prefix:表示整个语句块,以prefix的值作为前缀
<2>suffix:表示整个语句块,以suffix的值作为后缀
<3>prefixOverrides:表示整个语句块要去除掉的前缀
<4>suffixOverrides:表示整个语句块要去除掉的后缀
java接口内操作sql的方法(添加方法):
//trim 标签
int addUser3(UserEntity user);
.xml文件sql语句:
insert into userinfo
username,
password,
photo,
values
#{username},
#{password},
#{photo},
单元测试(我们这里只传递username和photo,最后一个参数的位置我们空下来):
@Transactional
@Test
void addUser3() {
String username="白无常";
String photo="bind.jpg";
UserEntity input=new UserEntity();
input.setUsername(username);
input.setPhoto(photo);
int result=userMapper.addUser3(input);
System.out.println("插入:"+result+"条");
}
注:生成的sql应该是 insert into userinfo(username,photo,) values(?,?);
经过trim标签的处理:看以下运行结果:
where标签又是来干什么的呢 主要避免什么都不输入的情况,你像你输入查询情况,他就默认全部给你看,查询再过滤掉你不看的
举个例子:
这里以文章表来说: 如果我想查询某几个信息
select * from articleinfo where id=#{id} and title like concat('%',#{title},'%');
如果此时没有输入id 和 title的话我们在.xml文件写的sql就会变成:
select * from articleinfo where 这就啥也不是了(下面开始演示where标签)
Java接口内操作sql的方法:
List getListByIdOrTitle(@Param("id") Integer id
,@Param("title")String title);
.xml文件的sql语句(where 还会清除if标签中前置and ,这是规定,遵守就行,所以我们尽量将and将在if标签内 要写的sql语句的前面):
单元测试(来看一下sql语句,以下测试三个结果):
@Test
void getListByIdOrTitle() {
List lists=aritcleMapper.getListByIdOrTitle(1,"Java");
System.out.println(lists.size());
}
运行结果:
set 关键字 针对sql语句来想起来的一定是修改,这就是给修改使用的 有了前面的三个标签,这个标签的使用方法也是一致的(这里就写一个修改的sql语句操作)
Java接口内操作sql的方法(修改内容直接传一个对象,如果实体类中属性进行添加了也不会有什么影响):
//set 标签
int updateById(UserEntity user);
.xml文件的SQL语句:
update userinfo
username=#{username},
password=#{password},
where id=#{id}
set标签有一个特点,就是if标签内后置的“逗号”set是会根据mysql 语法进行去除的,就像where标签可以去掉if标签内前置的and一样(都是一个道理,当然这些都是规定)
单元测试(观察password后面的“逗号”去除):
这里我们传的是对象,给对象设置id 就是where后面指定要修改的id,其他设置都是修改内容
@Transactional
@Test
void updateById() {
String username="小刘";
String password="admin";
UserEntity input=new UserEntity();
input.setId(3);
input.setUsername(username);
input.setPassword(password);
int result=aritcleMapper.updateById(input);
System.out.println("修改数:"+result);
}
运行结果:
注:这里只是告诉了友友们的使用特点,也不是说就只有这一种情况,这些标签可以混合使用
foreach可以设置五个参数:
<1>collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
<2>item:遍历时的每⼀个对象 (就相当于创建临时变量来接收一样)
<3>open:语句块开头的字符串
<4>close:语句块结束的字符串
<5>separator:每次遍历之间间隔的字符串
针对单表的多条数据删除也是比较常见,foreach也就是为了这样的操作(下面直接开始演示案例)
Java接口内操作sql方法:
// 根据文章id集合批量删除文章 foreach 标签
int delByIdList(List idList);
.xml文件sql语句:
delete from articleinfo
where id in
#{aid}
单元测试(我这里刚好有3条数据所以只添加了3个id作为演示,可以回滚):
@Transactional
@Test
void delByIdList() {
List lists=new ArrayList<>();
lists.add(1);
lists.add(2);
lists.add(3);
int result=aritcleMapper.delByIdList(lists);
System.out.println("删除行数:"+result);
}
运行结果: