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

2022-05-09 20:01:18 浏览数 (1)

目录

  • 一、 使用Maven创建一个Web项目
  • 二、使用MyBatis完成MySQL数据库访问
    • 2.1、添加依赖
    • 2.2、准备数据
    • 2.3、创建java Bean
    • 2.4、创建实例与表的映射文件
    • 2.5、创建MyBatisCfg.xml文件 
    • 2.6、实现数据访问功能
    • 2.7、测试运行
    • 2.8、整合log4j2
  • 三、使用Spring4.X整合MyBatis3.X初级版
    • 3.1、修改pom.xml添加依赖
    •  3.2、创建Spring上下文初始化配置文件
    •  3.3、测试运行
  •  四、Spring集成MyBatis升级版
    •  4.1、去掉MyBatisCfg.xml配置文件
    • 4.2、映射接口类自动扫描配置
    • 4.3、引入属性配置文件db.properties
    • 4.4、数据源与连接池
      • 4.4.1、DBCP
      • 4.4.2、C3P0
      • 4.4.3、Druid(德鲁伊)
    • 4.5、使用SqlSession
  • 五、示例下载

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、选择srcmainwebapp目录为目标目录,点击“Finish完成”保存并关闭。

1.13、如果此时项目还报错,随便修改pom.xml文件后保存后应该错误会消失。

 1.14、在srcmainwebapp目录下新建一个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文件中写上测试内容。

代码语言:javascript复制
<%@ 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文件如下:

代码语言:javascript复制
<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脚本如下:

代码语言:javascript复制
/*
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类型。

代码语言:javascript复制
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数据访问接口如下:

代码语言:javascript复制
package com.zhangguo.Spring61.mapping;

import java.util.List;

import com.zhangguo.Spring61.entities.BookType;

/**
 * 图书类型数据访问接口
 *
 */
public interface BookTypeDAO {
    /*
     * 获得所有图书类型
     */
    public List<BookType> getAllBookTypes();
}

BookTypeMapper.xml文件如下:

代码语言:javascript复制
<?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的运行环境,内容如下:

代码语言:javascript复制
<?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文件,该文件用于指定数据库的连接信息,内容如下:

代码语言:javascript复制
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db2
username=root
password=root

2.6、实现数据访问功能

为了更加方便的复用MyBatis实现数据访问不需要频繁的创建SQLSessionFactory和SQLSession对象,封装一个MyBatisUtil工具类如下:

代码语言:javascript复制
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实现数据访问功能,内容如下: 

代码语言:javascript复制
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 List<BookType> getAllBookTypes() {
        //获得会话对象
        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文件如下:

代码语言:javascript复制
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() {
        List<BookType> booktypes=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配置文件,文件内容如下所示:

代码语言:javascript复制
<?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文件如下所示:

代码语言:javascript复制
<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>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.0.RELEASE</spring.version>
    </properties>

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

 3.2、创建Spring上下文初始化配置文件

该文件取名为ApplicationContext.xml主要原因是“约束优于配置”的理由,使用Web监听器加载Spring时会默认找该名称的文件。在文件中我们可像以前学习Spring一样配置IOC与AOP,只不过这里整合了一些MyBatis内容。文件内容如下:

代码语言:javascript复制
<?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">

    <!--1定义一个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>

    <!--2创建一个sql会话工厂bean,指定数据源-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="jdbcDataSource" /><!-- 指定数据源 -->
        <property name="configLocation" value="classpath:MyBatisCfg.xml"></property> <!-- 指定配置文件 -->
    </bean>

    <!--3创建一个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>
    <!--下面的配置暂时未使用 -->
    <context:component-scan base-package="com.zhangguo">
    </context:component-scan>
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

从上面的代码可以看到分别创建了一个驱动管理数据源的对象,会话工厂与实现数据访问的对象通过Spring IOC完成,而不再是硬编码。第2段配置与下面的代码功能基本类似:

代码语言:javascript复制
    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代码基本类似:

代码语言:javascript复制
        SqlSession session = MyBatisUtil.getSession();
        try {
            BookTypeDAO bookTypeDAO = session.getMapper(BookTypeDAO.class);
            return bookTypeDAO.getAllBookTypes();
        } finally {
            session.close();
        }

 3.3、测试运行

代码语言:javascript复制
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容器替代,具体实现如下:

代码语言:javascript复制
    <!--创建一个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注解,否则将使用该注解对应的值作为此种类型的别名。

代码语言:javascript复制
<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文件,如果有多个目录,则可以使用如下的形式:

代码语言:javascript复制
       <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配置中,部分源代码如下所示:

代码语言:javascript复制
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接口实例的创建工厂,配置如下:

代码语言:javascript复制
    <!-- 创建一个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>

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

代码语言:javascript复制
    <!--自动扫描映射接口-->
    <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文件中,如下所示:

代码语言:javascript复制
    <!--定义一个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>
代码语言:javascript复制
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db2
username=root
password=root

根据我们写代码的原则“Write once only once”,连接字符信息应该只存在一个位置,我们可以采用下面的方法整合:

修改后的db.properties文件内容如下:

代码语言:javascript复制
#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文件内容如下:

代码语言:javascript复制
<?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"/>
    
    <!--定义一个jdbc数据源,创建一个驱动管理数据源的bean -->
    <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>

    <!--创建一个sql会话工厂bean,指定数据源 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 指定数据源 -->
        <property name="dataSource" ref="jdbcDataSource" />
        <!--类型别名包,默认引入com.zhangguo.Spring61.entities下的所有类 -->
        <property name="typeAliasesPackage" value="com.zhangguo.Spring61.entities"></property>
        <!--指定sql映射xml文件的路径 -->
        <property name="mapperLocations"
            value="classpath:com/zhangguo/Spring61/mapping/*Mapper.xml"></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>
    
    <!--下面的配置暂时未使用 -->
    <context:component-scan base-package="com.zhangguo.Spring61">
    </context:component-scan>
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

测试运行代码如下:

代码语言:javascript复制
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:连接池实现的依赖库,常用属性如下:

代码语言:javascript复制
#连接设置
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整合时设置:

代码语言:javascript复制
    <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中添加依赖:

代码语言:javascript复制
        <!--c3p0 连接池 -->
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

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

代码语言:javascript复制
    <!--定义一个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实现连接池。 常用属性如下:

代码语言:javascript复制
<!--当连接池中的连接耗尽的时候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>

4.4.3、Druid(德鲁伊)

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

在与Spring整合时设置:

代码语言:javascript复制
<!-- 配置数据源,使用的是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依赖方式:

代码语言:javascript复制
<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 作为构造方法的参数来创建。

代码语言:javascript复制
    <!-- 创建一个sqlSession对象 -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    
    <!--创建一个BTDImpl对象 -->
    <bean id="bTDImpl" class="com.zhangguo.Spring61.dao.BTDImpl">
        <property name="sqlSession" ref="sqlSession"></property>
    </bean>

新增一个BTDImpl类,实现接口BookTypeDAO,具体如下:

代码语言:javascript复制
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 List<BookType> getAllBookTypes() {
        return sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes");
    }

}

使用Spring的依赖注入在DAO中直接使用SqlSessionTemplate来访问数据库了。

测试代码:

代码语言:javascript复制
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中增加注解,代码如下:

代码语言:javascript复制
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 List<BookType> getAllBookTypes() {
        return sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes");
    }

}

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

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

五、示例下载

点击下载

0 人点赞