主要了解几个标签属性的作用
statementType
1.有三个值,statement,prepareStatement,callable(调取存储过程)
2.设置,获取的statement的类型
1.paramterType
1.传给sql填充的形参,可以省略
2.useGeneraterKeys = true,keyProperty = javabean属性值(执行插入通常)
1.执行完sql语句后,返回主键值赋值给javaBean,但是执行完sql的返回值照样返回
3.oracle不支持自增,oracle使用序列来模拟自增
1.在<insert>标签内 写一个标签<Selectkey> 这里写 查询 id的 sql语句 从序列表中查询</SelectKey>
2.<Selectkey>标签内 有 三个属性
1.keyProperty = javaBean的id
2.order = “before”/“after” 表示 这句sql 先/后执行(一般选择先执行)
3.resultType = 表示这句查询sql的返回值类型
2.后面写 具体的insert sql语句 插入的id 为 #{javaBean的id}
3.原理:
1.执行<SelectKey> 先查询序列表中的序列值代表 id
2.将 查询出的 序列中 赋值给 JavaBean的 id属性
3.执行insert 这时 javaBean已经有id值了,可以全部插入即可
4.参数处理
1.单个参数(java基本类型和String):mybatis不会做出特殊处理,#{参数名},取处参数值
2.多个参数:什么叫多个参数
1.(,,,)这叫多个参数
2.单个map,单个list,单个对象,单个数组,这也叫多个参数
3.(,,,)可以包含map,list,数组,对象,string,java基本数据类型
4.如果是(,,)这种的,就按1d的规则来
如果是容器作为单个参数,就得按2的规则来
5.具体的多个参数的解决办法
1.(,,,)这种类型的多个参数
mybatis会将多个参数封装成一个map集合
key:param1.....paramN
value:就是对应的value值
这样我们在#{}取值的时候,只能这样用#{param1}......,做不到见名思意
所以我们采用@param注解,这样出来的map集合:
key: 使用 @param指定的值
value:对应的值
这时,map中的key,可以是@param的值,也可以是param1,param2....
2.(单个参数是list,数组,对象,map的时候)
map:将这个map拆解,封装成一个map
key:map的key的值
value:map的value的值
对象:将这个对象拆解,封装一个map
key:对象的 变量名的字符串形式
value:对象的属性值
list/数组:将这个list/数组直接封装成一个map
key:"list"/"collection" 数组:"array"
注意:#{}取值的时候,都是采用的el那种模式,key的值本来是字符串模式的,它取值的时候直接是#{key的值去掉""}
参数处理,封装map的底层原理
1.mapper.方法(agrs),当mapper接口调用方法的时候
(这个底层原理也是sqlSession.getMapper(Mapper.class)
mapper.方法(agrs)底层也是调用了 sqlSession.insert/..("mapper中的方法名",agrs))
MapperProxy代理类来代理执行,进入它的invoke方法
执行 if(method 是object类中的原始方法) return method.invoke(this,agrs);
else mapperMethod.execut(sqlSession,args)
2.重点就是mapperMethod.execut这个方法
里面有 insert.... 4大类型的执行
都分成2步:
1.method.converArgsTosqlCommandParam(args),将传过来的args,封装成param
2.执行sqlSession.方法(mapper方法名,param)然后返回结果
3.进入 Object[] param = method.converArgsToSqlCommandParam(args)
return paramNameResolver.getNamedParams(args)这个是最后,将args,转换成params并返回的方法,进入
4.进入paramNameResovler.getNamedParams(args)中
1.获取names参数(map<Integer,String>)
1.拿到参数列表及其注解
2.有注解:name="注解名"
没有注解:name = names.size()
name = "参数名"(开启useActualName = true)
3.names.put(paramIndex,name[i]);
2.封装param
1.if args=null return null
2.if names.size = 1,并且这个参数没有注解 return args[naems.firseKey]
这就是单元素没有注解的情况
3.多个元素,或者有param注解的
1.遍历names 得到entry
2.param.put(entry.getValue(),args[entry.getKey()])
names的value作为key,names的key作为args下标
3.param.put(param1,args[0])....param.put(paramN,args[N-1]);
5.总结:获取可以用 #{param1..paramN}
或者#{0,1...},这种情况是多个参数没有注解的
或者#{注解名} 有注解的
或者#{参数名}没有注解,但是useParamName = true
关于返回值,resultType和resultMap
resultType:(数据查询出来,直接封装到resultType类型的参数里面)
1.如果 resultType和数据库字段不匹配,那么用resultType这种直接封装的方法
只能够,先将列名处理和其一样后,再封装,没其他方法
1.起别名
2.开启托峰
这都是处理数据库列名的几种方法,目的是与resultType进行匹配
2.resultType可以处理的几种数据类型
1.简单类型
2.对象/List集合 这两种resultType都是 元素对象,list只是查询出的记录有多条而已
3.Map<Object,Object> resultType = map
需求:如果想将查出的 一条记录 用 map来接收,就用这种
map的key 是 查询出的列名(起别名就是别名)
map的value 是 列的值
4.@MapKey("javabean中代表主键值的 属性名") resultType=对象
为什么是javabean中的,而不是 数据库的主键列的值
因为,查询出的数据先封装到javabean中,然后从javaBean中取,而且可能起了别名,用主键列不合适
Map<Integer,Object>
需求:如果想将查询吃的 多条记录和对应的 主键值 用 map来接收
map的key是 被@MapKey()标注的javabean中的 代表主键的属性名
map的value是javaBean对象
resultMap:处理更加复杂的,javaBean和数据库字段名不对应的情况
而且:它最大的优点是可以封装对象中有对象属性或者list的属性的情况
resultMap
1.resultMap 是一个 容器,可以将查询出来的记录(包括起别名了的),暂时封装起来
然后再将 我们自己定义的 resultMap容器 和 resultType做映射
最终都是返回resultType
2.resultMap的用法:
1.封装的javaBean中没有对象或者,list属性的
这种情况,就简单的 封装容器,然后做映射即可
2.处理 javaBean中有对象属性的 <assocation>
3.处理 javaBean中有list属性的 <collection>
assocation 联合查询(将对象分离出来,然后resultMap单独 映射 对象)
1.javaBean中的对象属性,用级联查询的方式
<result column = "resultMap的 key" property = 主类中的对象.属性>
2.嵌套结果集
<assocation property “主类的对象名” javaType = 主类对象的类型>
<result column = "resultMap的key property = 对象的属性">
</assocation>
3.分段查询
<assocation property “主类的对象名” select ="查询对象的mapper方法" column = resultMap中的 一个参数,目的传参数>
注意:调用另一个mapper的方法时,他的resultType必须与对象的类型一致,不管
它用不用resultMap做容器,最后都是要返回resultType的
</assocation>
4.分段带延迟加载
全局配置文件开启延迟加载和属性按需加载
lazyloadingEnabled = true
aggressiveLazyloding = false
collection 集合查询 (将list分离出来,然后resultMap单独 映射 对象)
1.它无法用级联查询的方式,因为查询的部分是集合,无法用对象.的方式
2.嵌套结果集
<collection property “主类的list名” ofType = 主类对象的类型>
<result column = "resultMap的key property = list中对象的属性">
</collection>
3.分段查询
<collection property “主类的list名” select ="查询对象的mapper方法" column = resultMap中的 一个参数,目的传参数>
注意:调用另一个mapper的方法时,他的resultType必须与对象的类型一致,不管
它用不用resultMap做容器,最后都是要返回resultType的
</collection>
4.分段带延迟
全局配置文件开启延迟加载和属性按需加载
lazyloadingEnabled = true
aggressiveLazyloding = false
动态sql
1.六大标签,用来解决sql拼接问题
• 动态 SQL是MyBatis强大特性之一。极大的简化我们拼装SQL的操作。
• 动态 SQL 元素和使用 JSTL 或其他类似基于 XML 的文本处理器相似。
• MyBatis 采用功能强大的基于 OGNL 的表达式来简化操作。
OGNL就是一种xml格式语法,例如<>,xml不能识别,要改成...,但是也能识别
– if
– choose (when, otherwise)
相当于 switch case 只走一个分支,if可以走多个分支
– trim (where, set)
– foreach
2.规范写sql. and or 要写在每段 sql的前面,这样<where> 和<set>就可以起作用
3.<where>,<trim>,<set>三大标签都有标签内 sql字符串 的操作:添加字符,去除字符
<where>
1.可以去除第一个 sql字符串 前面(后面不行)and or
2.若sql字符串 不为null,<where> 代表 where
3.若sql字符串最后为null,那么<where> 标签失效,可以解决where 多余问题
<set>
1.可以去除 , 去除最后一个 ,
2.若sql字符串 不为null,<set> 代表 set
3.若sql,字符串最后为null,那么<set> 标签失效,可以解决set 多余问题
<trim>
1.专门用于,字符串的截取操作
2.四个属性:prefix,prefixoveride,sufix,sufixoveride
prefix:代表 给 串 加一个 前缀(字符)
prefixoveride:代表给 串 去掉最后 一个指定 后缀(字符)
3.若 串为 null,那么 <trim> 失效
4.mybatis内置参数
1._paramter
代表了整个mybatis接收的参数,常常用来判断整个参数是否为null
select * from table
<if test _paramter != null>
where ......
</if>
2._datebaseId(全局配置文件配置了 DateBaseIdProvider,而_datebaseId是数据库的别名)
用它,就不用在mapper.xml准备 多个 select标签(其中属性有dateBaseId = 这样就可以判断执行哪个select标签)
用一个select标签,然后用<if test _dateBaseId = > 这样的动态拼接,来执行不同的sql,这样只需准备一个 select标签
5.<bind标签>
bind 元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。简单来说
就是将 #{}的表达式,赋值给 name =
例如<bind name="lang" value="@io.choerodon.mybatis.helper.LanguageHelper@language()"/>
这样 在 sql语句里面就可以使用 #{lang}了
实质就是一个 值的绑定关系
而且用的最多就是 因为mybatis不能用 like "%" +#{}+ "%"
所以一般用 <bind name = value = "%" + #{} +"%">做一个绑定
6.抽取可重用的sql片段(跟四大标签平级的标签<sql>)
1.抽取常用的sq片段,方便以后引用
1.sql抽取,经常需要查询的列名,或者插入用的列名
2.在四大标签中 用<include> 标签 refid属性 来引用 <sql>标签,
并且可以在<include> 标签中自定义属性,<sql>标签可以用
例子:insert into table (
<include refid = sql标签的id>
<property name = "自定义的" value = "自定义的">
</include>)
values ()
<sql id = "自定义的">
列名,....,${property的name}
</sql>
缓存
1.缓存的接口是 cache接口,mybatis提供了它的几个实现
2.同样可以整合其他缓存,来实现mybatis提供的cache接口
3.mybatis原生的实现,其实是map来存储缓存数据
4.一级缓存默认开启,二级缓存都是默认不开启的,需要手动开启mapper.xml中显示的配置
<cache/>
5.缓存是mybatis的特性,不是mysql的
一级缓存
1.sqlSession级别的
2.会话关闭,sqlSession级别的缓存存入二级缓存中
3.一级缓存失效的四种情况
1、不同的SqlSession对应不同的一级缓存
2、同一个SqlSession但是查询条件不同
3、同一个SqlSession两次查询期间执行了任何一次增删改操作
4、同一个SqlSession两次查询期间手动清空了缓存
二级缓存
1.nameSpace级别的
2.新的sqlSession先去 二级缓存中拿数据,拿完存在一级缓存中
3.全局配置文件中开启二级缓存
1.<setting name="cacheEnabled" value="true"/>
2.需要使用二级缓存的映射文件处使用cache配置缓存<cache />
3、注意:POJO需要实现Serializable接口
缓存中相关属性
• eviction=“FIFO”:缓存回收策略:
• LRU – 最近最少使用的:移除最长时间不被使用的对象。
• FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
• SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
• WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
• 默认的是 LRU。
• flushInterval:刷新间隔,单位毫秒
• 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
• size:引用数目,正整数
• 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
• readOnly:只读,true/false
• true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象
不能被修改。这提供了很重要的性能优势。
• false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,
但是安全,因此默认是 false。
缓存的相关设置
• 1、全局setting的cacheEnable:
– 配置二级缓存的开关。一级缓存一直是打开的。
• 2、select标签的useCache属性:
– 配置这个select是否使用二级缓存。一级缓存一直是使用的
• 3、sql标签的flushCache属性:
– 增删改默认flushCache=true。sql执行以后,会同时清空一级和二级缓存。
- 查询默认flushCache=false。
• 4、sqlSession.clearCache():
– 只是用来清除一级缓存。
• 5、当在某一个作用域 (一级缓存Session/二级缓存Namespaces) 进行了 C/U/D 操作后
默认该作用域下所 有 select 中的缓存将被clear。