MyBatis 核心功能介绍
在大部分时候,我们都是在Spring里面去集成MyBatis,因为Spring对MyBatis的一些操作进行了封装,我们不能直接看到它的本质,所以先看下不使用容器的时候,也就是编程的方式,如何使用MyBatis。
pom.xml中添加MyBatis的依赖
创建一个全局的配置文件(mybatis-config.xml),这里面是对MyBatis的核心行为的控制。
创建映射器文件(mapper.xml), 通常是一张表对应一个mapper.xml文件,我们会在这个xml文件中配置我们的增删改查的SQL语句,以及参数和结果集的映射关系
跟JDBC代码一样,我们要执行对数据库的操作,必须创建一个会话,这个在MyBatis中叫做SqlSession。SqlSession又是工厂类根据全局配置文件创建的
所以整个流程是下面代码这样,最后我们通过SqlSession接口上的方法,传入我们的Statement ID来执行SQL,这是第一种方式。
这种方式有一个明显的缺点,就是对statement ID的硬编码,不能在编译时进行类型检查,所以通常我们会使用第二种方式,就是定义一个mapper接口,这个接口必须和mapper.xml里面的namespace对应起来,方法也要和statement ID对应起来。
这就是我们单独是用MyBatis的全部流程。
MyBatis核心对象的生命周期
在上面编程式的这个demo中,我们看到了MyBatis里面的几个核心对象:SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession和Mapper对象。这几个核心对象分别在MyBatis的整个工作流程里面的不同环节发挥作用,如果说我们不用容器,自己去管理这些对象的话,我们必须去思考一个问题:什么时候去创建和销毁这些对象?
在一些分布式的应用里面,多线程高并发的场景中,如果要写出高效的代码,必须要了解这四个对象的生命周期。这四个对象的生命周期在官网上面也可以找到。 [MyBatis](http://www.mybatis.org/mybatis-3/zh/getting-started.html)
下面我们从每个对象的作用的角度来理解一下,只有理解了他们是干什么的,才能知道什么时候去创建和销毁:
SqlSessionFactoryBuilder: 它是用来构建SqlSessionFactory的,而SqlSessionFactory只需要一个,所以只要构建了一个SqlSessionFactory,它的使命就完成了,也就没有存在的意义,所以它的生命周期只存在于方法的局部。
SqlSessionFactory: SqlSessionFactory是用来创建SqlSession的,每次应用程序访问数据库都需要创建一个会话,因为我们一直会有创建会话的需求,所以SqlSessionFactory会一直存在于应用的整个生命周期中。创建SqlSession只需要一个实例来做就可以了,否则会产生很多的混乱和资源浪费,SqlSessionFactory一般是采用单例模式。
SqlSession: SqlSession是一个会话,因为它不是线程安全的,不能线程间共享,所以我们在请求开始的时候创建一个新的SqlSession对象,在请求结束或者方法执行完成后要及时的关闭它。
Mapper: Mapper是从SqlSession中获取的(实际上获取到的是一个代理对象),他的作用是发送SQL来操作数据库中的数据,它的生命周期应该是在SqlSession事务方法之内。
MyBatis核心配置的解读
大部分时候我们只需要很少的配置就可以让MyBatis运行起来,但是其实MyBatis里面提供的配置项非常多,我们没有配置的时候使用的是MyBatis提供的默认值。
MyBatis-3的代码托管在github上面,[源码地址](https://github.com/mybatis/mybatis-3/releases)
一级标签
configuration: 是整个配置文件的根标签,实际上也对应着MyBatis里面最重要的配置类Configuration。它贯穿MyBatis执行流程的每一个环节,我们打开这个类看一下, 可以看到里面有很多属性,也可以和其它标签对应上。
注意: Mybatis全局配置文件顺序是固定的,否则启动会报错。
Properties
第一个是Properties标签,用来配置参数信息,比如最常见的数据库连接信息。为了避免把参数直接写死在xml文件中,我们通常会把参数放到单独的properties文件中,通过properties标签引入进来,这样在xml中可以使用${}就可以引用改了
Setting
Setting里面是MyBatis的一些核心配置
typeAliases
TypeAlias是类型别名,和Linux中的alias一样,主要用来简化全路径类名的拼写。比如我们的参数类型和返回值类型都可能会用到我们的Bean,如果每个地方都配置全路径名字的话,内容就比较多,也很容易拼错。
我们可以为自己的bean定义一个别名,既可以指定单个类,也可以指定一个package,自动转换。配置了别名以后,只需要写别名就可以了。比如com.domain.Blog都只要写blog就可以了。
MyBatis里面有系统预先定义好的类型别名,在TypeAliasRegistry中。
typeHandlers
由于Java类型和数据库的JDBC类型不是一一对应的(比如String与varchar),所以我们需要把Java对象转化成数据库的数据,和把数据库数据转化成Java对象,需要经过一定的转换,这两个方向的转换就要用到TypeHandler。
这时,我们可能会有疑问,我没有做任何类型的转化,为什么程序可以正常运行呢?这时因为MyBatis已经内置了很多TypeHandler,他们全部注册在TypeHandlerRegistry中,他们都继承了抽象类BaseTypeHandler,泛型就是要处理的Java数据类型。
当我们做类型转换的时候,就会自动调用对应的TypeHandler的方法。
如果我们需要自定义一些类型转换规则,或者要在处理类型的时候做一些特殊的动作,就可以编写自己的TypeHandler,跟系统自定义的TypeHandler一样,继承BaseTypeHandler<T>。它有四个抽象方法,我们可以分成两类:
Set方法是从Java类型转成JDBC类型:
get方法是从JDBC类型转成Java类型:
比如我们想要在获取或者设置String类型的时候做一些特殊处理,那我们可以写一个String类型的TypeHandler
然后在mybatis-config.xml文件中进行注册
最后在我们需要使用的字段上指定:
插入值的时候,从Java类型到JDBC类型,在字段属性中指定typeHandler
返回值的时候,从JDBC类型转到Java类型,在resultMap的列上指定typeHandler
objectFactory
当我们把数据库返回的结果集转化成实体类的时候,需要创建对象的实例,由于我们不知道需要处理的类型是什么,有哪些属性,所以不能用new的方式去创建。在MyBatis里面,它提供了一个工厂类的接口,叫做ObjectFactory,专门用来创建对象的实例。
ObjectFactory有一个默认的实现类DefaultObjectFactory,创建对象的方法最终都调用了instantiateClass(),是通过反射来实现的。
如果想要修改对象工厂在初始化实例类的时候的行为,就可以通过创建自己的对象工厂,集成DefaultObjectFactory来实现。
plugins
插件是MyBatis一个很强大的机制,和很多其它框架一样,MyBatis预留了插件的接口,让MyBatis更容易扩展。
根据官方的定义,插件可以拦截下面四个对象:
Executor: update、query、flushStatements、commit、rollback、getTransaction、close、isClosed
ParameterHandler: getParameterObject、setParameters
ResultSetHandler: handlerResultSets、handleOutputParameters
StatementHandler: prepare、parameterize、batch、update、query
environments
environments标签用来管理数据库的环境,比如我们可以有开发环境、测试环境、生产环境的数据库,可以在不同环境中使用不同的数据库地址和类型
一个environment标签就是一个数据源,代表一个数据库。这里面有两个关键的标签,一个是事务管理器,一个是数据源。
transactionManager如果配置成JDBC,则会使用connection对象的commit()、rollback()、close()管理事务。
如果配置成MANAGED,会把事务交给容器管理,比如JBoss。如果使用Spring + MyBatis,则没有必要配置,因为我们会直接在spring的applicationContext.xml文件中配置数据源,来覆盖MyBatis的配置。
mapper
mappers标签配置的是我们的映射器,也就是mapper.xml文件的路径。目的是让MyBatis在启动的时候去扫描这些映射器,创建映射关系。
settings
MyBatis的一些关键配置都在这个标签中定义,具体细节可以参考[官网文档](http://www.mybatis.org/mybatis-3/zh/configuration.html#settings)
版权声明: 本文为 InfoQ 作者【Java收录阁】的原创文章。
原文链接:【http://xie.infoq.cn/article/fde2ded1ece62fe259ecf8196】。文章转载请联系作者。
评论