目录
1、SqlSessionFactory和SqlSession
2、SqlSessionFactoryBuilder生命周期
一、MyBatis概述
历史
MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。
MyBatis特点
- 支持定制化 SQL、存储过程、基本映射以及高级映射的持久层框架
- 避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
- 可以使用简单的XML或注解用于配置和原始映射,将接口和Java的pojo映射成数据库中的记录
- 是一个半自动的ORM框架
ORM概述
相关概念: ORM (Object Relationship Mapping) 对象关系映射
- 对象:Java的实体类对象
- 关系:关系型数据库
- 映射:二者之间的对应关系(Mapping就是把数据库变成实体对象的过程)
Java概念 | 数据库概念 |
类 | 表 |
属性 | 字段/列 |
对象 | 记录/行 |
但是这个ORM是半自动化的,因为sql需要程序员自己来写
二、Mybatis入门
1、SqlSessionFactory和SqlSession
2、核心配置文件的加载
3、mybatis事务管理机制
4、第一个mybatis程序
5、mybatis继承日志
三、mybatis增删改查
1、增加
通过Map传值
通过实体类传值
#{} 里面就写对象属性名,本质上是通过get方法去掉get后面第一个字母变小写实现的
2、删除
3、修改
跟增差不多 也是这样对象就是通过get方法获得
4、查询
查询不一样,因为他说要查到东西之后封装成结果集的,所以需要指定返回的结果集要封装成什么类型的对象。要在sql上面指定resultType
实体类名和数据库的字段不对应就可能让查到的数据装不进指定实体类型的结果集里面,我们可以通过起别名来装机进去(最原始的解决方案)
如果是查list,用list来接收的(查多行数据),结果集写list里面封装的类型
5、命名空间
四、Mybatis核心配置文件
1、environment
在mybatis的核心配置文件中环境可以配置多个,可以有多个environment标签。
environments标签的default属性就是配置的是默认环境
一个环境一般是一个数据库,一个数据库是对应一个sqlSessionFactory的
2、dataSource(重点)
type属性有三个可以填
- UNPOOLED不使用(每次都用新连接对象,每次都是新建连接)
- POOLED使用mybatis自带的
- JNDI使用第三方(德鲁伊这些)
这个JNDI实际上是这个规范,大部分web服务器如:tomcat、jetty等,都实现了这个规范
那么我们要用德鲁伊等连接池都会先配在web服务器上如tomcat,那么他们都实现了JNDI规范,mybatis就不需要另外配置了,mybatis配置这个规范就可以直接用tomcat的连接池了
选POOLED或JNDI配置连接池
3、properties
五、在web项目中用mybatis
1、关于ThreadLocal
当我们在不同层要使用sqlSession的时候,他们拿到的sqlSession根本就不是同一个,那么我们要如何保证他是同一个呢
我们就得用到ThreadLocal 把sqlSession放在这里面,每次要的时候从里面取就是同一个
每当有一个线程的时候,就会有一个sqlSession(每个线程都有它自己的 sqlSesson 实例。一个线程一个,Sqlsession 的实不是线程安全的,因此是不能共享的)
2、SqlSessionFactoryBuilder生命周期
这类可以被实例化、使用和丢弃,一旦创建了 Sesionfactory,就不再需要它了。因此 SqlSessionfatoryBulder 实的最生用域是方法用域也就是局部变量)。
3、Sqlsessionfactory生命周期
sqlsesionfactory 一旦被就应在应用的运期一直存在,没有理由弃或重新的建另一实例。使用 sqlSesionfactory的最实战是在应用运行期间不要重复自建多次,多次重SqlSessionFactory 被视为一种码"坏惯”,因此 Sqlsessionfactory 的最佳作用域是应用作用域,有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式(静态代码块中使用单例模式 类加载new)
4、Sqlsession生命周期
每个线程都有它自己的 sqlSesson 实例。一个线程一个,Sqlsession 的实不是线程安全的,因此是不能共享的,所以它的最佳作用域是请求或方法作用域。绝对不将 Sqlsession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行
六、Mybatis小技巧
1、#{}和${}的区别
#{}底层使用的是PreparedStatement。特点:先进行SQL语句的编译,然后给sql语句得到占位符?传值。可以避免sql注入的风险。
${}底层用的是Statement。特点:先sql拼接再进行编译。存在sql注入风险
使用${}的情况
注意:当我们要从前端传入参数,比如升序还是降序拼接到sql语句就要用${}
由下图可只如果用#{}是先执行再把asc的值拼接进去,asc是字符串所有带‘’会报错
下面这种情况也是同理
批量删除
这里我们也是一样,得用${}来接收
模糊查询
第四种方式用得比较多
2、别名机制
想要给某个类起别名,可以在mybatis的核心配置文件以下配置,不指定alias的话就是类名car
就可以使用了,而且aaa是不区分大小写的
总结:
3、自动生成主键值
我们只需要在插入语句使用useGeneratedKeys="true"和keyProperty="id"
七、mybatis参数处理
1、单个简单类型参数
parameterType属性:指定传入单个参数的数据类型
parameterType可以省略,mybatis会自动推断,加上效率更高
2、参数为Map
map来传递的时候,#{}里面加的必须是传入map的key。
3、参数为pojo
当传入的是实体类,#{}里面必须是实体类的属性名。
4、多参数类型
也可以用@Param注解来指定参数名,就不需要arg0,arg1这些了
八、mybatis查询语句专题
1、返回car
当数据库的字段和实体类属性名不同的时候,返回类型设置为实体类会为null,这时候就可以通过下面这种起别名的方式赋值、
2、返回多个car
这时候返回多条数据,就必须用list<car>来接收了,但是resultType还是car
如果是用一个car对象来接收可能是多条数据的查询,就会报错
3、返回map
当返回的数据没有合适的java类来接收,那么我们就可以用map来接收,resultType是map
4、返回List<Map>
要查询多条数据,返回的类型是map,那么就用List<Map>来接收,resultType是map
5、返回Map<String,Map>
把map放到list集合里面,要取的时候不方便,要一个个遍历看还不知道是不是,所以我们可以map放到map里面,然后小map的id作为大map的key
6、resultMap结果映射
查询结果的列名和java对象的属性名对应不上怎么办?(面试题)
第一种方式: 在sql语句 as 给列起别名
第二种方式: 使用resultMap进行结果映射(列名和java对象的属性名的映射)
第三种方式:是否开启驼峰命名自动映射(配置settings)
7、驼峰命名自动映射
在核心配置文件中开启自动映射。必须得符合规范才可以:数据库下划线对应实体类驼峰
8、返回总记录条数
九、动态sql
1、if 标签
2、where 标签
所有条件为空时,where标签保证不会生成where子句。自动去处某些条件前面多余的or和and
3、trim 标签
4、set 标签
需求:在update的时候,只更新传入不为null的字段,其他字段保持原来样子
如果直接set(null,1,null,null)这种,其他为null的都会覆盖原来字段
这个时候就要用set标签,如下图(多余的,会自动去掉)
5、choose、when、otherwise
这三个标签一般是组合使用的,其代表的含义就是if、else if、else的含义
当我们要先根据什么查,没有就个根据什么查,没有根据什么查的时候用
6、foreach 标签
当我们要批量删除,前端传入的是一个数组的时候就可以用
批量插入多条数据的时候也可以使用,传入List<Car>
7、sql标签、include标签
可以把很多条sql都通用的公共语句提取出来,这样就能复用。
十、mybatis高级映射
1、多对一
多种方式,常见的包括三种:
(1)一条SQL语句,级联属性映射
(2)一条SQL语句,association
(3)两条SQL语句,分步查询(常用)
(这种方式常用: 优点一是可复用。优点二是支持懒加载。)
分开效率高,当只查学生时就不用查班级,也不同重新写一个sql,提高效率
懒加载(延迟加载):用到的时候再查询,不用的时候不查,提升效率
怎么开启懒加载呢?只需要在association加上fetchType=“lazy”
2、一对多
一对多的实现通常包括两种实现方式:
(1)collection
(2)分步查询(常用)
十一、mybatis的缓存
mybatis缓存包括:
- 一级缓存: 将查询到的数据存储到SglSession中。
- 二级缓存: 将查询到的数据存储到SqlSessionFactory中。
- 或用其它第三方的缓存: 比如EhCache[Java语言开发的]、Memcache[C开发的]、redis
注意:缓存只针对于DQL语句,也就是说缓存机制只对应select语句。
一级缓存
一级缓存默认就是开启,不需要任何配置。范围是SqlSession
只要使用同一个sqlSession对象执行同一条sql语句,就会走缓存。
思考: 什么时候一级缓存失效?
- 执行了sglSession的cLearCache()方法,这是手动清空缓存。
- 执行了INSERT或DELETE或UPDATE语句。不管你是操作哪张表的,都会清空一级缓存。
二级缓存
二级缓存的范围是SqlSessionFactory
怎么使用二级缓存(必须满足一下4点):
- <setting name="cacheEnabled" value="true"> 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认就是true,无需设置
- 在需要使用二级缓存的SglMapper.xml文件中添加配置: <cache />
- 使用二级缓存的实体类对象必须是可序列化的,也就是必须实现iava.io.Serializable接口
- SglSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。(sqlSeesion关了之后才能有二级缓存用)
二级缓存得到失效:只要两次查询之间出现了增删改操作,二级缓存就会失效
二级缓存相关配置(了解):
关于集成第三方缓存
当mybatis集成第三方缓存是为了替代mybatis自带的二级缓存,一级缓存是无法替代的。
十二、mybatis分页插件
获取数据不难,拿到pageNum和pageSize,算出startIndex去数据库查就行
难的是获取分页相关数据比较难,可以借助mybatis的pageHelper插件。
PageHelper插件
1、先引入依赖
2、在核心配置类配置分页的拦截器
3、直接使用
4、给前端返回pageInfo
第二个参数3,代表有3个标签,就是下面会出现3个页1,2,3