参考前人,因为参考的比较多,所以难以一一写出,后续会继续补充,
目录
4.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
6.Statement和PrepareStatement的区别:
7.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
9.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
13.Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理:
16.通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
1.对MyBatis的理解:
(百度百科)MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录
mybatis把sql语句从Java源程序中独立出来, 放在单独的XML文件中编写,给程序的维护带来了很大便利。 ibatis封装了底层JDBC API的调用细节,并能自动将结果集转换成Java Bean对象, 大大简化了Java数据库编程的重复工作。 因为Ibatis需要程序员自己去编写sql语句, 程序员可以结合数据库自身的特点灵活控制sql语句, 因此能够实现比hibernate等全自动orm框架更高的查询效率,能够完成复杂查询
2.Mybatis的优缺点:
- 优点
- 易于上手和掌握
- Sql写在xml里面,便于统一管理和优化
- 减少Sql与程序代码的耦合
- 提供xml标签,支持动态Sql编写
- 缺点
- Sql工作量大,尤其是字段多,关联表多时,更是如此
- Sql依赖于数据库,导致数据库移植性差
- 由于xml里面标签id必须唯一,导致DAO中方法不支持方法重载。所以dao层必须是接口
3.Mybatis的编程步骤:
-
创建SqlSessionFactoryBuilder
-
通过SqlsesionFactoryBuilder创建sqlSessionFactory
-
通过SqlSessionFactory创建sqlSession
-
通过sqlSession执行数据库操作
-
调用session.commit()提交事务
-
调用session.close()关闭会话
4.为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具。
5. #{}和${}的区别是什么?
-
#{}是预编译处理,${}是字符串替换。
-
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
-
Mybatis在处理${}时,就是把${}替换成变量的成变量的值,使用#{}可以有效的防止SQL注入,提高系统安全性
6.Statement和PrepareStatement的区别:
-
PreparedStatement:表示预编译的 SQL 语句的对象。
-
PrepareStatement可以使用占位符,是预编译的,批处理比Statement效率高
-
在对数据库只执行一次性存取的时侯,用 Statement 对象进行处理。
-
PreparedStatement的第一次执行消耗是很高的. 它的性能体现在后面的重复执行
7.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?
- 第一种:使用<resultMap>标签,逐一定义列名和对象属性名之间的映射关系
- 第二种:使用sql列的别名功能,将列别名书写为对象属性名,比如T_NAME AS NAME,对象属性名一般是name,小写,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成T_NAME AS NaMe,Mybatis一样可以正常工作
- 有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。(会报错no XXXSetter)
8.当实体类中的属性名与数据表中的字段名不同时,如何解决?
- 解决方式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>
9.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践而已。
原因就是namespace+id是作为Map<String, MappedStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也就不同。
10.如何获取自动生成的(主)键值:
- 解决思路:通过LAST_INSERT_ID()获取刚插入记录的自增主键值,在insert语句执行后,执行select LAST_INSERT_ID()就可以获取自增主键(mysql)
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
INSERT INTO USER(username,birthday,sex,address)
VALUES(#{username},#{birthday},#{sex},#{address)
</insert>
11.模糊查询like语句该怎么写?
<select id="selectlike">
select * from foo where bar like "%"#{value}"%"
</select>
-
表达式: name like"%"#{name}"%" #起到占位符的作用
-
表达式: name like '%${name}%' $进行字符串的拼接,直接把传入的值,拼接上去了,没有任何问题
-
表达式: name likeconcat(concat('%',#{username}),'%') 这是使用了cancat进行字符串的连接,同时使用了#进行占位
-
表达式: name like CONCAT('%','${name}','%') 对上面的表达式进行了简化,更方便了
12.在mapper中如何传递多个参数?
- 第1种:
//DAO层的函数
Public UserselectUser(String name,String area);
//对应的xml,#{0}代表接收的是dao层中的第一个参数,#{1}代表dao层中第二参数,更多参数一致往后加即可。
<select id="selectUser"resultMap="BaseResultMap">
select * fromuser_user_t whereuser_name = #{0} anduser_area=#{1}
</select>
- 第2种: 使用 @param 注解:
import org.apache.ibatis.annotations.param;
public interface usermapper {
user selectuser(@param(“username”) string username,
@param(“hashedpassword”) string hashedpassword);
}
<select id=”selectuser” resulttype=”user”>
select id, username, hashedpassword
from some_table
where username = #{username}
and hashedpassword = #{hashedpassword}
</select>
13.Mybatis动态sql是做什么的?都有哪些动态sql?简述一下动态sql的执行原理:
Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。
Mybatis提供了9种动态sql标签:trim|where|set|foreach|if|choose|when|otherwise|bind。(需熟练用法)
其执行原理为,从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。
14.一对一、一对多的关联查询 ?
整体思想:
- 本表中一条数据对应另一张表中数据条数判断两表间关系为一对一还是一对多;
- 如一对一,则在实体类中存另一表对应实体类对象作为成员变量,如一对多关系,则在本实体类中存另一表对应实体类对象的集合作为成员变量;
- 在mapper文件中,将两表的关系进行对应描述,
<mapper namespace="com.lcb.mapping.userMapper">
<!--association 一对一关联查询 -->
<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" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
</resultMap>
<!--collection 一对多关联查询 -->
<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"/>
<association property="teacher" javaType="com.lcb.user.Teacher">
<id property="id" column="t_id"/>
<result property="name" column="t_name"/>
</association>
<collection property="student" ofType="com.lcb.user.Student">
<id property="id" column="s_id"/>
<result property="name" column="s_name"/>
</collection>
</resultMap>
</mapper>
15.使用MyBatis的mapper接口调用有哪些要求:
-
Mapper接口方法名和mapper.xml中定义的每个sql的id相同
-
Mapper接口中输入的参数类型和mapper.xml中定义的每个sql的ParameterType相同
-
Mapper接口中输出的参数类型和mapper.xml中定义的每个sql的resultType相同
-
Mapper.xml文件中的namespace即是接口的类路径
16.通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?
-
Dao接口即Mapper接口,接口的全限名也就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。(mapper自动代理的四个规则)
-
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对象(如使用spring会注入到容器中),代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回
17.Mybatis缓存:
- 一级缓存(SqlSession级别)
MyBatis一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行后会将查询到的数据存储到缓存当中,第二次会从缓存中进行查找,从而提高查询效率,当一个SqlSession结束之后,一级缓存也将不存在,Mybatis默认开启一级缓存;
- 二级缓存(Mapper级别)
二级缓存的作用域是mapper的同一个namespace,执行两次相同的SQL语句,第一次执行后会将查询到的数据存储到缓存当中,第二次会从缓存中进行查找,从而提高查询效率,默认不开启。
18.Mybatis和Hibernate的区别
- Hibernate是全自动ORM映射工具,而Mybatis是半自动ORM映射工具
-
hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。
-
mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
-
Hibernate数据库移植性远大于mybatis
-
hibernate拥有完整的日志系统,mybatis则欠缺一些。
-
hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。
-
mybatis相比hibernate需要关心很多
-
sql直接优化上,mybatis要比hibernate方便很多。