上一章节学习了如果运用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 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,具体如下:
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); } }
运行结果:
也可以通过自动装配实现,使配置更加简单,在配置文件中可以删除“创建一个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);,运行结果同上。