一、MyBatis介绍
MyBatis 是持久层框架,它支持自定义 SQL、存储过程以及⾼级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置 和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.1 MyBatis功能
MyBatis 是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库工具
2.2 框架交互流程图
MyBatis 也是⼀个 ORM 框架, ORM(Object Relational Mapping),即对象关系映射。在面向
对象编程语言中,将关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象
的互相转换:
(1)将输⼊数据(即传⼊对象)+SQL 映射成原生SQL
(2)将结果集映射为返回对象,即输出对象
ORM 把数据库映射为对象:
-
数据库表(table)—> 类(class)
-
记录(record,行数据)—> 对象(object)
-
字段(field) —> 对象的属性(attribute)
一般的 ORM 框架,会将数据库模型的每张表都映射为⼀个 Java 类。 也就是说使用MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间的转换。
二、搭建MyBatis开发环
添加MyBatis框架时要同时添加对应数据库驱动,他们总是成对存在
项目所需基本依赖
创建完SSM项目,项目中添加了Mybatis + MySQL.之后,项目启动,一定会报错!!!这是正常现象,因为没有配置数据库连接信息
2.1 注解实现Mybatis操作
yml文件配置数据库连接信息
spring:
datasource:
# user是数据库的名称
url: jdbc:mysql://127.0.0.1:3306/user?characterEncoding=utf8&useSSL=false
# 数据库用户名
username: root
# 数据库密码
password: "123456"
通过注解来进行数据库的操作
(1)@Select
//Mapper层
@Mapper
public interface UserMapper {
//查询所有⽤⼾
@Select("select * from userinfo")
public List queryAllUser();
}
//service层
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
//查询所有用户
public List<UserInfo> queryAllUser(){
return userMapper.queryAllUser();
}
}
//controller层
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
//查询所有用户
@RequestMapping("/queryAllUser")
public List<UserInfo> queryAllUser(){
return userService.queryAllUser();
}
}
使⽤#{} 的方式获取⽅法中的参数
public interface UserInfoMapper {
@Select("select * from userinfo where id= #{id} ")
UserInfo queryById(Integer id);
}
数据库中的字段名与Java中对象名字不一致时,如何配置让数据库与属性匹配?
2.2 XML实现Mybatis(前提配置Maven)
2.2.1 配置数据库连接信息
1、配置数据库连接信息
spring:
datasource:
# user是数据库的名称
url: jdbc:mysql://127.0.0.1:3306/user?characterEncoding=utf8&useSSL=false
# 数据库用户名
username: root
# 数据库密码
password: "123456"
driver-class-name: com.mysql.cj.jdbc.Driver
2.2.2 配置 MyBatis 映射文件位置路径
这个配置使 MyBatis 能够扫描指定目录下的所有映射文件,并将它们加载到 MyBatis 的配置中,以便在运行时使用这些映射文件中的 SQL 语句和映射规则。此处映射到当前目录的mapper目录下的所有带有·Mapper.xml的文件
声明接口
@Mapper
public interface UserXmlMapper {
//声明查询所有用户信息的接口
public List<UserInfo> queryXmlAllUser();
}
2.2.3 xml文件实现sql语句查询
三、解决数据库字段名与java对象属性名不一致问题
如果Java属性和mysql的字段一样, mybatis会进行自动赋值,如果不一样,则不赋值
(1)起别名
(2)结果映射
使⽤
id
属性给该
Results
定义别名,使⽤
@ResultMap
注解来复⽤其他定义的
ResultMap
(3)开启驼峰命名
驼峰命名规则:abc_xyz=>abcXyz
• 表中字段名:abc_xyz
• 类中属性名:abcXyz
三、mybatis进阶
3.1 #{属性名}和${属性名}区别
当是$时,sql语句id中会被直接替换为设置的值
当是#时,sql语句中为预编译处理会被替换为?占位符
因此当
$:
如果是整数时,不受影响,当为字符串时直接为username=张三,但是sql只能识别username='张三',所以推荐使用#更安全
但在特定情况下只能使用$
比如给查询的数据排序select * from userinfo order by desc
此时传入排序规则desc/asc(逆序/顺序)必须使用
$直接替换,否则使用#会预编译处理识别成字符串加引号,这样sql识别,语句就会发生错误
#和$区别
1.$存在SQL注入的问题,会将参数作为sql的一部分,造成信息泄露等问题
2.$直接替换;#是预处理。
3.
$使用注意事项:一定是可以穷举的值,在使用之前一定要对传递的值进行合法性验证(安全性验证)。
四、动态SQL
4.1 if标签
//Controller
//1、if标签
@RequestMapping("/addUserByIf")
public Integer addUserByIf(){
UserInfo userInfo = new UserInfo();
userInfo.setAge(11);
userInfo.setPassword("ifififififfi");
userInfo.setUsername("if标签测试2");
return userXmlService.addUserByIf(userInfo);
}
//Service
//1、if标签
public Integer addUserByIf(UserInfo userInfo) {
return userXmlMapper.addUserByIf(userInfo);
}
//Mapper
Integer addUserByIf(UserInfo userInfo);
//xm文件
//
<insert id="addUserByIf" >
insert into userinfo(
username,
<if test="age != null">age,</if>
<if test="gender != null">gender,</if>
password)
values(
#{username},
<if test="age != null">#{age},</if>
<if test="gender != null"> gender,</if>
#{password}
)
</insert>
注册信息时有必填字段和非必填字段,可以使用if标签实现sql。使用if标签中的内容,如果程序中有数据则将字段执行到sql中,否则sql排除该字段
4.2 trim标签
•
prefix:表示整个语句块,以prefix的值作为前缀
•
suffix:表
示
整个语句块,以suffix的值作为后缀
•
prefixOverrides:表
示
整个语句块要去除掉的前缀
•
suffixOverrides:表
示
整个语句块要去除掉的后缀
<insert id="insertUserByCondition">
INSERT INTO userinfo
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username !=null"> username, </if>
<if test="password !=null"> password, </if>
<if test="age != null"> age, </if>
<if test="gender != null"> gender, </if>
<if test="phone != null"> phone, </if>
</trim>
VALUES
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="username !=null"> #{username}, </if>
<if test="password !=null"> #{password}, </if>
<if test="age != null"> #{age}, </if>
<if test="gender != null"> #{gender}, </if>
<if test="phone != null">#{phone} </if>
</trim>
</insert>
在以上sql动态解析时,会将第⼀个部分做如下处理:
•
基于
prefix
配置,开始部分加上
(
•
基于
suffix
配置,结束部分加上
)
•
多个组织的语句都以
,
结尾,在最后拼接好的字符串还会以
,
结尾,会基于
suffixOverrides
配置去掉最后⼀个
,
•
注意
中的
username
是传⼊对象的属性
4.3 where标签
<select id="queryByCondition" resultType="com.example.demo.model.UserInfo">
select id, username, age, gender, phone, delete_flag, create_time, update_time from userinfo
<where>
<if test="age != null"> and age = #{age} </if>
<if test="gender != null"> and gender = #{gender} </if>
<if test="deleteFlag != null"> and delete_flag = #{deleteFlag} </if>
</where>
</select>
删除代码块最前面的and
查询条件为空时去除where关键字
4.4 set标签
<update id="updateUserByCondition"> update userinfo
<set>
<if test="username != null"> username = #{username}, </if>
<if test="age != null"> age = #{age}, </if>
<if test="deleteFlag != null"> delete_flag = #{deleteFlag}, </if>
</set>
where id = #{id}
</update>
动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号.(⽤于update语句中)
4.5 foreach标签
对集合进⾏遍历时可以使⽤该标签。标签有如下属性:
•
collection:绑定方法参数中的集合,如List,Set,Map或数组对象
•
item:遍历时的每⼀个对象
•
open:语句块开头的字符串
•
close:语句块结束的字符串
•
separator:每次遍历之间间隔的字符串
<delete id="deleteByIds">
delete from userinfo
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
4.6 sql标签与include标签
<sql id="allColumn">
id, username, age, gender, phone, delete_flag, create_time, update_time
</sql>
<select id="queryAllUser" resultMap="BaseMap">
select
<include refid="allColumn"></include>
from userinfo
</select>
我们可以对重复的代码⽚段进⾏抽取,将其通过 标签封装到⼀个SQL⽚段,然后再通过标签进行引用。
•
定义可重用的SQL片段
•
通过属性refid,指定包含的SQL片段