#{}和${}的区别是什么?
${}
是
Properties
文件中的变量占位符,它可以用于标签属性值和
sql
内部,属于静态文本替
换,比如
${driver}
会被静态替换为
com.mysql.jdbc.Driver
。
#{}
是
sql
的参数占位符,
MyBatis
会将
sql
中的
#{}
替换为
?
号,在
sql
执行前会使用
PreparedStatement
的参数设置方法,按序给
sql
的
?
号占位符设置参数值,比如
ps.setInt(0,
parameterValue)
,
#{item.name}
的取值方式为使用反射从参数对象中获取
item
对象的
name
属性值,相当于
param.getItem().getName()
。
Xml 映射文件中,除了常见的 select|insert|update|delete 标签之外,还 有哪些标签?
还有很多其他的标签,
<resultMap>
、
<parameterMap>
、
<sql>
、
<include>
、
<selectKey>
,加上动态
sql
的
9
个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中为
sql
片段标签,通过 <include> 标签引入
sql
片段,
<selectKey>
为不支持自增的主键生成策略标签。
最佳实践中,通常一个 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
对象。
MyBatis 是如何进行分页的?分页插件的原理是什么?
MyBatis
使用
RowBounds
对象进行分页,它是针对
ResultSet
结果集执行的内存分页,而非物理
分页,可以在
sql
内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物 理分页。
分页插件的基本原理是使用
MyBatis
提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执 行的 sql
,然后重写
sql
,根据
dialect
方言,添加对应的物理分页语句和物理分页参数。
举例:
select _ from student
,拦截
sql
后重写为:
select t._ from
(
select \* from
student
)
t limit 0
,
10
MyBatis 的插件运行原理,以及如何编写一个插件。
MyBatis
仅可以编写针对
ParameterHandler
、
ResultSetHandler
、
StatementHandler
、
Executor
这
4
种接口的插件,
MyBatis
使用
JDK
的动态代理,为需要拦截的接口生成代理对象以实现 接口方法拦截功能,每当执行这 4
种接口对象的方法时,就会进入拦截方法,具体就是
InvocationHandler
的
invoke()
方法,当然,只会拦截那些你指定需要拦截的方法。
实现
MyBatis
的
Interceptor
接口并复写
intercept()
方法,然后在给插件编写注解,指定要拦截哪一 个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么?
MyBatis
仅支持
association
关联对象和
collection
关联集合对象的延迟加载,
association
指的就
是一对一,
collection
指的就是一对多查询。在
MyBatis
配置文件中,可以配置是否启用延迟加载
lazyLoadingEnabled=true|false
。
它的原理是,使用
CGLIB
创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 a.getB().getName() ,拦截器
invoke()
方法发现
a.getB()
是
null
值,那么就会单独发送事先保存 好的查询关联 B
对象的
sql
,把
B
查询上来,然后调用
a.setB(b)
,于是
a
的对象
b
属性就有值了,接着 完成 a.getB().getName()
方法的调用。这就是延迟加载的基本原理。
当然了,不光是
MyBatis
,几乎所有的包括
Hibernate
,支持延迟加载的原理都是一样的。
MyBatis 是否可以映射 Enum 枚举类?
MyBatis
可以映射枚举类,不单可以映射枚举类,
MyBatis
可以映射任何对象到表的一列上。映射
方式为自定义一个
TypeHandler
,实现
TypeHandler
的
setParameter()
和
getResult()
接口方
法。
TypeHandler
有两个作用,一是完成从
javaType
至
jdbcType
的转换,二是完成
jdbcType
至
javaType
的转换,体现为
setParameter()
和
getResult()
两个方法,分别代表设置
sql
问号占位符
参数和获取列查询结果。