Mybatis入门
Mybatis入门

序
Mybatis是持久层(也就是三层架构中的Dao层)的一款框架,简化了JDBC的开发。内容来自视频->Day08-14. Mybatis-入门-快速入门程序_哔哩哔哩_bilibili。
入门
快速入门
开启一个模版程序,实现使用Mybatis查询所有用户数据
- 准备工作(创建springboot文件,定义实际类User,数据库表user)
- 添加mybatis相关依赖,配置mybatis(数据库连接信息)
- 编写SQL语句(注解/XML)

创建springboot文件,与springboot入门中的创建方法基本一致,注意要勾选Mybatis Framework和MySQL Driver依赖。
实际类要与user的字段保证一致,int->Integer,varchar->String,tinyint->Short,主要使用其包装类,同时声明相应的getset方法、构造器、toString方法。
mybatis配置:
1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver |
编写SQL语句(注解/XML)
1 | //在运行时,MyBatis会扫描这个接口,并为其生成一个实现类对象(代理对象),并交给IOC管理 |
单元测试
1 | //springboot整合单元测试的注解 |
配置SQL提示
在上边的SQL语句中,如果没有配置,那么就不会显示相应的提示,即使写错了也不会提醒,这对于开发是非常不利的。好在Idea中可以为其配置MySQL数据库连接。
- 选中SQL语句,右键,配置为MySQL语句
- 点击右侧边栏的数据库选项,点击加号,数据源选择MySQL,填写host、port、用户和密码、数据库
数据库连接池
- 数据库连接池是个容器,负责分配、管理数据库连接
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
- 能够释放空闲时间超过最大空闲时间的连接,避免因为没有释放连接引起的数据库连接遗漏
- 好处:资源重用 提升系统响应速度 避免数据库连接遗漏
标准接口:DataSource
- 官方提供的数据库连接池接口,由第三方组织实现此接口
- 功能:获取连接
常见产品:C3P0、DBCP、Druid、Hikari
lombok
在序-快速入门中,在实际类的编写中我们自己手动构造了getset、toString等方法,较为繁琐。改进方法就是使用lombok。lombok是一个实用Java类库,能通过注解的形式自动生成getset方法、构造器、toString等方法,并可以自动化生成日志日志变量,简化Java开发、提高效率。
注解 | 作用 |
---|---|
@Getter、@Setter | 提供getset方法 |
@ToString | 提供tostring方法 |
@EqualsAndHashCode | 重写equals和hashCode方法 |
@Data | 上边三个的整合 |
@NoArgsConstructor | 无参构造器 |
@AllArgsConstructor | 含餐构造器 |
直接添加注解是会报错的,还需要导入lombok的依赖,可以写注解然后根据IDEA自动导入依赖。
CRUD操作
CRUD操作是mybatis使用的核心,这一部分以实操为主
首先进行工程的准备工作,和入门的工程基本一致。
关于实体类的创建的注意点:
- 注意在数据库表结构中字段名是使用下划线分隔的,但是在实体类中我们采用驼峰命名
在mybatis中实现删除操作
根据主键删除
在Mapper接口中编写如下方法和语句,#{…}是占位符,用于将方法的参数提取出来。
1 | //删除 |
日志输出
1 | #配置mybatis的日志,指定输出到控制台 |
日志的输出如下
==> Preparing: delete from user where id =? ==> Parameters: 9(Integer) <== Updates: 1
可以看到输出的SQL语句带有“?”,这个就被称为预编译SQL。
它有两大优势:
- 性能更高
- 更安全(防止SQL注入)
为什么性能更高?
需要从SQL语句具体的执行过程来分析
SQL语句执行
graph LR
A[Java] ==> B(SQL语法解析检查)
subgraph SQL处理流程[缓存]
B ==> C(优化SQL)
C ==> D(编译SQL)
end
D ==> E(执行SQL)
对比两种方式
第一种
delete from user where id =1
delete from user where id =2
delete from user where id =3
第二种
delete from user where id = ?
1
2
3
这两种性能的差别就是因为这个缓存的过程,在Java发送SQL语句之后,会先经过检查、优化、编译,然后被缓存起来,之后再发送的时候会先检查缓存种是否有这个SQL语句,如果有就直接执行了。
第一种的话由于三条SQL语句每条都不相同,所以需要编译三次,而第二种的话由于是预编译的形式,所以只用编译一次,后边三条SQL语句就可以直接执行。
由此我产生一个问题,使用多态性是否也同样能提高Java的效率?
为什么更安全?
这里主要是与另一种占位符作对比
#{…}
-
执行SQL时,会将#{…}替换为?,生成预编译SQL,会自动设置参数值
-
使用时机:参数传递,都使用#{…}
${…}
- 拼接SQL。直接将参数拼接在SQL语句中,存在SQL注入问题
- 使用时机:很少使用,如果对表名、列表进行动态设置时使用
SQL注入:通过操作输入的数据来修改实现定义好的SQL语句,以达到执行代码对服务器进行攻击的方法
举个栗子🌰
账户的登录操作其实就是查询数据库中用户表的相应username和password是否都存在
1 | select count(*) from emp where username='miku' and password ='123456'; |
如果count(*)>=1,那么我们就认为密码正确,就可以放行了。
若使用的是${…}
那么就是直接拼接的形式,如果传入的是这样的(“用户名任意填”,”‘ ’ or ‘1’=‘1”)
SQL语句就会变成
1 | select count(*) from emp where username='miku' and password ='' or '1'='1'; |
这样就是一个恒成立的条件,那么也会直接放行。
这里只是举个例子,实际上现在是个网站都会防SQL注入,渗透也没有这么简单。
若使用的是#{…}
那么就会直接传递给?,就会直接拿传递的参数去数据库查询,不会更改SQL的基本逻辑。
在mybatis中实现新增操作
基本插入
最简单的插入,不含占位符,无参数传递, 也最没有用
1 |
|
使用占位符传递,注意与实用类的属性名保持一致,使用小驼峰命名
1 |
|
获取主键
在@Insert注解上添加注解@Options(keyProperty = “id”,useGeneratedKeys = true)会自动将生成的主键值,赋值给emp对象的id属性
在mybatis中实现更新操作
很简单,会SQL语句就会更新操作
直接上代码
1 |
|
在mybatis中实现查询操作
根据Id查询
1 |
|
代码比较简单,就是设置一个传参的SQL语句就可以了
但是有一个问题,比如日期update_time这些MySQL和Java命名规范不一样的字段,是不会进行自动封装的,也就是说直接查是查不到的。相应有三种解决方案:
- 配置自动映射
1 | mybatis.configuration.map-underscore-to-camel-case=true |
这是最简单也是最推荐的一种方案,只要保证符合命名规范,就能够自动封装
- 使用别名
1 |
- 使用@Results注解
1 |
后两种都比较繁琐,很少用
条件查询
考虑下面一个需求:
查询员工,根据员工的姓名、性别、入职时间搜索满足条件的员工信息。要求:员工姓名支持模糊匹配,性别精确匹配,入职时间进行范围查询。对查询的结果根据最后修改时间进行倒序排序。
编写出的SQL语句应该是这样的:
1 | select * from user where name like '%张%' and gender=1 and entry_date between |
用Mybatis实现:
1 |
|
注意,在这里使用了concat (‘%’,#{name},‘%’)函数,这是因为如果直接替换为‘%#{name}%’,是不合法的,因为?占位符不能出现在引号内,只能使用${…},可是这样就会有性能低、安全性低的问题。那么就使用了SQL的函数concat,它用于将多个字符串拼接起来,这样就解决了问题。
参数名说明
在SpringBoot1.X版本,参数名前必须要加上@Param(“字段名”),才能进行传递,这是因为在这个版本是不会把形参名保留下来,所以就必须要加上注解。
XML映射文件
定义规范
- XML的文件名称与Mapper接口的名称一致,并且放置在相同包下(同包同名)
- XML的namespace属性与Mapper接口的全限定名一致
- XML中SQL语句的id与Mapper接口中的方法名一致,有返回值的要写resultType属性,这个是单条记录所封装的类型(也就是说如List结构,要写他的单挑记录的数据类型)
动态SQL
学习动态SQL就是要学习其响应的标签
1.
- 用判断条件是否成立,如果条件为true,则拼接SQL
- 形式:
1 | <if test="name != null">...</if> |
2.
- where元素只会在子元素有内容的情况下才插入where子句,而且会自动去除子句开头的and或or
3.
- 动态地在行首插入set关键字,并会删除额外的逗号。(用在update语句中)
4.
- SQL语句
1 | delete from user where id in(12,13,14); |
- 接口方法
1 | //批量删除 |
- XML映射文件
1 | <delete id="deleteBytes"> |
标签属性说明:
collection:集合名称
item:集合遍历出来的元素/项,与下边占位符名称一致
separator:每一次遍历使用的分隔符
open:遍历开始前拼接的片段
close:遍历结束后拼接的片段
5.
为提高复用性,可以将sql用
1 | <!--纪录--> |