数据源是JDBC2.0中引入的一个概念。在JDBC2.0扩展包javax.sql中定义了DataSource接口来描述这个概念。一般在相应数据库的JDBC驱动程序中都有该接口的实现类。
在程序中使用数据源有两种方式:
1.在程序中直接创建类的对象,该对象实现了JDBC驱动器中的DataSource接口,并使用该对象获得数据库的连接。
例如下面这个程序
package ch14;
import java.sql.*;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
/**
*
* 这个例子演示了如何直接使用数据源以获得数据库连接;
* 要运行该实例,请先启动mysql数据库,并将驱动器
* mysql-connector-java-3.1.10-bin.jar放置到类路径中!
*/
public class DirectUseDataSource {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost/sql_test";
String userName = "root";
String password = "123";
String sql = null;
Connection conn = null;
Statement stmt = null;
try {
Class.forName("com.mysql.jdbc.Driver");
} catch(ClassNotFoundException e) {
System.out.println("加载驱动器类时出现异常");
}
try {
// 创建数据源对象
MysqlDataSource mds = new MysqlDataSource();
// 设置数据源对象参数
mds.setURL(url);
mds.setUser(userName);
mds.setPassword(password);
mds.setLoginTimeout(60);
// 使用数据源获得数据库连接
conn = mds.getConnection();
stmt = conn.createStatement();
sql = "SELECT * FROM student";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
String id = rs.getString(1);
String name = rs.getString(2);
String address = rs.getString(3);
System.out.println(id + " " + name + " " + address);
}
rs.close();
stmt.close();
conn.close();
conn = null;
} catch(SQLException e) {
System.out.println("出现SQLException异常");
} finally {
//关闭语句和数据库连接
try {
if (conn != null) conn.close();
} catch(SQLException e) {
System.out.println("关闭数据库连接时出现异常");
}
}
}
}
从这个例子可以看出,这种直接创建并使用数据源获得数据库连接的方式与使用DriverManager.getConnection方法获得数据库连接的方式相比并没有明显的优势。一种更加实用的数据源的使用方式是先使用JNDI将数据源对象注册为一个命名服务,然后可以在程序中使用JNDI提供的接口按照名称查找得到对应的数据源。而大部分的应用服务都提供了这种JNDI命名服务。比如在Tomcat中就可以在server.xml文件中配置数据源,
2.首先使用JNDI注册数据源,然后可以在程序中查询获取在JNDI服务中的数据源,这样用户只需要提供一个逻辑名称,而不是数据库登录的具体细节。
接下来将介绍如何在Tomcat中配置和使用数据源。
(1)安装DBCP
就是拷贝三个jar文件及相应的JDBC驱动器放到tomcat_home/common/lib文件夹下。
commons-collections-3.1.jar
commons-dbcp-1.2.1.jar
commons-pool-1.2.jar
mysql-connector-java-3.1.10-bin.jar
(2)配置server.xml
在Tomcat中配置JNDI数据库需要在tomcat_home/conf/server.xml文件的<Context>和</Context>标签对之间添加资源声明。
<Context path="/Ch14" reloadable="true" docBase="Ch14" debug="0" releadable="true" crossContext="true">
<Resource name="jdbc/mysql/sql_test" auth="Container" type="javax.sql.DataSource"/>
<ResourceParams name="jdbc/mysql/sql_test">
<parameter>
<name>factory</name>
<value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
</parameter>
<!-- Maximum number of dB connections in pool. Make sure you configure your mysqld max_connections large enough to handle all of your db connections. Set to 0 for no limit.
-->
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<!-- Maximum number of idle dB connections to retain in pool.
Set to 0 for no limit.
-->
<parameter>
<name>maxIdle</name>
<value>30</value>
</parameter>
<!-- Maximum time to wait for a dB connection to become available in ms, in this example 10 seconds. An Exception is thrown if this timeout is exceeded. Set to -1 to wait indefinitely.
-->
<parameter>
<name>maxWait</name>
<value>10000</value>
</parameter>
<!-- MySQL dB username and password for dB connections -->
<parameter>
<name>username</name>
<value>root</value>
</parameter>
<parameter>
<name>password</name>
<value>123</value>
</parameter>
<!-- Class name for mysql JDBC driver -->
<parameter>
<name>driverClassName</name>
<value>com.mysql.jdbc.Driver</value>
</parameter>
<!-- The JDBC connection url for connectiong to your MySQL dB. The autoReconnect=true argument to the url makes sure that the mm.mysql JDBC Driver will automatically reconnect if mysqld closed the connection.mysqld by default closes idle connections after 8 hours
-->
<parameter>
<name>url</name>
<value>jdbc:mysql://localhost:3306/sql_test</value>
</parameter>
</ResourceParams>
</Context>
这样仅仅通过查询在些配置的JNDI名字jdbc/mysql/sql_test就可以获得在建立的sql数据库的连接;在程序中无需知道数据库的用户名和密码等敏感信息,所有与数据库连接相关的信息都只在配置文件server.xml中出现,这样增加了数据库的安全性并简化了在程序中连接数据库的过程,这也正是在JDBC规范中定义DataSource数据源接口的初衷。
(3)配置web.xml
要在Web应用中使用上面配置的JNDI数据源,还需要在相应的Web应用配置文件Web.xml中添加资源引用的配置。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<description>JSP中的高级数据库应用实例</description>
<resource-ref>
<description>DataSource</description>
<res-ref-name>jdbc/mysql/sql_test</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
配置好数据源后,怎么使用这个配置的数据源呢?
这里编了一个实例程序来说明如何使用,在这个应用中首先定义了一SqlTestDS作为数据库的全局唯一的访问点,它封装了查询JNDI数据源并获得连接的操作,它提供了一个类方法getConnection()用于获得连接。
下面是SqlTestDS类的源代码:
package ch14.datasource;
import javax.sql.DataSource;
import javax.naming.*;
import java.sql.*;
public class SqlTestDS {
private static DataSource ds = null;
static {
init();
}
private static void init() {
try {
// 1、创建命名服务环境
Context ctx = new InitialContext();
if (ctx == null)
throw new Exception("No Context");
// 2、从JNDI中查询数据源对象
ds = (DataSource) ctx.lookup("java:comp/env/jdbc/mysql/sql_test");
} catch (Exception e) {
e.printStackTrace();
}
}
// 将构造函数定义为private权限是为了保证全局只有一个SqlTestDS实例
// 也就是实现了单例模式
private SqlTestDS() {
}
public static Connection getConnection() throws SQLException {
if (ds == null) {
throw new SQLException("数据源对象为空!");
} else {
// 3、从数据源中获取数据库连接
return ds.getConnection();
}
}
}
从上面的代码可以看出,使用在Tomcat中配置的JNDI数据源的过程很简单,首先创建一个命名服务环境,然后利用该环境对象的lookup方法按名称查询得到JNDI数据源对象,最后调用得到的数据源对象的getConnection方法便可以获得数据库连接。
下面的DBStudent类就是使用SqlTestDS的getConnection方法获得数据库连接以查询student数据表的信息,其源代码如下:
package ch14.datasource;
import java.sql.*;
//import java.util.ArrayList;
//import java.util.Collection;
import java.util.Date;
import java.util.Vector;
public class DBStudent {
private String stuID;
private String name;
private String address;
private Date birthdate;
// 获得所有student表的记录返回为一个Vector
public static Vector getAllStudent() {
//Collection stuVector = new ArrayList();
Vector stuVector = new Vector();
Connection conn = null;
Statement stmt = null;
try {
conn = SqlTestDS.getConnection();
if (conn != null) {
stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM student");
while (rs.next()) {
DBStudent stu = new DBStudent();
stu.setStuID(rs.getString("stu_id"));
stu.setName(rs.getString("name"));
stu.setAddress(rs.getString("address"));
stu.setBirthdate(rs.getDate("birthdate"));
stuVector.add(stu);
}
}
} catch(SQLException e) {
e.printStackTrace();
}
return stuVector;
}
public String getAddress() {
return address;
}
public Date getBirthdate() {
return birthdate;
}
public String getName() {
return name;
}
public String getStuID() {
return stuID;
}
public void setAddress(String address) {
this.address = address;
}
public void setBirthdate(Date birthday) {
this.birthdate = birthday;
}
public void setName(String name) {
this.name = name;
}
public void setStuID(String stuID) {
this.stuID = stuID;
}
}
然后在datasourceTest.jsp页面中调用DBStudent类的方法,得到并显示所有student数据表的信息,其源代码如下:
<%@ page language="java" contentType="text/html;charset=GB2312"%>
<%@ page import="java.util.*"%>
<%@ page import="ch14.datasource.*"%>
<html>
<head>
<title>数据源测试页面</title>
<meta http-equiv="Content-Type" content="text/html;charset=GB2312">
</head>
<body>
<center>
<%
Vector stuVector = DBStudent.getAllStudent();
int length = stuVector.size();
%>
<h2>student表的查询结果:</h2>
<!--Student List-->
<table width="740" border="1" cellspacing="0" cellpadding="6">
<tr>
<td width="120" align="center" valign="middle">编号</td>
<td width="145" align="center">姓名</td>
<td width="253" align="center">地址</td>
<td width="148" align="center">出生日期</td>
</tr>
<%
for(int i=0;i<length;i++){
DBStudent stu = (DBStudent)stuVector.get(i);
%>
<tr>
<td height="40" align="center" valign="middle"><%=stu.getStuID()%></td>
<td align="center" valign="middle"><%=stu.getName()%></td>
<td valign="middle"><%=stu.getAddress()%></td>
<td align="center" valign="middle"><%=stu.getBirthdate()%></td>
</tr>
<%
}
%>
</table>
</center>
</body>
</html>