mybatis复习笔记----关于一些需记忆的点
POINT-一些点
一、sql插入后,返回自增主键值
mybatis也是利用statement.getGenreatedKeys()。
属性:
useGeneratedKeys="true"----使用自增主键获取主键值策略
keyProperty----指定对应的主键属性,也就是mybatis获取到主键值以后,将这个值封装给javaBean的哪个属性-->
例如:
<insert id="addEmp" parameterType="com.atguigy.mybatis.bean.Employee" useGeneratedKeys="true" keyProperty="id">
insert into tbl_employee(last_name,email,gender)values(#{lastName} ,#{emai1} ,#{gender})
</insert>
oracle不支持自增,但使用序列来模拟自增。
每次插入的数据的主键是从序列中拿到的值;如何获取到这个值;
<insert id="addEmp" databaseId="oracle">
<!- -
keyProperty:查出的主键值封装给javaBean的哪个属性order="BEFORE":当前s.ql在插入sgl之前运行
resultType:查出的数据的返回值类型
-->
<selectKey keyProperty="id" order="BEFORE"resultType="Integer">
<! --编写查询主键的s.gl语句-->
select EMPLOYEES_SEQ.nextval from dual
</selectkey>
<!--插入时的主键是从序列中拿到的 其实也可以直接在sql里写从序列里取值,即#{id}替换为employees_seq.nextval –->
insert into employees(EMPLOYEE_ID,LAST_NAME ,EMAIL)values(#{id} ,#{lastName} ,#{email})
</insert>
二、对于接口方法中传递参数处理
- @Param("")来指定参数对应的值
当接口方法传递多个参数时,对应mapper.xml默认使用map存储,key=param1...paramn表示,value=参数值,所以在sql中通过#{}取值时要通过param1...paramn来取
若想指定参数的key需要在接口参数前添加@Param("xxx")来指定。
即接口中传递过来的参数可以是pojo也可以是一个map,因为最后都是转为一个map
To: 如果多个参数不是业务模型中的数据,但是经常要使用,推荐来编写一个TO (Transfer object)数据传输对象
明确即接口对应.xml配置sql文件可传递:pojo、map、To(数据传输对象)
- 参数封装
对于传过来的collectio类型,或数组,若没有@Param注解表示,需要用list来取值,因为也是封装成一个map,但是key=list
例如:
public Employee getEmpById(List<Integer> ids);
取值:取出第一个id的值:错误:#{param1[0]},#{ids[0]}都是错的 正确:#{list[0]},
三、关于#{}与${}取值时的预编译与拼接
#{}:是以预编译的形式,将参数设置到sql语句中;Preparedstatement:防止sql注入
${}:取出的值直接拼装在sql语句中;会有安全问题;
大多情况下,我们去参数的值都应该去使用#{};
原生jdbc不支持占位符的地方我们就可以使用${}进行取值,比如按照年份分表拆分,分表、排序等;
select *from ${year}_salary where XXX3
select * from tbl_employee order by $if_name} ${order}
四、#{}更丰富的用法:
规定参数的一些规则:
javaType、jdbcType. mode(存储过程)、numericScale、
resultMap、typeHandler、jdbcTypeName、expression(未来准备支持的功能)
jdbcType通常需要在某种特定的条件下被设置:
在我们数据为null的时候,有些数据库可能不能识别mybatis对null的默认处理。比如Oracle(报错)﹔
JdbcType OTHER=无效的类型,因为mybatis对所有的nul1都映射的是原生Jdbc的OTHER类型,oracle不能处理。
由于全局配置中:jdbcTypeForNull=OTHER; oracle不支持;可通过以下两种方法解决。
1、#{emai1,jdbcType=OTHER];
2、jdbc TlypeForNu11=NULLl
五、resultType:如果返回的是一个集合,要写集合中存储元素的类型,而不是list类型
六、可以在接口方法中通过@MapKey("xxx")来指定接口对应.xml配置文件对应方法的sql语句返回类型为map时用什么来作为map的键
七、多个数据一起插入,mysql支持values后面跟‘,’分割的多个‘()’。如:insert into student values(101,"xhangsan"),(102,"lisi"),而oracle则不支持。
----解决oracle多数据插入:
1--多个insert语句放在begin ... end 里面
begin
insert into employees(employee_id,last_name , email)
values(employees_seq.nextval, 'test_001' , 'test_001@xiaoai.com');
insert into employees (employee_id,last_name , email)
values(employees_seq.nextval, 'test_002' , 'test_0e02@xiaoai.com');
end;
例如mabatis使用:
<insert id="addEmps" databaseId="oracLe">
<!-- oracle第一种批量方式-->
<foreach collection="emps" item= "emp" open="begin" close="end">
insert into employees(employee_id,1ast_name, email)
values(employees_seq.nextval,#{emp. lastName},#{emp.emai1}
</foreach>
</insert>
2--利用中间表
例如sql语句:
insert into employees(employee_id, last_name, email)
select employees_seq.nextval, lastName , email from(
select 'test_a_01', lastName, 'test_a_eO1’ email from dual
union
select 'test_a_02', lastName, 'test_a_e02' email from dual
union
select 'test_a_03', lastName, 'test_a_e03' email from dual
)
例如mabatis使用:
<insert id="addEmps" databaseId="oracLe">
<! -- oracle第二种批量方式-->
insert into employees(employee_id,last_name, email)
<foreach collection="emps " item="emp" separator="union"
open=" select employees_seq.nextva1,lastName , email from("
close=")">
select #{emp.lastName} lastName, #{emp.email} email from dual
</foreach>
</insert>
八、两个默认内置参数
_parameter:代表整个参数
单个参数:_parameter就是这个参数
多个参数:参数会被封装为一个map:_parameter就是代表这个map
_databaseId:如果配置了databaseIdProvider标签。
_databaseId就是代表当前数据库的别名|
例如使用:
当相同数据在不同数据库时,判断当前使用什么数据库对应查询什么表
<select id="getEmpsTestInnerParameter" resultType="com.xiaoai.employee">
<if test="_databaseId=='mysqL'">
select * from tbl_employee
</if>
<if test="_databaseld=='oracle'">
select * from employees
</if>
</ select>
缓存
一、一级缓存(本地缓存)
一级缓存是一直开启的,缓存即SqlSession级别的一个map
一级缓存失效情况:(即没有使用到当前一级缓存的情况,需要再向数据库发出查询)
1--sqlsession不同
2--sqlsession相同,查询条件不同(即当前一级缓存中还没有要查询的数据>
3--sqlsession相同,查询条件相同,但是两次查询之间进行过增删改操作(怕增删改对数据进行了更改)。
4--手动清除了一级缓存,即通过sqlsession.clearCache()清除缓存; .clearCache()只清除一级缓存,增删改时一、二级缓存都会清除。
二、二级缓存(全局缓存)
常用数据放到二级缓存中,基于namespace级别的缓存,一个namespace对应一个二级缓存。
工作机制
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容。
三、缓存设置
在接口对应.xml配置文件中通过【cache】标签设置
<cache eviction="" flushInterval="" readOnly="" size="" type=""></cache>
属性说明:
1--eviction:缓仔的回收策略:当缓存慢了以后,需要删除一些数据,会根据设置的策略进行删除 默认的是LRU。
LRU 最近最少使用的:移除最长时间不被使用的对象。
FIFO 先进先出:按对象进入缓存的顺序来移除它们。
SOFT 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
2--flushInterval:缓存刷新间隔 缓存多长时间清空一次,默认不清空,设置一个毫秒值
3--readOnly:是否只读:
true:只读; mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。 mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快
false:非只读:mybatis觉得获取的数据可能会被修改。 mybatis会利用序列化&反序列的技术克隆一份新的数据给你。安全,速席慢|
4--size:缓存存放多少元素;
5--type="":指定自定义缓存的全类名;实现Cache接口即可;
四、二级缓存使用
查出的数据默认放在一级缓存中,只有当sqlsession会话提交或者关闭后数据才会转移到二级缓存中。但前提是二级缓存开启了。
二级缓存的使用:
1--让Mybatis框架支持二级缓存(在主配置文件中配置)
<settings>
<!-- 开启二级缓存的支持 -->
<setting name="cacheEnabled" value="true"/>
</settings>
2--让当前接口方法的.xml映射文件支持二级缓存(在接口对应配置文件中配置)
<mapper namespace="com.itheima.dao.IUserDao">
<!-- 开启二级缓存的支持 -->
<cache></cache>
</mapper>
3--让当前操作支持二级缓存(在select等操作标签中配置)
<select id="findById" resultType="user" parameterType="int" useCache="true">
select * from user where id = #{uid}
</select>