MyBatis-Spring 会帮助你将 MyBatis 代码无缝地整合到 Spring 中。 使用这个类库中的类, Spring 将会加载必要的MyBatis工厂类和 session 类。 这个类库也提供一个简单的方式来注入MyBatis数据映射器和SqlSession到业务层的bean中。 而且它也会处理事务, 翻译MyBatis的异常到Spring的 DataAccessException异常(数据访问异常,译者注)中。最终它并不会依赖于MyBatis,Spring或MyBatis-Spring来构建应用程序代码。更多内容请查看官网帮助。
一、 使用Maven创建一个Web项目
为了完成Spring4.x与MyBatis3.X的整合更加顺利,先回顾在Maven环境下创建Web项目并使用MyBatis3.X,第一、二点内容多数是回顾过去的内容 。完成第一阶段与第二阶段的项目结构如下所示:
下载阶段一与阶段二示例
1.2、点击“File”->“New”->"Other"->输入“Maven”,新建一个“Maven Project”,如下图所示:
1.2、请勾选“Create a simple project”,创建一个简单的项目,不使用模板。也可以使用模板,选择WebApp,不过这里就不应该勾选。如下图所示:
1.3、填写好包名、项目名,选择打包类型为:war,如下图所示:
1.4、项目创建好后可能会发现有错误,选择项目,右键“属性properties”->"层面Project Facets"->"Java"修改版本号为1.7,默认为1.5;点击“Ok”保存后关闭。如下图所示:
1.5、重复上一个步骤,反勾Dynamic Web Module,将项目暂时变成非Web项目。点击“Ok”保存后关闭。
1.6、重复上一步骤,再进层面属性,勾选“Dynamic Web Module”选择Version为3.0。点击左下角的超链接“Further Configuration available...“。
1.7、勾选“Generate web.xml deployment descriptor”生成web.xml部署描述文件。点击“Ok”保存后关闭。
1.8、将生成的WebContent目录下的两个文件夹“META-INF”与“WEB-INF”复制到src/main/webapp目录下。
1.9、删除WebContent目录。
1.10、删除后会发现项目的pom.xml文件报错,是因为找不到指定位置的web.xml文件引起的。再进入项目的属性,选择“Deployment Assembly”项目部署项,删除“src/test/java”、“src/test/resources”与“WebContent”目录,因为这三项不需要部署出去。
1.11、点击“Add添加”后选择“Folder文件夹”为项目的最终部署结果指定Web内容根文件夹。
1.12、选择src\main\webapp目录为目标目录,点击“Finish完成”保存并关闭。
1.13、如果此时项目还报错,随便修改pom.xml文件后保存后应该错误会消失。
1.14、在src\main\webapp目录下新建一个index.jsp文件,作为测试使用。
1.15、新建完成后发现有错误,是因为没有JavaEE Server Runtime引起的,在项目上右键属性选择“Java Build Path”项,点击“Add Library...”添加引用。
1.16、选择Server Runtime项,点击“Next下一步”,再选择“Apache Tomcat v7.0”,这里可能要根据自己的运行环境选择了,如果还没Server,则应该先整合Tomcat。
1.17、在index.jsp文件中写上测试内容。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Hello World!title> head> <body> Hello World! <p> <%=new java.util.Date().toLocaleString() %> p> body> html>
1.18、在项目上右键选择“Run as”-> “Run on Server”运行项目,运行结果如下。
二、使用MyBatis完成MySQL数据库访问
2.1、添加依赖
要完成使用MyBatis访问MySQL数据库,需要添加一些依赖包,包含MyBatis3,连接驱动,JUnit,Log4j2等。可以去共享资源库中搜索,第一个网站地址是:http://mvnrepository.com/, 这里以搜索连接驱动为示例,搜索后的结果有5.xx版许多,也有6.xx版,但不建议使用6.xx版,因为MyBatis3不支持。
我们选择5.0版中的5.1.38,将Maven的依赖信息复制到项目中的pom.xml的dependencies结点下
当然也可去另外一个网站:http://search.maven.org/,这里以log4j为例子搜索如下:
有一些依赖也可以直接去官网查找,如MyBatis3:
项目的pom.xml文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>com.zhangguogroupId> <artifactId>Spring061artifactId> <version>0.0.1version> <packaging>warpackaging> <dependencies> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.38version> dependency> <dependency> <groupId>org.apache.logging.log4jgroupId> <artifactId>log4j-coreartifactId> <version>2.6.1version> dependency> <dependency> <groupId>org.mybatisgroupId> <artifactId>mybatisartifactId> <version>3.4.1version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.10version> dependency> dependencies> project>
引用结果:
如果在网速不稳定的情况下,下载包很有可能失败,可以试试强制项目重新下载;可以使用下载工具将jar包下载后手复制到本地资源库中。
2.2、准备数据
打开MySQL数据库,创建一个表,这里以booktypes表为例。
sql脚本如下:
/* Navicat MySQL Data Transfer Source Server : localhost Source Server Version : 50536 Source Host : localhost:3306 Source Database : db2 Target Server Type : MYSQL Target Server Version : 50536 File Encoding : 65001 Date: 2016-07-04 10:49:56 */ SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- -- Table structure for `booktypes` -- ---------------------------- DROP TABLE IF EXISTS `booktypes`; CREATE TABLE `booktypes` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '类型编号', `typeName` varchar(100) NOT NULL COMMENT '类型名称', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=94 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of booktypes -- ---------------------------- INSERT INTO `booktypes` VALUES ('1', '计算机软件开发'); INSERT INTO `booktypes` VALUES ('2', '计算机网络工程'); INSERT INTO `booktypes` VALUES ('3', '神话小说'); INSERT INTO `booktypes` VALUES ('4', '科幻小说'); INSERT INTO `booktypes` VALUES ('5', '外语'); INSERT INTO `booktypes` VALUES ('6', '测试类型'); INSERT INTO `booktypes` VALUES ('7', '91'); INSERT INTO `booktypes` VALUES ('8', '92'); INSERT INTO `booktypes` VALUES ('9', '93'); INSERT INTO `booktypes` VALUES ('91', '建筑设计'); INSERT INTO `booktypes` VALUES ('92', '工业设计'); INSERT INTO `booktypes` VALUES ('93', '船舶制造');
2.3、创建java Bean
在包com.zhangguo.Spring61.entities下添加类BookType类型。
package com.zhangguo.Spring61.entities; /** * 图书类型 * */ public class BookType { /** * 编号 */ private int id; /** * 类型名 */ private String typeName; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTypeName() { return typeName; } public void setTypeName(String typeName) { this.typeName = typeName; } @Override public String toString() { return this.getId()+"\t"+this.getTypeName(); } }
2.4、创建实例与表的映射文件
这里用接口+XML的形式完成,BookType数据访问接口如下:
package com.zhangguo.Spring61.mapping; import java.util.List; import com.zhangguo.Spring61.entities.BookType; /** * 图书类型数据访问接口 * */ public interface BookTypeDAO { /* * 获得所有图书类型 */ public ListgetAllBookTypes(); }
BookTypeMapper.xml文件如下:
xml version="1.0" encoding="UTF-8"?> DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zhangguo.Spring61.mapping.BookTypeDAO"> <select id="getAllBookTypes" resultType="BookType"> select id,typeName from booktypes select> mapper>
2.5、创建MyBatisCfg.xml文件
MyBatisCfg.xml文件用于配置MyBatis的运行环境,内容如下:
xml version="1.0" encoding="UTF-8"?> DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <properties resource="db.properties">properties> <typeAliases> <package name="com.zhangguo.Spring61.entities"/> typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> dataSource> environment> environments> <mappers> <mapper resource="com/zhangguo/Spring61/mapping/BookTypeMapper.xml" /> mappers> configuration>
因为配置中依赖了db.properties文件,该文件用于指定数据库的连接信息,内容如下:
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/db2 username=root password=root
2.6、实现数据访问功能
为了更加方便的复用MyBatis实现数据访问不需要频繁的创建SQLSessionFactory和SQLSession对象,封装一个MyBatisUtil工具类如下:
package com.zhangguo.Spring61.dao; import java.io.InputStream; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public abstract class MyBatisUtil { //GC不理static private static SqlSessionFactory factory=null; public static SqlSessionFactory getSqlSessionFactory(){ if(factory==null){ // 获得环境配置文件流 InputStream config = MyBatisUtil.class.getClassLoader().getResourceAsStream("MyBatisCfg.xml"); // 创建sql会话工厂 factory = new SqlSessionFactoryBuilder().build(config); } return factory; } //获得会话 public static SqlSession getSession(){ return getSqlSessionFactory().openSession(true); } /** * 获得得sql会话 * @param isAutoCommit 是否自动提交,如果为false则需要sqlSession.commit();rollback(); * @return sql会话 */ public static SqlSession getSession(boolean isAutoCommit){ return getSqlSessionFactory().openSession(isAutoCommit); } }
创建类BookTypeDAOImpl实现接口BookTypeDAO,这里要通过MyBatis实现数据访问功能,内容如下:
package com.zhangguo.Spring61.dao; import java.util.List; import org.apache.ibatis.session.SqlSession; import com.zhangguo.Spring61.entities.BookType; import com.zhangguo.Spring61.mapping.BookTypeDAO; /** * 实现图书类型数据访问 * */ public class BookTypeDAOImpl implements BookTypeDAO { @Override public ListgetAllBookTypes() { //获得会话对象 SqlSession session=MyBatisUtil.getSession(); try { //通过MyBatis实现接口BookTypeDAO,返回实例 BookTypeDAO bookTypeDAO=session.getMapper(BookTypeDAO.class); return bookTypeDAO.getAllBookTypes(); } finally { session.close(); } } }
2.7、测试运行
新建一个JUnit Test Case测试用例,如下所示:
测试用例TestBookTypeDAOImpl.java文件如下:
package com.zhangguo.Spring61.test; import static org.junit.Assert.*; import java.util.List; import org.junit.BeforeClass; import org.junit.Test; import com.zhangguo.Spring61.dao.BookTypeDAOImpl; import com.zhangguo.Spring61.entities.BookType; import com.zhangguo.Spring61.mapping.BookTypeDAO; public class TestBookTypeDAOImpl { static BookTypeDAO bookTypeDao; @BeforeClass public static void beforeClass() { bookTypeDao=new BookTypeDAOImpl(); } @Test public void testGetAllBookTypes() { Listbooktypes=bookTypeDao.getAllBookTypes(); for (BookType bookType : booktypes) { System.out.println(bookType); } assertNotNull(booktypes); } }
测试结果:
2.8、整合log4j2
上面的测试虽然通过,但是有一个错误提示“ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.”,大意是:日志记录器没有找到log4j2的配置文件。在源码的根目录下创建一个log4j2.xml配置文件,文件内容如下所示:
xml version="1.0" encoding="UTF-8"?> <Configuration status="off" monitorInterval="1800"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" /> Console> Appenders> <Loggers> <Root level="debug"> <AppenderRef ref="Console" /> Root> Loggers> Configuration>
再运行就会发现log4j2已经在运行了,从控制台可以看到MyBatis的运行状态信息:
程序向数据库发送的SQL请求,及数据库向程序响应的结果就清楚了。
下载阶段一与阶段二示例
三、使用Spring4.X整合MyBatis3.X初级版
在MyBatis的github官网(https://github.com/mybatis/spring)中有一个叫MyBatis Spring Adapter(MyBatis-Spring)的库,暂且翻译成:MyBatis Spring适配器,它的作用是:原话:“MyBatis-Spring adapter is an easy-to-use Spring3 bridge for MyBatis sql mapping framework.”,就是了为更容易的将MyBatis与Spring整合,充分发挥二两结合的优势,它相当于一个桥。
什么是:MyBatis-Spring?
MyBatis-Spring会帮助你将MyBatis代码无缝地整合到Spring中。使用这个类库中的类,Spring将会加载必要的MyBatis工厂类和session类。这个类库也提供一个简单的方式来注入MyBatis数据映射器和SqlSession到业务层的bean中。而且它也会处理事务,翻译MyBatis的异常到Spring的DataAccessException异常(数据访问异常,译者注)中。最终,它并不会依赖于MyBatis,Spring或MyBatis-Spring来构建应用程序代码。
3.1、修改pom.xml添加依赖
为了将Spring与MyBatis整合完成,需要依赖MyBatis,因为在上面的示例中已依赖完成,这里就不再需要,主要需依赖的是Spring核心,AOP,JDBC,MyBatis-Spring等jar包。具体的依赖结果pom.xml文件如下所示:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0modelVersion> <groupId>com.zhangguogroupId> <artifactId>Spring061artifactId> <version>0.0.1version> <packaging>warpackaging> <properties> <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> <spring.version>4.3.0.RELEASEspring.version> properties> <dependencies> <dependency> <groupId>mysqlgroupId> <artifactId>mysql-connector-javaartifactId> <version>5.1.38version> dependency> <dependency> <groupId>org.apache.logging.log4jgroupId> <artifactId>log4j-coreartifactId> <version>2.6.1version> dependency> <dependency> <groupId>org.mybatisgroupId> <artifactId>mybatisartifactId> <version>3.4.1version> dependency> <dependency> <groupId>junitgroupId> <artifactId>junitartifactId> <version>4.10version> dependency> <dependency> <groupId>org.mybatisgroupId> <artifactId>mybatis-springartifactId> <version>1.3.0version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-contextartifactId> <version>${spring.version}version> dependency> <dependency> <groupId>org.aspectjgroupId> <artifactId>aspectjweaverartifactId> <version>1.8.9version> dependency> <dependency> <groupId>org.springframeworkgroupId> <artifactId>spring-jdbcartifactId> <version>${spring.version}version> dependency> dependencies> project>
3.2、创建Spring上下文初始化配置文件
该文件取名为ApplicationContext.xml主要原因是“约束优于配置”的理由,使用Web监听器加载Spring时会默认找该名称的文件。在文件中我们可像以前学习Spring一样配置IOC与AOP,只不过这里整合了一些MyBatis内容。文件内容如下:
xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <bean id="jdbcDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/db2" /> <property name="username" value="root" /> <property name="password" value="root" /> bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="jdbcDataSource" /> <property name="configLocation" value="classpath:MyBatisCfg.xml">property> bean> <bean id="bookTypeDao" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.zhangguo.Spring61.mapping.BookTypeDAO">property> <property name="sqlSessionFactory" ref="sqlSessionFactory">property> bean> <context:component-scan base-package="com.zhangguo"> context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true">aop:aspectj-autoproxy> beans>
从上面的代码可以看到分别创建了一个驱动管理数据源的对象,会话工厂与实现数据访问的对象通过Spring IOC完成,而不再是硬编码。第2段配置与下面的代码功能基本类似:
private static SqlSessionFactory factory=null; public static SqlSessionFactory getSqlSessionFactory(){ if(factory==null){ // 获得环境配置文件流 InputStream config = MyBatisUtil.class.getClassLoader().getResourceAsStream("MyBatisCfg.xml"); // 创建sql会话工厂 factory = new SqlSessionFactoryBuilder().build(config); } return factory; }
第3段配置与下面的java代码基本类似:
SqlSession session = MyBatisUtil.getSession(); try { BookTypeDAO bookTypeDAO = session.getMapper(BookTypeDAO.class); return bookTypeDAO.getAllBookTypes(); } finally { session.close(); }
3.3、测试运行
package com.zhangguo.Spring61.test; import static org.junit.Assert.assertNotNull; import java.util.List; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.zhangguo.Spring61.entities.BookType; import com.zhangguo.Spring61.mapping.BookTypeDAO; public class TestMyBatisSpring01 { @Test public void test01() { //初始化容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml"); //获得bean BookTypeDAO bookTypeDao=ctx.getBean("bookTypeDao",BookTypeDAO.class); //访问数据库 Listbooktypes=bookTypeDao.getAllBookTypes(); for (BookType bookType : booktypes) { System.out.println(bookType); } assertNotNull(booktypes); } }
运行结果:
小结:此处的整合还是相对基础,更完善的整合内容将在后面的章节实现。另外在MyBatisCfg.xml文件中可以删除运行环境中数据源配置部分的内容,如下图所示。我们当前的示例使用的是Spring提供的数据源,其实也可以使用一第三方的数据源管理,如C3P0,Druid(德鲁伊,阿里巴巴开发)等。
下载第三阶段示例
四、Spring集成MyBatis升级版
4.1、去掉MyBatisCfg.xml配置文件
在没有Spring的环境下我们单纯使用MyBatis ORM框架时,我们是通过MyBatisCfg.xml完成sqlSessionFactory的构建工作,如果使用Spring则这部分配置的内容可以完全由Spring容器替代,具体实现如下:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="jdbcDataSource" /> <property name="typeAliasesPackage" value="com.zhangguo.Spring61.entities">property> <property name="mapperLocations" value="classpath:com/zhangguo/Spring61/mapping/*Mapper.xml">property> bean>
mapperLocations:它表示我们的Mapper文件存放的位置,当我们的Mapper文件跟对应的Mapper接口处于同一位置的时候可以不用指定该属性的值。
configLocation:用于指定Mybatis的配置文件位置。如果指定了该属性,那么会以该配置文件的内容作为配置信息构建对应的SqlSessionFactoryBuilder,但是后续属性指定的内容会覆盖该配置文件里面指定的对应内容。
typeAliasesPackage:它一般对应我们的实体类所在的包,这个时候会自动取对应包中不包括包名的简单类名作为包括包名的别名。多个package之间可以用逗号或者分号等来进行分隔。
typeAliases:数组类型,用来指定别名的。指定了这个属性后,Mybatis会把这个类型的短名称作为这个类型的别名,前提是该类上没有标注@Alias注解,否则将使用该注解对应的值作为此种类型的别名。
<property name="typeAliases"> <array> <value>com.tiantian.mybatis.model.Blogvalue> <value>com.tiantian.mybatis.model.Commentvalue> array> property>
我们修改了applicationContext.xml中的配置,通过容器完成了一个sqlSessionFactory Bean的创建, 1指定了数据源,2指定类型别名包这样在sql映射文件中使用类型时可以省去全名称,3指定了所有要加载的sql映射xml文件,如果有多个目录,则可以使用如下的形式:
<property name="mapperLocations"> <list> <value>classpath:com/...目录.../*_mapper.xmlvalue> <value>classpath:com/...目录.../*_resultmap.xmlvalue> list> property>
如果需要设置更多的属性则可以参考类型org.mybatis.spring.SqlSessionFactoryBean,如果不使用Spring,也不使用MyBatis配置文件我们照样可以获得一个sqlSessionFactory对象完成对MyBatis ORM框架的使用,因为可以直接实例化一个SqlSessionFactoryBean对象,只是此时该工作被Spring容器替代,按这个思路可以在SqlSessionFactoryBean类中找到更多的属性设置在applicationContext.xml配置中,部分源代码如下所示:
public class SqlSessionFactoryBean implements FactoryBean, InitializingBean, ApplicationListener { private static final Log LOGGER = LogFactory.getLog(SqlSessionFactoryBean.class); 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配置文件的,增加属性:
4.2、映射接口类自动扫描配置
在示例3的applicationContext.xml配置文件中有一段实现BookTypeDAO接口实例的创建工厂,配置如下:
<bean id="bookTypeDao" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.zhangguo.Spring61.mapping.BookTypeDAO">property> <property name="sqlSessionFactory" ref="sqlSessionFactory">property> bean>
如果有多个表,则需要配置多段信息,麻烦。我们可以通过自动扫描一次完成,配置如下:
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property> <property name="basePackage" value="com.zhangguo.Spring61.mapping">property> bean>
需要注意的是这里的sql会话工厂的指定可以使用sqlSessionFactoryBeanName属性指定,也可以使用sqlSessionFactory属性指定,但建议大家使用sqlSessionFactoryBeanName,否则会因为加载的先后顺序问题引起读不到properties文件的内容。其它属性的设置可以查看源码后再定义。
这样MapperScannerConfigurer就会扫描指定basePackage下面的所有接口,并把它们注册为一个个MapperFactoryBean对象。basePackage下面的并不全是我们定义的Mapper接口,为此MapperScannerConfigurer还为我们提供了另外两个可以缩小搜索和注册范围的属性。一个是annotationClass,另一个是markerInterface。
annotationClass:当指定了annotationClass的时候,MapperScannerConfigurer将只注册使用了annotationClass注解标记的接口。
markerInterface:markerInterface是用于指定一个接口的,当指定了markerInterface之后,MapperScannerConfigurer将只注册继承自markerInterface的接口。
sqlSessionFactory: 已废弃 。当使用多个数据源时就需要通过sqlSessionFactory来指定注册MapperFactoryBean的时候需要使用的SqlSessionFactory,因为在没有指定sqlSessionFactory的时候,会以Autowired的方式自动注入一个。换言之当我们只使用一个数据源的时候,即只定义了一个SqlSessionFactory的时候我们就可以不给MapperScannerConfigurer指定SqlSessionFactory。
sqlSessionFactoryBeanName:它的功能跟sqlSessionFactory是一样的,只是它指定的是定义好的SqlSessionFactory对应的bean名称。
sqlSessionTemplate: 已废弃 。它的功能也是相当于sqlSessionFactory的,MapperFactoryBean最终还是使用的SqlSession的getMapper方法取的对应的Mapper对象。当定义有多个SqlSessionTemplate的时候才需要指定它。对于一个MapperFactoryBean来说SqlSessionFactory和SqlSessionTemplate只需要其中一个就可以了,当两者都指定了的时候,SqlSessionFactory会被忽略。
sqlSessionTemplateBeanName:指定需要使用的sqlSessionTemplate对应的bean名称。
4.3、引入属性配置文件db.properties
从示例3的配置代码中可以发现数据库连接字符信息同时出现在两个位置,分别是applicationContext.xml与db.properties文件中,如下所示:
<bean id="jdbcDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/db2" /> <property name="username" value="root" /> <property name="password" value="root" /> bean>
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/db2 username=root password=root
根据我们写代码的原则“Write once only once”,连接字符信息应该只存在一个位置,我们可以采用下面的方法整合:
修改后的db.properties文件内容如下:
#jdbc jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/db2?useUnicode=true&characterEncoding=UTF-8 jdbc.uid=root jdbc.pwd=root #other .. other.msg=hello
修改后的 applicationContext.xml文件内容如下:
xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <context:property-placeholder location="classpath:db.properties"/> <bean id="jdbcDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.uid}" /> <property name="password" value="${jdbc.pwd}" /> bean> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="jdbcDataSource" /> <property name="typeAliasesPackage" value="com.zhangguo.Spring61.entities">property> <property name="mapperLocations" value="classpath:com/zhangguo/Spring61/mapping/*Mapper.xml">property> bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">property> <property name="basePackage" value="com.zhangguo.Spring61.mapping">property> bean> <context:component-scan base-package="com.zhangguo.Spring61"> context:component-scan> <aop:aspectj-autoproxy proxy-target-class="true">aop:aspectj-autoproxy> beans>
测试运行代码如下:
package com.zhangguo.Spring61.test; import static org.junit.Assert.assertNotNull; import java.util.List; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.zhangguo.Spring61.entities.BookType; import com.zhangguo.Spring61.mapping.BookTypeDAO; public class TestMyBatisSpring01 { @Test public void test01() { //初始化容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml"); //获得bean BookTypeDAO bookTypeDao=ctx.getBean(BookTypeDAO.class); //访问数据库 Listbooktypes=bookTypeDao.getAllBookTypes(); for (BookType bookType : booktypes) { System.out.println(bookType); } assertNotNull(booktypes); } }
测试结果同第3阶段,成功!
4.4、数据源与连接池
通过连接池可以增加数据访问的性能,因为访问数据库时建立连接与释放连接是耗时操作,JDBC默认不带连接池技术,但MyBatis是内置连接池功能的,还有一些第三方知名的连接池技术如:DBCP、C3P0、Druid(德鲁伊)。
4.4.1、DBCP
DBCP 是 Apache 软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序应在系统中增加如下两个 jar 文件:Commons-dbcp.jar:连接池的实现、Commons-pool.jar:连接池实现的依赖库,常用属性如下:
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy username=root password=XDP # initialSize=10 #最大连接数量 maxActive=50 # maxIdle=20 # minIdle=5 # maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:[属性名=property;] #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=UTF8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED
在与Spring整合时设置:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver">property> <property name="url" value="jdbc:mysql://localhost:3306/hlp?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull">property> <property name="username" value="root">property> <property name="password" value="1234">property> <property name="maxActive" value="100">property> <property name="maxIdle" value="30">property> <property name="maxWait" value="500">property> <property name="defaultAutoCommit" value="true">property> bean>
使用上面的代码替换原数据源的创建。
4.4.2、C3P0
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。dbcp没有自动回收空闲连接的功能,而c3p0有自动回收空闲连接功能。
在pom.xml中添加依赖:
<dependency> <groupId>c3p0groupId> <artifactId>c3p0artifactId> <version>0.9.1.2version> dependency>
在与Spring整合时修改applicationContext.xml,设置如下:
<bean id="jdbcDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.uid}" /> <property name="password" value="${jdbc.pwd}" /> <property name="acquireIncrement" value="5">property> <property name="initialPoolSize" value="10">property> <property name="minPoolSize" value="5">property> <property name="maxPoolSize" value="20">property> bean>
在测试的代码中设置断点,查看连接数,显示结果如下:
关于c3p0属性的细节与查看连接数据的方法请查看我的另一篇文章:Hibernate整合C3P0实现连接池。 常用属性如下:
<property name="acquireIncrement">3property> <property name="acquireRetryAttempts">30property> <property name="acquireRetryDelay">1000property> <property name="autoCommitOnClose">falseproperty> <property name="automaticTestTable">Testproperty> <property name="breakAfterAcquireFailure">falseproperty> <property name="checkoutTimeout">100property> <property name="connectionTesterClassName">property> <property name="factoryClassLocation">nullproperty> <property name="forceIgnoreUnresolvedTransactions">falseproperty> <property name="idleConnectionTestPeriod">60property> <property name="initialPoolSize">3property> <property name="maxIdleTime">60property> <property name="maxPoolSize">15property> <property name="maxStatements">100property> <property name="maxStatementsPerConnection">property> <property name="numHelperThreads">3property> <property name="overrideDefaultUser">rootproperty> <property name="overrideDefaultPassword">passwordproperty> <property name="password">property> <property name="preferredTestQuery">select id from test where id=1property> <property name="propertyCycle">300property> <property name="testConnectionOnCheckout">falseproperty> <property name="testConnectionOnCheckin">trueproperty> <property name="user">rootproperty> 在Hibernate(spring管理)中的配置: <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"><value>oracle.jdbc.driver.OracleDrivervalue>property> <property name="jdbcUrl"><value>jdbc:oracle:thin:@localhost:1521:Testvalue>property> <property name="user"><value>Kayvalue>property> <property name="password"><value>rootvalue>property> <property name="minPoolSize" value="10" /> <property name="maxPoolSize" value="100" /> <property name="maxIdleTime" value="1800" /> <property name="acquireIncrement" value="3" /> <property name="maxStatements" value="1000" /> <property name="initialPoolSize" value="10" /> <property name="idleConnectionTestPeriod" value="60" /> <property name="acquireRetryAttempts" value="30" /> <property name="breakAfterAcquireFailure" value="true" /> <property name="testConnectionOnCheckout" value="false" /> bean> 编辑本段相关信息连接池配置(以Hibernate为例) ########################### ### C3P0 Connection Pool### ########################### #hibernate.c3p0.max_size 2 #hibernate.c3p0.min_size 2 #hibernate.c3p0.timeout 5000 #hibernate.c3p0.max_statements 100 #hibernate.c3p0.idle_test_period 3000 #hibernate.c3p0.acquire_increment 2 #hibernate.c3p0.validate false 在hibernate.cfg.xml文件里面加入如下的配置: <property name="hibernate.c3p0.max_size">20property> <property name="hibernate.c3p0.min_size">5property> <property name="hibernate.c3p0.timeout">120property> <property name="hibernate.c3p0.max_statements">100property> <property name="hibernate.c3p0.idle_test_period">120property> <property name="hibernate.c3p0.acquire_increment">2property> <property name="hibernate.c3p0.validate">trueproperty>
4.4.3、Druid(德鲁伊)
Druid首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个SQL Parser。阿里巴巴是一个重度使用关系数据库的公司,我们在生产环境中大量的使用Druid,通过长期在极高负载的生产环境中实际使用、修改和完善,让Druid逐步发展成最好的数据库连接池。Druid在监控、可扩展性、稳定性和性能方面都有明显的优势。
在与Spring整合时设置:
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="url" value="${jdbc_url}" /> <property name="username" value="${jdbc_username}" /> <property name="password" value="${jdbc_password}" /> <property name="initialSize" value="0" /> <property name="maxActive" value="20" /> <property name="maxIdle" value="20" /> <property name="minIdle" value="0" /> <property name="maxWait" value="60000" /> <property name="validationQuery" value="${validationQuery}" /> <property name="testOnBorrow" value="false" /> <property name="testOnReturn" value="false" /> <property name="testWhileIdle" value="true" /> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <property name="minEvictableIdleTimeMillis" value="25200000" /> <property name="removeAbandoned" value="true" /> <property name="removeAbandonedTimeout" value="1800" /> <property name="logAbandoned" value="true" /> <property name="filters" value="mergeStat" /> bean>
使用上面的代码替换原数据源的创建。
maven依赖方式:
<dependency> <groupId>com.alibabagroupId> <artifactId>druidartifactId> <version>1.0.20version> dependency>
github:https://github.com/alibaba/druid,阿里的其它开源框架:https://github.com/alibaba
4.5、使用SqlSession
Mybatis-Spring为我们提供了一个实现了SqlSession接口的SqlSessionTemplate类,它是线程安全的,可以被多个Dao同时使用。同时它还跟Spring的事务进行了关联,确保当前被使用的SqlSession是一个已经和Spring的事务进行绑定了的。而且它还可以自己管理Session的提交和关闭。当使用了Spring的事务管理机制后,SqlSession还可以跟着Spring的事务一起提交和回滚。修改applicationContext.xml文件,增加一个bean。
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 id="bTDImpl" class="com.zhangguo.Spring61.dao.BTDImpl"> <property name="sqlSession" ref="sqlSession">property> bean>
新增一个BTDImpl类,实现接口BookTypeDAO,具体如下:
package com.zhangguo.Spring61.dao; import java.util.List; import org.apache.ibatis.session.SqlSession; import com.zhangguo.Spring61.entities.BookType; import com.zhangguo.Spring61.mapping.BookTypeDAO; public class BTDImpl implements BookTypeDAO { private SqlSession sqlSession; public void setSqlSession(SqlSession sqlSession) { this.sqlSession = sqlSession; } @Override public ListgetAllBookTypes() { return sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes"); } }
使用Spring的依赖注入在DAO中直接使用SqlSessionTemplate来访问数据库了。
测试代码:
package com.zhangguo.Spring61.test; import static org.junit.Assert.assertNotNull; import java.util.List; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.zhangguo.Spring61.dao.BTDImpl; import com.zhangguo.Spring61.entities.BookType; public class TestMyBatisSpring02 { @Test public void test01() { //初始化容器 ApplicationContext ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml"); //获得bean BTDImpl bTDImpl=ctx.getBean("bTDImpl",BTDImpl.class); //访问数据库 Listbooktypes=bTDImpl.getAllBookTypes(); for (BookType bookType : booktypes) { System.out.println(bookType); } assertNotNull(booktypes); } }
运行结果:
也可以通过自动装配实现,使配置更加简单,在配置文件中可以删除“创建一个BTDImpl对象”这一段,在类BTDImpl中增加注解,代码如下:
package com.zhangguo.Spring61.dao; import java.util.List; import javax.annotation.Resource; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import com.zhangguo.Spring61.entities.BookType; import com.zhangguo.Spring61.mapping.BookTypeDAO; @Repository public class BTDImpl implements BookTypeDAO { @Resource private SqlSession sqlSession; public void setSqlSession(SqlSession sqlSession) { this.sqlSession = sqlSession; } @Override public ListgetAllBookTypes() { return sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes"); } }
测试方法获得bean要修改成:BTDImpl bTDImpl=ctx.getBean(BTDImpl.class);,运行结果同上。
实在太乱了,应大家的要求,打算在另外一篇文章中再继续写。
五、示例下载
点击下载