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