Java Web基础入门第五十八讲 开源数据库连接池

现在很多WEB服务器(Weblogic、WebSphere、Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。也有一些开源组织提供了数据源的独立实现:

  • DBCP数据库连接池;
  • C3P0数据库连接池;
  • Tomcat内置的连接池(其实使用的是Apache DBCP数据库连接池)

实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。

DBCP数据源

DBCP是Apache软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序在系统中增加如下两个jar文件:

  • commons-dbcp-1.4.jar:连接池的实现;
  • commons-pool-1.6.jar:连接池实现的依赖库。
    温馨提示:commons-pool已经到2.0时代了,但是如果使用pool2的包的话,会说找不到类,因为包结构已经变了!

Tomcat服务器的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。

在应用程序中加入DBCP连接池

首先,导入以上两个相关jar包。然后,在类目录下加入DBCP数据源的配置文件,即dbcpconfig.properties。dbcpconfig.properties配置文件的内容如下:

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/day16
username=root
password=yezi

#
initialSize=10

#最大连接数量
maxActive=50

#
maxIdle=20

#
minIdle=5

#
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=READ_COMMITTED

如下图所示:
Java Web基础入门第五十八讲 开源数据库连接池_第1张图片
接着在获取数据库连接的工具类(如JdbcUtils类)的静态代码块中创建池。

package cn.liayun.utils;

import java.io.InputStream;
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.dbcp.BasicDataSourceFactory;

public class JdbcUtils_DBCP {
	private static DataSource ds = null;
	
	//在静态代码块里面初始化DBCP链接池
	static {
		try {
			InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
			Properties prop = new Properties();
			prop.load(in);
			
			BasicDataSourceFactory factory = new BasicDataSourceFactory();
			ds = factory.createDataSource(prop);
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static Connection getConnection() throws SQLException {
		return ds.getConnection();// 不会将真正的MySQL驱动返回的Connection返回给你
	}

	public static void release(Connection conn, Statement st, ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			rs = null;
		}
		
		if (st != null) {
			try {
				st.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			st = null;
		}
		
		if (conn != null) {
			try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
}

最后,测试DBCP数据源。

package cn.liayun.demo;

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

import cn.liayun.utils.JdbcUtils_DBCP;

public class Demo4 {

	public static void main(String[] args) throws SQLException, InterruptedException {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils_DBCP.getConnection();
			System.out.println(conn.getClass().getName());//org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper
			
			//在链接上做一些操作......
			
//			conn.commit();
		} finally {
			JdbcUtils_DBCP.release(conn, st, rs);
		}
	}

}

运行以上程序,在Eclipse的控制台打印:
Java Web基础入门第五十八讲 开源数据库连接池_第2张图片

C3P0数据源(Spring内置)

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。
Java Web基础入门第五十八讲 开源数据库连接池_第3张图片

在应用程序中加入C3P0连接池

首先,导入相关jar包。

  • c3p0-0.9.5.2.jar
  • mchange-commons-java-0.2.11.jar
    温馨提示:如果操作的是Oracle数据库,那么还需要导入c3p0-oracle-thin-extras-0.9.5.2.jar。

然后,在类目录下加入C3P0的配置文件,即c3p0-config.xml。关于该配置文件怎么写,可以参考C3P0数据源的文档。在下载并解压的c3p0-0.9.5.2文件夹中打开c3p0-0.9.5.2\doc下的index.html页面,找到如下的位置:
Java Web基础入门第五十八讲 开源数据库连接池_第4张图片
就能知道c3p0-config.xml文件怎么编写了,并且该配置文件的名称一定得是c3p0-config。下面是我的c3p0-config.xml配置文件中的内容。

<c3p0-config>
	
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driverproperty>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/day16property>
		<property name="user">rootproperty>
		<property name="password">liayunproperty>
		
		<property name="initialPoolSize">10property>
		<property name="maxIdleTime">30property>
		<property name="maxPoolSize">20property>
		<property name="minPoolSize">5property>
		<property name="maxStatements">200property>
	default-config>

	
	<named-config name="mysql">
		<property name="acquireIncrement">50property>
		<property name="initialPoolSize">100property>
		<property name="minPoolSize">50property>
		<property name="maxPoolSize">1000property>

		
		<property name="maxStatements">0property>
		<property name="maxStatementsPerConnection">5property>
	named-config>
	
	<named-config name="oracle">
		<property name="acquireIncrement">50property>
		<property name="initialPoolSize">100property>
		<property name="minPoolSize">50property>
		<property name="maxPoolSize">1000property>

		
		<property name="maxStatements">0property>
		<property name="maxStatementsPerConnection">5property>
	named-config>
c3p0-config>

如下图所示:
Java Web基础入门第五十八讲 开源数据库连接池_第5张图片
接着,在获取数据库连接的工具类(如JdbcUtils类)的静态代码块中创建池。

package cn.liayun.utils;

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

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JdbcUtils_C3P0 {
	private static ComboPooledDataSource ds = null;
	
	//在静态代码块里面初始化C3P0链接池
	static {
		try {
			// 通过读取C3P0的xml配置文件创建数据源,C3P0的xml配置文件c3p0-config.xml必须放在src目录下
			ds = new ComboPooledDataSource();// 使用配置文件的缺省配置,配置文件名称必须是c3p0-config.xml
			
			//下面是通过代码创建C3P0数据库连接池
			/*
			ds = new ComboPooledDataSource();
			ds.setDriverClass("com.mysql.jdbc.Driver");
			ds.setJdbcUrl("jdbc:mysql://localhost:3306/day16");
			ds.setUser("root");
			ds.setPassword("liayun");
			ds.setMaxPoolSize(30);//最大允许30个链接
			ds.setMinPoolSize(5);//最小允许5个链接
			ds.setInitialPoolSize(10);//初始化时找数据库要10个链接
			*/
		} catch (Exception e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	public static Connection getConnection() throws SQLException {
		return ds.getConnection();// 不会将真正的MySQL驱动返回的Connection返回给你
	}

	public static void release(Connection conn, Statement st, ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			rs = null;
		}
		
		if (st != null) {
			try {
				st.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			st = null;
		}
		
		if (conn != null) {
			try {
				conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			conn = null;
		}
	}
}

最后,测试C3P0数据源。

package cn.liayun.demo;

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

import cn.liayun.utils.JdbcUtils_C3P0;

public class Demo4 {

	public static void main(String[] args) throws SQLException, InterruptedException {
		Connection conn = null;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			conn = JdbcUtils_C3P0.getConnection();
			System.out.println(conn.getClass().getName());//返回使用动态代理技术构建出来的一个代理对象,com.mchange.v2.c3p0.impl.NewProxyConnection
			
			//在链接上做一些操作......
			
//			conn.commit();
		} finally {
			JdbcUtils_C3P0.release(conn, st, rs);
		}
	}

}

运行以上程序,在Eclipse的控制台打印:
Java Web基础入门第五十八讲 开源数据库连接池_第6张图片

配置Tomcat数据源

在实际开发中,我们有时候还会使用服务器提供给我们的数据库连接池,比如我们希望Tomcat服务器在启动的时候可以帮我们创建一个数据库连接池,那么我们在应用程序中就不需要手动去创建数据库连接池了,直接使用Tomcat服务器创建好的数据库连接池即可。要想让Tomcat服务器在启动的时候帮我们创建一个数据库连接池,那么需要简单配置一下Tomcat服务器。

JNDI技术简介

JNDI(Java Naming and Directory Interface),Java命名和目录接口,它对应于J2SE中的javax.naming包。这套API的主要作用在于:它可以把Java对象放在一个容器中(JNDI容器),并为容器中的Java对象取一个名称,以后程序想获得Java对象,只需通过名称检索即可。其核心API为Context,它代表JNDI容器,其lookup方法为检索容器中对应名称的对象。
Tomcat服务器创建的数据源是以JNDI资源的形式发布的,所以说在Tomat服务器中配置一个数据源实际上就是在配置一个JNDI资源,通过查看Tomcat文档,我们知道使用如下的方式可以配置Tomcat服务器的数据源:

<Context>
	<Resource name="jdbc/EmployeeDB"
            auth="Container"
            type="javax.sql.DataSource"
            username="root"
            password="liayun"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/day16"
            initialSize="10"
            maxActive="30"
            maxIdle="4"/>
Context>

服务器创建好数据源之后,我们的应用程序又该怎么样得到这个数据源呢?Tomcat服务器创建好数据源之后是以JNDI资源的形式绑定到一个JNDI容器中的,我们可以把JNDI想象成一个大大的容器,我们可以往这个容器中存放一些对象,一些资源,JNDI容器中存放的对象和资源都会有一个独一无二的名称,应用程序想从JNDI容器中获取资源时,只需要告诉JNDI容器要获取的资源的名称,JNDI根据名称去找到对应的资源后返回给应用程序。

小结

我们平时做JavaEE开发时,服务器会为我们的应用程序创建很多资源,比如request对象,response对象,服务器创建的这些资源有两种方式提供给我们的应用程序使用:

  • 第一种方式是通过方法参数的形式传递进来。比如我们在Servlet中重写的doPost和doGet方法使用到的request对象和response对象就是服务器以参数的形式传递给我们的;
  • 第二种方式就是JNDI的方式,服务器把创建好的资源绑定到JNDI容器中去,应用程序想要使用资源时,就直接从JNDI容器中获取相应的资源即可。

亦可这样说:在服务器下做编程,我们要获取一个资源,现在多了一种新的方式。以前,一个浏览器去访问服务器时,服务器调用你写的Servlet,会传递一些对象给你,对象是怎么传递给你的呢?都是调用你写的Servlet的方法时,把对象传递给你。现在我们学了这种模型之后,将来在服务器下做开发,服务器还有一种方式传对象给你,并不是在调用你Servlet的方法时,把对象作为参数传递给你,而是会把对象放在一个JNDI容器里面,你需要的时候就从容器里面取。
对于上面的name=”jdbc/EmployeeDB”数据源资源,在应用程序中可以用如下的代码去获取:
在这里插入图片描述
用图来表示即为:
Java Web基础入门第五十八讲 开源数据库连接池_第7张图片

配置Tomcat数据源

为了配置Tomcat数据源,我们可参考Tomcat服务器文档(http://localhost:8080/docs/config/context.html),找到如下的位置:
Java Web基础入门第五十八讲 开源数据库连接池_第8张图片
注意上面标红的句子,我们重点关注这句话。翻译过来大致意思就是: 一个单独的文件,在应用程序文件/META-INF/context.xml内。这句话告诉我们应该在Web项目的WebRoot目录下的META-INF目录新建一个context.xml文件。如下图所示:
Java Web基础入门第五十八讲 开源数据库连接池_第9张图片
更加详细的内容大家可以参考我以前的笔记《Java Web基础入门第九讲 Java Web开发入门——再探Tomcat服务器》。context.xml文件创建出来了,怎么编写里面的内容呢?所以我们又要参考Tomcat服务器的文档(http://localhost:8080/docs/jndi-resources-howto.html)了,找到如下的位置:
Java Web基础入门第五十八讲 开源数据库连接池_第10张图片
对照着以上代码修修改改就可以了。下面是我的context.xml配置文件(配置的是Tomcat服务器的数据源)的内容:


<Context>
	<Resource name="jdbc/EmployeeDB"
            auth="Container"
            type="javax.sql.DataSource"
            username="root"
            password="liayun"
            driverClassName="com.mysql.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/day16"
            initialSize="10"
            maxActive="30"
            maxIdle="4"/>
Context>

以上为某一个Web应用配置了一个资源,资源的类型是javax.sql.DataSource,即配置了一个连接池,Tomcat在启动的时候就会为你的Web应用创建一个连接池,并且Tomcat会把这个连接池以JNDI资源的形式绑定到jdbc/EmployeeDB这么一个名称上面去,即你的应用程序等一会要用连接池,只需根据这个名称检索就行了,即可拿到连接池;auth="Container"该参数指定由Web服务器来创建连接池。
接着,将数据库的驱动jar文件放置在Tomcat的lib目录下。如下图所示:
Java Web基础入门第五十八讲 开源数据库连接池_第11张图片
特别提醒:此种配置下,数据库的驱动jar文件需放置在Tomcat的lib目录下。再说一遍,千万注意,由于是服务器来创建连接池,所以说数据库驱动jar包一定要加到Tomcat服务器的lib目录里面去。否则会报异常:

java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

最后,在获取数据库连接的工具类(如JdbcUtils类)的静态代码块中获取JNDI容器中的数据源。所以,在cn.liayun.utils包下创建获取数据库连接的JdbcUtils工具类,该类的代码如下所示:

package cn.liayun.utils;

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

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class JdbcUtils {
	private static DataSource ds;
	
	static {
		try {
			Context initCtx = new InitialContext();// 初始化JNDI
			Context envCtx = (Context) initCtx.lookup("java:comp/env");//找到Tomcat服务器里面的JNDI容器
			ds = (DataSource) envCtx.lookup("jdbc/EmployeeDB");//从JNDI容器中根据关键字找到数据源
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static Connection getConnection() throws SQLException {
		return ds.getConnection();
	}
}

下面,写一个小程序来测试JNDI数据源。在cn.liayun.dao包下创建一个类——Dao.java,其代码如下所示:

package cn.liayun.dao;

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

import cn.liayun.utils.JdbcUtils;

public class Dao {

	public void add() {
		Connection conn = null;
		try {
			conn = JdbcUtils.getConnection();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		System.out.println(conn);
	}
	
}

然后,在cn.liayun.web.servlet包下创建一个Servlet——Servlet1.java,其代码如下所示:

package cn.liayun.web.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.liayun.dao.Dao;

@WebServlet("/Servlet1")
public class Servlet1 extends HttpServlet {
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Dao dao = new Dao();
		dao.add();
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}

}

在浏览器中输入访问服务器的地址http://localhost:8080/day16_datasource/Servlet1,然后就可以在Eclipse的控制台下看到如下结果:
Java Web基础入门第五十八讲 开源数据库连接池_第12张图片

你可能感兴趣的:(Java,Web基础入门)