SPRING学习(三十八)--SPRING集成MYBATIS之数据库连接池和多种数据源配置方式(三)

上一章节学习了如果运用spring集成mybatis,数据源配置使用的spring提供的数据源配置方式,另外还有一些第三方数据源配置方式,而且可以配置数据库连接池。

通过数据库连接池可以增加数据访问的性能,因为访问数据库时建立连接与释放连接是耗时操作,JDBC默认不带连接池技术,但MyBatis是内置连接池功能的,还有一些第三方知名的连接池技术如:DBCP、C3P0、Druid(德鲁伊)。

1、DBCP

DBCP 是 Apache 软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序应在系统中增加如下两个 jar 文件:Commons-dbcp.jar:连接池的实现、Commons-pool.jar:连接池实现的依赖库,常用属性如下:

(1)pom.xml文件添加依赖

     <!--propertiesUtil 读取配置文件-->
    <dependency>
        <groupId>commons-configuration</groupId>
        <artifactId>commons-configuration</artifactId>
        <version>1.10</version>
    </dependency>
    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <!-- mybatis驱动包 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.1</version>
    </dependency>
    <!--mybatis-spring适配器 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>
    <!--Spring java数据库访问包,在本例中主要用于提供数据源 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- 为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- apache dbcp 方式配置数据源驱动包 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <!-- apache 数据库连接池包 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool</artifactId>
        <version>1.6</version>
    </dependency>

(2)db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mytestdatabase?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username=qiaozhong
password=1
initialSize=2
maxActive=5
minIdle=2
maxIdle=5
maxWait=10

(3)spring-mybatis.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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
    
    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:mybatisConfig/db.properties" />
    </bean>

    <!-- 数据源与数据库连接池配置 -->
       <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${initialSize}" />
        <!-- 连接池最大数量 -->
        <property name="maxActive" value="${maxActive}" />
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${maxIdle}" />
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${minIdle}" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${maxWait}" />
    </bean>

    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件,**表示迭代查找 -->
        <property name="mapperLocations" value="classpath:mybatis/**.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 ,包下的类需要使用@MapperScan注解,否则容器注入会失败 -->
    <bean id="mapperScanConfig" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="mybatis.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>
    
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

上述通过DBCP方式配置了数据源和数据库连接池,如何验证我们的数据库连接池配置生效呢?

可以通过查看数据库连接数来判断,查看命令:D:ProgramFilesMySQLMySQL Server 5.7in>mysqladmin  -uqiaozhong -p1 -h127.0.0.1 -P3306 status

先进入到mysql安装目录D:ProgramFilesMySQLMySQL Server 5.7in

执行:mysqladmin  -uqiaozhong -p1 -h127.0.0.1 -P3306 status

其中-u为数据库用户名,-p为密码password,-h为数据库ip,-P为端口port

返回值中的Threads为数据库连接数。

验证流程:

1>不启动程序,执行命令查看mysql连接数为1。

2>在测试类中打个断点,对数据库测试函数进行debug,执行命令查看mysql连接数变为3。因为db.properties中配置的数据库连接池初始化连接数和最小空闲连接数均为2。

3>连接池配置成功。

 2、C3P0

 C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。dbcp没有自动回收空闲连接的功能,而c3p0有自动回收空闲连接功能。

(1)pom.xml文件增加依赖:

     <!--propertiesUtil 读取配置文件-->
    <dependency>
        <groupId>commons-configuration</groupId>
        <artifactId>commons-configuration</artifactId>
        <version>1.10</version>
    </dependency>
    
    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <!-- mybatis驱动包 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.1</version>
    </dependency>
    <!--mybatis-spring适配器 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>
    <!--Spring java数据库访问包,在本例中主要用于提供数据源 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- 为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!--c3p0 连接池 -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>

(2)db.properties配置:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mytestdatabase?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username=qiaozhong
acquireIncrement=3
password=1
initialSize=1
maxActive=5
minIdle=1
maxIdle=5
maxWait=10
idleConnectionTestPeriod=60

(3)spring-mybatis.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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
    
    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:mybatisConfig/db.properties" />
    </bean>

    <!-- C3P0数据源与数据库连接池配置 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${driver}" />
        <property name="jdbcUrl" value="${url}" />
        <property name="user" value="${username}" />
        <property name="password" value="${password}" />
        <!-- acquireIncrement:链接用完了自动增量的数量。 -->
        <property name="acquireIncrement" value="${acquireIncrement}" />
        <!--initialPoolSize:初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。 --> 
        <property name="initialPoolSize" value="${initialSize}" />
        <!--maxPoolSize:连接池中保留的最小连接数。 -->
        <property name="minPoolSize" value="${minIdle}" />
        <!--maxPoolSize:连接池中保留的最大连接数。 -->
        <property name="maxPoolSize" value="${maxIdle}" />
        <!--maxIdleTime:最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。-->
        <property name="maxIdleTime" value="${maxWait}" />
        <!--idleConnectionTestPeriod:检查所有连接池中的空闲连接的时间间隔,单位秒--> 
        <property name="idleConnectionTestPeriod"  value="${idleConnectionTestPeriod}" />
    </bean>
    
    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件,**表示迭代查找 -->
        <property name="mapperLocations" value="classpath:mybatis/**.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 ,包下的类需要使用@MapperScan注解,否则容器注入会失败 -->
    <bean id="mapperScanConfig" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="mybatis.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>
    
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

3、Druid(德鲁伊)

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

 (1)pom.xml配置:

    <!-- mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.13</version>
    </dependency>
    <!-- mybatis驱动包 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.1</version>
    </dependency>
    <!--mybatis-spring适配器 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>
    <!--Spring java数据库访问包,在本例中主要用于提供数据源 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- 为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- druid(德鲁伊)数据源和连接池 -->
    <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>druid</artifactId>
         <version>1.0.20</version>
    </dependency>

(2)db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mytestdatabase?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username=qiaozhong
password=1
initialSize=1
maxActive=5
minIdle=1
maxIdle=5
maxWait=10
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=25200000

(3)spring-mybatis.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:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    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.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
    
    <!-- 引入配置文件 -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location" value="classpath:mybatisConfig/db.properties" />
    </bean>
    
    <!-- 配置数据源与数据库连接池,使用的是alibaba的Druid(德鲁伊)数据源 -->
    <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <property name="driverClassName" value="${driver}" />
        <property name="url" value="${url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="${initialSize}" />
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="${maxActive}" />
        <!-- 连接池最大空闲 -->
        <property name="maxIdle" value="${maxIdle}" />
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="${minIdle}" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="${maxWait}" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}" />
        <!-- 监控数据库 -->
        <property name="filters" value="mergeStat" />
    </bean>
    
    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- 自动扫描mapping.xml文件,**表示迭代查找 -->
        <property name="mapperLocations" value="classpath:mybatis/**.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring会自动查找其下的类 ,包下的类需要使用@MapperScan注解,否则容器注入会失败 -->
    <bean id="mapperScanConfig" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="mybatis.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>
    
    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

4、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 >
        <constructor-arg index="0" ref="sqlSessionFactory" />
    </bean>
    
    <!--创建一个BTDImpl对象 -->
    <bean >
        <property name="sqlSession" ref="sqlSession"></property>
    </bean>

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

package com.zhangguo.Spring61.dao;

import java.util.List;
import org.apache.ibatis.session.SqlSession;
import com.zhangguo.Spring61.entities.BookType;
import com.zhangguo.Spring61.mapping.BookTypeDAO;

public class BTDImpl implements BookTypeDAO {
    private SqlSession sqlSession;

    public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<BookType> getAllBookTypes() {
        return sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes");
    }

}

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

测试代码:

package com.zhangguo.Spring61.test;

import static org.junit.Assert.assertNotNull;
import java.util.List;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhangguo.Spring61.dao.BTDImpl;
import com.zhangguo.Spring61.entities.BookType;

public class TestMyBatisSpring02 {
    @Test
    public void test01() {
        //初始化容器
        ApplicationContext ctx=new ClassPathXmlApplicationContext("ApplicationContext.xml");
        //获得bean
        BTDImpl bTDImpl=ctx.getBean("bTDImpl",BTDImpl.class);
        //访问数据库
        List<BookType> booktypes=bTDImpl.getAllBookTypes();
        for (BookType bookType : booktypes) {
            System.out.println(bookType);
        }
        assertNotNull(booktypes);
    }
}

运行结果:

 SPRING学习(三十八)--SPRING集成MYBATIS之数据库连接池和多种数据源配置方式(三)

也可以通过自动装配实现,使配置更加简单,在配置文件中可以删除“创建一个BTDImpl对象”这一段,在类BTDImpl中增加注解,代码如下:

package com.zhangguo.Spring61.dao;

import java.util.List;

import javax.annotation.Resource;

import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;

import com.zhangguo.Spring61.entities.BookType;
import com.zhangguo.Spring61.mapping.BookTypeDAO;

@Repository
public class BTDImpl implements BookTypeDAO {
    @Resource
    private SqlSession sqlSession;

    public void setSqlSession(SqlSession sqlSession) {
        this.sqlSession = sqlSession;
    }

    @Override
    public List<BookType> getAllBookTypes() {
        return sqlSession.selectList("com.zhangguo.Spring61.mapping.BookTypeDAO.getAllBookTypes");
    }

}

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