Q&A-06 Mybatis
Mybatis中#{}与${}的区别
#{}
1、#{} 是 sql 的参数占位符,Mybatis 会将 sql 中的 #{} 替换为?号,在 sql 执⾏前会使⽤PreparedStatement 的参数设置⽅法,按序给 sql 的?号占位符设置参数值,⽐如ps.setInt(0, parameterValue), #{item.name} 的取值⽅式为使⽤反射从参数对象中获取item 对象的 name 属性值,相当于 param.getItem().getName()。
2、#{}将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:select * from user where id= #{user_id},如果传入的值是11,那么解析成sql时的值为where id="11" 。
3、如果sql语句中只有一个参数,此时参数名称可以随意定义
如果sql语句有多个参数,此时参数名称应该是与当前表关联[实体类的属性名]或则[Map集合关键字],不能随便写,必须对应!如下图。
${}
{driver}会被静态替换为 com.mysql.jdbc.Driver 。
1、select * from user where id = {user_id},如果传入的值是11,那么解析成sql时的值为where id=11
2、$ {value}
中value
值有限制只能写对应的value值不能随便写,因为${}
不会自动进行jdbc类型转换
3、简单来说,在JDBC
不支持使用占位符的地方,都可以使用${}
Mybatis中#{}与${}的区别
在JDBC能使用占位符的地方,最好优先使用#{}。
在JDBC不支持使用占位符的地方,就只能使用${},典型情况就是 动态参数。
比如 有两张表,分别是emp_2017 和 emp_2018 .如果需要在查询语句中 动态指定表名,就只能使用${}
<select>
select * from emp_ ${year}
<select>
复制代码再比如MyBatis 排序时使用order by 动态参数时,此时也只能使用${}
<select>
select * from dept order by ${name}
</select>
MyBatis实现一对一有几种方式?具体怎么操作的?
有联合查询和嵌套查询。
-
联合查询是几个表联合查询,只查询一次,通过resultMap里面配置association节点配置一对一的类就可以完成。
-
嵌套查询是先查一个表,根据这个表里面的结果的外键id,再去另一个表里查询数据,也是通过association配置,但另外一个表的查询通过select属性配置。
Mybatis的一级缓存和二级缓存?
1)一级缓存 Mybatis的一级缓存是指SQLSession,一级缓存的作用域是SQlSession, Mybits默认开启一级缓存。 在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 当执行SQL时候两次查询中间发生了增删改的操作,则SQLSession的缓存会被清空。 每次查询会先去缓存中找,如果找不到,再去数据库查询,然后把结果写到缓存中。 Mybatis的内部缓存使用一个HashMap,key为hashcode+statementId+sql语句。Value为查询出来的结果集映射成的java对象。 SqlSession执行insert、update、delete等操作commit后会清空该SQLSession缓存。
2)二级缓存是mapper级别的,Mybatis默认是没有开启二级缓存的。 第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放代该mapper对应的二级缓存区域。 第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。 如果调用相同namespace下的mapepr映射文件中增删改sql,并执行了commit操作
一级缓存:也称为本地缓存,用于保存用户在一次会话过程中查询的结果,用户一次会话中只能使用一个sqlSession,一级缓存是自动开启的,不允许关闭。
二级缓存:也称为全局缓存,是mapper级别的缓存,是针对一个表的查结果的存储,可以共享给所有针对这张表的查询的用户。也就是说对于mapper级别的缓存不同的sqlsession是可以共享的。
最佳实践中,通常⼀个 Xml 映射⽂件,都会写⼀个 Dao 接⼝与之对应,请问,这个 Dao 接⼝的⼯作原理是什么?Dao 接⼝⾥的⽅法,参数不同时,⽅法能重载吗?
Dao 接⼝,就是⼈们常说的 Mapper 接⼝。
接⼝的全限名,就是映射⽂件中的 namespace的值;
接⼝的⽅法名,就是映射⽂件中 MappedStatement 的 id 值;
接⼝⽅法内的参数,就是传递给 sql 的参数。
Mapper 接⼝是没有实现类的,当调⽤接⼝⽅法时,接⼝全限名+⽅法名拼接字符
串作为 key 值,可唯⼀定位⼀个 MappedStatement ,举例: com.mybatis3.mappers.StudentDao.findStudentById ,可以唯⼀找到 namespace 为 com.mybatis3.mappers.StudentDao 下⾯ id = findStudentById 的 MappedStatement 。
在 Mybatis 中,每⼀个 <select> 、 <insert> 、 <update> 、 <delete> 标签,都会被解析为⼀个 MappedStatement 对象。
Dao 接⼝⾥的⽅法,是不能重载的,因为是全限名+⽅法名的保存和寻找策略。
Dao 接⼝的⼯作原理是 JDK 动态代理,Mybatis 运⾏时会使⽤ JDK 动态代理为 Dao 接⼝⽣成代理 proxy 对象,代理对象 proxy 会拦截接⼝⽅法,转⽽执⾏ MappedStatement 所代表的 sql,然后将 sql 执⾏结果返回。
分页
- 数组分页
查询出全部数据,然后再list中截取需要的部分。
students.subList(firstIndex, lastIndex); //直接在list中截取
- sql分页
<select id="queryStudentsBySql" parameterType="map" resultMap="studentmapper">
select * from student limit #{currIndex} , #{pageSize}
</select>
-
拦截器分页
-
RowBounds分页
- 分⻚插件
分⻚插件的基本原理是使⽤ Mybatis 提供的插件接⼝,实现⾃定义插件,在插件的拦截⽅法内拦截待执⾏的 sql,然后重写 sql,根据 dialect ⽅⾔,添加对应的物理分⻚语句和物理分⻚参数。
举例: select _ from student ,拦截 sql 后重写为: select t._ from ( select * from student ) t limit 0,10
参考链接:
Mybatis四种分页方式
《JavaGuide》