MyBatis知识点总结

MyBatis中文文档

1、什么是MyBatis

(1)Mybatis是一个半ORM(对象关系映射)框架(Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完 成,所以,称之为半自动ORM映射工具。Hiber nate属于全自动ORM映射工具,使用Hiber nate查询关联对象或者 关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。),它内部封装了JDBC,开发时只需要关注SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql,可以严格控制sql执行性能,灵活度高。
(2)MyBatis 可以使用 XML 或注解来配置和映射原生信息,将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
(3)通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。
在这里插入图片描述

2、MyBatis的优点和缺点

优点:
(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。
(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。
(4)能够与Spring很好的集成;
(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。

缺点
(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定
要求。
(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。

3、Mybatis 中#和$的区别?

#预编译处理,相当于对数据 加上 双引号,$相当于直接显示数据,直接替换。

  1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql 时的值为order by “111”, 如果传入的值是id,则解析成的sql 为order by “id”.
  2. $将传入的数据直接显示生成在sql 中。如:order by u s e r i d user_id userid,如果传入的值是111,那么解析成sql 时的值为order by user_id, 如果传入的值是id,则解析成的sql 为order by id.
  3. #方式能够很大程度防止sql 注入。
  4. $方式无法防止Sql 注入。
  5. $方式一般用于传入数据库对象,例如传入表名.
  6. 一般能用#的就别用$.

4、JDBC 编程有哪些不足之处,MyBatis 是如何解决这些问题的?

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
    解决:在SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
  2. Sql 语句写在代码中造成代码不易维护,实际应用sql 变化的可能较大,sql 变动需要改变java 代码。
    解决:将Sql 语句配置在XXXXmapper.xml 文件中与java 代码分离。
  3. 向sql 语句传参数麻烦,因为sql 语句的where 条件不一定,可能多也可能少,占位符需要和参数一一对应。
    解决: Mybatis 自动将java 对象映射至sql 语句。
  4. 对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成pojo 对象。
    解决:Mybatis 自动将sql 执行结果映射至java 对象。

5、使用MyBatis 的mapper 接口调用时有哪些要求?

  1. Mapper 接口方法名和mapper.xml 中定义的每个sql 的id 相同
  2. Mapper 接口方法的输入参数类型和mapper.xml 中定义的每个sql 的parameterType 的类型相同
  3. Mapper 接口方法的输出参数类型和mapper.xml 中定义的每个sql 的resultType 的类型相同
  4. Mapper.xml 文件中的namespace 即是mapper 接口的类路径。

6、Mybatis 中一级缓存与二级缓存?

  1. 一级缓存: 基于PerpetualCache 的 HashMap 本地缓存,级缓存默认是开启的,其存储作用域为 Session,当 Session flush 或close 之后,该Session 中的所有 Cache 就将清空。
  2. 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为Mapper(Namespace),并且可自定义存储源,如 Ehcache。作用域为namespance 是指对该namespance 对应的配置文件中所有的select 操作结果都缓存,这样不同线程之间就可以共用二级缓存。启动二级缓存:在mapper 配置文件中:<cache />
    二级缓存可以设置返回的缓存对象策略:<cache readOnly="true">。当readOnly="true"时,表示二级缓存返回给所有调用者同一个缓存对象实例,调用者可以update 获取的缓存实例,但是这样可能会造成其他调用者出现数据不一致的情况(因为所有调用者调用的是同一个实例)。当readOnly="false"时,返回给调用者的是二级缓存总缓存对象的拷贝,即不同调用者获取的是缓存对象不同的实例,这样调用者对各自的缓存对象的修改不会影响到其他的调用者,即是安全的,所以默认是readOnly=“false”;
  3. 对于缓存数据更新机制,当某一个作用域(一级缓存Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被clear。

7、MyBatis 在insert 插入操作时返回主键ID

数据库为MySql 时:

<insert id="insert" parameterType="com.test.User" keyProperty="userId"
useGeneratedKeys="true" >

“keyProperty”表示返回的id 要保存到对象的那个属性中,“useGeneratedKeys”表示主键id 为自增长模式。MySQL 中做以上配置就OK 了

数据库为Oracle 时:

<insert id="insert" parameterType="com.test.User">
<selectKey resultType="INTEGER" order="BEFORE" keyProperty="userId">
 SELECT SEQ_USER.NEXTVAL as userId from DUAL
 </selectKey>
 insert into user (user_id, user_name, modified, state)
 values (#{userId,jdbcType=INTEGER}, #{userName,jdbcType=VARCHAR},
#{modified,jdbcType=TIMESTAMP}, #{state,jdbcType=INTEGER})
 </insert>

由于Oracle 没有自增长一说法,只有序列这种模仿自增的形式,所以不能再使用“useGeneratedKeys”属性。
而是使用<selectKey>将ID 获取并赋值到对象的属性中,insert 插入操作时正常插入id。

8、体类中的属性名和表中的字段名不一样 ,怎么办 ?(Mybatis是如何将sql执行结果封装为目标对象并返回的)

第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种: 通过来映射字段名和实体类属性名的一一对应的关系。

<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是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页。可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言

10、 如何执行批量插入?

首先,创建一个简单的insert语句:
然后在java代码中像下面这样执行批处理插入:

<select id="getOrder" parameterType="int" resultMap="orderresultmap">
select * from orders where order_id=#{id}
</select>

代码中像下面这样执行批处理插入:

list<string> names = new arraylist();
names.add(“fred”);
names.add(“barney”);
names.add(“betty”);
names.add(“wilma”);

// 注意这里 executortype.batch
sqlsession sqlsession = sqlsessionfactory.opensession(executortype.batch);
try {
namemapper mapper = sqlsession.getmapper(namemapper.class);
for (string name : names) {
mapper.insertname(name);
}
sqlsession.commit();
}catch(Exception e){
e.printStackTrace();
sqlSession.rollback();
throw e;
}
finally {
sqlsession.close();
}

11、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,支持延迟加载的原理都是一样的。

12、 简述Mybatis的插件运行原理,以及如何编写一个插件?

  1. Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、 StatementHandler、Executor 这 4 种接口的插件,Mybatis 通过动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行 这4种接口对象的方法时,就会进入拦截方法,具体就是
    In vocatio nHa ndler的inv oke()方法,当然,只会拦截那些你指定需要拦截 的方法。
  2. 实现Mybatis的In terceptor接口并复写in tercept()方法,然后在给插件 编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置 文件中配置你编写的插件。

13、Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?动态sql 的执行原理?

  1. <resultMap〉、<parameterMap>、<sql>、 <include>、<selectKey>其 中<sql>为sql片段标签,通过<include>标签引入sql片 段,<selectKey>自增的主键生成策略标签。
  2. Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动 态sql,完成逻辑判断和动态拼接sql的功能。
  3. Mybatis提供了 9种动态sql标签:
    trim|where|set|foreach|if|choose|when|otherwise|bind。
  4. 其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表 达式的值动态拼接sql,以此来完成动态sql的功能

14、 MyBatis 与 Hibernate 有哪些不同?

〔.Mybatis和hiber nate不同,它不完全是一个ORM框架,因为MyBatis 需要程序员自己编写Sql语句,不过mybatis可以通过XML或注解方式灵 活配置要运行的sql语句,并将java对象和sql语句映射生成最终执行的 sql,最后将sql执行的结果再映射生成java对象。
2.Mybatis学习门槛低,简单易学,程序员直接编写原生态sql,可严格控 制sql执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开 发,例如互联网软件、企业运营类软件等,因为这类软件需求变化频繁, —但需求变化要求成果输出迅速。但是灵活的前提是mybatis无法做到数 据库无关性,如果需要实现支持多种数据库的软件则需要自定义多套sql 映射文件,工作量大。
3. Hibe rnate对象/关系映射能力强,数据库无关性好,对于关系模型要求 高的软件(例如需求固定的定制化软件)如果用hibe rn ate开发可以节省很多 代码,提高效率。但是Hiber nate的缺点是学习门槛高,要精通门槛更 高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡,以及怎样 用好Hibernate需要具有很强的经验和能力才行。总之,按照用户的需求 在有限的资源环境下只要能做出维护性、扩展性良好的软件架构都是好架 构,所以框架只有适合才是最好。

15、接口绑定有几种实现方式,分别是怎么实现的?

接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加 上@Select@Update等注解里面包含Sql语句来绑定,另外一种就是通过 xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的 namespace必须为接口的全路径名.

16、MyBatis实现一对一有几种方式?具体怎么操作的?

有联合查询和嵌套查询,联合查询是几个表联合查询,只查询一次,通过在 resultMap里面配置associati on节点配置一对一的类就可以完成;嵌套查询 是先查一个表,根据这个表里面的结果的外键id,去再另外一个表里面查询 数据,也是通过associati on配置,但另外一个表的查询通过select属性配 置。

17、 Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式, 以及它们之间的区别?

能,Mybatis不仅可以执行一对一、一对多的关联查询,还可以执行多对 ―,多对多的关联查询,多对一查询,其实就是一对一查询,只需要把 selectO ne()修改为selectListO即可;多对多查询,其实就是一对多查询,只 需要把selectO ne()修改为selectListO即可。

18、 接口绑定有几种实现方式,分别是怎么实现的?

接口绑定有两种实现方式,一种是通过注解绑定,就是在接口的方法上面加 上@Select@Update等注解里面包含Sql语句来绑定,另外一种就是通过 xml里面写SQL来绑定,在这种情况下,要指定xml映射文件里面的 namespace必须为接口的全路径名.

19、通常一个Xml映射文件,都会写一个Dao接口与之对应,Dao的工 作原理,是否可以重载?

不能重载,因为通过Dao寻找Xml对应的sql的时候全限名+方法名的保 存和寻找策略。接口工作原理为jdk动态代理原理,运行时会为dao生成 proxy,代理对象会拦截接口方法,去执行对应的sql返回数据。

20、Mybatis映射文件中,如果A标签通过include引用了 B标签的内 容,请问,B标签能否定义在A标签的后面,还是说必须定义在A标签 的前面?

虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标 签依然可以定义在任何地方,Mybatis都可以正确识别。原理是,Mybatis 解析A标签,发现A标签引用了 B标签,但是B标签尚未解析到,尚不 存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下 的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被 标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也 就可以正常解析完成了

21、Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重 复?

不同的Xml映射文件,如果配置了 n amespace,那么id可以重复;如果没 有配置namespace,那么id不能重复;毕竟n amespace不是必须的,只 是最佳实践而已。原因就是namespace+id是作为Map<St ring, MappedStatement>的key使用的,如果没有namespace,就剩下id,那 么,id重复会导致数据互相覆盖。有了 namespace,自然id就可以重 复,namespace不同,namespace+id自然也就不同。

22、Mybatis都有哪些Executor执行器?它们之间的区别是什么?

Mybatis有三种基本的Executor执行器, SimpleExecutor、
ReuseExecutor、 BatchExecutor。
I.SimpleExecutor:每执行一次 update 或 select,就开启一个Statement对象,用完立刻关闭Statement对象。默认的
2. ReuseExecutor:执行 update 或 select,以 sql 作为 key 查找 Stateme nt 对象,存在就使用,不存在就创建,用完后,不关闭Stateme nt对象,而 是放置于Map
3. BatchExecutor:完成批处理。

23、Mybatis中如何指定使用哪一种Executor执行器?

在Mybatis配置文件中,可以指定默认的ExecutorType执行器类型,也可 以手动给DefaultSqlSessio nFactory的创建SqlSession的方法传递 ExecutorType 类型参数。

24、Mybatis是否可以映射Enum枚举类?

Mybatis可以映射枚举类,不单可以映射枚举类,Mybatis可以映射任何对 象到表的一列上。映射方式为自定义一个TypeHa ndler,实现TypeHa ndler 的 setParameterO 和 getResult。接口方法。
TypeHa ndler有两个作用,一是完成从javaType至jdbcType的转换,二 是完成 jdbcType 至 javaType 的转换,体现为 setParameterO 和 getResult。 两个方法,分别代表设置sql问号占位符参数和获取列查询结果。

25、如何获取自动生成的(主)键值?

配置文件设置usegeneratedkeys为true

26、 在mapper中如何传递多个参数?

  1. 直接在方法中传递参数,xml文件用#{0} #{1}来获取
  2. 使用@param注解:这样可以直接在xml文件中通过#{n ame}来获取

27、 resultType resultMap 的区别?

在使用mybatis进行数据库连接操作时对于SQL语句返回结果的处理通常有两种方式,一种就是resultType另一种就是resultMap,下面说下我对这两者的认识和理解

resultType:当使用resultType做SQL语句返回结果类型处理时,对于SQL语句查询出的字段在相应的pojo中必须有和它相同的字段对应,而resultType中的内容就是pojo在本项目中的位置。

因此对于单表查询的话用resultType是最合适的。但是,如果在写pojo时,不想用数据库表中定义的字段名称,也是可以使用resultMap进行处理对应的。多表连接查询时,若是一对一的连接查询,那么需要新建一个pojo,pojo中包括两个表中需要查询出的所有的字段,这个地方的处理方式通常为创建一个继承一个表字段的pojo,再在里面添加另外一个表内需要查询出的字段即可。若是一对多查询时,若是使用内连接查询,则很可能出现查询出的字段有重复。使用双重for循环嵌套处理即可。

resultMap:当使用resultMap做SQL语句返回结果类型处理时,通常需要在mapper.xml中定义resultMap进行pojo和相应表字段的对应。

28、 Mybatis比IBatis比较大的几个改进是什么?

  1. 有接口绑定,包括注解绑定sql和xml绑定Sql
  2. 动态sql由原来的节点配置变成OGNL表达式
  3. 在一对一,一对多的时候引进了 associati on,在一对多的时候引入了 collection节点,不过都是在resultMap里面配置

29、 IBatis和MyBatis在核心处理类分别叫什么?

IBatis里面的核心处理类交SqlMapClient,
MyBatis里面的核心处理类叫做 SqlSession。

30、 IBatis和MyBatis在细节上的不同有哪些?

  1. 在sql里面变量命名有原来的#变量#变成了#{变量},原来的 变 量 变量 变成了${变量}
  2. iBatis是parameterClass,而MyBatis是可以不写的,也可以用parameterType;parameterClass,而MyBatis是可以不写的,也可以用parameterType;
    iBatis的传出参数关键字是:resultClass,而MyBatis是resultMap。
iBatis: <select id="selectDeviceByWhere" parameterClass="Map" resultClass="BaseResultMap"> </select>
MyBatis:<select id="selectDeviceByWhere" parameterType="Map" resultMap="BaseResultMap"> </select>
  1. 判断语句,这个也是非常常用和重要的地方。
    对于MyBatis的很简单,只要在where 或者if 的标签里面添加test=""就可以了,里面写判断条件了。但是IBatis的就麻烦了许多了,它将每个都方法都进行了封装。例如
    isNull:判断property字段是否是null
<isNull prepend="and" property="id">   </isNull>
isEqual相当于equals,判断状态值。
<isEqual property="state" compareValue="0">  </isEqual>` 或
<isEqual property="state" compareProperty="nextState">  </isEqual>
isEmpty判断参数是否为Null或者空,满足其中一个条件则其true。
isNotEmpty相反,当参数既不为Null也不为空是其为true
  1. 原来的 queryForObject queryForList 变成了 selectOne selectList
  2. 原来的 别名设置在映射文件里面,变成了放在了核心配置文件里
  3. MyBatis使用的是ForEach方法。他可以遍历List,Map三种元素,iBatis是使用Iterate:这属性遍历整个集合
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值