数据库连接池
之前存在的问题
其实之前的代码没有任何问题, 用来操作数据库足够了
但获取连接对象(driverManager.getConnection(String driverClassName, String url, String password);
)这一步是很消耗资源的. 每次用的时候创建连接对象, 用完就关闭, 下一次需要使用时在创建, 这样非常消耗性能
设计这样一种方案, 我们每次需要用到连接对象时创建对象, 用完后保存起来(而不是立刻关闭), 下一次使用时直接取出来, 而不用新创建, 这样对性能提升很有帮助
而这样一种保存连接对象的组件, 我们称为数据库连接池(datasource)
说白了, 数据库连接池就是用来获取连接对象的. 以后获取Connection对象用连接池来获取, 提高性能
- 使用连接池和不使用连接池的区别
- 不使用连接池
- 连接对象使用driverManager获取
Connection conn = driverManager.getConnection(String driverClassName, String url, String password);
- 使用完后关闭连接, 释放资源
conn.close();
- 使用连接池
- 连接对象用DataSource对象获取
Connection conn = datasource.getConnection();
- 使用完后将连接对象归还给连接池
conn.close();
- 不使用连接池
连接池的使用
//创建一个连接池对象
public DataSource getDataSource(){
//创建连接池对象
BasicDataSource ds = new BasicDataSource();
//设置连接数据库的四要素
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/jdbcdemo");
ds.setUsername("root");
ds.setPassword("1092568516");
return ds;
}
@Test
public void test01() throws Exception{
String sql = "SELECT * FROM `user`";
//创建连接池对象
DataSource ds = this.getDataSource();
//通过连接池对象获取连接
Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
while(rs.next()){
System.out.println(rs.getLong("id"));
}
}
DataSource
是数据库连接池接口,BasicDataSource
是其实现类- 创建好一个
DataSource
对象后, 使用setXxx()
设置连接四要素: 驱动名, url, 账号, 密码(不设置的话怎么知道你要连接的是哪一个数据库?) - 使用创建好的连接池对象获取连接
使用连接池和不使用连接池的区别很明显了: 不使用连接池时, 连接四要素通过参数传递; 使用连接池时, 连接四要素通过setXxx()
方法设置(连接四要素指明了你要连接什么数据库, 连接哪一台电脑的哪一个数据库, 账号和密码, 所以是必须的, 不管是不是用连接池都需要写明)
抽取工具类
之前写JDBC代码时, 因为很多步骤是重复的, 如加载驱动, 获取连接等, 所以我们将这些重复的步骤抽取jdbcutil工具类. 使用连接池时也可以这样做
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
public class DBCPUtil {
static{
BasicDataSource basicDs = new BasicDataSource();
basicDs.setDriverClassName("com.mysql.jdbc.Driver");
basicDs.setUrl("jdbc:mysql://localhost:3306/jdbcdemo");
basicDs.setUsername("root");
basicDs.setPassword("1092568516");
}
public static Connection getConn(){
try {
//从连接池中获取Connection对象
return basicDs.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(Connection conn, Statement st, ResultSet rs){
try{
if(rs != null){
rs.close();
}
}catch(Exception e){
}finally{
try{
if(st != null){
st.close();
}
}catch(Exception e){
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
}
}
}
}
}
与JDBC一样, 将数据库的连接四要素写在properties文件中, 降低耦合. 这里使用的是一个叫DBCP的数据库连接池, 使用工厂来创建datasource, 而非new出来(将new BasiceDataSource
和setXxx()
封装到BasicDataSourceFactory
中, 底层依然是new BasicDataSource().setXxx();
) 代码如下:
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
public class DBCPUtil {
private static DataSource ds = null;
static{
//BasicDataSource basicDs = new BasicDataSource();
//basicDs.setDriverClassName("com.mysql.jdbc.Driver");
//basicDs.setUrl("jdbc:mysql://localhost:3306/jdbcdemo");
//basicDs.setUsername("root");
//basicDs.setPassword("1092568516");
try {
Properties p = new Properties();
//加载配置文件
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("dbcp.properties"));
//通过BasicDataSourceFactory创建DataSource对象
ds = BasicDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConn(){
try {
//从连接池中获取Connection对象
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
properties配置文件代码如下:
#key不能乱写, 必须是BasicDataSource里的属性(查看源代码可以知道, 其实底层就是setter方法)
DriverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcdemo
username=root
password=1092568516
druid连接池
阿里的数据库连接池, 号称是全世界最好的数据库连接池
使用方法和DBCP很像, 把BasicDataSourceFactory换为DruidDataSourceFactory即可
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
public class DruidUtil {
private static DataSource ds = null;
static{
try {
Properties p = new Properties();
p.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("druid.properties"));
//创建DataSource对象
// ds = BasicDataSourceFactory.createDataSource(p);
ds = DruidDataSourceFactory.createDataSource(p);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConn(){
try {
//从连接池中获取Connection对象
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public static void close(Connection conn, Statement st, ResultSet rs){
try{
if(rs != null){
rs.close();
}
}catch(Exception e){
}finally{
try{
if(st != null){
st.close();
}
}catch(Exception e){
}finally{
try{
if(conn != null){
conn.close();
}
}catch(Exception e){
}
}
}
}
}