Mybaits-Spring

1.   Mybaits-Spring介绍

1.1. 什么是Mybaits-Spring?

MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。 使用这个类库中的类, Spring 将会加载必要的 MyBatis 工厂类和 session 类。 这个类库也提供一个简单的方式来注入 MyBatis 数据映射器和 SqlSession 到业务层的 bean 中。 而且它也会处理事务, 翻译 MyBatis 的异常到Spring 的 DataAccessException 异常(数据访问异常,译者注)中。最终,它并不会依赖于 MyBatis,Spring 或 MyBatis-Spring 来构建应用程序代码。

1.2. Requirements

在开始使用 MyBatis-Spring 的整合之前,很重要的一点是,你要熟悉 Spring 和MyBatis 这两个框架还有和它们有关的术语,本手册中不会提供二者的基本内容,安装和配置教程。

MyBatis-Spring 需要 Java 5 或者更高 并且请参考以下MyBatis 和 Spring的版本信息:

MyBatis-Spring

MyBatis

Spring

1.0.0 and 1.0.1

3.0.1 to 3.0.5

3.0.0 or higher

1.0.2

3.0.6

3.0.0 or higher

1.1.0

3.1.0 or higher

3.0.0 or higher

 

2.  入门

本章将会以简略的步骤告诉你如何安装和创建 MyBatis-Spring,并构建一个简单的数据 访问事务性的应用程序

2.1.配置

要使用MyBatis-Spring 模块,你只需要包含 mybatis-spring-x.x.x.jar 文 件就可以了,并在类路径中加入相关的依赖。

如果你使用 Maven,那么在 pom.xml 中加入下面的代码即可:

<dependency>
         <groupId>org.mybatis</groupId>
         <artifactId>mybatis-spring</artifactId>
         <version>x.x.x</version>
</dependency>

2.2.快速设置

要和Spring 一起使用 MyBatis,你需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory 和至少一个数据映射器类。

在MyBatis-Spring 中,SqlSessionFactoryBean 是用于创建 SqlSessionFactory 的。要配置这个工厂 bean,放置下面的代码在 Spring 的 XML 配置文件中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

要注意 SqlSessionFactory 需要一个 DataSource(数据源,译者注) 。这可以是任意 的DataSource,配置它就和配置其它 Spring 数据库连接一样。

假设你有一个如下的mapper class定义:

public interface UserMapper {
  @Select("SELECT * FROM users WHERE id = #{userId}")
  User getUser(@Param("userId") String userId);
} 

那么可以使用 MapperFactoryBean,像下面这样来把接口加入到 Spring 中:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

要注意,所指定的映射器类必须是一个接口,而不是具体的实现类。在这个示例中,注 解被用来指定 SQL 语句,但是 MyBatis 的映射器 XML 文件也可以用。

一旦配置好,你可以用注入其它任意 Spring 的bean 相同的方式直接注入映射器到你的 business/service 对象中。MapperFactoryBean 处理 SqlSession 的创建和关闭它。如果使用了 Spring 的事务,那么当事务完成时,session 将会提交或回滚。最终,任何异常都会被翻 译成 Spring 的 DataAccessException 异常。

调用 MyBatis 数据方法现在只需一行代码:

public class FooServiceImpl implements FooService {
private UserMapper userMapper;
public void setUserMapper(UserMapper userMapper) {
  this.userMapper = userMapper;
}
public User doSomeBusinessStuff(String userId) {
  return this.userMapper.getUser(userId);
}

3.  SqlSessionFactoryBean

在基本的 MyBatis 中,session 工厂可以使用 SqlSessionFactoryBuilder 来创建。而在MyBatis-Spring 中,则使用SqlSessionFactoryBean 来替代

3.1.Setup

要创建工厂 bean,放置下面的代码在 Spring 的 XML 配置文件中:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
</bean>

要注意 SqlSessionFactoryBean 实现了 Spring 的 FactoryBean 接口(请参考Spring 文 档的 3.8 章节)。这就说明了由 Spring 最终创建的 bean 不是 SqlSessionFactoryBean 本身,而是该工厂getObject()的返回结果。既然如此,Spring 将会在应用启动时为你创建 SqlSessionFactory 对象,然后将它以 SqlSessionFactory 为名来存储。在 Java 中, 相同的代码是:

SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
SqlSessionFactory sessionFactory = factoryBean.getObject();

在一般的 MyBatis-Spring 用法中, 你不需要直接使用 SqlSessionFactoryBean 或和其对 应的SqlSessionFactory。相反,session 工厂将会被注入到 MapperFactoryBean 或其它DAOS扩展了 SqlSessionDaoSupport。

3.2.Properties

SqlSessionFactory有一个必须属性,就是 JDBC 的 DataSource。可以是任意的DataSource,其配置和其它 Spring 数据库连接是一样的。

一个通用的属性是 configLocation,它是用来指定 MyBatis 的 XML 配置文件路径的。 如果基本的 MyBatis 配置需要改变, 那么这就是一个需要它的地方。 通常这会是<settings> 或<typeAliases>的部分。

要注意这个配置文件不需要是一个完整的 MyBatis 配置。确切地说,任意环境数据源 和 MyBatis 的事务管理器都会被忽略。使用这些属性值,SqlSessionFactoryBean会自动创建MyBatis环境。

如果 MyBatis 映射器 XML 文件在和映射器类不在同一个类路径下,那么就需要进行配置了。使用这个配置,有两种选择。第一是手动在 MyBatis 的 XML 配 置文件中使用<mappers>部分来指定类路径。第二是使用工厂 bean 的 mapperLocations 属 性。

mapperLocations属性使用一个资源位置的 list。 这个属性可以用来指定 MyBatis 的 XML 映射器文件的位置。 它可以从基路径下递归搜索所有路径。比如:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml" />
</bean>

这会从类路径下加载在 sample.config.mappers 包和它的子包中所有的 MyBatis 映射器 XML 文件。

4.  事务

一个使用 MyBatis-Spring 的主要原因是它允许 MyBatis 参与到 Spring 的事务管理中。而不是MyBatis 创建一个新的特定的事务管理,MyBatis-Spring 利用了存在于Spring 中的 DataSourceTransactionManager。

一旦 Spring 的 PlatformTransactionManager 配置好了,你可以在 Spring 中以你通常的做 法来配置事务。@Transactional 注解和 AOP(Aspect-OrientedProgram,面向切面编程,译 者注)样式的配置都是支持的。在事务处理期间,一个单独的 SqlSession 对象将会被创建 和使用。当事务完成时,这个 session 会以合适的方式提交或回滚。

一旦事务创建之后,MyBatis-Spring 将会透明的管理事务。在你的 DAO 类中就不需要额外的代码了。

4.1.标准配置

要开启 Spring 的事务处理,在 Spring 的 XML 配置文件中简单创建一个 DataSourceTransactionManager 对象:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
</bean>

指定的 DataSource 一般可以是你使用 Spring 的任意 JDBC DataSource。这包含了连接 池和通过 JNDI 查找获得的 DataSource。

要注意, 为事务管理器指定的 DataSource 必须和用来创建 SqlSessionFactoryBean 的是同一个数据源,否则事务管理器就无法工作了。

4.2.容器管理事务

如果你正使用一个J2EE容器而且想让 Spring 参与到容器管理事务(Container managed transactions,CMT)中,那么Spring应该使用JtaTransactionManager或它的容 器指定的子类来配置。做这件事情的最方便的方式是用Spring 的事务命名空间:

<tx:jta-transaction-manager />

在这种配置中,MyBatis 将会和其它由 CMT 配置的 Spring 事务资源一样。Spring 会自动使用任意存在的容器事务,在上面附加一个 SqlSession。如果没有开始事务,或者需要基 于事务配置,Spring 会开启一个新的容器管理事务。

注意,如果你想使用CMT,而不想使用 Spring 的事务管理,你就必须配置SqlSessionFactoryBean 来使用基本的MyBatis 的 ManagedTransactionFactory 而不是其 它任意的 Spring 事务管理器:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="transactionFactory">
    <bean class="org.apache.ibatis.transaction.managed.ManagedTransactionFactory" />
  </property>  
</bean>

4.3.编程式事务管理

MyBatis的 SqlSession 提供指定的方法来处理编程式的事务。 但是当使用 MyBatis-Spring 时, bean 将会使用 Spring 管理的 SqlSession 或映射器来注入。 那就是说 Spring 通常是处理 事务的。

你不能在Spring管理的 SqlSession上调用 SqlSession.commit() ,SqlSession.rollback()或SqlSession.close()方法 。 如 果 这 样 做 了 , 就会抛出UnsupportedOperationException异常。注意在使用注入的映射器时不能访问那些方法。

无论 JDBC 连接是否设置为自动提交, SqlSession 数据方法的执行或在 Spring 事务之外 任意调用映射器方法都将会自动被提交。

如果你想编程式地控制事务,请参考 Spring 手册的 10.6节。这段代码展示了如何手动 使用在 10.6.2 章节描述的PlatformTransactionManager 来处理事务。

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
 
TransactionStatus status = txManager.getTransaction(def);
try {
  userMapper.insertUser(user);
}
catch (MyException ex) {
  txManager.rollback(status);
  throw ex;
}
txManager.commit(status);

注意这段代码展示了一个映射器,但它也能和 SqlSession 一起使用

5.  使用 SqlSession

在 MyBatis 中,你可以使用SqlSessionFactory 来创建 SqlSession。一旦你获得一个 session 之后,你可以使用它来执行映射语句,提交或回滚连接,最后,当不再需要它的时候, 你可以关闭 session。 使用 MyBatis-Spring 之后, 你不再需要直接使用 SqlSessionFactory 了,因为你的 bean 可以通过一个线程安全的 SqlSession 来注入,基于 Spring 的事务配置 来自动提交,回滚,关闭 session。

注意通常不必直接使用 SqlSession。 在大多数情况下 MapperFactoryBean, 将会在 bean 中注入所需要的映射器。下一章节中的MapperFactoryBean(6.1 节)会解释这个细节。

5.1.SqlSessionTemplate

SqlSessionTemplate是 MyBatis-Spring 的核心。 这个类负责管理 MyBatis 的 SqlSession, 调用 MyBatis 的 SQL 方法, 翻译异常。 SqlSessionTemplate 是线程安全的, 可以被多个 DAO 所共享使用。

当调用 SQL 方法时, 包含从映射器getMapper()方法返回的方法, SqlSessionTemplate 将会保证使用的 SqlSession 是和当前 Spring 的事务相关的。此外,它管理 session 的生命 周期,包含必要的关闭,提交或回滚操作。

SqlSessionTemplate实现了 SqlSession 接口,这就是说,在代码中无需对 MyBatis 的SqlSession 进行替换。 SqlSessionTemplate 通常是被用来替代默认的 MyBatis 实现的 DefaultSqlSession , 因为模板可以参与到 Spring 的事务中并且被多个注入的映射器类所使 用时也是线程安全的。相同应用程序中两个类之间的转换可能会引起数据一致性的问题。

SqlSessionTemplate对象可以使用 SqlSessionFactory 作为构造方法的参数来创建。

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

这个 bean 现在可以直接注入到 DAO bean 中。你需要在 bean 中添加一个 SqlSession 属性,就像下面的代码:

public class UserDaoImpl implements UserDao {
 
  private SqlSession sqlSession;
 
  public void setSqlSession(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
  }
 
  public User getUser(String userId) {
    return (User) sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

如下注入 SqlSessionTemplate:

<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>

SqlSessionTemplate有一个使用 ExecutorType 作为参数的构造方法。这允许你用来 创建对象,比如,一个批量 SqlSession,但是使用了下列 Spring 配置的 XML 文件:

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
  <constructor-arg index="1" value="BATCH" />
</bean>

现在你所有的语句可以批量操作了,下面的语句就可以在 DAO 中使用了。

public void insertUsers(User[] users) {
   for (User user : users) {
     sqlSession.insert("org.mybatis.spring.sample.mapper.UserMapper.insertUser", user);
   }
 }

注意,如果所需的执行方法和默认的 SqlSessionFactory 设置不同,这种配置风格才 能使用。

对这种形式需要说明的是当这个方法被调用时,不能有一个存在使用不同 ExecutorType 运行的事务。也要保证在不同的事务中,使用不同执行器来调用 SqlSessionTemplate 时, (比如 PROPAGATION_REQUIRES_NEW)或完全在一个事务外面。

5.2.SqlSessionDaoSupport

SqlSessionDaoSupport是 一 个 抽象 的支 持 类, 用来 为你 提供SqlSession 。 调 用 getSqlSession()方法你会得到一个 SqlSessionTemplate,之后可以用于执行 SQL 方法, 就像下面这样:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
  public User getUser(String userId) {
    return (User) getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}

通常 MapperFactoryBean 是这个类的首选,因为它不需要额外的代码。但是,如果你 需要在 DAO 中做其它非MyBatis 的工作或需要具体的类,那么这个类就很有用了。

SqlSessionDaoSupport需要一个sqlSessionFactor或 sqlSessionTemplate 属性来设置。这些被明确地设置或由Spring来自动装配。如果两者都被设置 了,那么SqlSessionFactory 是被忽略的。

假设类UserMapperImpl是SqlSessionDaoSupport的子类,它可以在 Spring 中进行如 下的配置:

<bean id="userMapper" class="org.mybatis.spring.sample.mapper.UserDaoImpl">
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

6.  注入映射器

为了代替手工使用SqlSessionDaoSupport或SqlSessionTemplate编写数据访问对象 (DAO)的代码,MyBatis-Spring 提供了一个动态代理的实现:MapperFactoryBean。这个类可以让你直接注入数据映射器接口到你的service 层 bean 中。当使用映射器时,你仅仅如调用你的 DAO 一样调用它们就可以了,但是你不需要编写任何 DAO 实现的代码,因为MyBatis-Spring 将会为你创建代理。

使用注入的映射器代码,在 MyBatis,Spring 或MyBatis-Spring 上面不会有直接的依赖。 MapperFactoryBean 创建的代理控制开放和关闭 session,翻译任意的异常到 Spring 的 DataAccessException 异常中。此外,如果需要或参与到一个已经存在活动事务中,代理将 会开启一个新的 Spring 事务。

6.1.MapperFactoryBean

数据映射器接口可以按照如下做法加入到 Spring中:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

MapperFactoryBean创建的代理类实现了 UserMapper 接口,并且注入到应用程序中。因为代理创建在运行时环境中(Runtime,译者注) ,那么指定的映射器必须是一个接口,而 不是一个具体的实现类。

如果 UserMapper 有一个对应的 MyBatis的XML 映射器文件,如果XML文件在类路径的位置和映射器类相同时,它会被MapperFactoryBean自动解析.没有必要在 MyBatis配置文件中去指定映射器,除非映射器的XML文件在不同的类 路径下。可以参考SqlSessionFactoryBean 的 configLocation 属性(第三章)来获取更多信息。

注意,当MapperFactoryBean需要SqlSessionFactory或 SqlSessionTemplate 时.这些可以通过各自的 SqlSessionFactory 或 SqlSessionTemplate属性来设置,或者可以由 Spring 来自动装配。如果两个属性都设置了,那么SqlSessionFactory就会被忽略,因为SqlSessionTemplate是需要有一个 session 工厂的设置; 那个工厂会由 MapperFactoryBean.来使用。

你可以直接在 business/service 对象中以和注入任意 Spring bean 的相同方式直接注入映射器:

<bean id="fooService" class="org.mybatis.spring.sample.mapper.FooServiceImpl">
  <property name="userMapper" ref="userMapper" />
</bean>

这个 bean 可以直接在应用程序逻辑中使用:

public class FooServiceImpl implements FooService {
  private UserMapper userMapper;
  public void setUserMapper(UserMapper userMapper) {
    this.userMapper = userMapper;
  }
  public User doSomeBusinessStuff(String userId) {
    return this.userMapper.getUser(userId);
  }
}

注意在这段代码中没有 SqlSession 或 MyBatis 的引用。也没有任何需要创建,打开或 关闭 session 的代码,MyBatis-Spring会来关心它的。

6.2. MapperScannerConfigurer

没有必要在 Spring 的 XML 配置文件中注册所有的映射器。相反,你可以使用一个 MapperScannerConfigurer , 它 将 会 查 找 类 路 径 下 的 映 射 器 并 自 动 将 它们 创 建 成 MapperFactoryBean。

要创建 MapperScannerConfigurer,可以在 Spring 的配置中添加如下代码:

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  <property name="basePackage" value="org.mybatis.spring.sample.mapper" />
</bean>

basePackage 属性是让你为映射器接口文件设置基本的包路径。 你可以使用分号或逗号 作为分隔符设置多于一个的包路径。每个映射器将会在指定的包路径中递归地被搜索到.

MapperScannerConfigurer属不支持使用了PropertyPlaceholderConfigurer 的属性替换,因为会在 Spring 其中之前来它加载。但是,你可以使用 PropertiesFactoryBean 和 SpEL 表达式来作为替代。

注 意 , 没 有 必 要 去 指 定 SqlSessionFactory 或 SqlSessionTemplate , 因为MapperScannerConfigurer将会创建MapperFactoryBean,之后自动装配。但是,如果你使 用了一个 以上的 DataSource ,那 么自动 装配可 能会失效 。这种 情况下 ,你可以使用 sqlSessionFactoryBeanName 或sqlSessionTemplateBeanName 属性来设置正确的 bean 名 称来使用。这就是它如何来配置的,注意 bean 的名称是必须的,而不是 bean 的引用,因 此,value 属性在这里替代通常的 ref:

<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />

MapperScannerConfigurer 支 持 过 滤 由 指 定 的 创 建 接 口 或 注 解 创 建 映 射 器 。 annotationClass 属性指定了要寻找的注解名称。markerInterface 属性指定了要寻找的父 接口。如果两者都被指定了,加入到接口中的映射器会匹配两种标准。默认情况下,这两个 属性都是 null,所以在基包中给定的所有接口可以作为映射器加载。

被发现的映射器将会使用 Spring 对自动侦测组件(参考 Spring 手册的3.14.4)默认的命 名策略来命名。也就是说,如果没有发现注解,它就会使用映射器的非大写的非完全限定类 名。但是如果发现了@Component 或 JSR-330 的@Named 注解,它会获取名称。注意你可以配 置 到 org.springframework.stereotype.Component ,javax.inject.Named(如果你使用 JSE 6 的话)或你自己的注解(肯定是自我注解)中,这 样注解将会用作生成器和名称提供器。

你可能感兴趣的:(spring)