数据库连接池

连接池原理

数据库连接池负责分配、管理和释放数据库连接,它的核心思想就是连接复用,通过建立一个数据库连接池,这个池中有若干个连接对象,当用户想要连接数据库,就要先从连接池中获取连接对象,然后操作数据库。一旦连接池中的连接对象被用院了,判断连接对象的个数是否已达上限,如果没有可以再创建新的连接对象,如果已达上限,用户必须处于等待状态,等待其他用户释放连接对象,直到连接池中有被释放的连接对象了,这时候等待的用户才能获取连接对象,从而操作数据库。这样就可以使连接池中的连接得到高效、安全的复用,避免了数据库连接频繁创建、关闭的开销。这项技术明显提高对数据库操作的性能。

  • 无连接池
    在这里插入图片描述

  • 有连接池

在这里插入图片描述

连接池优点

程序启动的时候就已经创建好了连接,不需用户请求的时候创建
用户关闭时不会销毁连接,需要将连接归还,就可以达到复用的效果
如果超过了使用的连接会进行上限的判断,如果没有达到最大值,可以继续创建
如果有空闲连接,会默认的进行销毁(释放)一些连接,让系统达到最优

手动实现连接池原理

手动实现连接池 (了解) 
步骤:
创建一个连接池类,需要借助于封装的jdbcUtils工具类
初始化连接数量
创建一个集合,存储多个连接对象
创建一个从池子里面获取连接的方法
创建一个向连接池里面归还连接的方法
测试
//连接池类
public class MyDataPool {

//初始化连接数量
private static int initSize = 5;

//创建一个集合, 存储多个连接对象
private static List<Connection> list = new ArrayList<Connection>();

static {
    for(int i = 0; i < initSize; i++) {
                //借助于JDBCUtils工具类获取连接
                Connection conn = JDBCUtils.getConnection();
                list.add(conn);
    }
    System.out.println("初始化连接的数量为: " + initSize);
}

//获取连接
public static Connection getConnFromPool() {
//从集合中取出连接
Connection connection = list.get(0);
//还要取走的连接移除
list.remove(0);
System.out.println("用户正在使用" + connection + "连接, 当前池子中剩余连接为: " + list.size());
return connection;
}

//归还连接
public static void closeAll(ResultSet rs, PreparedStatement psvm, Connection conn) {
    //判断
    if(rs != null) {
                try {
                            rs.close();
                } catch (SQLException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                }
    }
    if(psvm != null) {
        try {
                    psvm.close();
        } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
        }
}
if(conn != null) {
        try {
                    //conn.close();
                    //归还
                    list.add(conn);
                  System.out.println("用户正在归还" + conn +"连接, 当前池子中剩余连接为:" + list.size());
        } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
        }
    }
}
           
 
}
测试类:
package com.ujiuye.test;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import com.ujiuye.pool.MyDataPool;
 
public class myDataPoolTest {
public static void main(String[] args) throws Exception {
            //直接获取连接
            Connection conn = MyDataPool.getConnFromPool();
            //归还连接
            MyDataPool.closeAll(null, null, conn);
            System.out.println("==========================");
            Connection conn1 = MyDataPool.getConnFromPool();
            String sql = "select * from user where uid = ?";
            PreparedStatement psvm = conn1.prepareStatement(sql);
            //设置参数
            psvm.setInt(1, 1);
            //执行
            ResultSet rs = psvm.executeQuery();
            while(rs.next()) {
                        int uid = rs.getInt("uid");
                        String username = rs.getString("username");
                        String password = rs.getString("password");
                        System.out.println(uid + "\t" + username + "\t" + password);
            }
            //归还
            MyDataPool.closeAll(rs, psvm, conn1);
            }
}
测试类:
package com.ujiuye.test;
 
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
 
import com.ujiuye.pool.MyDataPool;
 
public class myDataPoolTest {
            public static void main(String[] args) throws Exception {
                        //直接获取连接
                        Connection conn = MyDataPool.getConnFromPool();
                        //归还连接
                        MyDataPool.closeAll(null, null, conn);
                        System.out.println("==========================");
                        Connection conn1 = MyDataPool.getConnFromPool();
                        String sql = "select * from user where uid = ?";
                        PreparedStatement psvm = conn1.prepareStatement(sql);
//设置参数
 psvm.setInt(1, 1);
 //执行
ResultSet rs = psvm.executeQuery();
while(rs.next()) {
int uid = rs.getInt("uid");
String username = rs.getString("username");
String password = rs.getString("password");
 System.out.println(uid + "\t" + username + "\t" + password);
                        }
//归还
MyDataPool.closeAll(rs, psvm, conn1);
            }
}

DBCP连接池

DBCP也是一个开源的连接池,直接进行使用步骤介绍

  1. 导包 commons-dbcp-1.4.jar和commons-pool-1.5.6.jar
  2. 编写数据库连接的配置文件
    配置文件名称:*.properties
    配置文件位置:建议放在src下
    需求:测试连接池查询商品的名字。
    配置文件dbcpconfig.properties
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day09_jdbc
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=gbk

#指定由连接池所创建的连接的自动提交(auto-commit)状态。
defaultAutoCommit=true

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

方式一:

public class DBCPDemo {
	public static void main(String[] args) throws Exception {
		//创建properties文件对象
		Properties properties = new Properties();
		//通过流的方式获取properties文件
		FileReader reader = new FileReader("src/dbcpconfig.properties");
		//加载properties文件
		properties.load(reader);
		//创建数据源
		DataSource datasource = BasicDataSourceFactory.createDataSource(properties);
//		System.out.println(datasource);
		//通过数据源获取连接
		Connection conn = datasource.getConnection();
		
		//执行sql进行预编译
		PreparedStatement psvm = conn.prepareStatement("select * from product");
		//执行
		ResultSet rs = psvm.executeQuery();
		while(rs.next()) {
			int pid = rs.getInt("pid");
			String pname = rs.getString("pname");
			double price = rs.getDouble("price");
			System.out.println(pid+pname+price);
		}
		//释放资源
		rs.close();
		psvm.close();
		conn.close();
	}
}

方式二:

public class DBCPDemo2 {
	public static void main(String[] args) throws Exception {
		//创建properties文件对象
		Properties properties = new Properties();
		//通过流的方式获取properties文件
//		DBCPDemo2.class.getClassLoader() 获取当前类的类加载
		InputStream inputStream = DBCPDemo2.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
		//加载properties文件
		properties.load(inputStream);
		//创建数据源                                             数据源工厂                                          创建数据源                   从properties里面获取
		DataSource datasource = BasicDataSourceFactory.createDataSource(properties);
//		System.out.println(datasource);
		//通过数据源获取连接
		Connection conn = datasource.getConnection();
		
		//执行sql进行预编译
		PreparedStatement psvm = conn.prepareStatement("select * from product");
		//执行
		ResultSet rs = psvm.executeQuery();
		while(rs.next()) {
			int pid = rs.getInt("pid");
			String pname = rs.getString("pname");
			double price = rs.getDouble("price");
			System.out.println(pid+pname+price);
		}
		//释放资源
		rs.close();
		psvm.close();
		conn.close();
	}
}

在这里插入图片描述

C3P0连接池

  1. 导包 c3p0-0.9.1.2和mchange-commons-java-0.2.3.4
  2. 倒入配置文件,放在src下(在使用c3p0连接获取数据源时,会自动读取配置文件,无需读取操作)

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<!-- 默认配置,如果没有指定则使用这个配置 -->
	<default-config>
		<!-- 四项基本配置 -->
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/day09_jdbc</property>
		<property name="user">root</property>
		<property name="password">123456</property>
		
		<!-- 当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
  			SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
		<property name="checkoutTimeout">30000</property>
		
		<!--隔多少秒检查连接池的空闲连接,0表示不检查-->
		<property name="idleConnectionTestPeriod">30</property>
		
		<!-- 初始化连接数 -->
		<property name="initialPoolSize">10</property>
		
		<!-- 连接的最大空闲时间,默认为0秒、不会关闭任何连接。设置30秒,30秒到期后,
			连接若未使用就会被关闭 -->
		<property name="maxIdleTime">30</property>
		
		<!-- 池中最多的连接存放数目 -->
		<property name="maxPoolSize">100</property>
		
		<!-- 池中最少的连接存放数目 -->
		<property name="minPoolSize">10</property>
		<property name="maxStatements">200</property>
		<user-overrides user="test-user">
			<property name="maxPoolSize">10</property>
			<property name="minPoolSize">1</property>
			<property name="maxStatements">0</property>
		</user-overrides>
	</default-config>
	<!-- 命名的配置 -->
	<named-config name="offcn">
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/day09_jdbc</property>
		<property name="user">root</property>
		<property name="password">123456</property>
		<property name="acquireIncrement">5</property>
		<property name="initialPoolSize">20</property>
		<property name="minPoolSize">10</property>
		<property name="maxPoolSize">40</property>
		<property name="maxStatements">0</property>
		<property name="maxStatementsPerConnection">5</property>
	</named-config>
</c3p0-config>

测试类

public class DemoC3p0 {
	public static void main(String[] args) throws Exception {
		//创建数据源对象
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		//获取连接 
		Connection conn = dataSource.getConnection();
		//System.out.println(conn);//com.mchange.v2.c3p0.impl.NewProxyConnection@224aed64
		//执行sql进行预编译  不用createStatement是为了解决sql注入问题
        PreparedStatement psvm = conn.prepareStatement("select * from product");
        //执行
        ResultSet rs = psvm.executeQuery();
        while(rs.next()) {
        	int pid = rs.getInt("pid");
        	String pname = rs.getString("pname");
        	double price = rs.getDouble("price");
        	System.out.println(pid+pname+price);
        }
	}
}

也可以对其进行封装

public class C3p0Utils {
	//创建数据源对象
	private static DataSource dataSource = new ComboPooledDataSource();
	
	//创建连接池   为了DBUtils工具提前准备
	public static DataSource getDataSource() {
		return dataSource;
	}
	
	//获取连接
	public static Connection getConnection() {
		try {
			Connection conn = dataSource.getConnection();
			return conn;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}

Druid连接池

  1. 导包 druid-1.0.9
  2. 倒入配置文件 放在src下面
    druid.properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=123456

# 初始化连接数
initialSize=5
#最大连接数
maxActive=10
#超时时间
maxWait=3000
  1. 写一个工具类对配置文件进行读取操作
public class DruidUtils {
	private static DataSource dataSource;
	
	//在静态代码块里面完成对数据源的初始化
	static {
		//拿到数据源对象
		Properties properties = new Properties();
		//获取配置文件
		try {
            FileInputStream inputStream = new FileInputStream("src/druid.properties");
            //加载通过数据源进去
            properties.load(inputStream);
            //druid下面的方法
            dataSource = DruidDataSourceFactory.createDataSource(properties);
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//获取数据源方法
	public static DataSource getDataSource() {
		return dataSource;
	}
}
  1. 测试
    第一种:手动
public class TestDruid {
	public static void main(String[] args) throws Exception {
     /**
		 * 有了数据源之后
		 * 要么手动获取连接 就是 调用getConnection()的方法获取
		 * 要么就是创建QueryRunner时指定获取连接
		 */
		//增加
		DataSource dataSource = DRUIDUtils.getDataSource();
		Connection connection = dataSource.getConnection();
		QueryRunner queryRunner = new QueryRunner();
		int row = queryRunner.update(connection,"insert into user values(null,?,?,?)","都是","145","男");
		System.out.println(row>0?"添加成功":"添加失败");
		//释放资源
		//因为不是手动创建的,而是调用的连接池里面的,所以释放资源是放回连接池当中,而不是销毁
		org.apache.commons.dbutils.DbUtils.close(connection);
	}
}

第二种:自动

public class TestDruid {
	public static void main(String[] args) throws Exception {
		/**
		 * 有了数据源之后
		 * 要么手动获取连接 就是 调用getConnection()的方法获取
		 * 要么就是创建QueryRunner时指定获取连接
		 */
		//第二种自动的
		QueryRunner qr = new QueryRunner(DruidUtils.getDataSource());
		String sql = "select * from product where pid = ?";
		Product product = qr.query(sql, new BeanHandler<Product>(Product.class),2);
		System.out.println(product);
	}
}

总结:

使用Properties获取文件对象的时候
DBCP和Druid都需要读取配置文件,C3P0会自动读取配置文件(前提是放在src下),获取的时候用get方法获取就好
QueryRunner方法获取对象的时候
Druid,c3p0,DBCP都可创建实体类进行操作

DBCP连接池与C3P0连接池的区别:

  1. DBCP连接池使用效率高, 而C3P0效率相比较偏低;
  2. C3P0安全性较高, 而DBCP安全性偏低, 容易丢失连接;
需要的jar包

链接:https://pan.baidu.com/s/1_nqg99Fb83FA1KaFXsip_g
提取码:1314
复制这段内容后打开百度网盘手机App,操作更方便哦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值