Spring学习总结(五)——Spring整合MyBatis(Maven+MySQL)一

目录

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.0</modelVersion>
    <groupId>com.zhangguo</groupId>
    <artifactId>Spring061</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.6.1</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </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;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setId(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getTypeName() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> typeName;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setTypeName(String typeName) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.typeName =<span style="color: rgba(0, 0, 0, 1)"> typeName;
}
@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.getId()+"\t"+<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.getTypeName();
}

}

2.4、创建实例与表的映射文件

这里用接口 +XML 的形式完成,BookType 数据访问接口如下:

package com.zhangguo.Spring61.mapping;

import java.util.List;

import com.zhangguo.Spring61.entities.BookType;

/**

  • 图书类型数据访问接口

/
public interface BookTypeDAO {
/

* 获得所有图书类型
*/
public List<BookType> getAllBookTypes();
}

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">
    <!--id 应该是接口中的方法,结果类型如没有配置别名则应该使用全名称 -->
    <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>
    <!--类型别名,默认引入 com.zhangguo.Spring61.entities 下的所有类 -->
    <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 {

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">GC不理static</span>
<span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> SqlSessionFactory factory=<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactory getSqlSessionFactory(){
    </span><span style="color: rgba(0, 0, 255, 1)">if</span>(factory==<span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">){
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 获得环境配置文件流</span>
    InputStream config = MyBatisUtil.<span style="color: rgba(0, 0, 255, 1)">class</span>.getClassLoader().getResourceAsStream("MyBatisCfg.xml"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建sql会话工厂</span>
    factory = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactoryBuilder().build(config);
    }
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> factory;
}

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获得会话</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> SqlSession getSession(){
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> getSqlSessionFactory().openSession(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
}

</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
 * 获得得sql会话
 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> isAutoCommit 是否自动提交,如果为false则需要sqlSession.commit();rollback();
 * </span><span style="color: rgba(128, 128, 128, 1)">@return</span><span style="color: rgba(0, 128, 0, 1)"> sql会话
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> SqlSession getSession(<span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isAutoCommit){
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> 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
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;BookType&gt;<span style="color: rgba(0, 0, 0, 1)"> getAllBookTypes() {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获得会话对象</span>
    SqlSession session=<span style="color: rgba(0, 0, 0, 1)">MyBatisUtil.getSession();
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过MyBatis实现接口BookTypeDAO,返回实例</span>
        BookTypeDAO bookTypeDAO=session.getMapper(BookTypeDAO.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> bookTypeDAO.getAllBookTypes();
    } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
        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 {

</span><span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> BookTypeDAO bookTypeDao;
@BeforeClass
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> beforeClass()
{
    bookTypeDao</span>=<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> BookTypeDAOImpl();
}

@Test
</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> testGetAllBookTypes() {
    List</span>&lt;BookType&gt; booktypes=<span style="color: rgba(0, 0, 0, 1)">bookTypeDao.getAllBookTypes();
    </span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> (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🇲🇲ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
        </Console>        
    </Appenders>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">Loggers</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>            
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">Root </span><span style="color: rgba(255, 0, 0, 1)">level</span><span style="color: rgba(0, 0, 255, 1)">="debug"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">AppenderRef </span><span style="color: rgba(255, 0, 0, 1)">ref</span><span style="color: rgba(0, 0, 255, 1)">="Console"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">Root</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">Loggers</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</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.0</modelVersion>
    <groupId>com.zhangguo</groupId>
    <artifactId>Spring061</artifactId>
    <version>0.0.1</version>
    <packaging>war</packaging>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">properties</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">project.build.sourceEncoding</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>UTF-8<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">project.build.sourceEncoding</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">spring.version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>4.3.0.RELEASE<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">spring.version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">properties</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">mysql数据库驱动 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mysql<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mysql-connector-java<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>5.1.38<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">log4j日志包 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.apache.logging.log4j<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>log4j-core<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>2.6.1<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> mybatis ORM框架 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.mybatis<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mybatis<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>3.4.1<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> JUnit单元测试工具 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>junit<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>junit<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>4.10<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">mybatis-spring适配器 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.mybatis<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>mybatis-spring<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>1.3.0<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">Spring框架核心库 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-context<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>${spring.version}<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> aspectJ AOP 织入器 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.aspectj<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>aspectjweaver<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>1.8.9<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">Spring java数据库访问包,在本例中主要用于提供数据源 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>org.springframework<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">groupId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>spring-jdbc<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">artifactId</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
        <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>${spring.version}<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">version</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependency</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">dependencies</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</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">
<span style="color: rgba(0, 128, 0, 1)">&lt;!--1</span><span style="color: rgba(0, 128, 0, 1)">定义一个jdbc数据源,创建一个驱动管理数据源的bean </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span><span style="color: rgba(255, 0, 0, 1)">
    class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.jdbc.datasource.DriverManagerDataSource"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClassName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.mysql.jdbc.Driver"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="url"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="jdbc:mysql://localhost:3306/db2"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="username"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="root"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="root"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--2</span><span style="color: rgba(0, 128, 0, 1)">创建一个sql会话工厂bean,指定数据源</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionFactoryBean"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span><span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="configLocation"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="classpath:MyBatisCfg.xml"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span> <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定配置文件 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--3</span><span style="color: rgba(0, 128, 0, 1)">创建一个booTypeDAO</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="bookTypeDao"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.mapper.MapperFactoryBean"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">指定映射文件 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="mapperInterface"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.mapping.BookTypeDAO"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定sql会话工厂</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">下面的配置暂时未使用 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy </span><span style="color: rgba(255, 0, 0, 1)">proxy-target-class</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</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);
//访问数据库
List<BookType> booktypes=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 容器替代,具体实现如下:

    <!--创建一个 sql 会话工厂 bean,指定数据源 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 1 指定数据源 -->
        <property name="dataSource" ref="jdbcDataSource" />
        <!-- 2类型别名包,默认引入 com.zhangguo.Spring61.entities 下的所有类 -->
        <property name="typeAliasesPackage" value="com.zhangguo.Spring61.entities"></property>
        <!-- 3指定 sql 映射 xml 文件的路径 -->
        <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.Blog</value>
        <value>com.tiantian.mybatis.model.Comment</value>
    </array>
</property>

我们修改了 applicationContext.xml 中的配置,通过容器完成了一个 sqlSessionFactory Bean 的创建, 1 指定了数据源,2 指定类型别名包这样在 sql 映射文件中使用类型时可以省去全名称,3 指定了所有要加载的 sql 映射 xml 文件,如果有多个目录,则可以使用如下的形式:

       <property name="mapperLocations">
            <list>
                <value>classpath:com/... 目录.../*_mapper.xml</value>
                <value>classpath:com/... 目录.../*_resultmap.xml</value>
            </list>
        </property>

如果需要设置更多的属性则可以参考类型 org.mybatis.spring.SqlSessionFactoryBean,如果不使用 Spring,也不使用 MyBatis 配置文件我们照样可以获得一个 sqlSessionFactory 对象完成对 MyBatis ORM 框架的使用,因为可以直接实例化一个 SqlSessionFactoryBean 对象,只是此时该工作被 Spring 容器替代,按这个思路可以在 SqlSessionFactoryBean 类中找到更多的属性设置在 applicationContext.xml 配置中,部分源代码如下所示:

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {

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 配置文件的,增加属性:<property name="configLocation" value="classpath:MyBatisCfg.xml"></property>

4.2、映射接口类自动扫描配置

在示例 3 的 applicationContext.xml 配置文件中有一段实现 BookTypeDAO 接口实例的创建工厂,配置如下:

    <!-- 创建一个 booTypeDAO -->
    <bean id="bookTypeDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
        <!--指定映射文件 -->
        <property name="mapperInterface" value="com.zhangguo.Spring61.mapping.BookTypeDAO"></property>
        <!-- 指定 sql 会话工厂 -->
        <property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
    </bean>

 如果有多个表,则需要配置多段信息,麻烦。我们可以通过自动扫描一次完成,配置如下:

    <!--自动扫描映射接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 指定 sql 会话工厂,在上面配置过的 -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
        <!-- 指定基础包,即自动扫描 com.zhangguo.Spring61.mapping 这个包以及它的子包下的所有映射接口类 -->
        <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 文件中,如下所示:

    <!--定义一个 jdbc 数据源,创建一个驱动管理数据源的 bean -->
    <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">
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">属性占位文件引入,可以通过${属性名}获得属性文件中的内容</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">context:property-placeholder </span><span style="color: rgba(255, 0, 0, 1)">location</span><span style="color: rgba(0, 0, 255, 1)">="classpath:db.properties"</span><span style="color: rgba(0, 0, 255, 1)">/&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">定义一个jdbc数据源,创建一个驱动管理数据源的bean </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span><span style="color: rgba(255, 0, 0, 1)">
    class</span><span style="color: rgba(0, 0, 255, 1)">="org.springframework.jdbc.datasource.DriverManagerDataSource"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="driverClassName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.driver}"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="url"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.url}"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="username"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.uid}"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="password"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="${jdbc.pwd}"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">创建一个sql会话工厂bean,指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.SqlSessionFactoryBean"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定数据源 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="dataSource"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="jdbcDataSource"</span> <span style="color: rgba(0, 0, 255, 1)">/&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">类型别名包,默认引入com.zhangguo.Spring61.entities下的所有类 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="typeAliasesPackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.entities"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">指定sql映射xml文件的路径 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="mapperLocations"</span><span style="color: rgba(255, 0, 0, 1)">
        value</span><span style="color: rgba(0, 0, 255, 1)">="classpath:com/zhangguo/Spring61/mapping/*Mapper.xml"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">自动扫描映射接口</span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">class</span><span style="color: rgba(0, 0, 255, 1)">="org.mybatis.spring.mapper.MapperScannerConfigurer"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定sql会话工厂,在上面配置过的 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactoryBeanName"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="sqlSessionFactory"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)"> 指定基础包,即自动扫描com.zhangguo.Spring61.mapping这个包以及它的子包下的所有映射接口类 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="basePackage"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.mapping"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">下面的配置暂时未使用 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan </span><span style="color: rgba(255, 0, 0, 1)">base-package</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">context:component-scan</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy </span><span style="color: rgba(255, 0, 0, 1)">proxy-target-class</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">aop:aspectj-autoproxy</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>

</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);
//访问数据库
List<BookType> booktypes=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
#<!-- 超时等待时间以毫秒为单位 6000 毫秒 /1000 等于 60 秒 -->
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&amp;characterEncoding=UTF-8&amp;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 中添加依赖:

        <!--c3p0 连接池 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

 在与 Spring 整合时修改 applicationContext.xml,设置如下:

    <!--定义一个 jdbc 数据源,创建一个驱动管理数据源的 bean -->
    <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 实现连接池 常用属性如下:

<!--当连接池中的连接耗尽的时候 c3p0 一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement">3</property>
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<property name="acquireRetryAttempts">30</property>
<!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
<property name="acquireRetryDelay">1000</property>
<!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
<property name="autoCommitOnClose">false</property>
<!--c3p0 将建一张名为 Test 的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么
属性 preferredTestQuery 将被忽略。你不能在这张 Test 表上进行任何操作,它将只供 c3p0 测试
使用。Default: null-->
<property name="automaticTestTable">Test</property>
<!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
保留,并在下次调用 getConnection() 的时候继续尝试获取连接。如果设为 true,那么在尝试
获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
<property name="breakAfterAcquireFailure">false</property>
<!--当连接池用完时客户端调用 getConnection() 后等待获取新连接的时间,超时后将抛出
SQLException, 如设为 0 则无限期等待。单位毫秒。Default: 0 -->
<property name="checkoutTimeout">100</property>
<!--通过实现 ConnectionTester 或 QueryConnectionTester 的类来测试连接。类名需制定全路径。
Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
<property name="connectionTesterClassName"></property>
<!--指定 c3p0 libraries 的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认 null 即可
Default: null-->
<property name="factoryClassLocation">null</property>
<!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
(文档原文)作者强烈建议不使用的一个属性-->
<property name="forceIgnoreUnresolvedTransactions">false</property>
<!--每 60 秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod">60</property>
<!--初始化时获取三个连接,取值应在 minPoolSize 与 maxPoolSize 之间。Default: 3 -->
<property name="initialPoolSize">3</property>
<!--最大空闲时间,60 秒内未使用则连接被丢弃。若为 0 则永不丢弃。Default: 0 -->
<property name="maxIdleTime">60</property>
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize">15</property>
<!--JDBC 的标准参数,用以控制数据源内加载的 PreparedStatements 数量。但由于预缓存的 statements
属于单个 connection 而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果 maxStatements 与 maxStatementsPerConnection 均为 0,则缓存被关闭。Default: 0-->
<property name="maxStatements">100</property>
<!--maxStatementsPerConnection 定义了连接池内单个连接所拥有的最大缓存 statements 数。Default: 0 -->
<property name="maxStatementsPerConnection"></property>
<!--c3p0 是异步操作的,缓慢的 JDBC 操作通过帮助进程完成。扩展这些操作可以有效的提升性能
通过多线程实现多个操作同时被执行。Default: 3-->
<property name="numHelperThreads">3</property>
<!--当用户调用 getConnection() 时使 root 用户成为去获取连接的用户。主要用于连接池连接非 c3p0
的数据源时。Default: null-->
<property name="overrideDefaultUser">root</property>
<!--与 overrideDefaultUser 参数对应使用的一个参数。Default: null-->
<property name="overrideDefaultPassword">password</property>
<!--密码。Default: null-->
<property name="password"></property>
<!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:
测试的表必须在初始数据源的时候就存在。Default: null-->
<property name="preferredTestQuery">select id from test where id=1</property>
<!--用户修改系统配置参数执行前最多等待 300 秒。Default: 300 -->
<property name="propertyCycle">300</property>
<!--因性能消耗大请只在需要的时候使用它。如果设为 true 那么在每个 connection 提交的
时候都将校验其有效性。建议使用 idleConnectionTestPeriod 或 automaticTestTable
等方法来提升连接测试的性能。Default: false -->
<property name="testConnectionOnCheckout">false</property>
<!--如果设为 true 那么在取得连接的同时将校验连接的有效性。Default: false -->
<property name="testConnectionOnCheckin">true</property>
<!--用户名。Default: null-->
<property name="user">root</property>
在 Hibernate(spring 管理)中的配置:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass"><value>oracle.jdbc.driver.OracleDriver</value></property>
<property name="jdbcUrl"><value>jdbc:oracle:thin:@localhost:1521:Test</value></property>
<property name="user"><value>Kay</value></property>
<property name="password"><value>root</value></property>
<!--连接池中保留的最小连接数。-->
<property name="minPoolSize" value="10" />
<!--连接池中保留的最大连接数。Default: 15 -->
<property name="maxPoolSize" value="100" />
<!--最大空闲时间,1800 秒内未使用则连接被丢弃。若为 0 则永不丢弃。Default: 0 -->
<property name="maxIdleTime" value="1800" />
<!--当连接池中的连接耗尽的时候 c3p0 一次同时获取的连接数。Default: 3 -->
<property name="acquireIncrement" value="3" />
<property name="maxStatements" value="1000" />
<property name="initialPoolSize" value="10" />
<!--每 60 秒检查所有连接池中的空闲连接。Default: 0 -->
<property name="idleConnectionTestPeriod" value="60" />
<!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
<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">20</property>
<!-- 最小连接数 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 获得连接的超时时间, 如果超过这个时间, 会抛出异常,单位毫秒 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 最大的 PreparedStatement 的数量 -->
<property name="hibernate.c3p0.max_statements">100</property>
<!-- 每隔 120 秒检查连接池里的空闲连接 ,单位是秒-->
<property name="hibernate.c3p0.idle_test_period">120</property>
<!-- 当连接池里面的连接用完的时候,C3P0 一下获取的新的连接数 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 每次都验证连接是否可用 -->
<property name="hibernate.c3p0.validate">true</property>
c3p0 常用属性 + 展开

4.4.3、Druid(德鲁伊)

Druid 首先是一个数据库连接池,但它不仅仅是一个数据库连接池,它还包含一个 ProxyDriver,一系列内置的 JDBC 组件库,一个 SQL Parser。阿里巴巴是一个重度使用关系数据库的公司,我们在生产环境中大量的使用 Druid,通过长期在极高负载的生产环境中实际使用、修改和完善,让 Druid 逐步发展成最好的数据库连接池。Druid 在监控、可扩展性、稳定性和性能方面都有明显的优势。

在与 Spring 整合时设置:

<!-- 配置数据源,使用的是 alibaba 的 Druid(德鲁伊) 数据源 -->
    <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="poolPreparedStatements" value="true" /> 
        <property name="maxPoolPreparedStatementPerConnectionSize" value="33" /> 
        -->
        <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" />
        <!-- 打开 removeAbandoned 功能 -->
        <property name="removeAbandoned" value="true" />
        <!-- 1800 秒,也就是 30 分钟 -->
        <property name="removeAbandonedTimeout" value="1800" />
        <!-- 关闭 abanded 连接时输出错误日志 -->
        <property name="logAbandoned" value="true" />
        <!-- 监控数据库 -->
        <!-- <property name="filters" value="stat" /> -->
        <property name="filters" value="mergeStat" />
    </bean>

 使用上面的代码替换原数据源的创建。

 maven 依赖方式:

<dependency>
     <groupId>com.alibaba</groupId>
     <artifactId>druid</artifactId>
     <version>1.0.20</version>
</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 作为构造方法的参数来创建。

    <!-- 创建一个 sqlSession 对象 -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
<span style="color: rgba(0, 128, 0, 1)">&lt;!--</span><span style="color: rgba(0, 128, 0, 1)">创建一个BTDImpl对象 </span><span style="color: rgba(0, 128, 0, 1)">--&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">bean </span><span style="color: rgba(255, 0, 0, 1)">id</span><span style="color: rgba(0, 0, 255, 1)">="bTDImpl"</span><span style="color: rgba(255, 0, 0, 1)"> class</span><span style="color: rgba(0, 0, 255, 1)">="com.zhangguo.Spring61.dao.BTDImpl"</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
    <span style="color: rgba(0, 0, 255, 1)">&lt;</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="sqlSession"</span><span style="color: rgba(255, 0, 0, 1)"> ref</span><span style="color: rgba(0, 0, 255, 1)">="sqlSession"</span><span style="color: rgba(0, 0, 255, 1)">&gt;&lt;/</span><span style="color: rgba(128, 0, 0, 1)">property</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span>
<span style="color: rgba(0, 0, 255, 1)">&lt;/</span><span style="color: rgba(128, 0, 0, 1)">bean</span><span style="color: rgba(0, 0, 255, 1)">&gt;</span></pre>

新增一个 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;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setSqlSession(SqlSession sqlSession) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sqlSession =<span style="color: rgba(0, 0, 0, 1)"> sqlSession;
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;BookType&gt;<span style="color: rgba(0, 0, 0, 1)"> getAllBookTypes() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes"<span style="color: rgba(0, 0, 0, 1)">);
}

}

使用 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);
//访问数据库
List<BookType> booktypes=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;

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setSqlSession(SqlSession sqlSession) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sqlSession =<span style="color: rgba(0, 0, 0, 1)"> sqlSession;
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span> List&lt;BookType&gt;<span style="color: rgba(0, 0, 0, 1)"> getAllBookTypes() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes"<span style="color: rgba(0, 0, 0, 1)">);
}

}

 测试方法获得 bean 要修改成:BTDImpl bTDImpl=ctx.getBean(BTDImpl.class);,运行结果同上。

 实在太乱了,应大家的要求,打算在另外一篇文章中再继续写。

五、示例下载

点击下载