发展历程
MyBatis原名是iBatis,是Apache的开源项目。2010.6月跟随开发团队投入Google code旗下。在IBatis3.x正式更名为MyBatis。它提供了持久层架包包括SQL Maps和DATA Access Object(DAO);
安装(我没用,直接maven)
网址:https://github.com/mybatis/mybatis-3
Mybatis特性
MyBatis支持定制化SQL、存储过程以及高级映射
MyBatis避免了几乎所有的JDBC代码和手动设置参数以及结果集解析操作
MyBatis可以使用简单的XML或注解实现配置和原始映射;将接口和Java的POJO(Plain Ordinary Java Object,普通的Java对象)映射成数据库中的记录
Mybatis是一个半自动的ORM(Object Relation Mapping)框架
与其他持久层的技术对比
jdbc(唯一连接方式)但是耦合度高,开发效率低,不利于开发(所以要进行保证)
Hibernate和JPA:操作简单,但是复杂查询不足
MyBatis:轻量级。sql与java代码分开,效率略逊色于Hibernate
创建MyBatis(Maven(pom创建)版本,因为它一般不会单用,所以我直接写出它最终单用版本)
1.创建一个普通Maven(方法看我上一次传的)
2.创建好后,在pom.xml中导入以下代码(这些是maven导入的jar)
org.mybatis
mybatis
3.5.7
junit
junit
4.12
test
mysql
mysql-connector-java
8.0.17
log4j
log4j
1.2.17
3.在resource文件夹中创建一个新文件(mybatis-config.xml)
4.在新创的文件mybatis-config.xml中加入mybatis的API中的getting started(新手入门)中关于mybatis-config.xml的内容(加以修改数据源--->jdbc是连接数据库唯一的方式)
5.在resources文件夹下创建文件夹mapper,在创建XxxMapper.xml(Xxx--->数据库表名)
6.在XxxMapper.xml文件下填写如下getting started的内容(修改一些数据,下面具体说)---->我创建的数据库叫curd,表叫user(具体的看源码)
7.创建接口和实体类
8.创建测试类
链接:https://pan.baidu.com/s/1Fq0qdRkjY4l69luLwR-xPA
提取码:0303
MyBatis核心配置文件
核心文件configuration有严格的顺序要求:(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)
MyBatis获取参数的两种方式
获得方式为:${} 和 #{}
方法的本质:${}---->字符串的拼接;#{}---->占位符的复制
优缺点:${}凭借字符串或日期的时候,需要手动加单引号(等一下可以看事例);#{}则会自动添加
当参数数量不同的时候,实例分析:
1.当只有一个字面量(八大基本类型+对应的包装类+string)参数的时候
两种都可以用,里面的参数可以为任意字符串,但是${}里面不能为纯数字或以数字开头的字符串,因为它本身具有运算效果
2.当有多个字面量参数的时候
多个参数的时候,它会自动存在一个map集合中,key只有arg和param两种。注意:arg是从0开始,param是从一开始,他们不能超过参数的数目
3.当有多个字面量参数的时候,可以自定义一个map集合存储
我们需要手动创建一个map集合,然后复制,key的值为我们自定义的值
4.当参数是一个对象的时候
我们可以直接写对应JavaBean的成员变量名
-- INSERT INTO USER VALUES( NULL,'${username}','${role}','${pass}')
INSERT INTO USER VALUES( NULL,#{username},#{role},#{pass})
5.当参数添加注解的时候
我们可以在接口中为参数添加注解,注解里面的字面量可以为key值;param1,param2也可以作为key值
6.当参数为对象加注解的时候
这时候只可以使用 语法:--->注解的值.bean的成员名
INSERT INTO USER VALUES( NULL,#{user.username},#{user.role},#{user.pass})
MyBatis的查询情况(5)
resultType和resultMap两种返回结果集
resultType--->1.真实的类(全类名) 2.类的别名(自定义的别名和默认别名(八大基本类型及对应的包装类))
resultMap--->自定义映射;值为自己定义一个resultMap的id(主要可以解决数据库字段名和实体类的属性名不一致的问题)
1.查询返回一个实体类
2.查询返回一个list集合
如果返回值为list集合 返回结果映射为<>泛型里面的值
3.查询返回一个数据
这是根据字段名并不是字段值查询的,所以是string类型而不是int类型
查询返回一条数据返回为map集合(唯一的好处可以不需要创建bean,可以当临时变量的存储)
结果:{role=辅助, id=3, username=瑶}
查询多条数据返回为一个map集合(不常用)
在接口上添加一个注解,字段作为key,value是每天map集合
结果:
{2={role=射手, pass=123,
id=2, username=后羿}, 3={role=辅助, id=3, username=瑶},
6={role=ly, pass=123, id=6, username=ly},
7={role=c, id=7, username=c},
8={role=ss, id=8, username=ss},
12={role=sl, pass=123, id=12, username=ls}}
特殊的sql(模糊查询和批量删除及返回主键)
1.模糊查询
注意:单引号中如果用#{}获取参数,这时候#{}并不是作为占位符?存在,而是作为字符?号存在,会报错;只能使用concat连接字符串方法
2.批量删除
批量删除只能用${};当参数为字符串的时候
DELETE FROM USER WHERE id in (${ids})
3.返回主键
useGeneratedKeys 取值范围true、false 默认值是:false。 含义:设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域型属性中;keyProperty则是指定主键值赋值给哪个字段名
INSERT INTO USER VALUES( NULL,#{user.username},#{user.role},#{user.pass})
自定义映射
问题:实体类和数据库字段名不一致的时候,不能直接映射赋值?
解决方案:
1.在sql语句中取别名
2.在mybatis-config配置文件中开启下划线转驼峰(实体类(驼峰)和表的字段名符(_)合对应规则)--->看上面的核心配置文件
3.自定义映射(resultMap)(可以自己设置值对应,eg:把实体类username的值对应字段名pass,这样username就可以接收pass的值)--->可以只设定与字段名不一致的属性
①实体类中映射关系的表示会写在多的一方
②对一用对象表示,对多用集合表示
多对一映射关系(对象)
1.级联方式(不太推荐--->可以只写出第二张表的resultMap映射)
2.设置多对一的映射关系
3.分步查询(延时加载,按需加载)
1.如果想要延迟加载;那么就必须在配置文件中配置mybatis-config--->看核心配置文件
2.分步查询(如果查getById()那么就不会执行整个方法;但是查询getAll()会执行所有)
一对多关系(集合)
1.映射关系
这里必须写完整,不然映射不到
2.分步查询(获取单个元素可以只执行一条sql语句)
这里dept 的id映射必须写 不然不能获取
动态(dynamic)SQL语句
1.if(
1.if标签和1=1/2=2恒成立联用--->and是关联字 不可少
2.if和where标签的组合使用(可以省略第一个and;但是我个人不推荐省略)-->where标签可以省略前面的and,但是不能省略表达式后面的and
2.trim
3.trim的可以添加一个或删除一个前缀(后缀)
3.choose,when和otherwise---->相当于if....if else....else....
这是单条件,所有不需要加and,而且如果满足任何一个条件,后面的就不会执行;otherwise标签如果前面没有执行的,那么它必定会执行
注意:1.insert添加语句必须所有元素一起添加,少一个都不行;2.choose,when,otherwise可以赋值;3.性别必须加单引号(要符合sql规范)
INSERT INTO USER VALUES(
null,
#{userName},
#{role},
#{pass},
'女'
'男'
null
)
4.foreach
如果参数是list集合:foreach属性:①collection(可以填arg0或collection或list三选一)设置循环的数组或集合类型 ②item:表示数组或集合中的一天数据 ③循环体之间的分隔符号
insert into user values
(null,#{user.userName},#{user.role},#{user.pass},#{user.gender})
如果参数是数组①collection(array,arg0)④open:foreach标签的开始符号;⑤close:foreach的结束符号
delete from user where id in
'${id}'
open和colse不常用
delete from user where
id=#{id}
5.sql
sql片段,截取公共的片段,通过include来引用(注意写规范,比如‘_’ 和驼峰的别名那些)
id,user_name userName,role,pass,gender
select from user
MyBatis的缓存--->只针对查询语句有效果
本质:map集合
一级缓存
概述:一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问
存储:以json数据存储
作用域:一个session会话中
默认开启
失效的情况(4种):
1) 不同的SqlSession对应不同的一级缓存
2) 同一个SqlSession但是查询条件不同
3) 同一个SqlSession两次查询期间执行了任何一次增删改操作
4) 同一个SqlSession两次查询期间手动清空了缓存
二级缓存
概念:二级缓存是namespace级别的,即映射文件级别的,不管使用的是哪个SqlSession,只要执行的是该映射文件中的查询语句,结果就会被缓存;此后若再次执行映射文件中相同的查询语句,结果就会从缓存中取
开启条件:
a>在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
b>在映射文件中设置标签\
c>二级缓存必须在SqlSession关闭或提交之后有效
d>查询的数据所转换的实体类类型必须实现序列化的接口
二级缓存失效情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
标签种设置flushCache和useCache为false;增删改种只有flushCache,而且默认为false
第三方缓存(不常用)
。。。。。。
MyBatis--逆向工程
1.引入jar插件
org.mybatis.generator
mybatis-generator-maven-plugin
1.3.0
org.mybatis.generator
mybatis-generator-core
1.3.2
com.mchange
c3p0
0.9.2
mysql
mysql-connector-java
8.0.17
2.写逆向生成的配置文件--generatorConfig.xml(主要生成(要修改的地址)三个,1.实体类;2.接口;3.接收的映射)
3.生成命令
mybatis--分页插件PageHelper
1.导入jar包
com.github.pagehelper
pagehelper
5.0.0
com.github.jsqlparser
jsqlparser
0.9.5
2.在核心配置文件配置(注意顺序)--->看核心配置文件
3.使用并认识分页插件的属性(2个)
①Page login = PageHelper.startPage(1, 3);
参数:当前页,每一页的记录数
System.out.println(login);
结果属性:Page{count=true, pageNum=1, pageSize=3,
startRow=0, endRow=3, total=0,
pages=0, reasonable=null, pageSizeZero=null}
要了解的:pageNum-->当前页 ; pageSize-->每一页的记录数 ;
startROW-->从第几行数据开始 ; endRow-->第几行结束
total-->总记录数 ; pages-->页码数
②PageInfo users =new PageInfo<>(loginUsers,1);
参数:查询的list结果集 ; 逻辑导航分页数
System.out.println(users);
结果属性:PageInfo{pageNum=1, pageSize=3, size=3, startRow=1,
endRow=3, total=14, pages=5,
list=Page{count=true, pageNum=1, pageSize=3, startRow=0,
endRow=3, total=14, pages=5, reasonable=false, pageSizeZero=false},
prePage=0, nextPage=2, isFirstPage=true,
isLastPage=false, hasPreviousPage=false,
hasNextPage=true, navigatePages=1,
navigateFirstPage1, navigateLastPage1, navigatepageNums=[1]}
要了解的:size-->每一页的真实数 ;prePage-->上一页的页码数 ;nextPage-->下一页的页码数 ;
isFirstPage-->是否是第一页 ; isLastPage-->是否是最后一页 ;
hasPreviousPage---> 是否有上一页 ;hasNextPage--->是否有下一页;
navigatePages--->导航分页数(下面的哪个);navigateFirstPage-->导航分页从第几行开始 ;
navigateLastPage--> 导航分页到第几行结束;navigatepageNums-->显示当前的导航数(集合显示)