之前介绍了MyBatis的快速入门以及Mapper代理开发,作为一款优秀的持久层框架,就不得不探讨一下MyBatis实现的增删改查功能了,而这也是我们学习的重点和核心所在。这次通过b站黑马的品牌数据增删改查案例,来学习MyBatis实现的增删改查功能,内容如下。
一、环境准备 1、创建tb_brand表,添加数据 打开Navicat,连接MySQL,选择一个数据库,通过新建查询的方式创建tb_brand表,并添加数据。 对应的sql代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 drop table if exists tb_brand;create table tb_brand( id int primary key auto_increment, brand_name varchar (20 ), company_name varchar (20 ), ordered int , description varchar (100 ), status int ); insert into tb_brand (brand_name, company_name, ordered, description, status)values ('三只松鼠' , '三只松鼠股份有限公司' , 5 , '好吃不上火' , 0 ), ('华为' , '华为技术有限公司' , 100 , '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界' , 1 ), ('小米' , '小米科技有限公司' , 50 , 'are you ok' , 1 ); SELECT * FROM tb_brand;
2、编写实体类 Brand 新建一个mybatis-demo1的Maven项目,pom.xml里的坐标信息只需要将上次的复制过来就行。在其java目录下创建一个Brand实体类(com.itweb.pojo.Brand)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 package com.itweb.pojo;public class Brand { private Integer id; private String brandName; private String companyName; private Integer ordered; private String description; private Integer status; public Integer getId () { return id; } public void setId (Integer id) { this .id = id; } public String getBrandName () { return brandName; } public void setBrandName (String brandName) { this .brandName = brandName; } public String getCompanyName () { return companyName; } public void setCompanyName (String companyName) { this .companyName = companyName; } public Integer getOrdered () { return ordered; } public void setOrdered (Integer ordered) { this .ordered = ordered; } public String getDescription () { return description; } public void setDescription (String description) { this .description = description; } public Integer getStatus () { return status; } public void setStatus (Integer status) { this .status = status; } @Override public String toString () { return "Brand{" + "id=" + id + ", brandName='" + brandName + '\'' + ", companyName='" + companyName + '\'' + ", ordered=" + ordered + ", description='" + description + '\'' + ", status=" + status + '}' ; } }
3、准备测试用例 在项目的 test目录下创建一个MyBatisTest的测试类(com.itweb.test.MyBatisTest),如下
4、安装MyBatisX插件 MybatisX是一款基于IDEA的快速开发插件,为效率而生。 主要功能: 1)XML和接口方法相互跳转 2)根据接口方法生成statement 安装步骤: File->settings->Plugins,搜索MybatisX,点击install安装即可,如下。
二、查询功能 1、查询所有数据 1.1 实现步骤 1)编写接口方法 (Mapper接口)
参数:无 结果:List<Brand>
在java目录下创建一个BrandMapper接口(com.itweb.mapper.BrandMapper),代码如下
1 2 3 4 5 6 7 8 9 10 11 package com.itweb.mapper;import com.itweb.pojo.Brand;import java.util.List;public interface BrandMapper { public List<Brand> selectAll () ; }
2)编写SQL语句 (SQL映射文件) 在resources目录下创建一个mapper目录(com/itweb/mapper),并在该目录下创建一个BrandMapper.xml文件。同时直接在resources目录下复制之前用到的logback.xml和mybatis-config.xml文件。
注:在resources目录下创建分层的包要用 / 而不是 .
BrandMapper映射文件里的代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 <?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.itweb.mapper.BrandMapper" > <select id ="selectAll" resultType ="com.itweb.pojo.Brand" > select * from tb_brand; </select > </mapper >
3)编写测试用例并执行方法 在之前准备好的MyBatisTest的测试类下,编写如下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package com.itweb.test;import com.itweb.mapper.BrandMapper;import com.itweb.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 MyBatisTest { @Test public void testSelectAll () throws IOException { String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); List<Brand> brands = brandMapper.selectAll(); System.out.println(brands); sqlSession.close(); } }
执行方法,结果如下,虽然成功查询出了所有数据,但是存在字段为null的问题,这是由于实体类的属性名与数据库表的列名不一致造成的。
4)解决属性名与列名不一致问题 在BrandMapper.xml映射文件中做相应的修改。 法1:
起别名,对不一样的类名起别名,别名与实体类属性名一样。缺点是每次查询都要定义一次别名。解决方案 => 定义 sql片段,提高复用性(但该方法又有不灵活的缺点)。
1 2 3 4 5 6 7 8 9 10 <sql id ="brand_column" > id, brand_name as brandName, company_name as companyName, ordered, description, status </sql > <select id ="selectAll" resultType ="com.itweb.pojo.Brand" > select <include refid ="brand_column" /> from tb_brand; </select >
法2:resultMap (最常用) (1)定义<resultMap>标签 (2)在<select>标签中,使用resultMap属性替换resultType属性
定义 resultMap 完成不一致的属性名和列名的映射。其中id是主键字段的映射,result是一般字段的映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <resultMap id ="brandResultMap" type ="com.itweb.pojo.Brand" > <result column ="brand_name" property ="brandName" /> <result column ="company_name" property ="companyName" /> </resultMap > <select id ="selectAll" resultMap ="brandResultMap" > select * from tb_brand; </select >
修改完成后,再次运行测试类,就可以正常显示了。 至此,查询所有数据的功能已实现。
2、查看详情 2.1 实现步骤 1)编写接口方法 (Mapper接口)
参数: id 结果: Brand
在BrandMapper接口里添加方法
1 2 3 4 Brand selectById (int id) ;
2)编写SQL语句 (SQL映射文件) 在BrandMapper.xml映射文件里添加SQL
1 2 3 <select id ="selectById" resultMap ="brandResultMap" > select * from tb_brand where id = #{id}; </select >
3)编写测试用例并执行方法 在MyBatisTest测试类里面添加测试方法(直接复制一份之前的把方法名还有其他一些稍作改动即可) 执行结果如下图 4)相关总结
3、条件查询 3.1 多条件查询实现步骤 sql语句分析
注:like为模糊查询
1)编写SQL语句 (SQL映射文件) 在BrandMapper.xml映射文件里添加SQL
1 2 3 4 5 6 7 <select id ="selectByCondition" resultMap ="brandResultMap" > select * from tb_brand where status = #{status} and company_name like #{companyName} and brand_name like #{brandName} </select >
2)编写接口方法 (Mapper接口)
参数:所有查询条件 结果:List<Brand>
SQL 语句设置多个参数的方式(3种)
在BrandMapper接口里添加方法
1 2 3 4 5 6 7 8 9 10 11 12 List<Brand> selectByCondition (@Param("status") int status,@Param("companyName") String companyName,@Param("brandName") String brandName) ; List<Brand> selectByCondition (Brand brand) ; List<Brand> selectByCondition (Map map) ;
3)编写测试用例并执行方法 在MyBatisTest测试类里面添加测试方法(直接复制一份之前的把方法名还有其他一些稍作改动即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @Test public void testSelectByCondition () throws IOException { int status = 1 ; String companyName = "华为" ; String brandName = "华为" ; companyName = "%" + companyName + "%" ; brandName = "%" + brandName + "%" ; String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName); System.out.println(brands); sqlSession.close(); }
运行结果,查询成功。同理可运行2或3,打开注释运行即可,结果一样都能查询成功。 4)存在问题分析 上述虽然可以查询成功,但却是基于用户将各搜索框都输入了之后才能查询成功,比如有3个搜索框,当用户只输入1个时,就不能查询成功了。因此,接下来的动态条件查询就是用于解决该问题。
3.2 多条件动态查询 动态SQL:SQL语句会随着用户的输入或外部条件的变化而变化。
参考官方文档:https://mybatis.org/mybatis-3/dynamic-sql.html
Mapper接口不用变,只需要改造SQL语句就行。在BrandMapper.xml映射文件里修改SQL,将上一次条件查询的代码注释掉,添加如下代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <select id ="selectByCondition" resultMap ="brandResultMap" > select * from tb_brand /* where 1 = 1*/ <where > <if test ="status != null" > and status = #{status} </if > <if test ="companyName != null and companyName != '' " > and company_name like #{companyName} </if > <if test ="brandName != null and brandName != '' " > and brand_name like #{brandName} </if > </where > </select >
执行测试方法,只往Map集合里添加一个字段如companyName,即相当于用户查询时只输入一个条件,发现成功查询出数据。
3.3 单条件动态查询
1.从多个条件中选择一个 2.choose (when, otherwise):选择,类似于Java中的 switch语句
1)编写接口方法 (Mapper接口)
参数:brand 结果:List<Brand>
在BrandMapper接口里添加方法
1 2 3 4 5 6 List<Brand> selectByConditionSingle (Brand brand) ;
2)编写SQL语句 (SQL映射文件) 在BrandMapper.xml映射文件里添加SQL(用了<where>标签)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <select id ="selectByConditionSingle" resultMap ="brandResultMap" > select * from tb_brand <where > <choose > <when test ="status != null" > status = #{status} </when > <when test ="companyName != null and companyName != '' " > company_name like #{companyName} </when > <when test ="brandName != null and brandName != ''" > brand_name like #{brandName} </when > </choose > </where > </select >
3)编写测试用例并执行方法 在MyBatisTest测试类里面添加测试方法(直接复制一份之前的把方法名还有其他一些稍作改动即可)
三、添加功能
1、实现步骤 1)编写接口方法 (Mapper接口) 在BrandMapper接口里添加方法
1 2 3 4 5 void add (Brand brand) ;
2)编写SQL语句 (SQL映射文件) 在BrandMapper.xml映射文件里添加SQL
1 2 3 4 5 <insert id ="add" > insert into tb_brand(brand_name,company_name,ordered,description,status) values (#{brandName},#{companyName},#{ordered},#{description},#{status}); </insert >
3)编写测试用例并执行方法 在MyBatisTest测试类里面添加测试方法(直接复制一份之前的把方法名还有其他一些稍作改动即可)
注:不要忘记提交事务,非常关键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 / 添加 @Test public void testAdd () throws IOException { int status = 1 ; String companyName = "波导手机" ; String brandName = "波导" ; String description = "手机中的战斗机" ; int ordered = 100 ; Brand brand = new Brand (); brand.setStatus(status); brand.setCompanyName(companyName); brand.setBrandName(brandName); brand.setDescription(description); brand.setOrdered(ordered); String resource = "mybatis-config.xml" ; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder ().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class); brandMapper.add(brand); sqlSession.commit(); sqlSession.close(); }
上面的方法为手动提交事务,除此之外,还可以设置自动提交事务。
1 2 SqlSession sqlSession = sqlSessionFactory.openSession(true );
执行测试方法,测试成功后返回 Navicat查询数据库表,发现添加成功。
2、主键返回 返回添加数据的主键
1 <insert useGeneratedKeys="true" keyProperty="id" >
四、修改功能 1、修改全部字段
1.1 实现步骤 1)编写接口方法 (Mapper接口)
参数:所有数据 结果: void
在BrandMapper接口里添加方法
1 2 3 4 5 6 int update (Brand brand) ;
2)编写SQL语句 (SQL映射文件) 在BrandMapper.xml映射文件里添加SQL
1 2 3 4 5 6 7 8 9 10 11 <update id ="update" > update tb_brand set brand_name = #{brandName}, company_name = #{companyName}, ordered = #{ordered}, description = #{description}, status = #{status} where id = #{id} </update >
3)编写测试用例并执行方法 在MyBatisTest测试类里面添加测试方法(直接复制一份之前的把方法名还有其他一些稍作改动即可),如下 执行测试方法,测试成功后返回 Navicat查询数据库表,发现修改成功。
2、修改动态字段 接口方法和之前的一样,SQL语句的修改见上图,测试方法如下(只接收某个字段如 status) 执行测试方法,测试成功后返回 Navicat查询数据库表,发现修改成功。
五、删除功能 1、删除一个 接口方法和SQL语句见上图,测试代码也只需简单修改即可,如下 执行测试方法,发现数据成功被删除。
2、批量删除 所谓批量删除,就是可以一次选中多个并删除。 接口方法和SQL语句见上图,测试代码也只需简单修改即可。关于SQL语句的编写,需要注意如下
1 2 3 4 5 6 7 8 9 10 11 12 13 <delete id ="deleteByIds" > delete from tb_brand where id in <foreach collection ="ids" item ="id" separator ="," open ="(" close =")" > #{id} </foreach > ; </delete >
执行测试方法 返回 Navicat查询结果,发现批量删除成功。
六、参数传递
结论:建议将来都使用 @Param注解来修改 Map集合中默认的键名,并使用修改后的名称来获取值,这样可读性更高!
1、多个参数 封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
1 2 3 4 5 6 7 8 9 map.put("arg0" ,参数值1 ) map.put("param1" ,参数值1 ) map.put("param2" ,参数值2 ) map.put("agr1" ,参数值2 ) ---------------@Param("username") map.put("username" ,参数值1 ) map.put("param1" ,参数值1 ) map.put("param2" ,参数值2 ) map.put("agr1" ,参数值2 )
1 User select (@Param( "username") string username ,string password) ;
2、单个参数 2.1 POJO类型 直接使用,属性名 和 参数占位符名称一致
2.2 Map集合 直接使用,键名 和 参数占位符名称一致
2.3 Collection 封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
1 2 map.put("arg0" ,collection集合); map.put("collection" ,collection集合);
2.4 List 封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
1 2 3 map.put("arg0" ,list集合); map.put("collection" ,list集合); map.put("list" ,list集合);
2.5 Array 封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
1 2 map.put("arg0" ,数组); map.put("array" ,数组);
2.6 其他类型 直接使用
七、注解开发 使用注解开发,编写的接口方法,如
1 2 @Select("select * from tb_user where id = #{id}") User selectById (int id) ;
可以看出,确实更加方便简洁,但注解不是任何情况下都是好用的。下面截取的是官方文档原话。
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java注解不仅力不从心,还会让你本就复杂的SQL语句更加混乱不堪。因此,如果你需要做一些很复杂的操作,最好用XML来映射语句。