JDBC是用于运行SQL的一种解决方案,开发人员使用JDBC的标准接口,数据库厂商对接口进行实现,这样开发人员就无需接触底层数据库驱动程序的差异性。
1.连接数据库
为了连接数据库系统,必须要有JDBC驱动程序,可以将驱动程序JAR包放在WEB应用的/WEB-INF/lib下。通常,要执行以下几个步骤:
(1)加载驱动:
可以通过java.lang.Class类的forName(),动态加载驱动。
try{
Class.forName("com.mysql.jdbc.Driver");
}
catch(ClassNotFoundException e) {
System.out.println("找不到指定类");
}
一旦类被加载,DriverManager就会注册驱动类的实例,稍后要取得Connection实例,DriverManager就知道使用哪个实例来生产Connection实例。
(2)提供JDBC URL
JDBC URL定义了连接数据库时的协议、子协议、数据源等标识。
Mysql的JDBC URL编写方式如下:
jdbc:mysql://主机名:连接端口:/数据库名?参数=值&参数=值
如果使用中文访问,还要给定参数useUnicode及characterEncoding。
jdbc:mysql://localhost:3306/demo?user=root&password=123&useUnicode=true&characterEncoding=UTF-8
(3)取得Connection实例
要连接数据库,可以向DriverManager取得Connection对象。一个Connection对象就代表一个数据库连接。
Connection conn = null;
try {
String url = "jdbc:mysql://localhost:3306/demo?" +
"user=root&password=123456";
conn = DriverManager.getConnection(url);
...
}
finally {
if(conn != null) {
try {
conn.close();
}
catch(SQLException e) {
...
}
}
}
getConnection()也可以在参数上指定用户名与密码:
String url = "jdbc:mysql://localhost:3306/demo" ;
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
由于取得Connection的方法依所使用的环境及程序需求有所不同,直接在程序代码中固定取得Connection的方式并不是明智之举。在Java EE的环境中,将取得连接等与数据库来源相关的行为规范在javax.sql.DataSource接口,而实际如何取得Connection则由实现接口的对象来负责。
问题简化为如何取得DataSource实例。为了让应用程序在需要取得某些与系统相关的资源对象时,能与实际的系统资源配置、实体机器位置、环境架构等无关,在Java应用程序中可以通过JNDI来取得所需的资源对象。
try {
Context initContext = new InitialContext();
Context envContext = (Context)initContext.lookup("java:comp/env");
dataSource = (DataSource)envContext.lookup("jdbc/demo");
} catch(NamingException e) {
...
}
假如有以下代码:DatabaseBean.java
import java.sql.*;
import java.util.logging.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class DatabaseBean {
private DataSource dataSource;
public DatabaseBean() {
try {
Context initContext = new InitialContext();
Context envContext = (Context)
initContext.lookup("java:/comp/env");
dataSource = (DataSource) envContext.lookup("jdbc/demo");
} catch (NamingException ex) {
Logger.getLogger(DatabaseBean.class.getName())
.log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
public boolean isConnectedOK() {
boolean ok = false;
Connection conn = null;
try {
conn = dataSource.getConnection();
if (!conn.isClosed()) {
ok = true;
}
} catch (SQLException ex) {
Logger.getLogger(DatabaseBean.class.getName())
.log(Level.SEVERE, null, ex);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
Logger.getLogger(DatabaseBean.class.getName())
.log(Level.SEVERE, null, ex);
}
}
}
return ok;
}
}
只看这里的代码,不会知道实际上使用了哪个驱动程序,数据库名称,密码是什么。这些都由数据库管理员或者服务器管理员设置,你唯一要知道的就是jdbc/demo这个JNDI名称,并且在web.xml中设置。
<resource-ref>
<res-ref-name>jdbc/demo</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
可以通过下面的代码测试这个类:
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<jsp:useBean id="db" class="DatabaseBean"/>
<!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>测试数据库连接</title>
</head>
<body>
<c:choose>
<c:when test="${db.connectedOK}">连接成功!</c:when>
<c:otherwise>连接失败!</c:otherwise>
</c:choose>
</body>
</html>
就一个Java开发者的角度,它的工作已经完成了。现在假设你是服务器管理员,负责设置JNDI相关资源,假设应用程序部署在Tomcat 6上,可以要求应用程序在封装为WAR时,在META-INF文件夹下包括一个context.xml。
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/JDBCDemo">
<Resource name="jdbc/demo" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="!123456" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF8"/>
</Context>
2.执行数据库操作
要执行SQL,必须取得java.sql.Statement对象,取得之后金额以使用executeUpdate()和executeQuery()来执行SQL。
executeUpdate()返回int值,表示数据变动的条数;executeQuery()返回java.sql.ResultSet对象,代表查询结果。
import java.sql.*;
import java.util.*;
import java.util.logging.*;
import javax.naming.*;
import javax.sql.DataSource;
public class GuestBookBean {
private DataSource dataSource;
public GuestBookBean() {
try {
Context initContext = new InitialContext();
Context envContext = (Context)
initContext.lookup("java:/comp/env");
dataSource = (DataSource) envContext.lookup("jdbc/demo");
} catch (NamingException ex) {
Logger.getLogger(DatabaseBean.class.getName())
.log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
public void setMessage(Message message) {
Connection conn = null;
Statement statement = null;
try {
conn = dataSource.getConnection();
statement = conn.createStatement();
statement.executeUpdate(
"INSERT INTO t_message(name, email, msg) VALUES ('"
+ message.getName() + "', '"
+ message.getEmail() +"', '"
+ message.getMsg() + "')");
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
if (statement != null) {
statement.close();
}
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
try {
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
}
public List<Message> getMessages() {
Connection conn = null;
Statement statement = null;
ResultSet result = null;
List<Message> messages = null;
try {
conn = dataSource.getConnection();
statement = conn.createStatement();
result = statement.executeQuery("SELECT * FROM t_message");
messages = new ArrayList<Message>();
while (result.next()) {
Message message = new Message();
message.setId(result.getLong(1));
message.setName(result.getString(2));
message.setEmail(result.getString(3));
message.setMsg(result.getString(4));
messages.add(message);
}
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
} finally {
try {
if (result != null) {
result.close();
}
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
try {
if (statement != null) {
statement.close();
}
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
try {
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
Logger.getLogger(GuestBookBean.class.getName()).log(Level.SEVERE, null, ex);
throw new RuntimeException(ex);
}
}
return messages;
}
}
在使用完Connection、Statement或ResultSet时,要将之关闭以释放相关资源。