📋 个人简介
- 💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜
- 📝 个人主页:馆主阿牛🔥
- 🎉 支持我:点赞👍+收藏⭐️+留言📝
- 📣 系列专栏:java 小白到高手的蜕变🍁
- 💬格言:要成为光,因为有怕黑的人!🔥
目录
- 📋 个人简介
- 前言
- 查询
- 查看详情
- 条件查询
- 动态条件查询
- 多条件动态查询
- 单条件动态查询
- 添加和修改
- 添加
- 修改
- 删除
- 使用注解方实增删改查
- 结语
前言
上一节主要写了MyBatis入门案例以及Mapper代理,这节主要结合前面的知识实现MyBatis的增删改查,涉及动态sql的使用!
查询
查询所有在入门案例里已经举例过了,这里不再写案例!
查看详情
首先补充mybatis-config.xml核心配置文件:
可以添加类型别名,然后对应的sql映射文件里resultType就可以直接简写返回值类型了,而且不区分大小写!
下面进入案例:
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 执行sql (只有这块需要手写,其他步骤直接复制)
MemberMapper memberMapper = sqlSession.getMapper(MemberMapper.class);
int id = 2;
Member member = memberMapper.selectById(id);
System.out.println(member);
//4. 释放资源
sqlSession.close();
}
这里要对参数占位符作出说明:
mybatis提供了两种参数占位符:
- #{} :执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。从上述例子可以看出使用#{} 底层使用的是PreparedStatement
- ${} :拼接SQL。底层使用的是 Statement ,会存在SQL注入问题。
接下来来看另为的问题:
这里sql语句>是没有问题的,但小于号<是xml标签的开始符号,会报错!
有两种解决方式:
方式一:使用<的转义字符:
<select id="selectById" resultType="member">
select * from member where id < #{id}
</select>
方式二:使用CDATA区:
<select id="selectById" resultType="member">
select * from member where id
<![CDATA[
<
]]>
#{id}
</select>
CDATA区里的字符会当做纯文本处理!
条件查询
sql映射文件:MemberMapper.xml
而该功能有2个参数,我们就需要考虑定义接口时,参数应该如何定义。Mybatis针对多参数有多种实现:
1.使用 @Param(“参数名称”) 标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位!
int age = 28;
String name = "张";
// 模糊匹配,参数处理
name = '%' + name + '%';
List<Member> members = memberMapper.selectByCondition(age,name);
System.out.println(members);
2.将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和实体类属性名保持一致。
int age = 28;
String name = "张";
// 模糊匹配,参数处理
name = '%' + name + '%';
// 封装对象
Member member = new Member();
member.setAge(age);
member.setName(name);
List<Member> members = memberMapper.selectByCondition(member);
System.out.println(members);
3.将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容}时,里面的内容必须和map集合中键的名称一致。
int age = 28;
String name = "张";
// 模糊匹配,参数处理
name = '%' + name + '%';
// 封装map对象
HashMap map = new HashMap();
map.put("age",age);
map.put("name",name);
List<Member> members = memberMapper.selectByCondition(map);
System.out.println(members);
动态条件查询
多条件动态查询
上述功能实现存在很大的问题,假如我们在做开发遇到用户在输入条件时,这个需求肯定不会所有的条件都填写,一种是对于不同填写情况判断,用不同的sql,但这样比较麻烦,写的sql也多,所以MyBatis提供了动态sql,可以帮助我们一条语句就搞定这种搜索查询情况!
<!-- 条件查询-->
<select id="selectByCondition" resultType="member">
select *
from member
where age = #{age}
and name like #{name};
</select>
上面的意思就是说,这样的sql查询必须是两个或者多个参数都有才能查出来,而我们的需求是两个甚至多个条件任选都满足查询,这就是动态sql,只需一条sql就搞定,那下面就来看看怎么搞!
<!-- 动态条件查询-->
<select id="selectByCondition" resultType="member">
select *
from member
where
<if test="age != null">
age = #{age}
</if>
<if test="name != null and name != ''">
and name like #{name}
</if>
</select>
用动态sql的if标签即可满足!if标签可以判断参数是否有值,使用test属性判断!
可以看到此时只有一个条件,依然满足!
但是如果是第一个条件没有,此时就会出问题:
报错也很明显,多了一个and,对于这种情况有两种解决方式!
方式一:不常用
```xml
<!-- 动态条件查询-->
<select id="selectByCondition" resultType="member">
select *
from member
where 1=1
<if test="age != null">
and age = #{age}
</if>
<if test="name != null and name != ''">
and name like #{name}
</if>
</select>
加一个1=1恒等式不就行了,但我们sql可不这么写,所以用第二个方法!
方法二:使用where 标签
- 作用:
- 替换where关键字
- 会动态的去掉第一个条件前的 and
- 如果所有的参数没有值则不加where关键字
<select id="selectByCondition" resultType="member">
select *
from member
<where>
<if test="age != null">
age = #{age}
</if>
<if test="name != null and name != ''">
and name like #{name}
</if>
</where>
</select>
单条件动态查询
还有一个情况就是我们的条件只有一个,但我们不知道是哪一个条件!
这就需要使用到 choose(when,otherwise)标签 实现, 而 choose 标签类似于Java 中的switch语句。
<!-- 单条件动态条件查询-->
<select id="selectByCondition" resultType="member">
select *
from member
where
<choose> <!--相当于switch -->
<when test="age != null"> <!--相当于case -->
age = #{age}
</when>
<when test="name != null and name != ''">
and name like #{name}
</when>
</choose>
</select>
但这样有个问题是当单个条件都没有时会多出一个where,此时跟上面一样,有两种解决方案!
方案一:借助otherwise多写一个恒等式
<!-- 单条件动态条件查询-->
<select id="selectByCondition" resultType="member">
select *
from member
where
<choose> <!--相当于switch -->
<when test="age != null"> <!--相当于case -->
age = #{age}
</when>
<when test="name != null and name != ''">
and name like #{name}
</when>
<otherwise> <!--相当于default -->
1 = 1
</otherwise>
</choose>
</select>
方案二 :用where标签
<!-- 单条件动态条件查询-->
<select id="selectByCondition" resultType="member">
select *
from member
<where>
<choose> <!--相当于switch -->
<when test="age != null"> <!--相当于case -->
age = #{age}
</when>
<when test="name != null and name != ''">
and name like #{name}
</when>
</choose>
</where>
</select>
添加和修改
添加
sql映射文件:
<insert id="add">
insert into member (name,gender,age)
values (#{name},#{gender},#{age});
</insert>
mapper接口
void add(Member member);
主要代码:
package com.aniu;
import com.aniu.mapper.MemberMapper;
import com.aniu.pojo.Member;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author:Aniu
* @Date:2023/4/13 22:07
* @description 增加
*/
public class MyBatisDemo4 {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// SqlSession sqlSession = sqlSessionFactory.openSession(true); // 开启自动提交
//3. 执行sql (只有这块需要手写,其他步骤直接复制)
MemberMapper memberMapper = sqlSession.getMapper(MemberMapper.class);
String name = "阿牛";
String gender = "男";
int age = 21;
Member member = new Member();
member.setGender(gender);
member.setName(name);
member.setAge(age);
memberMapper.add(member);
//手动提交事务
sqlSession.commit();
//4. 释放资源
sqlSession.close();
}
}
在数据添加成功后,有时候需要获取插入数据库数据的主键(主键是自增长)。
此时直接从pojo类中获取不到,sql映射文件里的insert语句要添加两个属性:
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into member (name,gender,age)
values (#{name},#{gender},#{age});
</insert>
修改
有修改部分字段,有全部修改,这里依旧使用动态sql来实现全部需求
sql映射文件:
<update id="update">
update member
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="gender != null and gender != ''">
gender = #{gender},
</if>
<if test="age != null">
age = #{age}
</if>
</set>
where id = #{id};
</update>
依然有逗号问题,所以用set标签处理
mapper接口:
int update(Member member);
主要实现:
public class MyBatisDemo4 {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// SqlSession sqlSession = sqlSessionFactory.openSession(true); // 开启自动提交
//3. 执行sql (只有这块需要手写,其他步骤直接复制)
MemberMapper memberMapper = sqlSession.getMapper(MemberMapper.class);
String name = "aniu";
int id = 5;
Member member = new Member();
member.setName(name);
member.setId(id);
int count = memberMapper.update(member);
System.out.println(count);
//手动提交事务
sqlSession.commit();
//4. 释放资源
sqlSession.close();
}
}
删除
根据id删除:
void deleteById(int id);
<delete id="deleteById">
delete from member where id = #{id};
</delete>
批量删除:
/**
* 批量删除
*/
void deleteByIds(int[] ids);
编写SQL语句:
在 MemberMapper.xml 映射配置文件中编写删除多条数据的 statement 。
编写SQL时需要遍历数组来拼接SQL语句。Mybatis 提供了 foreach 标签供我们使用:
- foreach 标签:用来迭代任何可迭代的对象(如数组,集合)。
- collection 属性:mybatis会将数组参数,封装为一个Map集合。
默认:array = 数组
使用@Param注解改变map集合的默认key的名称。 - item 属性:本次迭代获取到的元素。
- separator 属性:集合项迭代之间的分隔符。 foreach 标签不会错误地添加多余的分隔符。也就是最 后一次迭代不会加分隔符。
- open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
- close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
- collection 属性:mybatis会将数组参数,封装为一个Map集合。
<delete id="deleteByIds">
delete from member where id
in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
;
</delete>
使用@Param注解改变map集合的默认key的名称后:
void deleteByIds(@Param("ids") int[] ids);
主要测试代码:
package com.aniu;
import com.aniu.mapper.MemberMapper;
import com.aniu.pojo.Member;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
/**
* @Author:Aniu
* @Date:2023/4/14 19:36
* @description 批量删除
*/
public class MyBatisDemo5 {
public static void main(String[] args) throws IOException {
//1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取SqlSession对象,用它来执行sql
SqlSession sqlSession = sqlSessionFactory.openSession();
// SqlSession sqlSession = sqlSessionFactory.openSession(true); // 开启自动提交
//3. 执行sql (只有这块需要手写,其他步骤直接复制)
MemberMapper memberMapper = sqlSession.getMapper(MemberMapper.class);
int[] ids = {1,2,3};
memberMapper.deleteByIds(ids);
//手动提交事务
sqlSession.commit();
//4. 释放资源
sqlSession.close();
}
}
使用注解方实增删改查
使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发:
@Select(value = "select * from member where id = #{id}")
public Member select(int id);
注意:
- 注解是用来替换映射配置文件方式配置的,所以使用了注解,就不需要再映射配置文件中书写对应的 statement。
Mybatis 针对 CURD 操作都提供了对应的注解,已经做到见名知意。如下:
- 查询 :@Select
- 添加 :@Insert
- 修改 :@Update
- 删除 :@Delete
注意:在官方文档中 入门 中有这样的一段话:
所以,注解完成简单功能,配置文件完成复杂功能。这里对注解的使用不再举例!
结语
如果你觉得博主写的还不错的话,可以关注一下当前专栏,博主会更完这个系列的哦!也欢迎订阅博主的其他好的专栏。
🏰系列专栏
👉flask框架入门到实战
👉软磨 css
👉硬泡 javascript