线程池的种类和日常使用

需求:

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

常用的连接池有:C3P0(占80%以上的使用率,是比较常用的)、DBCP

自己也可以自定义连接池

主要的模型图如下:

java线程池 mainlock JAVA线程池有几种_连接池

代码如下:

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);
	}
...
}
  • 增强一个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();
		
	}
	
}
【使用装饰者模式增强Connection的close方法】
public class MyConnection implements Connection{
 
	private Connection conn;
	private List<Connection> list;
 
	public MyConnection(Connection conn,List<Connection> list) {
		this.conn = conn;
		this.list = list;
	}连接池的getConnection方法:
	@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);
		MyConnection myConn = new MyConnection(conn, list);
		return myConn;
	}
 
 
	@Override
	public void close() throws SQLException {
		list.add(conn);
	}
     ...
}

当然嫌麻烦,你可以使用别人已经封装好的。日常的框架程序中,我们也是用C3P0和DBCP也更多一些。

两种常用连接池的规范和使用步骤

【DBCP连接池的使用】
第一步:引入DBCP连接池的jar包.
第二步:编写DBCP代码.

  • 手动设置参数:
  • 配置文件设置参数:
    【DBCP连接池的使用】
@Test
	/**
	 * 手动方式:
	 */
	public void demo1(){
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setDriverClassName("com.mysql.jdbc.Driver");
		dataSource.setUrl("jdbc:mysql:///web_07");
		dataSource.setUsername("root");
		dataSource.setPassword("123");
		try{
			// 获得连接:
			conn = dataSource.getConnection();
			// 编写SQL:
			String sql = "select * from category";
			// 预编译SQL:
			stmt = conn.prepareStatement(sql);
			// 执行SQL:
			rs = stmt.executeQuery();
			while(rs.next()){
				System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils.release(rs,stmt, conn);
		}
	}
	
	@Test
	/**
	 * 配置文件方式:
	 */
	public void demo2(){
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		Properties properties = new Properties();
		
		try{
			properties.load(new FileInputStream("src/dbcpconfig.properties"));
			DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
			// 获得连接:
			conn = dataSource.getConnection();
			// 编写SQL:
			String sql = "select * from category";
			// 预编译SQL:
			stmt = conn.prepareStatement(sql);
			// 执行SQL:
			rs = stmt.executeQuery();
			while(rs.next()){
				System.out.println(rs.getInt("cid")+"   "+rs.getString("cname"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils.release(rs,stmt, conn);
		}
	}

【C3P0连接池的使用】
**第一步:引入C3P0连接池的jar包.
**第二步:编写代码.

  • 手动设置参数:
  • 配置文件设置参数:

【C3P0改造工具类】

public class JDBCUtils2 {
	private static final ComboPooledDataSource DATA_SOURCE =new ComboPooledDataSource();
	/**
	 * 获得连接的方法
	 */
	public static Connection getConnection(){
		Connection conn = null;
		try {
			conn = DATA_SOURCE.getConnection();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return conn;
	}
...

ResultSetHandler

总结:

  • 我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可以希望把ResultSet的数据放到一个List中,也可能想把数据放到一个Map中,或是一个Bean中。
• DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。
 DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了。• MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键!
• MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;
• BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;
• BeanListHandler:多行处理器!把结果集转换成List;
• ColumnListHandler:多行单列处理器!把结果集转换成List,使用
 ColumnListHandler时需要指定某一列的名称或编号,例如:new
 ColumListHandler(“name”)表示把name列的数据放到List中。• ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select count(*) from
 tab_student。