数据库连接池是什么?解决什么问题?
用户每次请求都需要向数据库获得链接,数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、宕机
使用数据库连接池能优化程序性能.数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,同时可以释放空闲时间超过最大空闲时间的数据库连接,来避免因为没有释放数据库连接而引起的数据库连接遗漏.
编写一个基本的连接池实现连接复用
编写连接池需实现DataSource接口,实现DataSource接口,并实现连接池功能的步骤:
1. 在DataSource构造函数中批量创建数据库连接,并把创建的连接加入LinkedList对象中
2. 实现getConnection方法,getConnection方法每次调用时,从LinkedList中取一个Connection返回给用户
3. 当用户使用完Connection,调用Connection.close()方法时,Collection对象应保证将自己返回到LinkedList中,而不要把conn还给数据库(包装设计模式)
配置文件
host=localhost
port=3306
db=my05test7
user=root
password=123456
//DBUtils
//trycatch省略,方便查看
public class DBUtils
{
static Properties properties;
static String host;
static String port;
static String db;
static
{
// 加载驱动
Class.forName("com.mysql.jdbc.Driver").newInstance();
String path = DBUtils.class.getClassLoader().getResource("conn.prop").getPath();
// 建立连接
properties = new Properties();
properties.load(new FileInputStream(path));
host = properties.getProperty("host");
port = properties.getProperty("port");
db = properties.getProperty("db");
}
//连接数据库
public static Connection getConnection() throws SQLException
{
String url = "jdbc:mysql://" + host + ":" + port + "/" + db;
return DriverManager.getConnection(url, properties);
}
//释放资源
public static void releaseResource(Statement st, ResultSet rs,
Connection conn)
{
if (st != null)
{
st.close();
}
if (rs != null)
{
rs.close();
}
if (conn != null)
{
conn.close();
}
}
}
// 连接池的原理
//trycatch省略,方便查看
public class MyDataConnectionPool
{
// 有个池子,存放连接
// 有个容器 ,存放初始化的连接
private static LinkedList<Connection> connPool = new LinkedList<Connection>();
// 初始化,放10个连接
static
{
for (int i = 0; i < 10; i++)
{
Connection connection = DBUtils.getConnection();
connPool.add(connection);
}
}
// 有个API,用户可以调用,从池子里拿一个没有人用的connection
public Connection getConnectionFromPool()
{
Connection connection = null;
if (connPool.size() > 0)
{
connection = connPool.getFirst();
return connection;
}
else
{
throw new RuntimeException("连接池里没有更多的连接了");
}
}
// 有个API,用户用完之后,可以放回到池子里
public void returnToConnectionPool(Connection conn)
{
connPool.addLast(conn);
}
}
开源数据库连接池
DataSource的实现,称之为数据源,数据源中都包含了数据库连接池的实现
DBCP 数据库连接池
//DBCP 数据库连接池
static
{
InputStream in = MyDBCPUtils.class.getClassLoader()
.getResourceAsStream("dbcpconfig.properties");
Properties prop = new Properties();
prop.load(in);
// 框架提供的数据源
BasicDataSourceFactory factory = new BasicDataSourceFactory();
ds = factory.createDataSource(prop);
}
//配置文件
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/my05test7
username=root
password=123456
#<!-- 初始化连接 -->
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=REPEATABLE_READ
////DBCP 的使用
public void testQuery()
{
Connection connection =null;
Statement st =null;
ResultSet rs =null;
List<User> userList = new ArrayList<User>();
try {
//建立连接
connection = MyDBCPUtils.getConnection();
st =connection.createStatement();
//查user表
rs =st.executeQuery("select * from user;");
while (rs.next())
{
String username = rs.getString(1);
String password = rs.getString(2);
String email = rs.getString(3);
String path = rs.getString(4);
userList.add(new User(username, password, email, path));
}
} catch (SQLException e)
{
e.printStackTrace();
}finally
{
MyDBCPUtils.releaseResource(st, rs, connection);
}
for (User user : userList)
{
System.out.println(user);
}
C3P0 数据库连接池
//C3P0 数据库连接池
static{
cpds = new ComboPooledDataSource();
cpds.setDriverClass( "com.mysql.jdbc.Driver" );
cpds.setJdbcUrl( "jdbc:mysql://localhost/mytest" );
}
c3p0-config
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="user">root</property>
<property name="password">123456</property>
<property name="checkoutTimeout">30000</property>
<property name="idleConnectionTestPeriod">30</property>
<property name="initialPoolSize">10</property>
<property name="maxIdleTime">30</property>
<property name="maxPoolSize">100</property>
<property name="minPoolSize">10</property>
<property name="maxStatements">200</property>
</default-config>
</c3p0-config>
//使用C3P0DBUtils
public void testQuery()
{
Connection conn=null;
Statement st =null;
ResultSet rs =null;
List<User> userList = new ArrayList<User>();
try {
//建立连接
conn = C3P0DBUtils.getConnection();
st =conn.createStatement();
//查询user表
rs =st.executeQuery("select * from user;");
while (rs.next())
{
String username = rs.getString(1);
String password = rs.getString(2);
String email = rs.getString(3);
String path = rs.getString(4);
userList.add(new User(username, password, email, path));
}
} catch (SQLException e)
{
e.printStackTrace();
}finally
{
C3P0DBUtils.releaseResource(st, rs, conn);
}
//打印出来
for (User user : userList)
{
System.out.println(user);
}
}