zoukankan      html  css  js  c++  java
  • Mybatis-Spring包学习

    MyBatis-Spring包用来将MyBatis无缝整合到Spring中。使用这个类库中的类, Spring将会加载必要的MyBatis工厂类和Session类。 这个类库也提供一个简单的方式来注入 MyBatis 数据映射器和 SqlSession 到业务层的 bean 中。github: http://github.com/mybatis/spring

    首先引入jar包

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

    在 Spring 应用上下文中定义一个 SqlSessionFactory

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

    在MyBatis中session工厂可以使用SqlSessionFactoryBuilder来创建。而在MyBatis-Spring中,使用SqlSessionFactoryBean来替代,SqlSessionFactoryBean 是用于创建 SqlSessionFactory的.

    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 或其它扩展了 SqlSessionDaoSupport的DAO(Data Access Object数据访问对象)中。

    SqlSessionFactory 有一个必须的属性DataSource:

        <!-- 指定数据源配置文件 -->
        <context:property-placeholder location="classpath:jdbc.properties" />
        
        <!-- 数据源 -->
        <bean id="dataSource_dev" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <property name="driverClassName" value="${driver}" />
            <property name="url" value="${url}" />
            <property name="username" value="${username}" />
            <property name="password" value="${password}" />
        </bean>

    configLocation属性用来指定MyBatis的XML配置文件路径。改变基本的MyBatis配置, 这个配置文件不需要是一个完整的MyBatis配置。环境,数据源和MyBatis的事务管理器都可被忽略,SqlSessionFactoryBean会自动创建。

    mapperLocations属性来指定Mapper所在位置, 它的值可以加载一个目录中所有文件, 或者从基路径下递归搜索所有路径。

    事务管理

    MyBatis-Spring可以通过利用Spring中的DataSourceTransactionManager使MyBatis运用到Spring的事务管理中。

    首先需要在Spring的配置文件中创建一个DataSourceTransactionManager对象来开启Spring的事务处理:

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

    DataSource必须和创建SqlSessionFactoryBean的是同一个数据源,否则事务管理器无法工作。

    配置好后就可以在Spring中以通常的做法来配置事务。@Transactional注解和AOP样式的配置都是支持的。

    在事务处理期间,一个单独的SqlSession对象将会被创建和使用。当事务完成时,这个session会以合适的方式提交或回滚。

    这样在DAO层中就不需要额外的代码了,MyBatis-Spring将会透明的管理事务。

    容器管理的事务

    如果你正使用一个 JEE 容器而且想让 Spring 参与到容器管理事务(Container managed transactions)中,那么 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>

    使用 SqlSession

    MyBatis中, 使用SqlSessionFactory来创建SqlSession。获得一个session之后就可以使用它来执行映射语句,提交或回滚连接,最后不再需要它的时候, 可以关闭session。

    使用MyBatis-Spring之后, 不再需要直接使用SqlSessionFactory了,因为你的bean可以通过一个线程安全的SqlSession来注入;基于Spring的事务管理来自动提交,回滚,关闭session。

    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)或完全在一个事务外面。

    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 需要一个 sqlSessionFactory 或 sqlSessionTemplate 属性来 设 置 。 这 些 被 明 确 地 设 置 或 由 Spring 来 自 动 装 配 。 如 果 两 者 都 被 设 置 了 , 那 么 SqlSessionFactory 是被忽略的。

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

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

    注入映射器

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

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

    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 会来关心它的。

     

    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 表达式来作为替代。

    如果只有一个DataSource,就不用指定SqlSessionFactory或SqlSessionTemplate , 因为MapperScannerConfigurer将会创建 MapperFactoryBean,之后自动装配。

    如果有多个DataSource ,那么自动装配可能会失效 。可以使用 sqlSessionFactoryBeanName 或 sqlSessionTemplateBeanName 属性来设置正确的bean名称来使用:

    <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 的话)或你自己的注解(肯定是自我注解)中,这 样注解将会用作生成器和名称提供器。

    使用 MyBatis API

    使用了MyBatis-Spring, 还可以继续使用MyBatis的API,比如Spring中的SqlSessionFactoryBean来创建一个SqlSessionFactory:

    public class UserMapperSqlSessionImpl implements UserMapper {
      // SqlSessionFactory would normally be set by SqlSessionDaoSupport
      private SqlSessionFactory sqlSessionFactory;
    
      public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
      }
    
      public User getUser(String userId) {
        // note standard MyBatis API usage - opening and closing the session manually
        SqlSession session = sqlSessionFactory.openSession();
    
        try {
          return (User) session.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
        } finally {
          session.close();
        }
      }
    }

    但是需要注意的是:

    1. 这样不会参与到 Spring 的事务之中。

    2. 如果 SqlSession 使用 DataSource,它也会被 Spring 事务管理器使用,而且当前有事务在进行时,这段代码会抛出异常。

    3. MyBatis的DefaultSqlSession是线程不安全的。如果在 bean中注入了它,就会发生错误。

    4. 使用 DefaultSqlSession创建的映射器也不是线程安全的。如果你将它们注入到 bean中就会发生错误的。

    5. 必须保证在 finally 块中来关闭 SqlSession。

    所以还是不要这样写。

    end

  • 相关阅读:
    vs.net 2005 C# WinForm GroupBOX 的BUG?尝试读取或写入受保护的内存。这通常指示其他内存已损坏
    Git安装及基本使用
    c++实现将表达式转换为逆波兰表达式
    2015年倒数第6周学习报告
    读过的书及读后感
    c++实现队列
    链表插入排序(insertion-sort-list)
    test
    [转]maven入门
    几个学习Maven不错的网址
  • 原文地址:https://www.cnblogs.com/luangeng/p/6151479.html
Copyright © 2011-2022 走看看