zoukankan      html  css  js  c++  java
  • Java Persistence with MyBatis 3(中国版) 第五章 与Spring集成

        MyBatis-Spring它是MyBatis子模块框。它用来提供流行的依赖注入框架Spring无缝集成。

        Spring框架是一个基于依赖注入(Dependency Injection)和面向切面编程(Aspect Oriented Programming,AOP)的Java框架,鼓舞使用基于POJO的编程模型。

    另外,Spring提供了声明式和编程式的事务管理能力。能够非常大程度上简化应用程序的数据訪问层(data access layer)的实现。在本章中,我们将看到在基于Spring的应用程序中使用MyBatis而且使用Spring的基于注解的事务管理机制。

     

    本章将包括下面话题:

    • 在Spring应用程序中配置MyBatis

               安装

               配置MyBatis Beans

    • 使用SqlSession
    • 使用映射器
    • 使用Spring进行事务管理

    5.1 在Spring应用程序中配置MyBatis

    本节将讨论怎样在基于Spring的应用程序中安装和配置MyBatis。

    5.1.1 安装

    假设你正在使用Maven构建工具,你能够配置MyBatis的spring依赖例如以下:

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.2.0</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context-support</artifactId>
      <version>3.1.3.RELEASE</version>
      <exclusions>
        <exclusion>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>3.1.3.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>3.1.3.RELEASE</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>1.6.8</version>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.6.8</version>
    </dependency>
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib-nodep</artifactId>
      <version>2.2</version>
    </dependency>
    <dependency>
      <groupId>commons-dbcp</groupId>
      <artifactId>commons-dbcp</artifactId>
      <version>1.4</version>
    </dependency>
    

        假设你没有使用Maven。你能够从http://code.google.com/p/mybatis/上下载mybatis-spring-1.2.0-boundle.zip。将其加入,将mybatis-1.2.0.jar包加入到classpath中。

        你能够从http://www.springsource.org/download/community/上下载Spring框架包spring-framework-3.1.3.RELEASE.zip。将其内全部jar包加入到classpath中。

        假设你仅仅使用MyBatis而没有使用Spring,在每个方法中,我们须要手动创建SqlSessionFactory对象,并且从SqlSessionFactory对象中创建SqlSession。并且我们还要负责提交或者回滚事务、关闭SqlSession对象。

        通过使用MyBatis-Spring模块,我们能够在Spring的应用上下文ApplicationContext中配置MyBatis Beans,Spring会负责实例化SqlSessionFactory对象以及创建SqlSession对象,并将其注入到DAO或者Service类中。而且,你能够使用Spring的基于注解的事务管理功能,不用自己在数据訪问层中书写事务处理代码了。

    5.1.2 配置MyBatis Beans

    为了让Spring来实例化MyBatis组件如SqlSessionFactory、SqlSession、以及映射器Mapper对象。我们须要在Spring的bean配置文件里配置它们,如果在applicationContext.xml中。配配置例如以下:

    <beans>
      <bean id="dataSource" class="org.springframework.jdbc.datasource. DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/elearning" />
        <property name="username" value="root" />
        <property name="password" value="admin" />
      </bean>
      <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliases" value="com.mybatis3.domain.Student, com.mybatis3.domain.Tutor" />
        <property name="typeAliasesPackage" value="com.mybatis3.domain" />
        <property name="typeHandlers" value="com.mybatis3.typehandlers.PhoneTypeHandler" />
        <property name="typeHandlersPackage" value="com.mybatis3.typehandlers" />
        <property name="mapperLocations" value="classpath*:com/mybatis3/**/*.xml" />
        <property name="configLocation" value="WEB-INF/mybatisconfig.xml" />
      </bean>
    </beans>
    

    使用上述的bean定义,Spring会使用例如以下配置属性创建一个SqlSessionFactory对象:

    •         ž dataSource:它引用了dataSource bean
    •         ž typeAliases:它指定了一系列的全然限定名的类名列表,用逗号隔开。这些别名将通过默认的别名规则创建(将首字母小写的非无全然限定类名作为别名)。
    •         ž typeAliasesPackage:它指定了一系列包名列表,用逗号隔开,包内含有须要创建别名的JavaBeans。

    •         ž typeHandlers:它指定了一系列的类型处理器类的全然限定名的类名列表,用逗号隔开。

    •         ž typeHandlersPackage: 它指定了一系列包名列表。用逗号隔开。包内含有须要被注冊的类型处理器类。

    •         ž mapperLocations:它指定了SQL映射器Mapper XML配置文件的位置
    •          configLocation:它指定了MyBatisSqlSessionFactory配置文件所在的位置。

    5.2 使用SqlSession

    一旦SqlSessionFactory bean被配置,我们须要配置SqlSessionTemplate bean。SqlSessionTemplatebean 是一个线程安全的Spring bean,我们能够从中获取到线程安全的SqlSession对象。

    因为SqlSessionTemplate提供线程安全的SqlSession对象,你能够在多个Spring bean实体对象中共享SqlSessionTemplate对象。从概念上看,SqlSessionTemplate和Spring的DAO模块中的JdbcTemplate很相似。

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

    如今我肯能够将SqlSessionbean实体对象注射到随意的Springbean实体中,然后使用SqlSession对象调用SQL映射语句。

    public class StudentDaoImpl implements StudentDao
    {
        private SqlSession sqlSession;
        public void setSqlSession(SqlSession session)
        {
            this.sqlSession = session;
        }
        public void createStudent(Student student)
        {
            StudentMapper mapper =
                this.sqlSession.getMapper(StudentMapper.class);
            mapper.insertStudent(student);
        }
    }
    
    假设你正在使用基于XML来配置Spring beans,你能够将SqlSessionbean实体对象注射到StudenDaoImpl bean 实体对象中。例如以下:

    <bean id="studentDao" class="com.mybatis3.dao.StudentDaoImpl">
      <property name="sqlSession" ref="sqlSession" />
    </bean>
    
    假设你使用基于注解的方式配置Spring beans。你例如以下将SqlSession bean实体对象注入到StudentDaoImplbean实体对象中:

    @Repository
    public class StudentDaoImpl implements StudentDao
    {
        private SqlSession sqlSession;
        @Autowired
        public void setSqlSession(SqlSession session)
        {
            this.sqlSession = session;
        }
        public void createStudent(Student student)
        {
            StudentMapper mapper =
                this.sqlSession.getMapper(StudentMapper.class);
            mapper.insertStudent(student);
        }
    }
    

    还有第二种注入Sqlsession对象的方法,即。通过拓展继承SqlSessionDaoSupport。这样的方式让我们能够在运行映射语句时,增加不论什么自己定义的逻辑。

    public class StudentMapperImpl extends SqlSessionDaoSupport implements
        StudentMapper
    {
        public void createStudent(Student student)
        {
            StudentMapper mapper =
                getSqlSession().getMapper(StudentMapper.class);
            mapper.insertAddress(student.getAddress());
            //Custom logic
            mapper.insertStudent(student);
        }
    }
    

    <bean id="studentMapper" class="com.mybatis3.dao.StudentMapperImpl">
      <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    

    在以上的这些方式中。我们注入了SqlSession对象,获取Mapper实例,然后运行映射语句。

    这里Spring会为我们提供一个线程安全的SqlSession对象,以及当方法结束后关闭SqlSession对象。

    然而。MyBatis-Spring模块提供了更好的方式,我们能够不通过SqlSession获取映射器Mapper,直接注射Sql映射器Mapper bean。我们下节将讨论它。

    5.3 使用映射器

    我们能够使用MapperFactoryBean将映射器Mapper接口配置成Spring bean实体。

    例如以下所看到的:

    public interface StudentMapper
    {
        @Select("select stud_id as studId, name, email, phone from
                students where stud_id=#{id}")
        Student findStudentById(Integer id);
    }
    
    <bean id="studentMapper" class="org.mybatis.spring.mapper. MapperFactoryBean">
      <property name="mapperInterface" value="com.mybatis3.mappers. StudentMapper" />
      <property name="sqlSessionFactory" ref="sqlSessionFactory" />
    </bean>
    
    如今StudentMapper bean实体对象能够被注入到随意的Spring bean实体对象中,并调用映射语句方法,例如以下所看到的:
    public class StudentService
    {
        private StudentMapper studentMapper;
        public void setStudentMapper (StudentMapperstudentMapper)
        {
            this. studentMapper = studentMapper;
        }
        public void createStudent(Student student)
        {
            this.studentMapper.insertStudent(student);
        }
    }
    
    <bean id="studentService" class="com.mybatis3.services. StudentService">
      <property name="studentMapper" ref="studentMapper" />
    </bean>
    

    分别配置每个映射器Mapper接口是一个很单调的过程。

    我们能够使用MapperScannerConfigurer来扫描包(package)中的映射器Mapper接口。并自己主动地注冊。

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

    假设映射器Mapper接口在不同的包(package)中,你能够为basePackage属性指定一个以逗号分隔的包名列表。

    MyBatis-Spring-1.2.0介绍了两种新的扫描映射器Mapper接口的方法:

    • l   使用<mybatis:scan/>元素
    • l   使用@MapperScan注解(需Spring3.1+版本号)

    5.3.1 <mybatis:scan />

    <mybatis:scan>元素将在特定的以逗号分隔的包名列表中搜索映射器Mapper接口。使用这个新的MyBatis-Spring名空间你须要加入下面的schema声明:

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://mybatis.org/schema/mybatis-spring 
            http://mybatis.org/schema/mybatis-spring.xsd">
        <mybatis:scan base-package="com.mybatis3.mappers" />
    </beans>
    

    <mybatis:scan>元素提供了下列的属性来自己定义扫描过程:

    •         annotation: 扫描器将注冊全部的在base-package包内而且匹配指定注解的映射器Mapper接口。

    •         factory-ref:当Spring上下文中有多个SqlSessionFactory实例时。须要指定某一特定的SqlSessionFactory来创建映射器Mapper接口。

      正常情况下,仅仅有应用程序中有一个以上的数据源才会使用。

    •         ž marker-interface: 扫描器将注冊在base-package包中的而且继承了特定的接口类的映射器Mapper接口
    •         ž template-ref: 当Spring上下文中有多个SqlSessionTemplate实例时。须要指定某一特定的SqlSessionTemplate来创建映射器Mapper接口。正常情况下,仅仅有应用程序中有一个以上的数据源才会使用。
    •          name-generator:BeannameGenerator类的全然限定类名,用来命名检測到的组件。

    5.3.2 MapperScan

    Spring 框架3.x+版本号支持使用@Configuration和@Bean 注解来提供基于Java 的配置。假设你倾向于使用基于Java的配置,你能够使用@MapperScan注解来扫描映射器Mapper接口。@MapperScan和<mybatis:scan/>工作方式同样,而且也提供了相应的自己定义选项。

    @Configuration
    @MapperScan("com.mybatis3.mappers")
    public class AppConfig
    {
        @Bean
        public DataSource dataSource()
        {
            return new PooledDataSource("com.mysql.jdbc.Driver",
                                        "jdbc:mysql://localhost:3306/elearning", "root", "admin");
        }
        @Bean
        public SqlSessionFactory sqlSessionFactory() throws Exception
        {
            SqlSessionFactoryBeansessionFactory = new
            SqlSessionFactoryBean();
            sessionFactory.setDataSource(dataSource());
            return sessionFactory.getObject();
        }
    }
    

    @MapperScan注解有下面属性供自己定义扫描过程使用:

          ž annotationClass: 扫描器将注冊全部的在base-package包内而且匹配指定注解的映射器Mapper接口。

          ž markerInterface: 扫描器将注冊在base-package包中的而且继承了特定的接口类的映射器Mapper接口

          ž sqlSessionFactoryRef:当Spring 上下文中有一个以上的SqlSesssionFactory时,用来指定特定SqlSessionFactory

          ž sqlSessionTemplateRef: 当Spring 上下文中有一个以上的sqlSessionTemplate时,用来指定特定sqlSessionTemplate

          ž nameGenerator:BeanNameGenerator类用来命名在Spring容器内检測到的组件。

          ž basePackageClasses:basePackages()的类型安全的替代品。包内的每个类都会被扫描。

          ž basePackages:扫描器扫描的基包,扫描器会扫描内部的Mapper接口。注意包内的至少有一个方法声明的才会被注冊。详细类将会被忽略。



    5.4 使用Spring进行事务管理

    仅仅使用MyBatis。你须要写事务控制相关代码,如提交或者回退数据库操作。

    public Student createStudent(Student student)
    {
        SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory().
                                openSession();
        try
        {
            StudentMapper mapper =
                sqlSession.getMapper(StudentMapper.class);
            mapper.insertAddress(student.getAddress());
            mapper.insertStudent(student);
            sqlSession.commit();
            return student;
        }
        catch (Exception e)
        {
            sqlSession.rollback();
            throw new RuntimeException(e);
        }
        finally
        {
            sqlSession.close();
        }
    }
    

    我们能够使用Spring的基于注解的事务处理机制来避免书写上述的每一个方法中控制事务的冗余代码。

    为了能使用Spring的事务管理功能,我们须要在Spring应用上下文中配置TransactionManagerbean实体对象:

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

    事务管理器引用的dataSource和SqlSessionFactory bean使用的dataSource同样。

    在Spring中使用基于注解的事务管理特性,例如以下:

    <tx:annotation-driven transaction-manager="transactionManager"/>
    如今你能够在Spring service bean上使用@Transactional注解。表示在此service中的每个方法都应该在一个事务中执行。假设方法成功执行完成,Spring会提交操作。假设有执行期异常发生,则会执行回滚操作。另外,Spring会将MyBatis 的异常转换成合适的DataAccessExceptions,这样会为特定错误上提供额外的信息。

    @Service
    @Transactional
    public class StudentService
    {
        @Autowired
        private StudentMapper studentMapper;
        public Student createStudent(Student student)
        {
            studentMapper.insertAddress(student.getAddress());
            if(student.getName().equalsIgnoreCase(""))
            {
                throw new RuntimeException("Student name should not be
                                           empty.");
            }
            studentMapper.insertStudent(student);
            return student;
        }
    }
    

    以下是一个Spring的applicationContext.xml完毕配置:

    <beans>
      <context:annotation-config />
      <context:component-scan base-package="com.mybatis3" />
      <context:property-placeholder location="classpath:application.properties" />
      <tx:annotation-driven transaction-manager="transactionManager" />
      <bean id="transactionManager" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
      </bean>
      <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.mybatis3.mappers" />
      </bean>
      <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
      </bean>
      <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliases" 
    value="com.mybatis3.domain.Student,com.mybatis3.domain.Tutor" />
        <property name="typeAliasesPackage" value="com.mybatis3.domain" />
        <property name="typeHandlers" value="com.mybatis3.typehandlers.PhoneTypeHandler" />
        <property name="typeHandlersPackage" value="com.mybatis3.typehandlers" />
        <property name="mapperLocations" value="classpath*:com/mybatis3/**/*.xml" />
      </bean>
      <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
      </bean>
    </beans>
    
    如今让我们写一个独立的測试client来測试StudentService,例如以下:

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:applicationContext.xml"
                         )
    public class StudentServiceTest
    {
        @Autowired
        private StudentService studentService;
        @Test
        public void testCreateStudent()
        {
            Address address = new Address(0, "Quaker Ridge
                                          Rd.", "Bethel", "Brooklyn", "06801", "USA");
            Student stud = new Student();
            long ts = System.currentTimeMillis();
            stud.setName("stud_" + ts);
            stud.setEmail("stud_" + ts + "@gmail.com");
            stud.setAddress(address);
            Student student = studentService.createStudent(stud);
            assertNotNull(student);
            assertEquals("stud_" + ts, student.getName());
            assertEquals("stud_" + ts + "@gmail.com", student.getEmail());
            System.err.println("CreatedStudent: " + student);
        }
        @Test(expected = DataAccessException.class)
        public void testCreateStudentForException()
        {
            Address address = new Address(0, "Quaker Ridge
                                          Rd.", "Bethel", "Brooklyn", "06801", "USA");
            Student stud = new Student();
            long ts = System.currentTimeMillis();
            stud.setName("Timothy");
            stud.setEmail("stud_" + ts + "@gmail.com");
            stud.setAddress(address);
            studentService.createStudent(stud);
            fail("You should not reach here");
        }
    }
    

    这里在testCreateStudent()方法中,我们为Address和Student赋上了合适的数据,所以Address和Student会被分别插入到表ADDRESSES和STUDENTS中。在testCreateStudentForException()方法我们设置了名字为Timothy,该名称在数据库中已经存在了,所以当你尝试将此student记录插入到数据库中。MySQL会抛出一个UNIQUE KEY 冲突的异常。Spring会将此异常转换成DataAccessException异常。而且将插入ADDRESSES表中的数据回滚(rollback)掉。

    5.5 总结

    在本章中我们学习了如何将MyBatis与Spring框架集成。我们还学习了如何安装Spring类库而且在Spring 的应用上下文ApplicationContext上注冊MyBatis bean实体对象。

    我们还看到如何配置和注入SqlSession和Mapper bean实体对象以及调用映射语句。我们还学习了利用Spring基于注解的事务处理机制来使用MyBatis。

     

    你已经读完本书,祝贺你!

    如今,你应该知道如何高效地使用MyBatis与数据库工作。你学会了如何发挥你的Java和SQL技巧的优势使MyBatis更富有成效。

    你知道了如何以更清晰的方式使用MyBatis写出数据持久化代码,不用管被MyBatis框架处理的全部底层细节。

    另外,你学会了如何在最流行的依赖注入框架-Spring中使用MyBatis。

     

    MyBatis框架很易于使用,但它提供了强大的特性。因此它对于基于Java的项目而言。是一个很好的数据库持久化解决方式。

    MyBatis也提供了一些工具如MyBatis Generator(http://www.mybatis.org/generator/),能够被用来从已经存在的数据库schema中,产生持久化代码如数据库实体(databaseentities),映射器Mapper 接口,MapperXML配置文件,使MyBatis入门很方便。另外,MyBatis还有它的姊妹项目如MyBatis.NET和MyBatis-Scala,分别为.NET 和Scala编程语言提供了一样强大的特性。

     

    MyBatis随着每个版本号的公布。添加了一些特性。正变得越来越好。想了解很多其它的新特性,你能够訪问MyBatis官方站点https://code.google.com/p/mybatis/.订阅MyBatis 的使用者邮件列表是一个不错的想法。我们祝你一切顺利,编码快乐!(We wish you all the best, and happy coding!)




    《Java Persistence with MyBatis 3(中文版)》导航:

    Java Persistence with MyBatis 3(中文版)

    Java Persistence with MyBatis 3(中文版) 前言

    Java Persistence with MyBatis 3(中文版) 第一章 MyBatis入门

    Java Persistence with MyBatis 3(中文版) 第二章 引导MyBatis

    Java Persistence with MyBatis 3(中文版) 第三章 使用XML配置SQL映射器

    Java Persistence with MyBatis 3(中文版) 第四章 使用注解配置SQL映射器

    Java Persistence with MyBatis 3(中文版) 第五章 与Spring集成 



    -----------------------------------------------------------------------------------------------------------------------
    作者声明:这篇文章是源http://blog.csdn.net/luanlouis,如需转载。转载请注明出处。






  • 相关阅读:
    async和await是如何实现异步编程?
    HD-ACM算法专攻系列(23)——Crixalis's Equipment
    HD-ACM算法专攻系列(22)——Max Sum
    HD-ACM算法专攻系列(21)——Wooden Sticks
    HD-ACM算法专攻系列(20)——七夕节
    HD-ACM算法专攻系列(19)——Leftmost Digit
    搭建Prometheus平台,你必须考虑的6个因素
    实用教程丨使用K3s和MySQL运行Rancher 2.4
    Kubernetes Ingress简单入门
    一文讲透Cluster API的前世、今生与未来
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/4736222.html
Copyright © 2011-2022 走看看