MyBatis
MyBatis中文官网https://mybatis.net.cn/
本篇笔记参照黑马程序员视频 教程 记录。
视频链接
MyBatis简介
- MyBatis是一款优秀的持久层框架,用于简化JDBC开发
持久层
- 负责将数据保存到数据库的那一层代码就是持久层
- JavaEE三层框架:表现层、业务层、持久层
JDBC缺点
- 硬编码
- 操作繁琐
MyBatis快速入门
步骤
- 创建表,添加数据
- 创建模块,导入坐标(MyBatis坐标、MySQL驱动坐标)
- 编写MyBatis核心配置文件--------》替换连接信息,解决硬编码问题
- 编写SQL映射文件------》统一管理SQL语句,解决硬编码问题
- 编码,写程序
- 定义POJO类
- 加载核心配置文件,获取SQLSessionFactory对象
- 获取Session对象,执行SQL语句
- 释放资源
第一次使用MyBatis
- 创建表,添加数据就不说了
- 在项目中导入MyBatis的jar包
- 在项目的resource目录下,编写mybatis的核心配置文件,MyBatis官网会有,直接复制过来即可,文件名称随意,但习惯是
mybatis-config.xml
,修改配置文件中的连接信息
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybase"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!-- 指定当前SQL映射文件-->
<mappers>
<!-- SQL映射文件,相对路径-->
<mapper resource="UserMapper.xml"/>
</mappers>
</configuration>
注意:
- MySQL8.0及以上版本,需要导入8.x的jar包,并且Driver地址为
com.mysql.cj.jdbc.Driver
, 之前版本不用变 - url的写法,一般是
jdbc:mysql://localhost:3306/数据库名
,也可以这样写jdbc:mysql:///数据库名
,默认就是localhost:3306
- 同样,在resources目录下编写SQL映射文件,这个文件也可以从官网直接复制过来,文件名称随意,但是一般都是以
ClassNameMapper.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">
<!--
namespace 命名空间
-->
<mapper namespace="test">
<!-- id是这条SQL语句的唯一标识
resultType是返回时的封装类型
-->
<!-- 对应类的全限名-->
<select id="selectAll" resultType="com.mybatis.Person">
select * from user;
</select>
</mapper>
- 编写数据库对应的类,并设置setter和getter方法,这个类名称一定要与SQL映射文件中的
resultType
相对应
package com.mybatis;
public class Person {
private int id ;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
- 加载MyBatis核心配置文件,获取SqlSessionFactory对象,这个官网也是直接复制过来即可:happy:
package com.mybatis;
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;
import java.util.List;
public class MyBatisDemo {
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对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.执行SQL,对应SQL语句的 namespace.id
List<Person> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
// 4.释放资源
sqlSession.close();
}
}
这就是最简单、入门的MyBatis流程了,刚开始确实感到繁琐
解决SQL语句报红提示
在入门案例映射配置文件中存在报红的情况。问题如下:
- 产生的原因:Idea和数据库没有建立连接,不识别表信息。但是大家一定要记住,它并不影响程序的执行。
- 解决方式:在Idea中配置MySQL数据库连接。
IDEA中配置MySQL数据库连接
-
点击IDEA右边框的
Database
,在展开的界面点击+
选择Data Source
,再选择MySQL
-
在弹出的界面进行基本信息的填写
-
点击完成后就能看到如下界面
而此界面就和
navicat
工具一样可以进行数据库的操作。也可以编写SQL语句
Mapper代理开发
概述
我们刚开始写的代码,也存在类似JDBC硬编码的问题
这个地方传递参数namespace.id
仍然是硬编码,不便于后期的维护。
如果使用Mapper代理方式则不存在硬编码问题,MyBatis官网也推荐使用Mapper的代理方式。
Mapper代理开发的规则
- 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和映射文件放置在同一目录下
- 设置SQL映射文件的
namespace.id
属性为Mapper接口权限名 - 在Mapper接口中定义方法,方法名就是SQL映射文件中的sql语句的id,并保持参数类型和返回值类型一致
实现
-
在源码目录下,创建Mapper包,包中创建
PersonMapper
接口 -
将SQL映射文件与mapper接口同目录下,有两种方法
-
第一种方式,我们可以直接将
xml
文件拖拽到mapper
包下但是这样不符合我们的规范,导致目录混乱
Maven中规定配置文件应该放置到
ressources
目录下 -
第二种方式,在
resources
目录下,创建与mapper
接口同结构目录这样,Maven在编译时,会自动将配置文件放置到mapper接口目录下
注意:在SQL映射文件中,
namespace
修改为对应接口的权限名,mybatis核心配置文件中映射文件的目录也要改 -
-
编写程序
package com.mybatis; import com.mybatis.mapper.PersonMapper; 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; import java.util.List; public class MyBatisDemo02 { public static void main(String[] args) throws Exception { // 1.加载mybatis配置文件 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 // 3.1 获取PersonMapper接口代理对象 PersonMapper personMapper = sqlSession.getMapper(PersonMapper.class); List<Person> perons = personMapper.selectAll(); System.out.println(perons); // 4.关闭资源 sqlSession.close(); } }
注意:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以在mybatis配置文件中,通过包扫描的方式简化SQL映射文件的加载
<!-- 指定当前SQL映射文件--> <mappers> <!-- <mapper resource="com/mybatis/mapper/PersonMapper.xml"/>--> <!-- 包扫描的方式--> <package name="com.mybatis.mapper"/> </mappers>
核心配置文件
MyBatis的核心配置文件有这些配置
在MyBatis的配置文件中的<configuration>
下,各种不同的标签应该按照这样的特点定的前后顺序来放置
environments
在核心配置文件的environments
标签中,可以配置多个environment
,使用id
给每个environment
做标识,在environments
标签中使用default=环境id
来指定使用哪一个环境
这些环境可以是不同的库,甚至可以是不同品牌的数据库
<environments default="test">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- 连接信息-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybase"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///mybase"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
类型别名
在SQL映射配置文件中,resultType
属性需要我们填写类的全限定名,特别麻烦。
MyBatis提供了typeAliases
可以简化这部分书写,别名不区分大小写
可以使用这种方式来为某一个特定的类起别名
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
我们还可以使用包扫描的方式来为包下的每一个类起一个别名,默认就是类名,且不区分大小写
<typeAliases>
<package name="com.mybatis"/>
</typeAliases>
这样,在SQL映射文件中可以直接使用类的名称
<select id="selectAll" resultType="Person">
select * from user;
</select>
配置文件完成增删改查
安装MyBatisX插件
MyBatisX是一款基于IDEA的快速开发插件,为效率而生
直接在IDEA中setting
—>plugins
搜索安装即可
主要功能
- XML映射配置文件和接口方法 间相互跳转
- 根据接口方法生成statement
查询所有数据
-
编写Mapper接口
package com.mybatis.mapper; import com.mybatis.pojo.Brand; import java.util.List; public interface BrandMapper { List<Brand> selectAll(); }
-
编写SQL映射文件
<?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"> <!-- namespace 命名空间 --> <mapper namespace="com.mybatis.mapper.BrandMapper"> <!-- id是这条SQL语句的唯一标识 resultType是返回时的封装类型 --> <select id="selectAll" resultType="Brand"> select * from tb_brand; </select> </mapper>
-
编写测试程序
package com.mybatisTest; import com.mybatis.mapper.BrandMapper; import com.mybatis.pojo.Brand; 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 org.junit.Test; import java.io.IOException; import java.io.InputStream; import java.util.List; public class testMybatis { @Test public void testSelectAll() throws IOException { // 1.加载mybatis配置文件 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 2.获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 3.获取对应的mapper BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); // 4.执行SQL List<Brand> brands = mapper.selectAll(); System.out.println(brands); // 4.释放资源 sqlSession.close(); } }
表字段与类属性名转换
我们发现这样一个问题,查询出来的结果并没有为实体类成功赋值
这是因为数据库中表的字段名与实体类的属性名不一致导致的
解决方法
-
使用别名
<select id="selectAll" resultType="Brand"> select id,brand_name as brandName,company_name as companyName,ordered,description,status from tb_brand; </select>
这样是可以解决的,但是如果查询的语句多了,这样写就会非常繁琐
-
使用SQL片段
我们将需要复用的SQL片段抽取到sql标签中,并为这段SQL片段设置id
<sql id="brandColumn">id,brand_name as brandName,company_name as companyName,ordered,description,status </sql>
在原来的sql语句上直接拼接即可,使用
<include refid="">
来引用<select id="selectAll" resultType="Brand"> select <include refid="brandColumn"/> from tb_brand; </select>
但是这种SQL片段仍然存在局限性,例如其他查询的字段名并不是这些,那么就需要重新抽取SQL片段,依然是很繁琐,不灵活
-
使用resultMap
就是给数据库表的字段名与类属性名之间做一个映射
只需要对不一样的字段做映射,使用
<resultMap>
来定义字段和属性的映射<resultMap id="mapBrand" type="brand"> <result column="brand_name" property="brandName"></result> <result column="company_name" property="companyName"></result> </resultMap>
SQL语句的返回值类型,需要指定结果映射id
<select id="selectAll" resultMap="mapBrand"> select * from tb_brand; </select>
查询一条数据
查看某一条具体的数据,在SQL语句中就需要传参了
-
编写
BrandMapper
接口中方法Brand selectById(int id);
-
编写SQL语句
注意: 使用的是
resultMap
不是resultType
<select id="selectById" resultMap="mapBrand"> select * from tb_brand where id = #{id}; </select>
-
编写测试方法
@Test public void testSelectById() throws IOException { int id = 1; // 1.加载mybatis配置文件 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 2.获取SqlSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); // 3.获取对应的mapper BrandMapper mapper = sqlSession.getMapper(BrandMapper.class); // 4.执行SQL Brand brand = mapper.selectById(id); System.out.println(brand); // 4.释放资源 sqlSession.close(); }
参数占位符
在Mapper接口中的方法需要传入参数,在与之对应的SQL映射文件中的SQL语句需要来接收这个参数。
mybatis提供了两种参数占位符
-
#{}
:执行SQL时,会将#{}
占位符替换为?
,将来运行时自动设置参数,底层用的是PreparedStatement
-
${}
:拼接SQL,底层是Statement
,存在SQL注入的问题
parameterType使用
对于有参数的mapper接口方法,我们在映射配置文件中可以使用parameterType
来指定参数类型,只不过该属性可以省略
<select id="selectById" parameterType="int" resultMap="mapBrand">
select * from tb_brand where id = #{id};
</select>
特殊字符处理
当sql 语句中存在特殊字符时,比如小于号<
解决方法
-
转义字符
<select id="selectById" parameterType="int" resultMap="mapBrand"> select * from tb_brand where id < #{id}; </select>
-
<!CDATA[内容]]>
<select id="selectById" parameterType="int" resultMap="mapBrand"> select * from tb_brand where id <![CDATA[ < ]]> #{id}; </select>
多条件查询
-
编写接口方法
该方法有三个参数,我们就需要考虑在定义接口时,参数应该如何定义,这些参数等会传到SQL语句那,如何才能让SQL语句辨别?MyBatis针对参数有多重实现方式
-
使用
@Param("参数名称")
标记一个参数,在SQL语句中需要用#{参数名称}
来占位Brand selectByCondition(@Param("status") int status, @Param("brandName") String brandName, @Param("companyName") String companyName);
-
将多个参数封装成一个实体对象,将该实体对象作为方法的参数。
要求实体对象中的属性名与SQL语句中的
#{占位符}
一致List<Brand> selectByCondition(Brand brand);
-
将这多个参数封装到Map集合中,将map集合作为方法的参数。
同样,也是要求Map集合中的键与sql语句中的
#{占位符名}
保持一致List<Brand> selectByCondition(Map map);
- 编写SQL语句
<select id="selectByCondition" resultMap="mapBrand">
select *
from tb_brand
where status = #{status}
and brand_name like #{brandName}
and company_name like #{companyName};
</select>
- 编写测试方法
@Test
public void testSelectByCondition() throws IOException {
// 假设的参数
int status = 1;
String brandName = "华为";
String companyName = "华为";
brandName = "%" + brandName + "%";
companyName = "%" + companyName + "%";
// 1.加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应的mapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 方式一:直接传参,注解的方式
// List<Brand> brands = mapper.selectByCondition(status, brandName, companyName);
// List<Brand> brands = mapper.selectByCondition(brand);
// 方式二:封装成对象
// Brand brand = new Brand();
// brand.setStatus(status);
// brand.setBrandName(brandName);
// brand.setCompanyName(companyName);
// List<Brand> brands = mapper.selectByCondition(brand);
// 方式三:封装成一个Map集合
Map map = new HashMap<String, String>();
map.put("status", status + "");
map.put("brandName", brandName);
map.put("companyName", companyName);
// 4.执行SQL
List<Brand> brands = mapper.selectByCondition(map);
System.out.println(brands);
// 4.释放资源
sqlSession.close();
}
}
动态SQL
多条动态查询
其实上面的代码处理还是有些问题:用户必须同时选择三个条件才可以查询得到。但是现实生活中,往往用户只会输入一个或两个条件,这样也应该查询出相对应的数据。
这就需要动态SQL了
当用户只输入当前状态时,SQL语句应该是这样的
select * from tb_brandd where status = #{status};
当用户只输入企业名称时,SQL语句应该是这样的
select * from tb_brand where company_name like #{companyName};
针对这种情况,就需要在SQL拼接时进行判断
MyBatis对动态SQL有很强大的支持
if
choose(when, otherwise)
trim(where,set)
foreach
-
if标签:条件判断
- 属性:test逻辑表达式
<!-- 动态SQL查询--> <select id="selectByCondition" resultMap="mapBrand"> select * from tb_brand where <if test="status != null"> status = #{status} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName} </if> ; </select>
查看运行结果
上面的SQL语句仍然存在Bug,当我们不给status值时,SQL语句就变成了这样
select * from and brand_name like #{brandName} and company_name like #{companyName};
显然不符合sql语句的规范,会导致出错
-
解决方案
- 添加恒等式,像这样,SQL语句就不会出错
<!-- 动态SQL查询--> <select id="selectByCondition" resultMap="mapBrand"> select * from tb_brand where 1=1 <if test="status != null"> and status = #{status} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName} </if> ; </select>
-
MyBatis提供了
<where>
标签,可以用来替代where关键字MyBatis会动态的判断某个条件前面需不需要加
and
<!-- 动态SQL查询--> <select id="selectByCondition" resultMap="mapBrand"> select * from tb_brand <where> <if test="status != null"> and status = #{status} </if> <if test="brandName != null and brandName != '' "> and brand_name like #{brandName} </if> <if test="companyName != null and companyName != '' "> and company_name like #{companyName} </if> </where> ; </select>
单条动态查询
当用户对条件作出选择时,选择出一个,类似于Java中的switch
对于这样的switch
结构,MyBatis中也是支持的
<choose> <!--相当于switch> -->
<when></when> <!--相当于case -->
<otherwise></otherwise> <!-- 相当于default -->
</choose>
<select id="selectBySingleCondition" resultMap="mapBrand">
select *
from tb_brand
where
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
</choose>
;
</select>
当用户 一个都不选的时候,我们的SQL语句就变成了这样
select * from tb_brand where;
可以通过<otherwise>
来指定默认的情况
<select id="selectBySingleCondition" resultMap="mapBrand">
select *
from tb_brand
where
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
;
</select>
这样写还是有些牵强,这时候<where>
标签又派上用场了,它能够判断里面的条件有没有成立的,从来来生成正确的SQL语句
<select id="selectBySingleCondition" resultMap="mapBrand">
select *
from tb_brand
<where>
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<when test="companyName != null and companyName != '' ">
company_name like #{companyName}
</when>
<otherwise>
1 = 1
</otherwise>
</choose>
</where>
;
</select>
添加数据
当在页面中添加一个商品时,就需要用到插入的功能了
商品的ID应该是不需要我们手动输入的,自增的主键
<insert id="add">
insert into tb_brand(brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
编写测试程序
@Test
public void testAdd() throws IOException {
// 假设的参数
int status = 1;
String brandName = "蓝翔挖掘机学校";
String companyName = "山东蓝翔";
String description = "挖掘技术哪家强,中国山东找蓝翔";
int orderd = 1999;
// 1.加载mybatis配置文件
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取对应的mapper
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 封装成对象
Brand brand = new Brand();
brand.setStatus(status);
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setDescription(description);
brand.setOrdered(orderd);
// 4.执行SQL
mapper.add(brand);
// 4.释放资源
sqlSession.close();
}
通过控制台的日志输出,我们知道添加成功了,但是在数据库查询却没有
这是因为MyBatis在执行这条SQL语句时,帮我们开启了事务,当SQL执行完成了,它又进行了事务回滚,就导致没有成功插入,这就需要我们手动提交事务。
可以在执行完成SQL语句后,通过调用方法来提交事务
// 4.执行SQL
mapper.add(brand);
// 提交事务
sqlSession.commit();
当然,我们也可以在获得SqlSession
对象的时候,设置参数为true,这样就能帮我们自动提交事务
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
主键返回
返回添加数据的主键
在数据添加成功后,有时候我们需要获取插入数据的主键,来用于接下来的操作
来看一下,通过该对象来获取id,发现是null
其实我们插入成功后,id值也就有了,但是没有绑定到我们的这个对象身上
可以在SQL语句部分这样写
<!-- useGenerateKeys:获取自动增长的主键值,true表示获取
keyProperty:指定主键是表的哪一个字段
-->
<insert id="add" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand(brand_name, company_name, ordered, description, status)
values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
这样就绑定到了对象身上
修改功能
修改全部字段
写SQL
<update id="update">
update tb_brand
set brand_name = #{brandName},
company_name = #{companyName},
brand_name = #{brandName},
description = #{description},
status = #{status}
where id = #{id};
</update>
注意 : 提交事务
修改动态字段
当用户需要修改一个字段时,并不需要修改全部字段,这时候就需要做出判断,之前也做过
<update id="update">
update tb_brand
set
<if test="brandName != null">
brand_name = #{brandName},
</if>
<if test="companyName != null">
company_name = #{companyName},
</if>
<if test="ddescription != null">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
where id = #{id};
</update>
经过前几次的学习,我们肯定能判断出这个SQL语句是有问题的,因为假如没有一个if
条件成立,那么SQL语句就会出错
同样,Mybatis中提供了与<where>
标签类似的功能,<set>
标签,他能够判断哪些条件成立,哪些条件不成立,做出争取的SQL语句
<update id="update">
update tb_brand
<set>
<if test="brandName != null and brandName != '' ">
brand_name = #{brandName},
</if>
<if test="companyName != null and companyName != '' ">
company_name = #{companyName},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null">
status = #{status}
</if>
<if test="ordered != null">
ordered = #{ordered}
</if>
</set>
where id = #{id};
</update>
删除功能
删除一个
没啥说的
<delete id="delete">
delete from tb_brand where id = #{id};
</delete>
批量删除
当用户需要批量删除时,对应的SQL语句就要发生变化了
在实际开发中,批量删除时,我们会将多个参数封装成一个数组,那么在接口中应该这样定义
void deleteByIds(int[] ids);
我们一般需要删除多条数据时,会这样写
delete from tb_brand where id in (?,?,?);
但是我们并不知道这个数组中有几个数据,所以就不知道写多少个占位符。
MyBatis中提供了<foreach>
标签来遍历容器
foreach标签
-
collection
属性,用来指定遍历的容器名注意:MyBatis会将数组参数,封装为一个Map集合
- 默认: array = 数组
- 可以在方法定义时,用
@Param
注解来指定map集合默认的key名称
-
item
属性:本次迭代获取的元素名称 -
separator
属性:集合迭代之间的分隔符 -
open
属性:该属性值是在拼接SQL语句时的符号 -
close
属性:拼接结束时的符号
<!-- 批量删除-->
<delete id="deleteByIds">
delete from tb_brand
where
id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
这样,当我们有数组中有几个元素,就会动态的生成几个?
参数传递
MyBatis的对接口中的参数以及在对应SQL语句之间参数是如何封装、传递的。
MyBatis接口方法中可以接收各种各样的参数
- 多个参数
- 单个参数: 可以是一下类型
- POJO类型:自定义类
- Map集合类型
- Collection集合类型
- List集合类型
- Array类型
- 其他类型
多个参数
当我们的接口方法中定义了多个参数时,MyBatis会将这些参数封装成Map集合对象,值就是参数值,当我们没有使用@Param
时,Map中默认的的键是这样的
以arg开头
第一个参数的键是"arg0",第二个参数的键是"arg1",以此类推
map.put(“arg0”,参数值1);
map.put(“arg1”,参数值2);
还有一个键,是以param开头的
map.put(“param1”,参数值1);
map.put(“param2”,参数值2);
这两个键都是适用的,可以掩饰一波
这是接口方法
Person select(Integer id, String name);
这是SQL映射文件中 的SQL语句
<select id="select" resultMap="personMap">
select *
from user
where id = #{arg0}
and name = #{arg1};
</select>
或
<select id="select" resultMap="personMap">
select *
from user
where id = #{param1}
and name = #{param2};
</select>
这两种SQL写法 都是可以查询到同样的结果
当我们使用了@Param
注解后,MyBatis会将arg替换成注解中的名称,但是param的键还是会存在的
接口方法
Person select(@Param("id") Integer id, String name);
SQL语句
<select id="select" resultMap="personMap">
select *
from user
where id = #{id}
and name = #{param2};
</select>
不推荐使用Map默认设置的两种键的方式,推荐使用注解参数的方式,因为这样代码的可读性就会变强
单个参数
-
POJO类型,也就是我们自定义的对象类型
直接使用,只要保证属性名和SQL语句的参数占位符名称一致即可
-
Map集合类型
直接使用,只要Map集合中的键与SQL语句的参数占位符名称一致即可
-
其他类型
直接使用,比如说,String , Integer等常用的类型
接下来的这几个对象就有些特殊了😄
-
Collection集合类型
MyBatis会将此类对象封装到map集合中
map.put("arg0",collection对象); map.put("collection",collection对象);
-
List集合类型
也会封装到Map集合中
map.put("arg0",list对象); map.put("collection",list集合); map.put("list",list集合);
-
Array类型
照样封装到Map集合中
map.put("arg0",数组); map.put("array",数组);
只需要记住,用注解@Param
来即可,书写起来更方便,代码的可读性更强
注解开发
使用配置文件和注解开发的本质是一样的,但是使用注解会更加方便
@Select("select * from user where id = #{id}")
Person select(int id);
针对不同类型的SQL语句,MyBatis提供了四种注解
- 查询:@Select
- 添加:@Insert
- 修改:@Update
- 删除:@Delete
使用注解来完成简单的SQL语句,使用SQL配置文件来完成复杂的SQL语句