mybatis映射文件

闻人花蜂
2023-12-01

主要了解几个标签属性的作用

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。		
 类似资料: