在学习使用mybatis后就可以尝试进行mybatis-spring整合。在mybatis-spring官网的看官方文档的中文版是发现其内容已经有些过时,因此这篇文章根据英文版进行了一些整理得到的。文档的后面给出的pom.xml则是我自己在部署项目时的部分结构,不涉及mvc部分。
如果整合是以xml的形式进行,则spring-mybatis.xml配置文件可按如的要求进行:
SqlSessionFactory
在只有mybatis时,sqlSessionFactory的创建由SqlSessionFactoryBuilder类完成。而在mybatis-spring项目中,sqlSession则由SqlSessionFactoryBean创建。在xml文件的的标准配置方法可以参考下面的格式:
<beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
<propertyname="dataSource"ref="dataSource"/>
</bean>
注意SqlSessionFactoryBean其实是实现了spring的FactoryBean接口的的。这就意味着sqlSessionFactoryBean的创建并不是由它自己创建的而是由它使用getObject()方法返回的一个实例。
在通常的配置中,我们最后使用的并不是SqlSessionFactory,而是将它注入到MapperFactoryBean中或者直接让daos继承SqlSessionDaoSupport(感觉这会导致项目与框架的耦合度增加?)。
<beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer">
<propertyname="basePackage"value="com.**.mapper"/>
<propertyname="sqlSessionFactoryBeanName"value="sqlSessionFactory"/>
</bean>
SqlSessionFactory有一个必须的属性—DataSource,这个属性用于声明它所要关联的数据源,由它提供的datasource应该和spring配置的datasource一致。
常用的属性还有configLocation,这个属性用于指向Mybatis 的xml配置文件,用于调用mybatis自身的一些可用的全局属性,常用于指定<setting> 或类别名<typeAlias>.除此之外如果我们所配置的mapper XML和mapper class分布在不同的文件路径下时也可以在这个调用的配置文件中设置他们的路径(<mappers>),在使用时效果并不理想。sqlSessionFactory提供了另一个选项--mapperLoctions,在配置时可以将Mapper xml所在的全文件路径赋值给它,也可以使用ant风格去加载一个文件夹下的指定的文件。
正如刚才所讲,configLoctaion并不是必须的,spring在调用这个配置文件时会自动忽略掉里面设置的environment配置,SqlSessionFactory会根据dataSurce去创建适合它自己的mybatis environment.
从1.3.0版本开始,mybatis-spring提供了configuration属性给SqlSessionFactory,通过它我们也可以配置使用mybatis的一些全局属性。
Transactions:
使用mybatis-spring的一个重要原因就是它的事务管理模式,它不用单独为Mybatis创建一个特殊的事务管理,而是直接使用Spring中原本就存在的DataSourceTransctionManager. 在mybatis-spring项目中,一旦我们配置好spring的配置管理,使用它就与常规的使用方式就没有什么区别。它同时支持注释@Transactional和AOP格式的事务管理配置方法。配置完成后SqlSession对象在运行时将会调用这个配置的transaction.当一个事务完成后session会被自动回滚或提交。
<beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<propertyname="dataSource"ref="dataSource"/>
</bean>
这里的dataSource必须和SqlSessionFactoryBean配置的相一致。
使用web容器管理时也可以采用另一个比较简单的方式配置事务管理空间。
<tx:jta-transaction-manager/>
Spring会自动使用容器中已经存在的事务并匹配到sqlSession上,如果容器一开始没有事务管理,spring将会请求容器新创建一个。这时配置文件中不能再配置spring事务管理,在sqlSesionFactory中则需要加上mybatis自身的事务管理:
<beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
<propertyname="dataSource"ref="dataSource"/>
<propertyname="transactionFactory">
<beanclass="org.apache.ibatis.transaction.managed.ManagedTransactionFactory"/>
</property>
</bean>
再次强调一点,在我们只使用mybatis时,我们可以使用mybatis提供的的一些方法去控制事务的一些行为,但当我们在使用My-spring时,默认来说这样做是不允许的,一旦我们尝试使用sqlSesion.commit()或sqlSession.rollback这样的方法程序将会抛出UnsupportedOperationEXception.
如果一定要自己来操纵事务的行为可以参考spring reference的第10章。
Using an SqlSession
利用mybatis-spring我们可以将SqlSessionFactory线程安全的注入到sqlSession中,它可以自动完成提交,而不在需要显式的提交和关闭session.要实现这一目的,SqlSessionTemplate是mybatis-spring的核心,它实现了SqlSession,这意味着原本需要SqlSession出现的地方都可以有它替换。相比原来的SqlSession,它的优势在于可以线程安全在各个Dao之间共享。
使用通过sqlSessionTemplate.getMapper()得到的Mapper的各种SQL方法时,它将保证使用的SqlSession都能绑定到当前spring的事务上。如上面所说的,这个事务将会接管session的生命周期。除此之外,sqlSessionTemplate还能够将Mybatis抛出的异常交割给spring的DataAccessException.
在配置文件中声明SqlSessionTemplate的格式如下:
<beanid="sqlSession"class="org.mybatis.spring.SqlSessionTemplate">
<constructor-argindex="0"ref="sqlSessionFactory"/>
</bean>
完成这个配置后在就可以javaBean按照一般的spring自依赖注入的方式注入sqlSessionTemplate。
SqlSessionDaoSupport是一个抽象的支持类,通过它的getSqlSession()
可以得到一个SqlSessionTemplate的实例对象。我们也可以让dao继承它来执行SQL方法。
一般来说使用MapperFacatoryBean就已经足够。但是如果我们的dao接口中还有一些非mybatis方法时,让daoImpl继承SqlSessionDaoSupport也是一个不错的选择。如果daoImpl继承来SqlSessionDaoSupport,它在Spring中可以这样配置:
<beanid="xxxMapper"class="com.xxx.mapper.mapperimpl.xxxDaoImpl">
<propertyname="sqlSessionFactory"ref="sqlSessionFactory"/>
</bean>
上面已经涉及到mapper在spring中的映射,不妨在接下来对它进行详细的展开。
在spring注册mapper的方式取决于我们使用的是传统的xml配置文件还是spring 3.0+以上开始流行的java Config方式。
如果采用的是xml配置文档,我们可以按如下的方式进行文档配置:
<beanid="xxxMapper"class="org.mybatis.spring.mapper.MapperFactoryBean">
<propertyname="mapperInterface"value="com.XXXX.mapper.xxxMapper"/>
<propertyname="sqlSessionFactory"ref="sqlSessionFactory"/>
</bean>
这样配置的要求是mybatis mapper xml配置文件和对应的mapper类在同一个文件路径下,如果不是,可以参考上面我们在进行SqlSessionFactoryBean时的配置。MapperFactoryBean需要一个sqlSessionFactory或者sqlSessionTemplate.如果两者都配置在MapperFactoryBean,sqlSessionFactory将会被忽略。
使用java Config则可以参考下面的格式:
@Bean
publicSqlSessionFactory sqlSessionFactory()throwsException{
SqlSessionFactoryBean sqlSessionFactory=newSqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource());
return(SqlSessionFactory) sqlSessionFactory.getObject();
}
@Bean
publicUserMapper userMapper()throwsException{
//注意这里不要使用mybatis提供的SqlSession
SqlSessionTemplate sessionTemplate =newSqlSessionTemplate(sqlSessionFactory());
return sessionTemplate.getMapper(UserMapper.class);
}
除了进行单个注册mapper以外,我们还可以使用批量扫描的方式进行mapper注入。Mybatis-spring提供了三种方式:
1. 使用<mybatis:scan/>
2. 使用注解@MapperScan
3. 使用传统的XML文件注册MapperScannerConfigurer
<mybatis:scan/>将会搜索指定包下的所有mapper,其使用方式和spring的<context:component-scan/>十分相似。
要使用<mybatis:scan/>只需在mybatis-spring.xml的头文件中添加
xmlns:mybatis=http://mybatis.org/schema/mybatis-spring
xsi:schemaLocation="
http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd"
使用格式如下:
<mybatis:scanbase-package="org.mybatis.spring.sample.mapper"/>
base-package属性用于指定我们mapper interface所在的位置。多个包之间可以使用逗号或分号隔开。它不需要我们把sqlSession或sqlSessionTemplate作为它的属性。但当我们同时使用了多个数据源或session工厂时我们应该使用template-ref或factory-ref去指定对应bean所使用的sqlsession.
marker-interface属性用于缩小我们搜索的范围,它表示只有继承了特殊接口的接口才会被认为是mapper,搜索到的Mapper将会按Spring 的默认命名策略进行命名。
Mapper的扫描必须有mybatis进行而不是spring context
如果使用的java Config来进行spring配置,就可以使用@MapperScan替代<mybatis:scan>
使用MapperScannerConfigurer的格式如下:
<beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer">
<propertyname="basePackage"value="org.mybatis.spring.sample.mapper"/>
//如果sqlSesion有特殊的配置则可以按这个格式进行配置,对mybatis-spring 1.0.2///以前的版本不能使用这个属性
<propertyname="sqlSessionFactoryBeanName"value="sqlSessionFactory"/
</bean>
此时pom.xml的结构如下:
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>empmangensystem</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>empmangensystem Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<spring.version>4.2.5.RELEASE</spring.version>
<mybatis.version>3.1.1</mybatis.version>
<mybatis-spring.version>1.2.0</mybatis-spring.version>
<mysql.version>5.1.39</mysql.version>
<druid.version>1.0.8</druid.version>
</properties>
<dependencies>
<!--springbegin-->
<!--https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.springframework/spring-context-support-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring end withmybatis begin-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!—-mybatis-spring整合-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<!--database-->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<!- -如果需要懒加载,则cglib必须添加-->
<!--https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.1</version>
</dependency>
<!--数据库数据库连接池-->
<!--https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.18</version>
</dependency>
<!--database end-->
<!--log begin-->
<!--https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<!--https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>empmangensystem</finalName>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
当准备完pom文件后添加各类属性文件:
Jdbc.properties.为datasource相关属性
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.connectionURL=jdbc:mysql://localhost:3306/mydatabase?useSSL=true
jdbc.userId=root
jdbc.password=****
log4j.properties.为log4j的配置文件:
## set log levels ###
log4j.rootLogger=INFO,console,debug,error
### console ###
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n\
### log file ###
log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender
log4j.appender.debug.File=../logs/springmvc-demo.log
log4j.appender.debug.Append=true
log4j.appender.debug.Threshold=INFO
log4j.appender.debug.layout=org.apache.log4j.PatternLayout
log4j.appender.debug.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c]- %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
### exception ###
log4j.appender.error=org.apache.log4j.DailyRollingFileAppender
log4j.appender.error.File=../logs/springmvc-demo_error.log
log4j.appender.error.Append=true
log4j.appender.error.Threshold=ERROR
log4j.appender.error.layout=org.apache.log4j.PatternLayout
log4j.appender.error.layout.ConversionPattern=%-d{yyyy-MM-dd HH\:mm\:ss} [%p]-[%c] %m%n\
###需要声明,然后下方才可以使druid sql输出,否则会抛出log4j.error.key not found
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %l%c%n%p: %m%n
### druid sql ###
log4j.logger.druid.sql=warn,stdout
log4j.logger.druid.sql.DataSource=warn,stdout
log4j.logger.druid.sql.Connection=warn,stdout
log4j.logger.druid.sql.Statement=warn,stdout
log4j.logger.druid.sql.ResultSet=warn,stdout