一、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 {@Autowiredprivate UserMapper userMapper;//查询所有用户public List<UserInfo> queryAllUser(){return userMapper.queryAllUser();}
}//controller层
@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate 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片段