教程揭秘 | 动力节点内部Java零基础教学文档第九篇:Mybatis
接上期后续
本期分享第九章节
Mybatis
已经分享过半了,你们都跟上了吗?
每天都在学习嘛?
有什么不会的嘛?
今日教学文档分享来了

今日新篇章
【Mybatis】
1. JDBC不足
JDBC作为Java操作数据库的模板,如果想要对数据库进行操作,必须使用JDBC,但是在使用JDBC进行数据库操作时,重复代码多,动态SQL构建繁琐,将查询结果转化为对象,相当麻烦,开发效率低。
基于JDBC开发效率相对低的情况,市面上各个组织,对JDBC进行封装,产生各种数据库操作层解决方案:
Hibernate 重量级的ORM框架
ibatis 轻量级ORM框架 与2010-06-16 改名 mybatis
Spring JPA
Mybatis plus
Spring JDBCTemplate
以上框架都是对JDBC的封装,处理Java操作数据库数据的问题。
2. 为什么要学习框架
2.1.1 提高开发效率
在Java中,框架在一定程度就是对某些功能的封装,对外暴露统一操作API,可以简化开发难度,提高开发效率。
2.1.2 提高代码的可维护性
由于框架在一定程度上说,就是模板,所有基于某个框架进行开发的项目,肯定要遵循模板规则,那么在维护时,只需要了解模板规则即可。
2.1.3 可以提高代码的健壮性
市面上相对比较流行的框架,被大多人使用,出现的问题能够及时暴露,问题也能得到较快的修复。
3. Mybatis概述
3.1 简介
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
Mybtais是一个ORM框架,轻量级的ORM框架。相对于重量级的ORM框架Hibernate而言,mybatis是一个半自动框架,而Hibernate是一个全自动框架。并且,Hibernate提出跨"平台",Hinernate的跨平台是指Hinernate可以在多种数据库下进行操作,同一套代码支持多种数据库,HQL语句,Hibernate方言,对数据库操作进行翻译,根据不同的数据,将API翻译成不同的SQL,对数据进行操作,依赖ORM思想。
Mybatis是一个半自动的框架,早期Hibernate在流行时,开发者发现Hibernate虽然功能强大,但是由于如果想使用全自动功能,将Hibernate和数据库关心进行配置,配置很繁琐,其二,Hibernate对功能进行全方面的封装,将用户的操作,转化为SQL语句,然后进行数据库操作,整个转换过程是Hibernate,开发无法控制,如果要进行SQL语句优化是没法实现的。所以,在数据库压力逐渐增大的情况下,Hibernate框架性能问题就出现了。基于这样的情况,Mybatis框架应运而生,mybatis将SQL语句的定义控制权,完全交给了开发者,并且暴露一套API,对JDBC中:事务,参数,查询结果等进行配置处理。Mybatis也是基于ORM思想.
Mybatis(半自动化):还是需要书写sql
Hibernate(全自动化):不需要写sql就能操作数据库--->HQL
3.2 ORM
ORM : Object relation mapping
对象关系映射
将数据库信息和Java中实体类进行映射
users: 1 张三 20 User: id、uName、age
4. Mybatis入门使用

4.1 创建数据库和表




4.2 创建空项目



4.3 创建Maven的java项目





4.4 引入Mybatis相关jar包依赖
1、导入依赖
2、书写mybatis的主配置文:连接信息 mybatis.xml
3、书写存放sql语句的局部配置文件 xxx.xml(与dao层类的类名保持一致)
4、关联主配置与局部配置
5、启动mybatis,调用核心类测试
4.5 编写实体类User
4.6 编写映射文件UserMapper接口
4.7 编写映射文件UserMapper.xml
4.8 编写mybatis.xml核心配置文件
4.9 编写测试类
4.10 执行过程简单分析
1.解析了xml 配置文件 ---> configuration
2. 将映射文件信息 解析 mappedStatements map结构 每个 mapper文件中的指令 被封装为MappedStatement
3. SqlSession 根据传入 statement 的key 从mappedStatements 中获取到对应 MappedStatement
4. MappedStatement 中已经定义了好了参数类型 返回结果的类型 还有原生sql
5. 获取原生sql 参数类型 返回结果的类型 ,根据参数类型 原生sql 可以内部预处理 sql 将sql 发送给数据库
6. 接收sql 执行的结果 ,将其封装为对应的返回类型

5. Mybatis进行CRUD
5.1 方式 一:指令ID方式
根据mybatis将映射信息封装为:MappedStatement对象,存在Map中,将namespace和指令ID当做key
根据key获取对应MappedStatement对象,进行数据库操作
5.1.1 创建项目修改pom.xml引入相关依赖

5.1.2 复制上个项目里面的所有类和配置

5.1.3 SqlSessionUtils工具类
5.1.4 数据库数据操作类UserDao
5.1.5 数据库数据操作映射配置UserMapper.xml
5.1.6 测试类
5.2 方式二:接口代理方式
使用Mapper接口的代理方式,根据方法名和映射文件中指令ID进行绑定,动态调用相关指令信息
5.2.1 创建项目修改pom.xml引入相关依赖

5.2.2 复制上个项目里面的所有类和配置文件

删除 dao
5.2.3 创建UserMapper接口
5.2.4 UserMapper.xml
5.2.5 测试类
6. Mybatis核心配置文件详解
6.1 数据源配置详解
6.2 引入db.properties配置文件详解
6.2.1 创建db.properties文件
6.2.2 修改mybatis.xml文件
6.3 别名优化详解
【注意】:别外配置必须是在enviroments之前
6.4 日志配置详解:有可能会报找不到日志类的异常
日志,就是将程序运行时,一些关键信息进行保存文件中的操作.当问题发生时,是无法观察控制台,将关键的信息保存在文件,便于后期检查。
日志主要分为以下级别:
debug调试模式时进行记录的调试信息
info具体信息
error 发生异常时可以进行记录的方法
debug级别最低
info级别高于DEBUG
error级别最高
6.4.1 引入日志相关jar包
6.4.2 创建log4j.properties的日志配置文件
6.4.3 修改mybatis.xml配置文件
6.4.4 测试并查看E盘的logs目录

7. Mybatis映射配置文件详解
7.1 结果映射
在mybatis中,默认将查询的结果返回一个实体类对象,查询结果和实体类根据结果列别名和类中属性名一一对应。当查询结果列别名和类属性名不一致。解决方案有两种:
l 将别名修改为一致
l 使用mybatis内置结果映射处理器
7.1.1 在映射文件中新增映射关系

7.1.2 注意
l 映射关系中,column查询结果的列别名,不是原始列名
l 在查询指令中,resultMap属性,指向定义的映射关系的ID
7.2 #和$(重点)
在mybatis中,会将开发者定义的sql进行解析,解析分为了2类sql:
静态sql ,在解析时,直接将参数拼接到sql中,这种就是静态sql conn.createStatement()
动态sql,在解析时,会使用?这个占位符,替代参数
conn.prepareStatement()
这两种解析方式,mybatis是根据${}和#{}进行区分的
${}的sql是静态sql ${uName}
#{}的sql是动态sql #{uName} #{arg0} #{param1} #{0}
不论是静态sql,还是动态sql都能获取传递参数,但是${}是使用的字符拼接,#{}使用PreparedStatement进行参数的预处理。
在一定程度上说,${}能实现的功能,#{}都能实现,并且由于#{}PreparedStatement进行SQL的预处理,一定程度上可以防止SQL注入攻击。所以在开发中,能使用#{}尽量使用#{}。
PreparedStatement预处理的本质是将参数进行转换为字符串,当做参数字符串处理。所以,如果参数信息是一个特殊的关键字,例如: 数据库名,表名,函数名,内置关键字,使用预处理,则关键字转为了字符串,无效了,此时必须使用字符串拼接。
7.2.1 $示例

7.2.2 #示例

7.3 SQL片段
在开发中,需要书写大量的SQL语句,并且这些SQL数据很大部分内容是重复内容,基于这样的情况,mybatis提供模板,可以在模板中定义需要使用sql语句的部分内容,然后在需要使用到这个部分内容的地方直接引入。
使用sql标签,定义SQL片段,使用include引入,sql片段
注意:
l 在sql片段中 id,是这个sql片段的唯一标识
l 在引入时,include标签中,refid关联sql片段的id
7.4 模糊查询(重点)
在mybatis中,模糊查询主要有3种方式:
l like concat('%',#{关键字},'%') 推荐
l like '%${关键字}%'
l mybatis推荐的bind标签
7.4.1 方案一[推荐]
7.4.2 方案二[拼接]
使用$存在sql注入攻击安全问题
7.4.3 方案三[bind]
7.5 多个参数问题(重点)
当mybatis传递参数存在多个时,mybatis支持三种方案:
argx 形式:arg 表示参数,x表示参数索引
paramX形式: param表示参数,x表示第几个参数
使用注解为参数取别名 @Param
方案三
7.6 分页查询(重点)
在mybatis中,分页查询解决方案最本质上回归原生SQL进行处理。
l 查询总页数,使用limit函数进行查询相应的数据
l mybatis中,提供了一个RowBounds这个类,用于进行分页查询数据
l 使用分页插件:PageHelper(推荐)
7.6.1 方案一[rowBounds]
使用RowBounds这种分页查询方式,在实际开发中是远远不够使用的,这种方式只是返回的相应的数据,总数据条数,页数,分页起始页都需要开发者自己处理。
7.6.2 方案二[分页插件]
市面主流分页插件: PageHelper
导入PageHelper的相关jar包
或者
在mybatis核心配置文件中开启插件
在代码显示声明后面紧邻(一次)查询语句需要使用分页
在PageHelper,每次开启分页,只对最近的一次查询有效。如果要多次分页查询,需要多次开启。
PageHelper是利用,拦截器原理,拦截最近的一次查询,然后在其基础拼接分页信息。PageHelper只对最近一次查询有效,这种模式,对本身的程序没有侵入,所以,本身程序该怎么写还是怎么写。
7.7 新增自增长(重点)
在mybatis中,支持数据库的自增长功能,因为在某些特殊的业务场景中,当前数据的ID,可能是另外某些数据的业务ID。
例如:
订单:总订单和子订单
每个子订单会有总订单ID
先插入总订单,并且要获取总订单ID
插入子订单
Mybatis在insert指令中,提供了2个属性:useGeneratedKeys、keyProperty、keyColumn
useGeneratedKeys:表示使用数据库自增长
keyProperty:自增长的列对应的类中的属性
keyColumn:自增长的列
Mybatis会自动将增长的值,封装到传入参数的属性中。
注意:
自增长值,会被自动封装在对象参数中
7.8 动态SQL(重点)
动态SQL是指根据不同的参数,产生不同的SQL语句。这样的SQL就是动态SQL。
Mybatis提供了一下标签,用于动态SQL的生成:
if
foreach
choose
where: 可以去除前置多余的and、or等挂关键字;不能去除后置
set
trim
7.8.1 if标签
在if标签中,test属性是必须有,test属性值是一个表达式,如果表达式值为true,则if标签包裹的内容会拼接在当前sql上。
and 并且
or 或者
== 等于
!= 不等于
示例:
7.8.2 foreach
循环标签,循环标签多用于批量操作。
例如:批量新增,批量删除等等
collection 待循环的容器
item 指代 每次循环容器中的元素
open 开始循环是拼接字符串
close 循环结束拼接字符串
separator 每次循环之间拼接的字符串
index 循环索引
choose
多条件分支标签:choose.
在choose标签,自上而下执行when中表达式,如果表达式为true,则将相应的字符串拼接在sql后面,且终止判断。如果所有的表达式都为false,则将otherwise中字符串,拼接在sql后面
7.8.3 where
在mybatis中,存在sql条件,当有多个sql条件时,需要处理and关键字问题,因为where后面的第一个条件不需要and,解决方案:
l 在where后面 拼接 1=1 类似的条件,这样其他条件都不是第一个条件,都需要拼接and
l mybatis 提供了where标签,取代where关键字,默认去掉第一个条件 and
注意:
建议,只在查询语句中使用where标签,因为当where标签中的条件都不成立时,会没有where关键字。
7.8.4 set标签
set标签是取代sql语句中的set关键字。set表示后面数据的更新。各个字段,需要使用逗号分隔。
set标签可以去掉最后一个逗号。
8. 缓存
mybatis为了提高查询效率、性能。提供了缓存,缓存分为2类:
l 一级缓存
l 二级缓存
一级缓存:是指SqlSession级别的缓存,在同一个SqlSession,同样的SQL语句只会执行一次,不是第一次执行的SQL会从缓存中获取数据。
二级缓存: 是指SqlSessionFactory级别的缓存,在同一个SqlSessionFactory中,同样的SQL语句,只会执行一次,不是第一次执行的SQL会从缓存中获取数据。
注意:
不论一级缓存还是二级缓存,否是JVM中缓存。当服务器有多台时,缓存容易发生无效,数据发生了更新。缓存没有更新。在实际使用,如果数据可能发生比较频繁的更新不建议使用mybatis。
8.1 一级缓存
8.2 二级缓存
二级缓存需要在映射文件中,开启缓存:
<cache />
并且被缓存的数据需要支持,序列化
9. Mybatis注解
mybatis配置虽然相对简单,但是还是麻烦。所以,mybatis为了简化配置,也提供了注解。
常用注解:
l @Select
l @Insert
l @Delete
l @Update
10. 逆向工程
1、 快速帮我们生成实体类
2、生成单表的crud
11. 联表查询(难点)
11.1 多表查询解决方案
1.写实体类,通过定义实体类,将多表的所有字段都涵盖,解决多表查询问题,但是,这种方案只能解决多对一,但是无法解决一对多问题。
例如:写实体类可以解决,一个学生类中班级信息问题,但是无法解决班级类中学生信息问题。
学生信息是一个数组。
2.多次查询。将需要结果拆分成多个简单的单表查询,连续查询多次。使用Java代码处理查询结果。
例如:学生班级信息。
查询某个学生学生信息及其班级信息。
根据ID查询学生信息
从学生信息中获取班级ID
根据班级ID查询班级信息
查询所有学生的信息及其班级信息
查询所有学生(100)(注意学生数据量)
查询所有班级(Map 使用ID 作为key 对象就是value)
循环学生,获取班级ID,从班级数据中,获取班级信息
注意:
mybatis解决联表查询的方法就是基于以上方案
11.2 多对一
11.2.1 将查询结果进行封装
11.2.2 进行多次查询
11.3 一对多
11.3.1 将查询结果封装
11.3.2 多次查询

更多干货我们下期再说!
下期会分享
第十章节
Spring
相关知识~
下期见!
