Mybatis框架基础案例实践

文章详细介绍了如何使用MyBatis进行数据库操作,包括查询所有数据、按条件查询、添加数据、修改数据和删除数据的方法。涉及到Mapper接口的定义、XML映射文件的编写、动态SQL的使用,以及参数处理等关键步骤。
摘要由CSDN通过智能技术生成

一、环境与数据准备

//(1).创建数据库表(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);

//(2).创建实体类 Brand
在 com.itheima.pojo 包下创建 Brand 实体类。
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private String description;
private Integer status;
//省略 setter and getter
}
//(3).编写测试用例
测试代码需要在 test/java 目录下创建包及测试用例。
//(4).安装mybatisX插件

二、查询
1. 查询所有方法
(1).编写接口方法:Mapper接口
查询所有数据功能是不需要根据任何条件进行查询的
List<Brand> selectAll();
(2).结果:List,将查询出来的每一条数据封装成一个 Brand 对象,而多条数据封装多个 Brand 对象,需要将这些对象封装到List集合中返回。
<select id = "selectAll" resultType = "brand">
        select * from tb_brand;
</select>

(3).执行方法测试

(案例实现)
//在 com.itheima.mapper 包写创建名为 BrandMapper 的接口。并在该接口中定义 List<Brand> selectAll() 方法。
public interface BrandMapper {
List<Brand> selectAll();
}
//在 reources 下创建 com/itheima/mapper 目录结构,并在该目录下创建名为 BrandMapper.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">
<mapper namespace="com.itheima.mapper.BrandMapper">
        <select id="selectAll" resultType="brand">
                select * from tb_brand;
        </select>
</mapper>
//在 MybatisTest 类中编写测试查询所有的方法
@Test
public void testSelectAll() throws IOException {
//1. 获取SqlSessionFactory
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 brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
List<Brand> brands = brandMapper.selectAll(); //前面部分是固定得写法
System.out.println(brands);
//5. 释放资源
sqlSession.close();
}
注意:以后只会写上面的第3步的代码,其他的都不需要我们来完成。

执行结果:有些数据封装成功了,而有些数据并没有封装成功。
brandName 和 companyName 这两个属性的数据没有封装成功,查询 实体类 和 表中的字段 发现,在实体类中属性名是 brandName 和 companyName ,而表中的字段名为 brand_name 和 company_name

这个问题可以通过两种方式进行解决:
给字段起别名;使用resultMap定义字段和属性的映射关系
说明:写sql语句时给这两个字段起别名,将别名定义成和属性名一致即可。
<select id="selectAll" resultType="brand">
        select id, brand_name as brandName, company_name as companyName, ordered, description, status from tb_brand;
</select>
上面的SQL语句中的字段列表书写麻烦,如果表中还有更多的字段,同时其他的功能也需要查询这些字段时就显得代码不够精炼。Mybatis提供了 sql 片段可以提高sql的复用性。
1.1 SQL片段(需要用就去定义,不灵活)
(1).将需要复用的SQL片段抽取到 sql 标签中
<sql id="brand_column">
        id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>
(2).在原
sql语句中进行引用
使用
include 标签引用上述的 SQL 片段,而 refid 指定上述 SQL 片段的id值。
<select id="selectAll" resultType="brand">
        select <include refid="brand_column" /> from tb_brand;
</select>
1.2 使用resultMap解决上述问题

(1). 在映射配置文件中使用resultMap定义 字段 和 属性 的映射关系
<resultMap id="brandResultMap" type="brand">
        <!--
                id:完成主键字段的映射
                column:表的列名
                property:实体类的属性名
                result:完成一般字段的映射
                column:表的列名
                property:实体类的属性名
        -->
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
</resultMap>
注意:在上面只需要定义 字段名 和 属性名 不一样的映射,而一样的则不需要专门定义出来。
(2).SQL语句正常编写
<select id="selectAll" resultMap="brandResultMap">
        select * from tb_brand;
</select>
2. 查询详情
(1). 编写接口方法:
Mapper接口
Brand selectByid(int id);
参数:
id —> 查询某一行数据,需要根据id进行查询。而id以后是由页面传递过来。
结果:Brand —> 据
id查询出来的数据只要一条,而将一条数据封装成一个Brand对象即可
(2). 编写SQL语句:SQL映射文件
<select id = "selectByid" parameterType = "int" resultType = "brand">
        select * from tb_brand where id = #{id};
</select>
(3). 执行方法 Brand brand = brandMapper.selectById(id);
1.1 参数占位符
#{} :执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。//打印出?
${} :拼接SQL。底层使用的是 Statement ,会存在SQL注入问题。//打印直接拼接
1.2 SQL语句中特殊字段处理
eg. select * from tb_brand where id < #{id};//报错了,> < 等这些字符在xml中有特殊含义
可用 &lt; 就是 < 的转义字符;< ! [ CDATA [ < ] ]>
3. 多条件查询
(1).编写接口方法
在 BrandMapper 接口中定义多条件查询的方法。
而该功能有三个参数,我们就需要考虑定义接口时,参数应该如何定义。
(1.1). 使用 @Param("参数名称") 标记每一个参数,在映射配置文件中就需要使用 #{参数名称} 进行占位
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String
companyName,@Param("brandName") String brandName);
(1.2). 将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和实体类属性名保持一致。
List<Brand> selectByCondition(Brand brand);
(1.3). 将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用 #{内容} 时,里面的内容必须和map集合中键的名称一致。
List<Brand> selectByCondition(Map map);

(2). 编写SQL语句
<select id="selectByCondition" resultMap="brandResultMap">
        select * from tb_brand where status = #{status}
        and company_name like #{companyName}
        and brand_name like #{brandName}
</select>
(3). 编写测试方法

int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
//4. 执行方法
//方式一 :接口方法参数使用 @Param 方式调用的方法
//List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);
//方式二 :接口方法参数是 实体类对象 方式调用的方法
//封装对象
/* Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);*/
//List<Brand> brands = brandMapper.selectByCondition(brand);
//方式三 :接口方法参数是 map集合对象 方式调用的方法
Map map = new HashMap();
map.put("status" , status);
map.put("companyName", companyName);
map.put("brandName" , brandName);
List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);

(4). 动态SQL
用户在输入条件时,肯定不会所有的条件都填写,这个时候我们的SQL语句就不能那样写的
(1.1). if 标签:条件判断
test 属性:逻辑表达式
<select id="selectByCondition" resultMap="brandResultMap">
        select * from tb_brand 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>
</select>
如果拼接语句为 select * from tb_brand where and company_name like ? and brand_name like ?
上面的语句中
where 关键后直接跟 and 关键字,这就是一条错误的SQL语句
(1.2). where 标签
替换where
关键字;会动态的去掉第一个条件前的and;如果所有的参数没有值则不加where关键字
//把原来得where换成 <where></where>
注意:需要给每个条件前都加上
and 关键字。
5. 单个条件(动态SQL)
(1). BrandMapper 接口中定义单条件查询的方法
List<Brand> selectByConditionSingle(Brand brand);
(2). 编写SQL语句
在 BrandMapper.xml 映射配置文件中编写 statement ,使用 resultMap 而不是使用 resultType
<select id="selectByConditionSingle" resultMap="brandResultMap">
        select * from tb_brand
        <where>
                <choose><!--相当于switch-->
                        <when test="status != null"><!--相当于case-->
                                status = #{status}
                        </when>
                        <when test="companyName != null and companyName != '' "><!--相当于case-->
                                company_name like #{companyName}
                        </when>
                        <when test="brandName != null and brandName != ''"><!--相当于case-->
                                brand_name like #{brandName}
                        </when>
                </choose>
        </where>
</select>
(3).编写测试方法
在 test/java 下的 com.itheima.mapper 包下的 MybatisTest类中 定义测试方法
//封装对象
Brand brand = new Brand();
//brand.setStatus(status);
brand.setCompanyName(companyName);
//brand.setBrandName(brandName);
List<Brand> brands = brandMapper.selectByConditionSingle(brand);
三、添加数据
1. 编写接口方法
void add(Brand brand);
参数:除了id之外的所有的数据。id对应的是表中主键值,而主键我们是自动增长生成的。
2. 编写SQL语句
<insert id = "add">
        insert into tb_brand(brand_name,company_name,ordered,description,status)
value(#{brandName},#{conpanyName},#{ordered},#{description},#{statue});
</insert>
3. 执行程序

//接收参数
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);

//4. 执行方法
brandMapper.add(brand);
//5. 提交事务
sqlSession.commit();//除了查询,其他都要提交事务

注意:想要返回id值,需要添加标签
在 insert 标签上添加如下属性:
useGeneratedKeys:是够获取自动增长的主键值。true表示获取
keyProperty :指定将获取到的主键值封装到哪儿个属性里

四、修改
​1. ​​​​​​ 编写接口方法
在 BrandMapper 接口中定义修改方法。
void update(Brand brand)
上述方法参数 Brand 就是封装了需要修改的数据,而id是有数据的,这也是和添加方法的区别。
2. 编写SQL语句
在 BrandMapper.xml 映射配置文件中编写修改数据的 statement 。
<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="ordered != null">
                        ordered = #{ordered},
                </if>
                <if test="description != null and description != ''">
                        description = #{description},
                </if>
                <if test="status != null">
                        status = #{status}
                </if>
        </set>
        where id = #{id};
</update>
set 标签可以用于动态包含需要更新的列,忽略其它不更新的列。
3. 执行程序

//接收参数
int status = 0;
String companyName = "波导手机";
String brandName = "波导";
String description = "波导手机,手机中的战斗机";
int ordered = 200;
int id = 6;
//封装对象
Brand brand = new Brand();
brand.setStatus(status);
// brand.setCompanyName(companyName);
// brand.setBrandName(brandName);
// brand.setDescription(description);
// brand.setOrdered(ordered);
brand.setId(id);
int count = brandMapper.update(brand);
System.out.println(count);

五、删除
1.删除一行数据
(1) .编写接口方法
在 BrandMapper 接口中定义根据id删除方法。
void deleteById(int id);
(2). 编写SQL语句
在 BrandMapper.xml 映射配置文件中编写删除一行数据的 statement
<delete id="deleteById">
        delete from tb_brand where id = #{id};
</delete>
(3). 执行程序
int id = 6;//接收参数
brandMapper.deleteById(id);//执行方法
2. 批量删除
(1). 编写接口方法
在 BrandMapper 接口中定义删除多行数据的方法。
void deleteByIds(int[] ids);//参数是一个数组,数组中存储的是多条数据的id
(2). 编写SQL语句
在 BrandMapper.xml 映射配置文件中编写删除多条数据的 statement 。
编写SQL时需要遍历数组来拼接SQL语句。
(1.1). foreach 标签 用来迭代任何可迭代的对象(如数组,集合)。
collection 属性:mybatis会将数组参数,封装为一个Map集合。
                默认:array = 数组
                使用@Param注解改变map集合的默认key的名称
item 属性:本次迭代获取到的元素。
separator 属性:集合项迭代之间的分隔符。 foreach 标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。
open 属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一次
close 属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
<delete id="deleteByIds">
        delete from tb_brand where id
        in
        <foreach collection="array" item="id" separator="," open="(" close=")">
                #{id}
        </foreach>
        ;
</delete>
(3). 运行代码
int[] ids = {5,7,8};//接收参数
brandMapper.deleteByIds(ids);//执行代码
六、Mybatis参数传递
1. 多个参数
接收两个参数,而接收多个参数需要使用 @Param 注解
User select(@Param("username") String username,@Param("password") String password); 
<select id="select" resultType="user">
        select * from tb_user
        where
                username=#{username}
                and password=#{password}
</select>
Mybatis 会将这些参数封装成 Map 集合对象,值就是参数值,而键在没有使用 @Param
以 arg 开头 :第一个参数就叫 arg0,第二个参数就叫 arg1
map.put("arg0",参数值1);map.put("arg1",参数值2)
以 param 开头 : 第一个参数就叫 param1,第二个参数就叫 param2
map.put("param1",参数值1);map.put("param2",参数值2);
结果分析:在映射配合文件的SQL语句中使用用 arg 开头的和 param 书写,代码的可读性会变的特别差,此时可以使用 @Param注解。
在接口方法参数上使用 @Param 注解,Mybatis 会将 arg 开头的键名替换为对应注解的属性值。
结论:以后接口参数是多个时,在每个参数上都使用 @Param 注解。这样代码的可读性更高。

2. 单个参数
(1). POJO 类型
直接使用。要求 属性名 和 参数占位符名称 一致
(2).Map 集合类型
直接使用。要求 map集合的键名 和 参数占位符名称 一致
(3).Collection 集合类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put("arg0",collection集合);
map.put("collection",collection集合;
可以使用 @Param 注解替换map集合中默认的 arg 键名。
(4).List 集合类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put("arg0",list集合);
map.put("collection",list集合);
map.put("list",list集合);
可以使用 @Param 注解替换map集合中默认的 arg 键名。
(5). Array 类型
Mybatis 会将集合封装到 map 集合中,如下:
map.put("arg0",数组);
map.put("array",数组);
可以使用 @Param 注解替换map集合中默认的 arg 键名。
(6).其他类型
int类型, 参数占位符名称 叫什么都可以。尽量做到见名知意
七、注解实现CRUD
使用注解开发会比配置文件开发更加方便。如下就是使用注解进行开发
@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);
注意:注解替换映射配置文件方式配置,使用了注解不需要再映射配置文件中写对应的 statement
查询 :@Select;添加 :@Insert;修改 :@Update;删除 :@Delete
具体操作步骤
(1).将之前案例中 UserMapper.xml 中的 根据id查询数据 的 statement 注释掉
(2).在 UserMapper 接口的 selectById 方法上添加注解
(3).运行测试程序也能正常查询到数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

符气满满

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值