MyBatis学习笔记,快速入门
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语句
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下