第 20章
JDBC入门
– 使用 JDBC连接数据库
– 使用 JDBC进行数据操作简介 JDBC
简介 JDBC
JDBC数据库驱动程序依实作方式可以分为四个类型
– Type 1,JDBC-ODBC Bridge
– Type 2,Native-API Bridge
– Type 3,JDBC-middleware
– Type 4,Pure Java Driver
连接数据库
载入 JDBC驱动程序
try {
Class.forName("com.mysql.jdbc.Driver");
}
catch(ClassNotFoundException e) {
System.out.println("找不到驱动程序类别 ");
}
连接数据库
提供 JDBC URL
– 协定,子协定,数据源识别
jdbc:mysql://主机名,端口 /数据库名称?参数 =值 &参数 =值
jdbc:mysql://localhost:3306/demo?user=root&password=123
jdbc:mysql://localhost:3306/demo?user=root&password=123&
useUnicode=true&characterEncoding=Big5
连接数据库
取得 Connection
try {
String url = "jdbc:mysql://localhost:3306/demo?" +
"user=root&password=123";
Connection conn = DriverManager.getConnection(url);
....
}
catch(SQLException e) {
....
}
String url = "jdbc:mysql://localhost:3306/demo";
String user = "root";
String password = "123";
Connection conn = DriverManager.getConnection(url,
user,password);
简单的 Connection工具类别
取得 Connection的方式,依所使用的环境及程序需求而有所不同
设计一个 DBSource界面
package onlyfun.caterpillar;
import java.sql.Connection;
import java.sql.SQLException;
public interface DBSource {
public Connection getConnection() throws SQLException;
public void closeConnection(Connection conn) throws SQLException;
}
简单的 Connection工具类别
public class SimpleDBSourceimplementsDBSource {

public SimpleDBSource(String configFile) throws IOException,
ClassNotFoundException {
props = new Properties();
props.load(new FileInputStream(configFile));
url = props.getProperty("onlyfun.caterpillar.url");
user = props.getProperty("onlyfun.caterpillar.user");
passwd = props.getProperty("onlyfun.caterpillar.password");
Class.forName(
props.getProperty("onlyfun.caterpillar.driver"));
}
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,passwd);
}
public void closeConnection(Connection conn) throws SQLException {
conn.close();
}
}
简单的 Connection工具类别
onlyfun.caterpillar.driver=com.mysql.jdbc.Driver
onlyfun.caterpillar.url=jdbc:mysql://localhost:3306/demo
onlyfun.caterpillar.user=root
onlyfun.caterpillar.password=123456
DBSource dbsource = new SimpleDBSource();
Connection conn = dbsource.getConnection();
if(!conn.isClosed()) {
System.out.println("数据库连接已开启 …");
}
dbsource.closeConnection(conn);
if(conn.isClosed()) {
System.out.println("数据库连接已关闭 …");
}
简单的连接池 ( Connectionpool)
数据库连接的取得是一个耗费时间与资源的动作
– 建立 Socket connection
– 交换数据(用户密码验证、相关参数)
– 数据库初始会话( Session)
– 日志( Logging)
– 分配行程( Process)
– …
简单的连接池( Connectionpool)
public synchronized Connection getConnection()
throws SQLException {
if(connections.size() == 0) {
return DriverManager.getConnection(url,user,passwd);
}
else {
int lastIndex = connections.size() - 1;
return connections.remove(lastIndex);
}
}
public synchronized void closeConnection(Connection conn)
throws SQLException {
if(connections.size() == max) {
conn.close();
}
else {
connections.add(conn);
}
}
简单的连接池( Connectionpool)
DBSource dbsource = newBasicDBSource("jdbc2.properties");
Connection conn1 = dbsource.getConnection();
dbsource.closeConnection(conn1);
Connection conn2 = dbsource.getConnection();
System.out.println(conn1 == conn2);
onlyfun.caterpillar.driver=com.mysql.jdbc.Driver
onlyfun.caterpillar.url=jdbc:mysql://localhost:3306/demo
onlyfun.caterpillar.user=root
onlyfun.caterpillar.password=123456
onlyfun.caterpillar.poolmax=10
简单的连接池( Connectionpool)
初始的 Connection数量
Connection最大 idle的数量
如果超过多久时间,要回收多少数量 的
Connection
Proxool
– http://proxool.sourceforge.net/index.html
Apache Jakarta的 Common DBCP
– http://jakarta.apache.org/commons/dbcp/
Statement,ResultSet
要执行 SQL的话,必须取得
java.sql.Statement物件,它是 Java当中一个 SQL叙述的具体代表对象
插入一笔数据,可以如下使用 Statement的
executeUpdate()方法
Statement stmt = conn.createStatement();
stmt.executeUpdate("INSERT INTO t_message VALUES(1,'justin'," +
"'justin@mail.com','mesage...')");
Statement,ResultSet
executeUpdate()会传回 int结果,表示资料变动的笔数
executeQuery()方法则是用于 SELECT等查询数据库 的 SQL
executeQuery()会传回 java.sql.ResultSet对象,
代表查询的结果
可以使用 ResultSet的 next()来移动至下一笔数据,
它会传回 true或 false表示是否有下一笔资料
使用 getXXX()来取得资料
Statement,ResultSet
指定域名来取得数据
ResultSet result =
stmt.executeQuery("SELECT * FROM t_message");
while(result.next()) {
System.out.print(result.getInt("id") + "\t");
System.out.print(result.getString("name") + "\t");
System.out.print(result.getString("email") + "\t");
System.out.print(result.getString("msg") + "\t");
}
Statement,ResultSet
使用查询结果的字段顺序来显示结果
ResultSet result =
stmt.executeQuery("SELECT * FROM t_message");
while(result.next()) {
System.out.print(result.getInt(1) + "\t");
System.out.print(result.getString(2) + "\t");
System.out.print(result.getString(3) + "\t");
System.out.print(result.getString(4) + "\t");
}
Statement,ResultSet
Statement的 execute()可以用来执行 SQL,并可以测试所执行的 SQL是执行查询或是更新
传回 true的话表示 SQL执行将传回 ResultSet表示查询结果,此时可以使用 getResultSet()取得
ResultSet物件
如果 execute()传回 false,表示 SQL执行会传回更新笔数或没有结果,此时可以使用
getUpdateCount()取得更新笔数
如果事先无法得知是进行查询或是更新,就可以使用 execute()
Statement,ResultSet
finally {
if(stmt != null) {
try {
stmt.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
dbsource.closeConnection(conn);
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
Statement,ResultSet
Connection对象默认为「自动认可」
( autocommit)
getAutoCommit()可以测试是否设定为自动认可
无论是否有无执行 commit()方法,只要 SQL
没有错,在关闭 Statement或 Connection前,
都会执行认可动作
PreparedStatement
preparedStatement()方法建立好一个预先编译( precompile)的 SQL语句
当中参数会变动的部份,先指定 "?"这个占位字符
PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO t_message VALUES(?,?,?,?)");
PreparedStatement
需要真正指定参数执行时,再使用相对应的 setInt(),setString()等方法,指定 "?"处真正应该有的参数
stmt.setInt(1,2);
stmt.setString(2,"momor");
stmt.setString(3,"momor@mail.com");
stmt.setString(4,"message2...");
LOB读写
BLOB全名 Binary LargeObject,用于储存大量的二进制数据
CLOB全名 Character LargeObject,用于储存大量的文字数据
在 JDBC中也提供了 java.sql.Blob与
java.sql.Clob两个类别分别代表 BLOB与
CLOB资料
LOB读写
取得一个档案,并将之存入数据库中
File file = new File("./logo_phpbb.jpg");
int length = (int) file.length();
InputStream fin = new FileInputStream(file);
//填入数据库
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO files
VALUES(?,?,?)");
pstmt.setInt(1,1);
pstmt.setString(2,"filename");
pstmt.setBinaryStream (3,fin,length);
pstmt.executeUpdate();
pstmt.clearParameters();
pstmt.close();
fin.close();
LOB读写
从数据库中取得 BLOB或 CLOB资料
Blob blob = result.getBlob(2); //取得 BLOB
Clob clob = result.getClob(2) //取得 CLOB
交易( Transaction)
可以操作 Connection的 setAutoCommit()方法,给它 false自变量
在下达一连串的 SQL语句后,自行呼叫
Connection的 commit()来送出变更交易( Transaction)
try {

conn.setAutoCommit(false); //设定 autocommit为 false
stmt = conn.createStatement();
stmt.execute("...."); // SQL
stmt.execute("....");
stmt.execute("....");
conn.commit(); //正确无误,确定送出
}
catch(SQLException e) { //喔喔!在 commit()前发生错误
try {
conn.rollback(); //撤消操作
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
}
交易( Transaction)
设定储存点( savepoint)
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.executeUpdate("....");
stmt.executeUpdate("....");
Savepoint savepoint = conn.setSavepoint(); //设定
savepoint
stmt.executeUpdate("....");
//如果因故 rollback
conn.rollback(savepoint);
.,,
conn.commit();
//记得释放 savepoint
stmt.releaseSavepoint(savepoint);
批处理
使用 addBatch()方法将要执行的 SQL叙述加入,然后执行 executeBatch()
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.addBatch("..."); // SQL
stmt.addBatch("...");
stmt.addBatch("...");
...
stmt.executeBatch();
conn.commit();
批处理
使用 PreparedStatement可以进行批处理
PreparedStatement stmt = conn.prepareStatement(
"INSERT INTO t_message VALUES(?,?,?,?)");
Message[] messages =,..;
for(int i = 0; i < messages.length; i++) {
stmt.setInt(1,messages[i].getID());
stmt.setString(2,messages[i].getName());
stmt.setString(3,messages[i].getEmail());
stmt.setString(4,messages[i].getMsg());
stmt.addBatch();
}
stmt.executeBatch();
ResultSet光标控制
可以在建立 Statement对象时指定 resultSetType
– ResultSet.TYPE_FORWARD_ONLY
– ResultSet.TYPE_SCROLL_INSENSITIVE
– ResultSet.TYPE_SCROLL_SENSITIVE
预设是第一个,也就是只能使用 next()来逐笔取得资料
指定第二个或第三个时,则可以使用 ResultSet的
afterLast(),previous(),absolute(),relative()等方法
ResultSet光标控制
还必须指定 resultSetConcurrency
– ResultSet.CONCUR_READ_ONLY
– ResultSet.CONCUR_UPDATABLE
createStatement()不给定参数时,预设是
TYPE_FORWARD_ONLY、
CONCUR_READ_ONLY
ResultSet光标控制
dbsource = new SimpleDBSource();
conn = dbsource.getConnection();
stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
ResultSet result = stmt.executeQuery(
"SELECT * FROM t_message");
result.afterLast();
while(result.previous()) {
System.out.print(result.getInt("id") + "\t");
System.out.print(result.getString("name") + "\t");
System.out.print(result.getString("email") + "\t");
System.out.println(result.getString("msg"));
}
ResultSet新增、更新、删除数据
建立 Statement时必须在 createStatement()
上指定 TYPE_SCROLL_SENSITIVE(或
TYPE_SCROLL_INSENSITIVE,如果不想取得更新后的数据的话) 与
CONCUR_UPDATABLE
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet新增、更新、删除数据
针对查询到的数据进行更新的动作
ResultSet result = stmt.executeQuery(
"SELECT * FROM t_message WHERE name='justin'");
result.last();
result.updateString("name","caterpillar");
result.updateString("email","caterpillar@mail.com");
result.updateRow();
ResultSet新增、更新、删除数据
如果想要新增数据
ResultSet result = stmt.executeQuery(
"SELECT * FROM t_message WHERE
name='caterpillar'");
result.moveToInsertRow();
result.updateInt("id",4);
result.updateString("name","jazz");
result.updateString("email","jazz@mail.com");
result.updateString("msg","message4...");
result.insertRow();
ResultSet新增、更新、删除数据
要删除查询到的某笔数据
ResultSet result = stmt.executeQuery(
"SELECT * FROM t_message WHERE
name='caterpillar'");
result.last();
result.deleteRow();
ResultSetMetaData
MetaData即「数据的数据」 ( Data
aboutdata)
ResultSet用来表示查询到的数据,而
ResultSet数据的数据,即描述所查询到的数据背后的数据描述,即用来表示表格名称、域名、字段型态
可以透过 ResultSetMetaData来取得
ResultSetMetaData
dbsource = new SimpleDBSource();
conn = dbsource.getConnection();
stmt = conn.createStatement();
ResultSet result = stmt.executeQuery(
"SELECT * FROM t_message");
ResultSetMetaData metadata =
result.getMetaData();
for(int i = 1; i <= metadata.getColumnCount(); i++) {
System.out.print(
metadata.getTableName(i) + ".");
System.out.print(
metadata.getColumnName(i) + "\t|\t");
System.out.println(
metadata.getColumnTypeName(i));
}