5月12日,晴天。“纷纷红紫已成尘,布谷声中夏令新。夹路桑麻行不尽,始知身是太平人。”
1、恰到好处的JDBC
在学生的练习、案例和小规模的开发,JDBC使用的很多。配置简单,规范,一眼就能明白是主要原因。但也存在问题,所以企业的实际开发时,多用JNDI。
主要问题:
(1)数据库服务器名称 、用户名和口令都可能需要改变,由此引发JDBC URL需要修改;
(2)数据库可能更换产品,比如开发使用MySQL,实际部署改为DB2或者Oracle,引发JDBC驱动程序包和类名需要修改;
(3)随着实际使用终端的增加,原配置的连接池参数可能需要调整。而JDBC的API中没有提供连接池的方法。
2、DataSource对象
在Java语言中,DataSource对象就是一个代表数据源实体的对象。应用程序通过一个连接来访问数据源,那么一个DataSource对象就是用于提供连接数据源的工具。DataSource接口提供了两个方法用于建立和数据源的连接,使用DataSource对象建立和数据库的连接比起使用DriverManager接口更加高效,虽然两者的使用范围都很相似,并且都提供了方法用于建立和数据库的连接。
但两者之间的区别更加明显,和DriverManager不同,一个DataSource对象能够识别和描述它所代表的数据源的属性,而DataSource对象的工作和JNDI(Javatm Naming and Directory Interface)具有密切的关系, DataSource的建立、发布、独立于应用程序的管理都依靠JNDI技术。
JDBC2.0提供了javax.sql.DataSource接口,它负责建立与数据库的连接,在应用程序访问数据库时不需要编写连接数据库的代码,可以直接从数据源获得数据库连接。在DataSource中事先建立了多个数据库连接,这些数据库连接保存在连接池(Connect Pool)中。Java程序访问数据库时,只需要从连接池中取出空闲状态的数据库连接;当程序访问数据库结束,再将数据库连接放回连接池。
3、好中择优的JNDI
可以简单地把JNDI理解为一种将对象和名字绑定的技术,对象工厂负责生产出对象,这些对象都和惟一的名字绑定。外部程序可以通过名字来获取对某个对象的引用。
DataSource对象是由Tomcat提供的,因此不能在程序中采用创建一个实例的方式来生产DataSource对象,而需要采用Java的另一个技术JNDI,来获得DataSource对象的引用。
Tomcat把DataSource作为一种可以配置的JNDI资源来处理。生成DataSource对象的工厂为org.apache.commons.dbcp.BasicDataSourceFactory。
在javax.naming包中提供了Context接口,该接口提供了将对象和名字绑定,以及通过名字检索对象的方法。Context中的主要方法有:
bind(String name,Object object):将对象与一个名字绑定。
lookup(String name):返回与指定的名字绑定的对象。
4、Tomcat中数据源的配置
自tomcat 5.5起数据库连接池的配置和以前的不同了,不推荐在server.xml中进行配置,而是在%Tomcat_Home%\webapps\yourApp\META-INF\context.xml中进行配置才是更好的方法。
而不是以前版本%Tomcat_Home%\conf\context.xml文件。这样就可以在不同的web应用下单独配置连接池了,且Tomcat会自动重载。当然你也可以更改%Tomcat_Home%\conf下的context.xml文件,将所有web应用下的连接池进行统一配置。
因为server.xml是不可动态重加载的资源,服务器一旦启动了以后,要修改这个文件,就得重启服务器才能重新加载。而context.xml文件则不然,tomcat服务器会定时去扫描这个文件。一旦发现文件被修改(时间戳改变了),就会自动重新加载这个文件,而不需要重启服务器。
注:这一步容易报错:Cannot create JDBC driver of class for connect URL null 一定要记得把你的MYSQL5.0驱动jar包考到Tomcat6.0 的lib文件下。
5、Web应用中使用数据源
javax.naming.Context提供了查找JNDI Resource的接口,可以通过三个步骤来使用数据源对象:
A.获得对数据源的引用:
Context ctx = new InitalContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/BookDb");
B.获得数据库连接对象:
Connection con = ds.getConnection();
C.返回数据库连接到连接池:
con.close();
在连接池中使用close()方法和在非连接池中使用close()方法的区别是:前者仅仅是把数据库连接对象返回到数据库连接池中,是连接对象又恢复到空闲状态,而非关闭数据库连接,而后者将直接关闭和数据库的连接。
6、实例说明
(1)使用MySQL建个数据库jsp_db,供测试之用。
drop database IF EXISTS jsp_db; create database if not exists jsp_db; USE jsp_db; DROP TABLE IF EXISTS student; CREATE TABLE student ( sid varchar(20) NOT NULL, name varchar(30) default NULL, sex int(1) default NULL, phone varchar(16) default NULL, birth date default NULL, Constraint primary key pk_student(sid) ) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
(2)编写context.xml。
context.xml的位置:在Eclipse中放的位置,如下图
如果直接放在在Tomcat下面,就放在\conf文件夹下。
<?xml version="1.0" encoding="UTF-8"?> <Context > <Resource name="jdbc/bn" auth="Container" type="javax.sql.DataSource" maxActive="30" maxIdle="10" maxWait="10000" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/jsp_db?characterEncoding=gb2312" username="root" password="root" /> </Context>相关说明: name 为当前数据源JNDI的名字,可以随意设定;
(3)编写测试代码
<!--测试连接池-->
<%@ page contentType="text/html; charset=gb2312"%>
<%@ page import="javax.naming.Context"%>
<%@ page import="javax.sql.DataSource"%>
<%@ page import="javax.naming.InitialContext"%>
<%@ page import="java.sql.*"%>
<%
//request.setCharacterEncoding("UTF-8");
DataSource ds = null;
try {
Context initCtx = new InitialContext();
//从Context中查找数据源
ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/bn");
if (ds != null) {
out.println("已经获得DataSource!");
out.println("<br>");
Connection conn = ds.getConnection();
java.sql.Statement stmt = conn.createStatement();
stmt.executeUpdate("insert into student(sid,name,sex,phone,birth) values('034','王五',1,'8725698','1986/06/01')");
out.println("数据:'034','王五',1,'8725698','1986/06/01' 添加成功");
//关闭连接、释放资源
stmt.close();
conn.close();
} else
out.println("连接失败!");
} catch (Exception ne) {
out.println(ne);
}
%>
(4)运行结果
说明:1、java:comp/env 是环境命名上下文(environment naming context(ENC)),是在EJB规范1.1以后引入的,引入这个是为了解决原来JNDI查找所引起的冲突问题,也是为了提高EJB或者J2EE应用的移植性。
2、java:comp/env/jdbc/bn(虚地址) ------> 映射描述符 ------> jdbc/bn (实际的地址)。
3、逻辑名jdbc/bn作为数据源名称的好处是为了提高可移植性,移植的时候只需要把配置文件改一下就可以,而应用程序可不用改动,JNDI名字其实说白了就是把JNDI名放到配置文件里。
4、通过jndi配置多个数据源。
<?xml version="1.0" encoding="UTF-8"?> <Context > <Resource name="jdbc/bn" auth="Container" type="javax.sql.DataSource" maxActive="30" maxIdle="10" maxWait="10000" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/jsp_db?characterEncoding=gb2312" username="root" password="root" /> <Resource name="jdbc/biz" auth="Container" type="javax.sql.DataSource" maxActive="30" maxIdle="10" maxWait="10000" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/bizdemo" username="root" password="root" /> </Context>5、 再编写一个测试代码
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@page import="java.sql.*"%> <%@page import="javax.naming.*"%> <%@page import="javax.sql.DataSource"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Tomcat6.0 JNDI 测试</title> </head> <body> This is my JSP page. <br> JNDI配置测试开始 ... <br> <% try { //初始化 Context 上下文对象; Context ctx = new InitialContext(); //Context envContext = (Context) ctx.lookup("java:/comp/env"); //DataSource ds = (DataSource) envContext.lookup("jdbc/biz"); //查找配置 //方法二: DataSource ds = (DataSource) ctx .lookup("java:comp/env/jdbc/biz"); Connection conn = ds.getConnection(); conn.close(); out.println("JNDI数据源配置成功了!"); } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } %> </body> </html>运行结果