MyBatis整理

MyBatis

1、前言

MyBatis 本是apache的一个开源项目iBatis。

2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。

2013年11月迁移到Github。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。它支持自定义 SQL、存储过程以及高级映射。

文档1
文档2

2、MyBatis原理

2)加载映射文件。映射文件即 SQL 映射文件,该文件中配置了操作数据库的 SQL 语句,需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

3)构造会话工厂:通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。

4)创建会话对象:由会话工厂创建 SqlSession 对象,该对象中包含了执行 SQL 语句的所有方法。

5)Executor 执行器:MyBatis 底层定义了一个 Executor 接口来操作数据库,它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句,同时负责查询缓存的维护。

6)MappedStatement 对象:在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等信息。

7)输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。

8)输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。

  • 编程步骤
    1、配置xml文件
    2、加载我们的xml文件
    3、创建SqlSessionFactoryBuilder(这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。)
    4、创建SqlSessionFactory(一旦被创建就应该在应用的运行期间一直存在,不要多次创建。)
    5、通过SqlSessionFactory调用openSession()创建SqlSession(SqlSession 的实例不是线程安全的)
    6、通过sqlsession执行数据库操作(用getMapper()来获取mapper接口)
    7、调用sqlsession.commit()提交事务
    8、调用sqlsession.close()关闭会话(关闭操作很重要)

3、MyBatis特点

  • 基于SQL语句编程,相当灵活;

  • 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;

  • 提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护

  • SQL 语句的编写工作量较大

  • SQL 语句依赖于数据库, 导致数据库移植性差

  • Hibernate 和 MyBatis 的区别

    • 都是对jdbc的封装,都是持久层的框架,都用于dao层的开发。
    • 映射关系:
      • MyBatis 是一个半自动映射的框架,配置Java对象与sql语句执行结果的对应关系,多表关联关系配置简单
      • Hibernate 是一个全表映射的框架,配置Java对象与数据库表的对应关系,多表关联关系配置复杂
    • SQL优化和移植性:
      • MyBatis 需要手动编写 SQL,支持动态 SQL、处理列表、动态生成表名、支持存储过程。开发工作量相对大些。直接使用SQL语句操作数据库,不支持数据库无关性,但sql语句优化容易。
      • Hibernate 对SQL语句封装,提供了日志、缓存、级联(级联比 MyBatis 强大)等特性,此外还提供 HQL(Hibernate Query Language)操作数据库,数据库无关性支持好,但会多消耗性能。如果项目需要支持多种数据库,代码开发量少,但SQL语句优化困难。
    • 开发难易程度和学习成本:
      • MyBatis 是轻量级框架,学习使用门槛低,适合于需求变化频繁的项目,比如:互联网电子商务系统
      • Hibernate 是重量级框架,学习使用门槛高,适合于需求相对稳定的项目,比如:办公自动化系统
  • ORM是什么
    ORM(Object Relational Mapping),对象关系映射,是一种为了解决关系型数据库数据与简单Java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系型数据库中。

4、MyBatis实例

1)先在src下创建jdbc.properties和mybatis-config.xml
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在com.controller下创建以下文件
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5、其他

1) 预编译

  • SQL 预编译指的是数据库驱动在发送 SQL 语句和参数给 DBMS 之前对 SQL 语句进行编译,这样 DBMS 执行 SQL 时,就不需要重新编译。
  • JDBC 中使用对象 PreparedStatement 来抽象预编译语句。
  • 防止sql注入。
  • 预编译阶段可以优化 SQL 的执行。
    • 预编译之后的 SQL 多数情况下可以直接执行,DBMS 不需要再次编译,越复杂的SQL,编译的复杂度将越大,预编译阶段可以合并多次操作为一个操作。
  • 同时预编译语句对象可以重复利用。
    • 把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来,下次对于同一个SQL,可以直接使用这个缓存的 PreparedState 对象。
  • Mybatis默认情况下,将对所有的 SQL 进行预编译。

2)Mybatis都有哪些Executor执行器

Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。

  • SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
  • ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。
  • BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。

3)Mybatis中如何指定使用哪一种Executor执行器

在Mybatis配置文件中,在设置(settings)可以指定默认的ExecutorType执行器类型;

也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数,如SqlSession openSession(ExecutorType execType)。

4)Mybatis是否支持延迟加载

Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。

它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器intercept()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。

5)#{}和${}的区别

#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理。

  • Mybatis 在处理#{}时,会将 sql 中的#{}替换为?号,调用 PreparedStatement 的set 方法来赋值;
  • Mybatis 在处理${}时,就是把{}替换成变量的值。使用#{}可以有效的防止 SQL 注入, 提高系统安全性。
  • 变量替换后,#{} 对应的变量自动加上单引号 ;${} 对应的变量不会加上单引号 。
  • #{} 的变量替换是在DBMS 中;${} 的变量替换是在 DBMS 外

6)模糊查询
INSTR(field, str)>0
CONCAT
like 不推荐

7)在mapper中如何传递多个参数

  • 顺序传参法:select * from user where name = #{0} and age= #{1}
  • @Param注解传参法:
    public User selectUser(@Param(“name”) String name, int @Param(“age”) age);
    select * from user where name = #{name} and age= #{age}
  • Map传参法
  • Java Bean传参法

8)Mybatis如何执行批量操作

使用foreach标签

使用ExecutorType.BATCH:
SqlSession sqlSession = factory.openSession(ExecutorType.BATCH);

Mybatis内置的ExecutorType有3种,默认为simple,该模式下它为每个语句的执行创建一个新的预处理语句,单条提交sql;而batch模式重复使用已经预处理的语句,并且批量执行所有更新语句,显然batch性能将更优; 但batch模式也有自己的问题,比如在Insert操作时,在事务没有提交之前,是没有办法获取到自增的id,这在某型情形下是不符合业务要求的

9)如何获取生成的主键

  • 支持主键自增的数据库(MySQL):标签useGeneratedKeys=“true” keyProperty=“userId”
  • 不管支不支持主键自增的数据库(Oracle)
    < selectKey keyColumn=“id” resultType=“long” keyProperty=“userId” order=“BEFORE”>
    SELECT USER_ID.nextval as id from dual
    < /selectKey>

如果Mysql 使用selectKey的方式获取主键,需要注意下面两点:
order : AFTER
获取递增主键值 :SELECT LAST_INSERT_ID()

10)实体类中的属性名和表中的字段名不一样
起别名、通过< resultMap>来映射

11)Mapper 编写有哪几种方式

  • 第一种:接口实现类继承 SqlSessionDaoSupport:使用此种方法需要编写mapper 接口,mapper 接口实现类、mapper.xml 文件。
    • 在 mybatis-config.xml 中配置 mapper.xml 的位置:
      < mappers>
      < mapper resource=“mapper.xml 文件的地址” />
      < mapper resource=“mapper.xml 文件的地址” />
      < /mappers>
    • 编写 mapper 接口
    • 实现类集成 SqlSessionDaoSupport
    • spring 配置sqlSessionFactory:
      < bean id=" " class=“mapper 接口的实现”>
      < property name=“sqlSessionFactory” ref=“sqlSessionFactory” />
      < /bean>
  • 第二种:使用 org.mybatis.spring.mapper.MapperFactoryBean:
    • 在 mybatis-config.xml 中配置 mapper.xml 的位置
    • 编写 mapper 接口:
    • mapper.xml 中的 namespace 为 mapper 接口的地址,定义的 statement 的 id 为mapper接口的方法名
    • Spring 中定义
      < bean id="" class=“org.mybatis.spring.mapper.MapperFactoryBean”>
      < property name=“mapperInterface” value=“mapper 接口地址” />
      < property name=“sqlSessionFactory” ref=“sqlSessionFactory” />
      < /bean>
  • 第三种:使用 mapper 扫描器:
    • mapper.xml 文件编写
    • 编写 mapper 接口
    • 配置 mapper 扫描器:
      < bean class=“org.mybatis.spring.mapper.MapperScannerConfigurer”>
      < property name=“basePackage” value=“mapper 接口包地址”/>
      < property name=“sqlSessionFactoryBeanName” value=“sqlSessionFactory”/>
      < /bean>

12)什么是MyBatis的接口绑定
接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。

接口绑定有两种实现方式:

  • 注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;
  • xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。

当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。

13)最佳实践中,通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗

Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement。

Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。

Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

14)Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复
不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复;毕竟namespace不是必须的,只是最佳实践而已。

原因就是namespace+id是作为Map<String, MappedStatement>的key使用的,如果没有namespace,就剩下id,那么,id重复会导致数据互相覆盖。

15)简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系
Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。

在Xml映射文件中,< parameterMap>标签会被解析为ParameterMap对象,其每个子元素会被解析为ParameterMapping对象。

< resultMap>标签会被解析为ResultMap对象,其每个子元素会被解析为ResultMapping对象。

每一个< select>、< insert>、< update>、< delete>标签均会被解析为MappedStatement对象,标签内的sql会被解析为BoundSql对象。

16)Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

  • 第一种是使用< resultMap>标签,逐一定义列名和对象属性名之间的映射关系。
  • 第二种是使用sql列的别名功能,将列别名书写为对象属性名,但是列名不区分大小写,Mybatis会忽略列名大小写,智能找到与之对应对象属性名。

有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。

17)Xml映射文件中,除了常见的select|insert|updae|delete标签之外,还有哪些标签?

< resultMap>、< parameterMap>、< sql>、< include>、< selectKey>
9个动态sql的标签:trim|where|set|foreach|if|choose|when|otherwise|bind

18)Mybatis映射文件中,如果A标签通过include引用了B标签的内容,请问,B标签能否定义在A标签的后面
虽然Mybatis解析Xml映射文件是按照顺序解析的,但是,被引用的B标签依然可以定义在任何地方,Mybatis都可以正确识别。

原理是,Mybatis解析A标签,发现A标签引用了B标签,但是B标签尚未解析到,尚不存在,此时,Mybatis会将A标签标记为未解析状态,然后继续解析余下的标签,包含B标签,待所有标签解析完毕,Mybatis会重新解析那些被标记为未解析的标签,此时再解析A标签时,B标签已经存在,A标签也就可以正常解析完成了。

19)MyBatis实现一对一,一对多有几种方式,怎么操作的

有联合查询和嵌套查询。

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

20)Mybatis是否可以映射Enum枚举类
Mybatis可以映射枚举类,不单可以映射枚举类,Mybatis可以映射任何对象到表的一列上。映射方式为自定义一个TypeHandler,实现TypeHandler的setParameter()和getResult()接口方法。

TypeHandler有两个作用,一是完成从javaType至jdbcType的转换,二是完成jdbcType至javaType的转换,体现为setParameter()和getResult()两个方法,分别代表设置sql问号占位符参数和获取列查询结果。

21)Mybatis动态sql
Mybatis动态sql可以让我们在Xml映射文件内,以标签的形式编写动态sql,完成逻辑判断和动态拼接sql的功能。

Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。

其执行原理为,使用OGNL从sql参数对象中计算表达式的值,根据表达式的值动态拼接sql,以此来完成动态sql的功能。

22)Mybatis是如何进行分页的

Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

举例:select * from student,拦截sql后重写为:select t.* from (select * from student) t limit 0, 10

23)简述Mybatis的插件运行原理,以及如何编写一个插件

Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件。

Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。

实现Mybatis的Interceptor接口并复写intercept()方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。

24)Mybatis的一级、二级缓存

  • 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
  • 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置< cache/> 。
  • 对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值