官方文档:mybatis – MyBatis 3 | Introduction
什么是MyBatis:
持久层框架、简化JDBC
如何获得MyBatis:
Maven仓库:
org.mybatis mybatis3.4.6
GitHub:Release mybatis-3.5.2 · mybatis/mybatis-3 · GitHub
中文文档:mybatis – MyBatis 3 | 简介
持久化:
数据:内存-->硬盘
为什么要持久化?因为内存里面的数据,一断电就没了
持久层:
完成持久化工作的代码块,并且层的界限十分明显
为什么需要MyBatis:
可以帮助程序员将数据存入到数据库中,并且传统的JDBC太复杂了,需要简化。
sql和代码分离,可维护性高。
第一个MyBatis程序:
思路:搭建环境-->导入MyBatis-->编写代码-->测试
搭建环境:
搭建数据库:
新建表:
插入数据:
然后得到表:
新建项目:
新建一个普通的Maven工程,并且删掉src目录,这样的话,就可以把它当做一个父工程了。再导入依赖:
然后在MyBatis工程里面,创建一个模块mybatis-01。
然后复制官方文档里面的xml配置文件:
粘贴到mybatis-config.xml中:
再修改一下:
然后编写Mybatis的工具类:
官方文档:
自己编写的工具类:
注意:一旦创建了SqlSessionFactory,就不再需要SqlSessionFactoryBuilder了。但是SqlSessionFactory一旦被创建,运行期间就一直存在。而且它默认是单例模式的。
SqlSession是线程不安全的,所以不能被共享。而且每次收到的Http请求,就可以打开一个SqlSession,返回一个响应,就关闭它(一定要关闭)。
所以要手动添加一个try..catch
编写代码:
实体类:
Dao接口:
接口实现类(由原来的UserDaoImpl转换为UserMapper.xml配置文件):
官方文档:
复制粘贴到UserMapper.xml 然后修改:
测试(用Junit):
运行之后会报一个错:
原因:没有把UserMapper.xml注册到mybatis-config.xml中,这也是之前埋的伏笔
运行之后又出现了一个错:
原因:没有添加资源过滤
解决办法:
在工程和模块的pom.xml中,都复制一份,然后clean Maven再重启IDEA就好了:
注意:xml配置文件中,如果出现中文,会报错,解决办法:把上面的UTF-8改成UTF8。
CRUD:
namespace中的包名要和Dao/mapper接口名一致
id就是对应的namespace中的方法名
resultType:sql语句执行的返回值
parameterType:参数类型
注意点:增删改需要提交事务。
灵活的Map:
如果我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map。
Map传递参数,直接在sql中取出key就可以了【parameterType="map"】
对象传递参数,直接在sql中获取对象的属性就可以了【parameterType="User"】
只有一个基本类型的情况下,可以直接在sql中取到。
多个参数用Map,或者注解。
模糊查询:
配置解析:
环境配置(environment):
mybatis可以适应多种环境,但是每个SqlSessionFactory实例只能选择一种环境。
mybatis默认的事务管理器:JDBC 连接池:POOLED
属性(properties):
我们可以通过properties属性来实现引用配置文件
先在resources目录下编写一个配置文件:
然后引入到mybatis-config.xml中:
类型别名:
作用:给Java类型设置一个短的名字
可以给单个类设置别名(类比较少的时候):
也可以指定一个包名,它就会在这个包下去找需要是Java Bean(类比较多的时候):
如果是com.pojo.User的话,相当于给它取一个别名user(首字母小写),其实大写也可以运行。但是可以用来区分,别人一看是小写的,就知道别名扫描的是包。
如果类多,指定了包名,又想单独改某些类的别名,也可以用注解:
设置:
| 设置名 | 描述 | 有效值 | 默认值 |
| cacheEnable | 缓存是否开启 | true/false | true |
| lazyLoadingEnabled | 懒加载 | true/false | false |
| useGeneratedKeys | 自动生成主键 | ture/false | false |
| mapUnderscoreToCamelCase | 是否自动开启自动驼峰命名的映射 | true/false | false |
| logImpl | 指定MyBatis所用日志的具体实现,没有指定的时候,就会自动查找 | LOG4J、LOG4J2、JDK_LOGGING、COMMONS_LOGGING、STDOUT_LOGGING、SLF4J、NO_LOGGING | 未设置 |
映射器:
MapperRegistry:注册绑定我们的Mapper文件
方式一(推荐使用):
方式二:
方式三:
生命周期和作用域:
生命周期和作用域,非常重要,因为用错了,会导致严重的并发问题。
SqlSessionFactoryBuilder:一旦用它创建了SqlSessionFactory,就不再需要它了。
(适合做局部变量)
SqlSessionFactory:可以理解为数据库连接池。一旦被创建,就一直存在。
(最佳作用域是应用作用域,最简单的是使用单例模式或者静态模式)
SqlSession:可以理解为连接到连接池的一个请求。SqlSession的实例不是线程安全的,所以最好的作用域是请求或者方法作用域。用完之后,需要赶紧关闭。否则资源被占用。
mapper:可以理解为一个具体的业务
解决属性名和字段不一致的问题:
数据库中的字段:
新建一个项目,拷贝之前的,测试实体类字段不一致的情况:
然后它的运行结果:
原因:
select * from mybatis.user where id = #{id};
等价于:
select id, name, pwd from mybatis.user where id = #{id};
解决方法:
select id, name, pwd as password from mybatis.user where id = #{id};
resultMap结果集映射:
日志工厂:
如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手。
主要掌握:STDOUT_LOGGING(默认)、LOG4J
在mybatis-config中,指定使用STUOUT_LOGGING日志:
输出结果:
LOG4J:可以控制日志信息输出的目的地是控制台、文件、GUI组件。可以控制每一条日志的输出格式和日志信息的级别。通过配置文件配置。
先导入依赖:
然后在resources目录下,新建log4j.properties:
#将等级为DEBUG的日志信息输出到console和file两个目的地
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#文件输出的相关配置
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}[%c]%m%n
#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
然后配置log4j为日志的实现:
运行结果:
简单使用:
1、在要使用的Lof4j的类中,导入包 import org.apache.log4j.Logger;
2、日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserMapperTest.class);
3、日志级别:
logger.info("info--->进入了testLog4j");
logger.debug("debug--->进入了testLog4j");
logger.error("error--->进入了testLog4j");
分页:
为什么需要分页?减少数据的处理量
使用Mybatis实现分页,核心SQL:
1、接口
ListgetUserByLimit(Map map);
2、Mapper.xml
3、测试
MyBatis分页插件:PageHelper
使用注解开发:
直接在接口的方法上,写sql语句,就不需要UserMapper.xml了
然后在mybatis-config.xml中,绑定UserMapper接口:
最后,写测试。
本质:反射
底层:动态代理
Mybatis详细的执行流程:
自动提交:
openSession(boolean autoCommit),不传参数的话,默认是false。不过,最好还是手动提交。
Lombok:
使用步骤:
1.在IDEA中安装Lombok插件
2.在项目中导入Lombok的jar包
3.在实体类上加注解
一对多和多对一的处理:
例子:多个学生对应一个老师。对于学生而言,多个学生关联一个老师【多对一】。对于老师而言,一个老师,会教很多个学生【一对多】。
步骤:
1.导入lombok
2.新建实体类
3.建立Mapper接口
4.建立Mapper.xml文件
5.在核心配置文件中绑定注册我们的Mapper接口或者配置文件
6.测试查询是否能成功
多对一的处理:
按查询嵌套处理(相当于Mysql里面的子查询):
按照结果嵌套处理(相当于Mysql里面的联表查询):
一对多的处理:
按照结果嵌套查询:
按照查询嵌套处理:
JavaType:用来指定实体类中属性的类型
ofType:用来指定映射到List或者集合中的pojo类型,泛型中的约束类型。
动态SQL:
什么是动态SQL?根据不同的条件,生成不同的SQL语句。
新建一张表:
CREATE TABLE `blog`(
`id` VARCHAr(50) NOT NULL COMMENT '博客id',
`title` VARCHAr(100) NOT NULL COMMENT '博客标题',
`author` VARCHAr(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8;
然后写一个给id字段,生成uuid的工具类:
然后插入数据:
if:
choose(when,otherwise):
choose:相当于java中的switch
trim(where, set):
where:把原来sql中的where关键字,改成了where标签。如果后面的条件,一个都没有满足,那么就自动去掉where关键字。如果只有一个满足,但是前面有and或者or,自动去掉。
set:把原来sql中的set关键字,改成了set标签。会自动去除多余的逗号。
总结:所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一些逻辑代码
SQL片段:把相同的sql片段提取出来,可以实现代码的复用
比如:
可以把这段代码里面的两个
变成这样:
注意事项:1.最好基于单表来定于SQL片段 2.SQL片段中,不要存在where标签
foreach:
例子:查询id是1或2或3的用户。
方式一:
但是这样有个问题是,把1 2 3写死了,如果以后想查id是3或4的用户,又要重新写sql
方法二:
Mybatis缓存:
什么是缓存?内存中的临时数据。将用户经常查询的数据,放在缓存中,用户去查询数据,就可以直接拿,不需要从磁盘上查了。
作用:减少和数据库的交互次数,减少系统开销,提高系统效率。
什么样的数据能使用缓存?经常查询并且不经常改变的数据。
一级缓存(默认开启,SqlSession级别,本地缓存):
SqlSession开启之后,关闭之前,有效。一级缓存就是一个Map。
在一个Session中查询2次相同的记录:
缓存失效的情况:
1.所有的select语句的结果将会被缓存,但是如果查询不一样的记录,缓存失效,因为之前的缓存里没有
2.insert、update和delete语句,会刷新缓存
3.查询不同的Mapper.xml(不在一级缓存作用域范围内)
4.手动清理缓存
二级缓存(需要手动开启和配置,namespace级别):
工作机制:查询的数据会默认被放到一级缓存中,但是如果当前会话关闭了,一级缓存中的数据会默认地被保存到二级缓存中,新的会话查询,就可以从二级缓存中取数据。不同的mapper查出来的数据,会放在自己对应的缓存(map)中。
步骤:
1.在mybatis-config.xml中,显式地开启二级缓存
2.在要使用二级缓存的mapper中,开启。
readOnly默认是false,需要序列化,改为true,就是只读,不需要序列化。不过最好还是把User的序列化加上。
3.User类序列化
4.测试
Mybatis缓存原理:
自定义缓存ehcache:
先导包:
然后在UserMapper.xml中配置:
然后在resources目录下,新建ehcache.xml文件:



