与Hibernate相比,MyBatis的优势在哪?
Hibernate的缺点:
- 运行效率低,内存占用比较严重。
- 针对单一对象的增删查改,适合Hibernate,而Hibernate在批量操作时处于弱势。
- 虽然Hibernate引入一二级缓存、lazyload、查询缓存等更多优化空间(对于那些改动不大且经常使用的数据,可将它们放入缓存中),但Hibernate对于持久层封装过于完整,导致开发人员无法对sql进行优化,不适用于大型项目。
MyBatis的优点:
- 代码量大大减少,开发效率高。
- SQL写在xml中,从程序代码中彻底分离,降低耦合度,便于统一管理和优化,并可重用。
- 运行效率高。
MyBatis框架的分层
MyBatis工作原理图
MyBatis原理图如下:
工作原理解析
MyBatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件(也可以用Java文件配置的方式,需要添加@Configuration)来构建SqlSessionFactory(SqlSessionFactory是线程安全的)。
然后,SqlSessionFactory的实例直接开启一个SqlSession,再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库CRUD和事务的提交,之后关闭SqlSession。
说明:SqlSession是单线程对象,因为它是非线程安全的,是持久化操作的独享对象,类似JDBC中的Connection,底层就封装了JDBC连接。
详细流程
- 加载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中几个重要对象间执行流程
SqlSession的四大对象
Exector
- MyBatis的执行器,用于执行增删查改操作,真正进行Java与数据库交互的对象。
- 有一个抽象实现类BaseExecutor(执行器基类)和实现类CachingExecutor(二级缓存执行器)。
- BaseExecutor有三个重要的子类:
- SimpleExecutor(简单执行器)
- ReuseExecutor(可重用执行器)
- BatchExecutor(批量处理执行器)
StatementHandler
- 语句处理器,数据库的处理对象,用于执行SQL语句。
- 有一个抽象实现类BaseStatementHandler和一个实现类RoutingStatementHandler。
- BaseStatementHandler有三个子类:
- PreparedStatementHandler
- CallableStatementHandler
- SimpleStatementHandler
ParameterHandler
- 处理SQL的参数对象。
- 有一个默认实现类DefaultParameterHandler。
- 把取到的参数(parameterObject)转换后(TypeHandler),注册到Configuration中(TypeHandler也是在其中配置好的)。
ResultSetHandler
- 处理SQL的返回结果集。
- 有一个默认实现类DefualtResultSetHandler。
其余的一些对象
Configuration
MyBatis所有的配置信息都保存在Configuration对象之中,配置文件的大部分配置都会存储到该类中。
SqlSessionFactoryBuilder
这个类可以被实例化、使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它了。因此SqlSessionFactoryBuilder实例的最佳作用域是方法作用域(也就是局部方法变量)。你可以重用SqlSessionFactoryBuilder来创建多个SqlSessionFactory实例,但是最好还是不要让其一直存在以保证所有的xml解析资源开放给更重要的事情。
SqlSessionFactory
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用SqlSessionFactory的最佳时间是在应用运行期间不要重复创建多次。因此SqlSessionFactory的最佳作用域是应用作用域(生命周期伴随应用)。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession
每个线程都应该有它自己的SqlSession实例。SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。sqlSession在每次用完之后必须关闭它。
TypeHandler
负责Java数据类型和JDBC数据类型(也可以说是数据表列类型)之间的映射和转换。
SqlSource
负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回。
BoundSql
表示动态生成的SQL语句以及相应的参数信息。
MyBatis的一级缓存和二级缓存
一级缓存
- 一级缓存是SqlSession级别的缓存,在操作数据库时需要创建出SqlSessino对象,该对象中有一个HashMap用于存储缓存数据,不同的SqlSession对象之间的缓存相互独立。
- 执行commit之后,SqlSession对象就会被销毁,因此缓存也会消失。
- 缓存存放于内存。
- 默认开启。
二级缓存
- 二级缓存是mapper级别的缓存,作用域是同一个namespace下的mapper映射文件内容,多个SqlSessino共享,底层仍是HashMap。
- 缓存可存放于内存,也可通过序列化方式存放于磁盘文件。
- 默认关闭,需要手动开启(修改配置文件中 cacheEnabled 为 true )。