现在很多WEB服务器(Weblogic、WebSphere、Tomcat)都提供了DataSoruce的实现,即连接池的实现。通常我们把DataSource的实现,按其英文含义称之为数据源,数据源中都包含了数据库连接池的实现。也有一些开源组织提供了数据源的独立实现:
实际应用时不需要编写连接数据库代码,直接从数据源获得数据库的连接。程序员编程时也应尽量使用这些数据源的实现,以提升程序的数据库访问性能。
DBCP是Apache软件基金组织下的开源连接池实现,要使用DBCP数据源,需要应用程序在系统中增加如下两个jar文件:
Tomcat服务器的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
首先,导入以上两个相关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
如下图所示:
接着在获取数据库连接的工具类(如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);
}
}
}
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。C3P0数据源在项目开发中使用得比较多。
首先,导入相关jar包。
然后,在类目录下加入C3P0的配置文件,即c3p0-config.xml。关于该配置文件怎么写,可以参考C3P0数据源的文档。在下载并解压的c3p0-0.9.5.2
文件夹中打开c3p0-0.9.5.2\doc
下的index.html页面,找到如下的位置:
就能知道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>
如下图所示:
接着,在获取数据库连接的工具类(如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);
}
}
}
在实际开发中,我们有时候还会使用服务器提供给我们的数据库连接池,比如我们希望Tomcat服务器在启动的时候可以帮我们创建一个数据库连接池,那么我们在应用程序中就不需要手动去创建数据库连接池了,直接使用Tomcat服务器创建好的数据库连接池即可。要想让Tomcat服务器在启动的时候帮我们创建一个数据库连接池,那么需要简单配置一下Tomcat服务器。
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,会传递一些对象给你,对象是怎么传递给你的呢?都是调用你写的Servlet的方法时,把对象传递给你。现在我们学了这种模型之后,将来在服务器下做开发,服务器还有一种方式传对象给你,并不是在调用你Servlet的方法时,把对象作为参数传递给你,而是会把对象放在一个JNDI容器里面,你需要的时候就从容器里面取。
对于上面的name=”jdbc/EmployeeDB”数据源资源,在应用程序中可以用如下的代码去获取:
用图来表示即为:
为了配置Tomcat数据源,我们可参考Tomcat服务器文档(http://localhost:8080/docs/config/context.html),找到如下的位置:
注意上面标红的句子,我们重点关注这句话。翻译过来大致意思就是: 一个单独的文件,在应用程序文件/META-INF/context.xml内。这句话告诉我们应该在Web项目的WebRoot目录下的META-INF目录新建一个context.xml文件。如下图所示:
更加详细的内容大家可以参考我以前的笔记《Java Web基础入门第九讲 Java Web开发入门——再探Tomcat服务器》。context.xml文件创建出来了,怎么编写里面的内容呢?所以我们又要参考Tomcat服务器的文档(http://localhost:8080/docs/jndi-resources-howto.html)了,找到如下的位置:
对照着以上代码修修改改就可以了。下面是我的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目录下。如下图所示:
特别提醒:此种配置下,数据库的驱动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的控制台下看到如下结果: