MyBatis

MyBatis概念

  • MyBatis是一款优秀的持久层框架,用于简化JDBC开发
  • MyBatis本是 Apache的一个开源项目iBatis, 2010年这个项目由apache softwarefoundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github
  • 官网:https://mybatis.org/mybatis-3/zh/index.html

持久层

  • 负责将数据到保存到数据库的那一层代码
  • avaEE三层架构:表现层、业务层、持久层

框架

  • 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
  • 在框架的基础之上构建软件编写更加高效、规范、通用、可扩展

为什么简化

简化jDBC:免除JDBC代码以及设置参数和获取结果集的工作。

JDBC存在的缺点:

  1. 硬编码
    • 注册驱动,获取连接
    • SQL语句
  2. 操作繁琐
    • 手动设置参数
    • 手动封装结果集

Mapper代理开发

  1. 定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下
  2. 设置SQL映射文件的namespace属性为Mapper接口全限定名
  3. 在Mapper接口中定义方法,方法名就是SQL映射文件中sql语句的id,并保持参数类型和返回值
    类型一致
  4. 编码
    • 通过SqlSession的getMapper方法获取Mapper接口的代理对象
    • 调用对应方法完成sql的执行
    • 细节:如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载
1
2
3
4
5
// 获取UserMapper接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
System.out.println(users);

UserMapper.xml配置文件内

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
<!--
namespace: 名称空间
id: 方法
resultType: 返回值类型
-->
<mapper namespace="com.jpc.mapper.UserMapper">

<select id="selectAll" resultType="com.jpc.pojo.User">
select * from tb_user;
</select>
</mapper>


<!--
数据库表的字段名称和实体类的属性名称不一样,则不能自动封装数据
*起别名:对不一样的列名起别名,让别名和实体类的属性名一样
缺点:每次查询都要定义一次别名
sql片段缺点:不灵活
*resultMap:
定义<resultMap>标签
使用resultMap属性替换resultType属性
-->

<resultMap id="userResultMap" type="user">
<!--
id: 完成主键字段的映射
column: 表的列名
property: 实体类的属性名
result: 完成一般字段的映射
-->
<result column="user_name" property="userName" />
</resultMap>
<select id="selectAll" resultMap="userResultMap">
select * from tb_user;
</select>

配置文件完成增删改查

查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--
参数占位符:
1. #{}:会将其替换为?防止SQL注入
2. ${}:拼接sql,会存在SQL注入问题
参数类型:parameterType(可以省略)
特殊字符处理:
1. 转移字符 如(< 是&lt;)
2. CDATA区 <![CDATA[ < ]]>
-->

<select id="selectById" parameterType="int" resultMap="brandResultMap">
select *
from tb_brand where id = #{id};
</select>

多条件查询

mapper接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//方法一:
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName);




//方法二:
List<Brand> selectByCondition(Brand brand);




//方法三:
List<Brand> selectByCondition(Map map);

调用

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
//方法一:
// 接收的参数
int status = 1;
String companyName = "华为";

// 参数处理,因为是模糊查询
companyName = "%" + companyName + "%";

List<Brand> brands = brandMapper.selectByCondition(status, companyName);

System.out.println(brands);



//方法二:
// 接收的参数
int status = 1;
String companyName = "华为";

// 参数处理,模糊查询
companyName = "%" + companyName + "%";

// 封装对象
Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);

List<Brand> brands = brandMapper.selectByCondition(brand);
System.out.println(brands);


//方法三:
// 接收的参数
int status = 1;
String companyName = "华为";

// 参数处理,模糊查询
companyName = "%" + companyName + "%";

// 封装对象
Map map = new HashMap();
map.put("status", status);
map.put("companyName", companyName);

List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);

mapper映射文件

1
2
3
4
5
6
7
8
9
10
<!--方法一:-->
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where
status = #{status}
and company_name like #{companyName}
</select>

<!--方法二三和方法一一样-->

添加

mapper接口

1
void add(Brand brand);

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
	// 接收的参数
int status = 2;
String companyName = "小米有限公司";
String brandNmae = "红米";
String description = "为烧焦而生";
int ordered = 1;

Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandNmae);
brand.setOrdered(ordered);
brand.setDescription(description);
brandMapper.add(brand);

// 提交事务
// sqlSession.commit();

mapper映射文件

1
2
3
4
5
6
7
<!--
主键返回:在数据添加成功之后需要获取插入数据库主键的值
-->
<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>

修改

mapper接口

1
void update(Brand brand);

调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 接收的参数
int id = 6;
int status = 2;
String companyName = "小米有限公司";
String brandNmae = "红米";
String description = "为发烧而生";
int ordered = 100;

Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandNmae);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setId(id);

brandMapper.update(brand);

mapper映射文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<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 and ordered != ''">
ordered = #{ordered},
</if>
<if test="description != null and description != ''">
description = #{description},
</if>
<if test="status != null and status != ''">
status = #{status}
</if>
</set>
where id = #{id};
</update>

删除

mapper接口

1
void deleteById(int id);

调用

1
brandMapper.deleteById(id);

mapper映射文件

1
2
3
<delete id="deleteById">
delete from tb_brand where id = #{id};
</delete>

MyBatis参数传递

MyBatis 接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式>

单个参数

  1. POJO类型
  2. Map集合
  3. Collection
  4. List
  5. Array
  6. 其他类型

多个参数: 封装为Map集合,可以使用@Param注解

​ map.put(“arg0”, 参数1)

​ map.put(“param1”, 参数1)

​ map.put(“param2”, 参数2)

​ map.put(“arg1”, 参数2)

​ 替换:@Param(“username”) —- > map.put(“username”, 参数1)