考核点:
Mybatis占位符的使用。
答:
#{}是预编译处理,${}是字符串替换;
Mybatis在处理#{}时,会将SQL中的#{}替换为?,本质上是调用PreparedStatement实现执行命令;
Mybatis在处理${}时,就是把${}替换成变量的值,本质上是调用Statement实现执行命令;
使用#{}可以有效的防止SQL注入,提高系统安全性。
考核点:ORM映射。
答:
第1种:通过在查询的SQL语句中定义字段名的别名,让字段名的别名和实体类的属性名一致:
<select id=”selectorder” parametertype=”int” resultetype=”me.gacl.domain.order”>
select order_id id, order_no orderno ,order_price price form orders where order_id=#{id};
</select>
第2种:通过resultMap标签来映射字段名和实体类属性名的一一对应的关系:
<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>
<resultMap type=”me.gacl.domain.order” id=”orderresultmap”>
<!–用id属性来映射主键字段–>
<id property=”id” column=”order_id”>
<!–用result属性来映射非主键字段,property为实体类属性名,column为数据表中的属性–>
<result property = “orderno” column =”order_no”/>
<result property=”price” column=”order_price” />
</reslutMap>
考核点:模糊查询
答:
第1种:在Java代码中添加SQL通配符;
//Java代码中:
String wildcardname = ”%smi%”;
list<name> names = mapper.selectlike(wildcardname);
//Mapper映射文件中:
<select id=”selectlike”>
select name from foo where bar like #{value}
</select>
第2种:在SQL语句中拼接通配符(MYSQL):
//Java代码中:
String wildcardname = ”smi”;
List<name> names = mapper.selectlike(wildcardname);
//Mapper映射文件中:
<select id=”selectlike”>
select name from foo where bar like ‘%’ #{value} ‘%’
</select>
第3种:在SQL语句中使用Concat函数拼接通配符,支持所有数据库:
//Java代码中:
String wildcardname = ”smi”;
List<name> names = mapper.selectlike(wildcardname);
//Mapper映射文件中:
<select id=”selectlike”>
select * from foo where bar like concat("%",concat(#{value},"%"))
</select>
考核点:Mybatis工作原理
答:
Dao接口里的方法为什么不能重载:
Dao接口,就是人们常说的Mapper接口;
Mybatis启动后需要加载Mapper.xml映射文件,映射文件中每一个<select>、<insert>、<update>、<delete>标签,都会被解析为一个MappedStatement对象;
Mybatis会将MapperStatement对象以键值对的形式维护起来,MappedStatementId(采用Mapper映射文件的namespace+标签的ID组成)作为键,MapperStatement对象作为值;
调用接口中的方法时,通反射获取Mapper接口的完整限定名+方法名确定MappedStatementId,然后使用MappedStatementId定位一个MappedStatement对象;
所以,Dao接口里的方法,是不能重载的,因为Mybatis是使用MappedStatementId的寻找策略定位具体的MappedStatement对象,而MappedStatement对象就是实际调用的SQL语句;
Dao接口的工作原理:
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象;
代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的SQL,然后将SQL执行结果返回。
考核点:Mybatis ORM映射。
答:
第一种是使用ResultMap标签,逐一定义数据库表的字段名和实体类的属性名之间的映射关系;
第二种是使用SQL语句为数据库表的字段定义别名功能,将字段别名设置为实体类的属性名;
设置了字段名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给实体类的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
考核点:动态SQL与SQL语句。
答:
第一种:在Java代码中,循环执行指定SQL语句。效率低,不推荐。
首先,创建一个简单的insert语句:
<insert id=”insertname”>
insert into names (name) values (#{value})
</insert>
然后在Java代码中像下面这样执行批处理插入:
list<string> names = new arraylist();
names.add(“fred”);
names.add(“barney”);
sqlsession sqlsession = sqlsessionfactory.opensession(true);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name : names) { mapper.insertname(name); }
sqlsession.commit();
} finally { sqlsession.close(); }
第二种:支持MYSQL版本
<insert id=”insertname”>
insert into names (name) values
<foreach collections="names" item="item" separator=","> (#{item}) </foreach>
</insert>
第三种:支持Oracle并支持序列
<insert id=”insertname”>
begin
<foreach collections="names" item="item" >
insert into names (name) values (#{item});
</foreach>
end;
</insert>
第四种:通用版本,但是不支持Oracle序列
<insert id=”insertname”>
insert into names (name,gender)
<foreach collections="names" item="item" separator="union">
select #{item.name} , #{item.gender}
</foreach>
</insert>
考核点:获取插入后主键值。
答:
insert方法总是返回一个int值,这个值代表的是插入的行数,而自动生成的键值在insert方法执行完后可以被设置到传入的参数对象中。
自增列示例:
<!--
useGeneratedKeys="true":设置使用自增列的值
keyProperty="stuId":设置自增列的值存入到JavaBean的哪个属性
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="stuId" parameterType="Student">
insert into student (stuName,age,gender,address) values (#{stuName},#{age},#{gender},#{address})
</insert>
序列示例:
<insert id="insert" parameterType="Student">
<selectKey order="BEFORE" resultType="integer" keyProperty="stuId" >
select seq.nextval from dual
</selectKey>
insert into student (stuId,stuName,age,gender,address)
values (seq.currval,#{stuName},#{age},#{gender},#{address})
</insert>
或
<insert id="insert" parameterType="Student">
<selectKey order="AFTER" resultType="integer" keyProperty="stuId" >
select seq.currval from dual
</selectKey>
insert into student (stuId,stuName,age,gender,address)
values (seq.nextval,#{stuName},#{age},#{gender},#{address})
</insert>
考核点:Mybatis参数映射。
答:
第1种:使用Mybatis默认参数别名之“paramn”
//Mapper接口中代码:
Public UserselectUser(String name,String area);
//Mapper.xml映射文件中代码:
<select id="selectUser"resultMap="BaseResultMap">
select * from user_user_t where user_name = #{param1} anduser_area=#{param2}
</select>
第2种:使用Mybatis默认参数别名之“argn”
//Mapper接口中代码:
Public UserselectUser(String name,String area);
//Mapper.xml映射文件中代码:
<select id="selectUser"resultMap="BaseResultMap">
select * from user_user_t where user_name = #{arg0} anduser_area=#{arg1}
</select>
第3种:使用@param注解设置别名
//Mapper接口中代码:
public user selectuser(@param(“username”) String username, @param(“hashedpassword”)
String hashedpassword);
//Mapper.xml映射文件中代码:
<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword from some_table
where username = #{username} and hashedpassword = #{hashedpassword}
</select>
考核点:动态SQL。
答:
Mybatis动态SQL:可以让我们在Xml映射文件内,以标签的形式编写动态SQL,完成逻辑判断和动态拼接SQL的功能;
Mybatis提供了10种动态SQL标签:trim|where|set|foreach|if|choose|when|otherwise|include|sql;
执行原理:使用OGNL计算表达式的值,根据表达式的值动态拼接SQL,以此来完成动态SQL的功能。
考核点:Mybatis工作原理。
答:
不同的Xml映射文件,如果配置了命名空间(namespace),那么标签的ID可以重复;如果没有配置命名空间,那么标签的ID不能重复,毕竟命名空间不是必须的,只是最佳实践而已;
原因:命名空间+标签的ID是作为Mybatis维护MapperStatemented对象集合的key使用的,如果没有命名空间,就剩下标签的ID,导致无法区分具体的MapperStatemented对象;
考核点:Mybatis关联映射。
答:
一对一的例子:
<select id="getClass" parameterType="int" resultMap="ClassesResultMap">
select * from class c,teacher t where c.teacher_id=t.t_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<association property="teacher" column=” teacher_id” javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
一对多的例子:
<select id="getClass2" parameterType="int" resultMap="ClassesResultMap2">
select * from class c,teacher t,student s where c.teacher_id=t.t_id and c.c_id=s.class_id and c.c_id=#{id}
</select>
<resultMap type="com.lcb.user.Classes" id="ClassesResultMap2">
<id property="id" column="c_id"/>
<result property="name" column="c_name"/>
<collection property="students" column=” c_id” ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
考核点:Mybatis的发展历史。
答:
维护组织:Ibatis本是apache的一个开源项目,2010年这个项目由apache software foundation 迁移到了google code,并且改名为mybatis;
接口式绑定:Mybatis实现了接口绑定,使用更加方便,而iBatis不支持;
关系映射的实现方式:IBatis实现关系映射使用的是子查询,而Mybatis不但支持子查询还增加了分步查询,效率更高;
OGNL表达式的支持:MyBatis采用功能强大的基于OGNL的表达式来消除其他元素,IBatis不支持;
SQL映射的语法区别:动态SQL、传入参数、接收参数、存储过程调用等语法不同。
考核点:Mybatis工作原理。
答:
加载Mybatis全局配置文件(数据源、Mapper映射文件等),解析配置文件,Mybatis基于XML配置文件生成Configuration,和一个个MappedStatement(包括了参数映射配置、动态SQL语句、结果映射配置),其对应着<select | update | delete | insert>标签项;
SqlSessionFactoryBuilder通过Configuration对象生成SqlSessionFactory,用来开启SqlSession;
SqlSession对象完成和数据库的交互;
用户程序调用Mybatis接口层API(即Mapper接口中的方法);
SqlSession通过调用API的Statement ID找到对应的MappedStatement对象;
通过Executor(负责动态SQL的生成和查询缓存的维护)将MappedStatement对象进行解析,SQL参数转化、动态SQL拼接,生成JDBC Statement对象;
JDBC执行SQL;
借助MappedStatement中的结果映射关系,将返回结果转化成HashMap、JavaBean等存储结构并返回。
考核点:Mybatis映射文件。
答:
Mybatis的Mapper映射文件中的Mapper配置节的namespace属性是命名空间。
作用:
使用类路径的完全限定名称的方式区分Mapper映射文件,防止SQL标签的ID重名;
namespace命名空间是Mybatis中mapperStatementId的重要组成部分。
考核点:Mybatis缓存。
答:
Mybatis的一级缓存是指SqlSession,一级缓存的作用域是SqlSession,Mybaits默认开启一级缓存;
在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取;
SqlSession执行insert、update、delete等操作commit后会清空该SqlSession缓存。
二级缓存是mapper级别的,Mybatis默认是没有开启二级缓存的;
第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放该mapper对应的二级缓存区域;
第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果;
如果调用相同namespace下的mapepr映射文件中增删改sql,并执行了commit操作,此时该缓存会清空。
总结:
一级缓存同会话,很少会重复查询,实用场景少;
二级缓存同namespace下(表级别缓存),执行更新操作,即清空缓存,所以实际应用场景一般使用三级缓存。
考核点:动态SQL
答:
if 标签:
if标签通常用于WHERE语句、UPDATE语句、INSERT语句中,通过判断参数值来决定是否使用某个查询条件、判断是否更新某一个字段、判断是否插入某个字段的值。
foreach标签:
foreach标签主要用于在sql中对集合进行迭代。也常用到批量删除、添加等操作中。
choose标签:
MyBatis提供了choose 元素,按顺序判断when中的条件出否成立,如果有一个成立,则choose结束。
当choose中所有when的条件都不满则时,则执行 otherwise中的sql。
类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。
where标签:
如果where标签包含的标签中有返回值的话,它就插入一个"where"。
此外,如果标签返回的内容是以AND或OR开头的,则它会剔除掉。
set标签:
使用set标签可以将动态的配置set关键字,和剔除追加到条件末尾的任何不相关的逗号。
trim标签:
格式化输出,也可以通过trim标签设定或忽略前后缀来实现格式化输出。
sql标签:
当多种类型的查询语句的查询字段或者查询条件相同时,可以将其定义为SQL片段,方便调用。
include标签:
用于引用定义的SQL片段。
考核点:动态SQL
答:
where关键字是SQL语句中的where子句,在Mybatis动态SQL中,若直接用where子句的话可能会导致SQL语法错误,查询失败;
where标签为MyBatis的动态语句,系统自动生成where子句,并且会自动去掉生成语句前面多出的"and|or"子串。
考核点:动态SQL
答:
foreach:循环标记;
collection:设置循环的集合、注意接口方法参数需要使用@Param()指定取值的key,如果不设置,默认key="list";
item:设置循环中取值一个元素的变量名称;
separator:设置语句的分割符号;
open:设置语句开始部分的子串;
close:设置语句结束部分的子串;
index:取出元素的索引。
相同点:
都属于ORM 框架;
都是对JDBC 的封装;
都属于持久层的框架。
不同点:
Hibernate 是面向对象的,Mybatis是面向SQL的;
Hibernate全自动的ORM,Mybatis是半自动的ORM;
Hibernate查询映射实体对象必须全字段查询,Mybatis可以不用;
Hibernate有级联操作,Mybatis则没有;
Hibernate编写HQL查询数据库大大降低了对象和数据库的耦合性,Mybatis提供动态SQL,需要手写SQL,与数据库之间的耦合度取决于程序员所写的SQL的方法,所以Hibernate的移植性要远大于Mybatis;
Hibernate有方言跨数据库,Mybatis 依赖于具体的数据库;
Hibernate拥有完整的日志系统,Mybatis 则相对比较欠缺;
答:
基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除SQL与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用;
与JDBC相比,减少了50%以上的代码量,消除了JDBC 大量冗余的代码,不需要手动开关连接;
很好的与各种数据库兼容(因为MyBatis 使用JDBC 来连接数据库,所以只要JDBC支持的数据库MyBatis都支持);
能够与Spring很好的集成;
提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系。
答:
SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求;
SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。