【学习笔记】JDBC连接池和DBUtils

1.JDBC连接池

(1)使用连接池改造JDBC工具类

传统JDBC的操作,每次创建和销毁连接都非常花费时间。可以使用连接池优化的程序。在程序开始的时候,可以创建几个连接,将连接放入到连接池中.用户使用连接的时候,可以从连接池中进行获取.用完之后,可以将连接归还连接池.

自定义连接池:sun公司提供了一个连接池的接口:javax.sql.DataSource。各个厂商需要让自己的连接池实现这个接口,这样应用程序就可以方便地切换不同厂商的连接池。常见连接池:DBCP,C3P0

自定义连接池代码如下(实现dataSource接口):(连接数据库只需要mysql-connector-xxx.jar)

public class MyDataSource implements DataSource{
	// 创建一个List集合用于存放多个连接对象.
	private List<Connection> list = new ArrayList<Connection>();
	// 在程序开始的时候,初始化几个连接,将连接存放到list中.
	public MyDataSource() {
		// 初始化3个连接:
		for(int i=1;i<=3;i++){
			Connection conn = JDBCUtils.getConnection();
			list.add(conn);
		}
	}
	
	@Override
	// 获得连接的方法:
	public Connection getConnection() throws SQLException {
		if(list.size() <= 0){
			for(int i=1;i<=3;i++){
				Connection conn = JDBCUtils.getConnection();
				list.add(conn);
			}	
		}
		Connection conn = list.remove(0);
		return conn;
	}
	
	// 归还连接的方法:
	public void addBack(Connection conn){
		list.add(conn);
	}

}

但是自定义连接池还需要记住自定义的API,解决:增强Connection的close方法,把原有的销毁变为归还。

 (2)增强一个Java类中的某个方法有几种方式?

  •  一种方式:继承的方式.

     能够控制这个类的构造的时候,才可以使用继承.

  • 二种方式:装饰者模式方式.

     包装对象和被包装的对象都要实现相同的接口.
     包装的对象中需要获得被包装对象的引用.
     缺点:如果接口的方法比较多,增强其中的某个方法.其他的功能的方法需要原有调用.

  •     三种方式:动态代理的方式.

      被增强的对象实现接口就可以.

  • 字节码增强

案例代码:

//继承和装饰者的案例:
/**
 * 继承的方式增强一个类中某个方法:
 */
class Man{
	public void run(){
		System.out.println("跑....");
	}
}
 
class SuperMan extends Man{
	public void run(){
		// super.run();
		System.out.println("飞....");
	}
}
 
/**
 * 使用装饰者的方式完成类的方法的增强
 */
interface Waiter{
	public void server();
}
 
class Waiteress implements Waiter{
 
	@Override
	public void server() {
		System.out.println("服务...");
	}
	
}
 
class WaiteressWrapper implements Waiter{
    private Waiter waiter;
 
	public WaiteressWrapper(Waiter waiter) {
    	this.waiter = waiter;
	}
	
	@Override
	public void server() {
		System.out.println("微笑...");
		// this.waiter.server();
		
	}
	
}

(3)使用装饰者模式增强Connection的close方法

代码:

package com.xing.utils.datasource;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;


public class MyDatasource{
	//创建连接池,存放conn.因为移除/添加操作较多,所以选择LinkedList
	private static LinkedList<Connection> pool=new LinkedList<Connection>();
	
	//静态代码块初始化连接池中的连接
	static {
		Connection conn=null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
			//创建三个连接放入连接池
			for(int i=0;i<3;i++) {
				conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/user", "root", "123");
				//将连接使用装饰类包装一下,然后添加到连接池,构造方法中将pool传递进去,便于连接归还
				StrongDataSource ds=new StrongDataSource(conn, pool);//包装对象
//				pool.add(conn);//将连接添加到连接池
				pool.add(ds);//将连接添加到连接池
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	//获得连接的方法
	public static Connection getConn() {
		if(!pool.isEmpty()) {
			Connection conn = pool.removeFirst();//一个Connection只能提供给当前的一个线程使用,因此要进行移除操作
			return conn;
		}else {
			try {
				Thread.sleep(5000);//池子空了,等待归还
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			return getConn();
		}
	}
	//归还连接
	public static void release(Connection conn) {
		if(conn!=null) {
			try {
				//close()缺点:把连接关闭了,而不是归还给连接池,连接池要重新创建连接。改进:方法增强
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
//			pool.add(conn);
		}
	}
	
	

}
//方法增强:装饰着设计模式
//装饰类
public class StrongDataSource implements Connection{
	private Connection conn;
	private LinkedList<Connection> pool;
	//编写构造方法
	public StrongDataSource(Connection conn,LinkedList<Connection> pool) {
		this.conn=conn;
		this.pool=pool;
	}
	
	//需要增强的方法
	@Override
	public void close() throws SQLException {
		System.out.println("归还:"+this);
		pool.add(conn);
		
	}
	
	//此方法必须覆盖!否则会出现空指针异常!!!
	@Override
	public PreparedStatement prepareStatement(String sql) throws SQLException {
		// TODO Auto-generated method stub
		return conn.prepareStatement(sql);
	}
	
	//以下是不需要增强的方法
...
}
package com.xing.utils.datasource;

import java.sql.Connection;
import java.sql.SQLException;

public class Test {
	//为了体现连接池的优势,开启十个线程,采用多线程并发访问,使同一个连接在不同时间被不同线程使用
	public static void main(String[] args) {
		for(int i=0;i<4;i++) {
			new MyThread().start();
		}
	}
}

class MyThread extends Thread{
	public void run() {
		Connection conn = MyDatasource.getConn();
		if(conn==null) {
			System.out.println("conn空了");
		}else {
			System.out.println("使用"+conn+"获得连接"+Thread.currentThread());
//			MyDatasource.release(conn);
			try {
				conn.close();//调用的实际是StrongDataSource的colse()方法
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
			
		}
};

2.常见的连接池:C3P0连接池

导入一个jar包c3p0....jar

配置文件c3p0-config.xml和测试:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
	<default-config>
		<property name="user">root</property>
		<property name="password">123</property>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql:///user</property>
	</default-config> 
</c3p0-config> 
package com.xing.utils.c3p0;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.xing.utils.datasource.MyDatasource;

public class C3P0Utils {
	
	/*private static ComboPooledDataSource source=new ComboPooledDataSource();
     public static void main(String[] args) {
		Connection connection=null;
		try {
			connection = source.getConnection();
			PreparedStatement ps = connection.prepareStatement("select * from user");
			ResultSet rs = ps.executeQuery();
			while(rs.next()) {
				System.out.println(rs.getObject(2));
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}*/
	
	public static void main(String[] args) {
		for(int i=0;i<4;i++) {
			new MyThread().start();
		}
	}
	
	
	

}
class MyThread extends Thread{
	private static ComboPooledDataSource source=new ComboPooledDataSource();
	public void run() {
		Connection conn=null;;
		try {
			conn = source.getConnection();
		} catch (SQLException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		if(conn==null) {
			System.out.println("conn空了");
		}
		System.out.println("使用" + conn + "获得连接" + Thread.currentThread());
		try {
			conn.close();// 调用的实际是StrongDataSource的colse()方法
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
			
		
};

3.DBCP连接池

DBCP连接池也是一个开源的连接池,是tomcat内置的连接池

导入jar包:commons-dbcp-1.4.jar和commons-pool.1.6.jar

配置文件和代码。注意:配置文件前面的key格式固定,不能更改

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/user
username=root
password=123
package com.xing.utils.DBCP;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

public class DBCPUtils {
	
	private static DataSource source;
	static {
		try {
			//加载配置文件
			InputStream input = DBCPUtils.class.getClassLoader().getResourceAsStream("com/xing/utils/test002.properties");
			Properties prop=new Properties();
			prop.load(input);
			//创建连接池
			source = BasicDataSourceFactory.createDataSource(prop);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static DataSource getDataSource() {
		return source;
	}
	
	
	public static Connection getConn() {
		Connection conn=null;
		try {
		 conn=source.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
}

4.DBUtils和JavaBean

如果只使用jdbc开发,那么冗余代码较多。为了简化,使用DBUtils(需要导入dbutils.jar),DBUtils是jdbc的简化开发工具包,需要使用技术:连接池,sql语句

相关知识:JavaBean组件:JavaBean就是一个类,常用于封装数据

DBUtils封装了对JDBC的操作,简化了实际的操作,减少了代码量。DBUtils三个核心供能介绍:

  1. QueryRunner提供了对sql语句操作的API
  2. ResultSetHandler接口,用于定义select操作后,怎样封装结果集
  3. DBUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

QueryRunner:

QueryRunner(Datasource ds):提供数据源
Update()
Query(String sql , ResultSetHandler<T>rsh , Object...params)

ResultSetHandler:

BeanHandler:将结果集中第一条记录封装到一个指定的javaBean中。
BeanListHandler:将结果集中每一条记录封装到指定的javaBean中,将这些javaBean封装到List中
ScalarHandler:它是用于单数据,例如select count(*)from表操作。

DBUtils类:

closeQuietly(Connection)关闭连接,如果有异常,try后不抛
commitAndCloseQuietly(Connection):提交并关闭连接
rollbackAndCloseQuietly(Connection):回滚并关闭连接

package com.xing.utils.DBUtils;

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import com.xing.utils.DBCP.DBCPUtils;
import com.xing.utils.c3p0.C3P0Utils;

public class DBUtils {
	
	public static void query() {

		QueryRunner runner=new QueryRunner(C3P0Utils.getDataSource());
		String sql="select*from user";
		try {
			List<User> query = runner.query(sql, new BeanListHandler<User>(User.class));
			for (User user : query) {
				System.out.println(user.getUsername());
			}
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		query();
	}
	
	

}

 

 

转载于:https://my.oschina.net/u/3943244/blog/1944517

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值