数据连接池
1、 如果没有任何一个用户使用连接,那么那么应该维持一定数量的连接,等待用户使用。
2、 如果连接已经满了,则必须打开新的连接,供更多用户使用。
3、 如果一个服务器就只能有100个连接,那么如果有第101个人过来呢?应该等待其他用户释放连接
4、 如果一个用户等待时间太长了,则应该告诉用户,操作是失败的。
下面对几个连接池进行示例配置:
在spring中,常使用数据库连接池来完成对数据库的连接配置,类似于线程池的定义,数据库连接池就是维护有一定数量数据库连接的一个缓冲池,一方面,能够即取即用,免去初始化的时间,另一方面,用完的数据连接会归还到连接池中,这样就免去了不必要的连接创建、销毁工作,提升了性能。当然,使用连接池,有一下几点是连接池配置所考虑到的,也属于配置连接池的优点,而这些也会我们后面的实例配置中体现:
在spring中,常用的连接池有:jdbc,dbcp,c3p0,JNDI4种,他们有不同的优缺点和适用场景。其中,spring框架推荐使用dbcp,hibernate框架推荐使用c3p0。经测试发现,c3p0与dbcp相比较,c3p0能够更好的支持高并发,但是在稳定性方面略逊于dpcp。
几个连接池的配置:
1.jdbc连接池配置
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver">
</property>
<property name="url" value="jdbc:mysql://localhost:3307/lucene?characterEncoding=UTF8" />
<property name="username" value="root"></property>
<property name="password" value="guo941102"></property>
</bean>
DriverManagerDataSource没有实现连接池化连接的机制,每次调用getConnection()获取新连接时,只是简单地创建一个新的连接。所以,一般这种方式常用于开发时测试,不用于生产。
2.c3p0连接池配置
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3307/lucene?characterEncoding=UTF8" />
<property name="user" value="root" />
<property name="password" value="guo941102" />
</bean>
他有以下常用的属性:
属性 | 说明 | 默认值 |
---|---|---|
acquireIncrement | 当连接池中的连接用完时,C3P0一次性创建新连接的数目 | 5 |
acquireRetryAttempts | 定义在从数据库获取新连接失败后重复尝试获取的次数 | 30 |
checkoutTimeout | 当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒 | 0 |
initialPoolSize | 初始化时创建的连接数,应在minPoolSize与maxPoolSize之间取值 | 3 |
maxIdleTime | 最大空闲时间,超过空闲时间的连接将被丢弃。为0或负数则永不丢弃 | 0 |
maxPoolSize | 连接池中保留的最大连接数 | 15 |
numHelperThreads | C3P0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能,通过多线程实现多个操作同时被执行 | 3 |
3.dbcp连接池配置实例(我的实例)
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"><!--设置为close使Spring容器关闭同时数据源能够正常关闭,以免造成连接泄露 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3307/lucene?characterEncoding=UTF8" />
<property name="username" value="root" />
<property name="password" value="guo941102" />
<property name="defaultReadOnly" value="false" /><!-- 设置为只读状态,配置读写分离时,读库可以设置为true -->
<!-- 在连接池创建后,会初始化并维护一定数量的数据库安连接,当请求过多时,数据库会动态增加连接数,
当请求过少时,连接池会减少连接数至一个最小空闲值 -->
<property name="initialSize" value="5" /><!-- 在启动连接池初始创建的数据库连接,默认为0 -->
<property name="maxActive" value="15" /><!-- 设置数据库同一时间的最大活跃连接默认为8,负数表示不闲置 -->
<property name="maxIdle" value="10"/><!-- 在连接池空闲时的最大连接数,超过的会被释放,默认为8,负数表示不闲置 -->
<property name="minIdle" value="2" /><!-- 空闲时的最小连接数,低于这个数量会创建新连接,默认为0 -->
<property name="maxWait" value="10000" /><!-- 连接被用完时等待归还的最大等待时间,单位毫秒,超出时间抛异常,默认为无限等待 -->
</bean>
以上的的配置都是在开发中经常用到的
对于DBCP连接池:
默认连接池的使用无需导入其他的jar包,但使用DBCP连接池需要导入jar包:依赖包中org.apache.commons文件夹中:
(1)com.springsource.org.apache.commons.dbcp-1.4.jar
(2)com.springsource.org.apache.commons.pool-1.6.jar
4.实例
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 使用XML Schema的p名称空间配置 -->
<bean name="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3307/lucene?characterEncoding=UTF8"
p:username="root"
p:password="guo941102" >
</bean>
<bean name="service" class="com.gym.dataService.Service"></bean>
</beans>
Service.java package com.gym.dataService;
import java.io.IOException;
import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class Service {
private ApplicationContext ctx;
public Service() {
super();
}
private DataSource getBasicDataSource() throws IOException {
//建立连接池资源
// BasicDataSource dataSource = new BasicDataSource();
// //读取配置信息
// Properties prop = new Properties();
// InputStream in = new BufferedInputStream (Service.class.getClassLoader().getResourceAsStream("config.properties"));
// prop.load(in);
// DriverClassName = prop.getProperty("driverclassname");
// Url = prop.getProperty("url");
//
// //进行配置
// dataSource.setDriverClassName(DriverClassName);
// //设置数据库访问的URL
// dataSource.setUrl(Url);
// //注意,在URL中已经设置过用户名和密码之后,就不需要再进行设置用户名和密码了,否则将会报错
//
// //设置数据库访问的用户名
dataSource.setUsername(this.Username);
//设置数据库访问密码
dataSource.setPassword(this.Password);
//
// //最大连接数量
// dataSource.setMaxActive(150);
// //最小空闲连接
// dataSource.setMinIdle(5);
// // 最大空闲连接
// dataSource.setMaxIdle(200);
// //初始化连接数量
// dataSource.setInitialSize(30);
// //连接被泄露是是否打印
// dataSource.setLogAbandoned(true);
// // 是否自动回收超时连接
// dataSource.setRemoveAbandoned(true);
// //设置超时等待时间
// dataSource.setRemoveAbandonedTimeout(10);
ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
DataSource dataSource= ctx.getBean("dataSource", DataSource.class);
return dataSource;
}
public JdbcTemplate getJdbcTemplate() throws IOException {
//加载source
JdbcTemplate jdbcTemplate = new JdbcTemplate(getBasicDataSource());
return jdbcTemplate;
}
}
//hints:刚开始,我使用注释处的方法配置的,后来发现web测试时,刷新两次就不能使用了,数据库拒绝连接,连接池创建多了。。。。,每次请求,实例化一次,肯定会炸,在JAVA application中运行还没事,移动到web上,忘记改了,就歇菜了
dataService.java
package com.gym.dataService;
import java.io.IOException;
import java.util.List;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
public class dataService {
public static Service service =
new ClassPathXmlApplicationContext("/applicationContext.xml").getBean("service",Service.class);
/**
* 懒汉单例模式
* 获取JdbcTemplate
* @return
* @throws IOException
*/
public static JdbcTemplate getTemplate() throws IOException {
// if(service == null) {
// //注入实例
// service = new Service();
// }
return service.getJdbcTemplate();
}
/**
*
* @param sql 执行的sql语句
* @param args 不定项参数
* @return
* @throws DataAccessException
* @throws IOException
*/
public static JSONArray toJSONArray(String sql, Object... args) throws DataAccessException, IOException {
// if(service == null) {
// //注入实例
// service = new Service();
// }
List list = service.getJdbcTemplate().queryForList(sql, args);
return JSONArray.fromObject(list);
}
public static JSONObject toJSONObject(String sql, Object... args) throws DataAccessException, IOException {
if(service == null) {
//实例化
service = new Service();
}
List list = service.getJdbcTemplate().queryForList(sql,args);
if(list.size() == 0) {
return new JSONObject();
}
return JSONObject.fromObject(list.get(0));
}
public static void main(String[] args) {
try {
JSONArray jsonArray = dataService.toJSONArray("select * from t_user where id = 2332 limit 10");
System.out.println(jsonArray);
for(int i=0;i<jsonArray.size();i++) {
JSONObject json = jsonArray.getJSONObject(i);
System.out.println("id:" + json.getString("id") + " username:"
+ json.getString("username") + " age:" + json.getString("age"));
}
} catch (DataAccessException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
} catch (IOException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
}
System.out.println("-----------------------");
try {
JSONObject json = dataService.toJSONObject("select * from t_user where id = 1212 limit 1");
System.out.println(json);
System.out.println("id:" + json.optString("id",null) + " username:"
+ json.optString("username",null) + " age:" + json.optString("age",null));
} catch (DataAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}