现在很多项目都是基于Spring框架进行开发的,这种情况下如果仍然按照上面的方式来配置使用mybatis则会有很多的不方便。好在针对Spring框架mybatis也提供了配置方案,主要是通过一系列的mybatis-spring-xxx.jar来实现组合的,下面就来介绍如何在Spring项目中配置使用mybatis框架。
spring-mybatis的整合配置方式有很多种,可以通过XML和注解进行配置,下面主要介绍基于注解的配置。配置mybatis-spring分为以下几个部分:配置数据源、配置SqlSessionFactory、配置SqlSessionTemplate、配置mapper(为dao层接口配置动态代理对象)和配置事务处理。
SqlSessionFactory的作用是生成SqlSession,在之前SqlSessionFactory是通过SqlSessionFactoryBuilder类的build()方法来进行生成的,在结合Spring之后可以直接将其配置成一个Bean。具体来说mybatis-spring项目中提供了org.mybatis.spring.SqlSessionFactoryBean类给我们进行配置,一般来说这个配置类需要的提供的参数是数据源和Mybatis配置文件的位置。一个示例如下:
id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/bank"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="mybatis-config.xml"/>
首先配置了一个数据源,这里用的是spring提供的DriverManagerDataSource类,但其实可以配置任何实现了javax.sql.DataSource的数据源都是可以配置的,所以这里可以灵活使用一些第三方的数据源,比如说使用连接池管理的C3PO数据源。然后是配置一个SqlSessionFactoryBean对象,配置的主要属性就是数据源和指定mybatis的配置文件,有了这些属性之后Spring在初始化IOC容器的时候会初始化SpringFactoryBean得到mybatis运行所需的上下文。
看到这里的配置,可能让人觉得奇怪为什么需要的是SqlSessionFactory对象却在这里配置了一个SqlSessionFactoryBean对象。实际上SqlSessionFactoryBean是一个实现了FactoryBean接口的工厂Bean,对于这种类型的Bean,spring容器注入实际上是这个Bean getObject()方法的返回值。下面是其getObject()方法:
public SqlSessionFactory getObject() throws Exception {
if(this.sqlSessionFactory == null) {
this.afterPropertiesSet();
}
return this.sqlSessionFactory;
}
可以看到确实是注入了一个SqlSessionFactory对象。
上面配置的mybatis-config.xml文件和原先配置的config文件的主要区别是少了数据源部分的配置,这是因为我们在这里显示的指定了数据源所以没有必要再重复配置,即使在文件里又配置了数据源也是不会生效的。除此之外mybatis-config.xml中任然可以配置其它的元素并且配置也都是有效的,比如settings、typeAliases、mappers等属性。实际上是完全可以通过只配置SqlSessionFactoryBean来完成mybatis的配置的,下面是SqlSessionFactoryBean所有可配置项:
private Resource configLocation;
private Configuration configuration;
private Resource[] mapperLocations;
private DataSource dataSource;
private TransactionFactory transactionFactory;
private Properties configurationProperties;
private SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
private SqlSessionFactory sqlSessionFactory;
//EnvironmentAware requires spring 3.1
private String environment = SqlSessionFactoryBean.class.getSimpleName();
private boolean failFast;
private Interceptor[] plugins;
private TypeHandler>[] typeHandlers;
private String typeHandlersPackage;
private Class>[] typeAliases;
private String typeAliasesPackage;
private Class> typeAliasesSuperType;
//issue #19. No default provider.
private DatabaseIdProvider databaseIdProvider;
private Class extends VFS> vfs;
private Cache cache;
private ObjectFactory objectFactory;
private ObjectWrapperFactory objectWrapperFactory;
可以看到原先需要在mybatis-config.xml中配置的属性,这里面都有;但实际上对于比较复杂的配置,还是会通过xml文件的形式进行配置,这样更易于管理并且可读性也会高一点。
前面说过SqlSession表示一个数据库会话,负责执行sql并获取返回结果。之前是通过SqlSessionFactory的openSession()方法来获取SqlSession对象的,实际上得到的是DefaultSqlSession类对象,而在mybatis-spring中提供了SqlSession接口的另一个实现SqlSessionTemplate。配置SqlSessionTemplate时支持两种方式,
一种是只指定SqlSessionFactory;另外一种是还指定Executor的类型,这里指定的类型会覆盖掉配置文件中设置的结果。下面是一个配置示例:
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg index="0" ref="sqlSessionFactory"/>
<constructor-arg index="1" value="BATCH"/>
bean>
过上面的配置,Spring就可以把SqlSessionFactory注入到SqlSessionTemplate中去,另外这里还可以指定sqlsession中的Executor类型,上面的就配置了BATCH类型的Executor。SqlSessionTemplate也提供了一些可以直接调用的方法,但是一般都不会直接去调用这些方法,而是通过调用Dao层接口的动态代理对象去执行相关的sql。
大部分情况下其实我们都是不关心SqlSessionTemplate的,而是直接通过Mapper接口和数据库打交道。在之前是通过SqlSession的getMapper()方法获取Mapper接口的动态代理对象,然后通过这个动态代理对象来负责sql的执行和结果的返回,但在spring是没有办法为一个接口生成一个实例的,所以mybatis-spring为Mapper接口提供了一个中间类MapperFactoryBean,我们可以给它传入需要包装的接口和需要的SqlSessionTemplate或SqlSessionFactory就可以为接口生成动态代理对象,并允许我们在代码中直接注入使用。
<bean id="branchDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.sankuai.lkl.BranchDao"/>
<property name="sqlSessionTemplate" ref="sqlSessionTemplate"/>
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
bean>
这里的MapperFactoryBean也是一个继承了FactoryBean的工程Bean,同样看下它的getObject()方法:
@Override
public T getObject() throws Exception {
return getSqlSession().getMapper(this.mapperInterface);
}
这里看到其实还是调用sqlSession的getMapper()方法来获取的配置的接口的动态代理对象,所以注入的就是这个动态代理对象。
上面的配置是针对单个Dao的,但是在实际的工程中一般都会有很多的Dao层接口,我们当然可以像上面一样为每个Dao层接口配置一个MapperFactoryBean但这样太过于繁琐,mybatis-spring中提供了MapperScannerConfigurer来实现对指定包的扫描:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.sankuai.lkl.dao"/>
<property name="sqlSessionTemplateBeanName" value="sqlSessionTemplate"/>
bean>
这样会给配置路径下的每个接口都生成一个动态代理对象,并注入到spring容器中。
mybatis和spring是使用AOP来管理事务的,分为编程式事务和声明式事务,目前用的最多的是声明式事务,下面是声明式事务的配置:
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
bean>
<tx:annotation-driven transaction-manager="txManager"/>
这样配置之后就可以通过在类或方法加上 @Transactional注解来开启事务了。在这个注解里还可以指定事务的超时时间、事务隔离级别、事务传播规则等。