A-A+

jdbc 入门通透讲解

2012年03月31日 综合技术 暂无评论 阅读 3,980 次

1.1 JDBC 入门
1.1.1 JDBC 简介
JDBC 是 Java 平台上的数据库访问标准,几乎所有数据库都支持通过 JDBC 进行访问。
和微软平台的 ODBC 、 ADO 、 ADO.NET 等类似, JDBC 的作用是屏蔽 Java 程序访问各种 不
同数据库操作的差异性。使用 JDBC ,开发人员可以通过同样的程序接口访问不同的数据 库 ,
大大增强了系统的可移植性,同时也简化了开发人员的工作。
需要注意的就是, JDBC 只是一个定义了访问接口的标准规范,针对不同的数据库有 不
同的实现,这些不同的时间被称为对应数据库平台的 “ JDBC 驱动 ” 。不过开发人员无需关
心这些 “ JDBC 驱动 ” 的实现细节,只需在程序初始化的时候指定采用哪个 “ JDBC 驱动 ”
即可,其后的数据库操作完全是标准的 JDBC 操作。
1.1.2 JDBC 驱动
不同的数据库有相对应的不同的 JDBC 驱动,这些 JDBC 驱动通常是以 Jar 包的形式 存
在的,在使用这些驱动的时候需要到相应网站上去下载,下面列出常用数据库的驱动下载 地
址:
MySQL:http://www.mysql.com
Oracle:http://www.oracle.com/
Microsoft SQLServer: http://www.microsoft.com
DB2:http://www.ibm.com
下载完成以后把下载包中的相应的 jar 包添加到 CLASSPATH 中即可。这些 JDBC 驱动
中有一个驱动类是暴露给开发人员的,在使用相应的 JDBC 驱动之前必须首先加载这个驱 动
类,在后边将讲解如何加载这个 JDBC 驱动类,这里只列出这些驱动类的名称:
MySQL: com.mysql.jdbc.Driver
Oracle:oracle.jdbc.driver.OracleDriver
Microsoft SQLServer:com.microsoft.jdbc.sqlserver.SQLServerDriver
DB2:Com.ibm.db2.jdbc.net.DB2Driver
1.1.3 连接字符串
在连接数据库的时候,我们必须告诉 JDBC 关于要连接数据库的具体信息,比如数据 库
服务器的 IP 地址是多少、要连接的数据库名字是什么等等。由于这些连接信息的复杂性以
及在各个不同数据库平台上信息的差异性,因此我们需要把这些信息以字符串的形式发送 给
JDBC 。不同的 JDBC 驱动对字符串的格式要求也是不同的,这是学习 JDBC 的一个难点,
因此下面我们列出这些产用的 JDBC 驱动的连接字符串的格式:
( 1 ) MySQL:jdbc:mysql:// 数据库的主机名或者 IP 地址 :3306/ 数据库名。例如我要
连接 IP 地址为 192.168.88.88 的 MySQL 服务器上的名字为 afa 的数据库, 那
么正确的连接字符串即为: jdbc:mysql://192.168.88.88:3306/afa 。
( 2 ) Oracle : jdbc:oracle:thin:@ 数据库的主机名或者 IP 地址 :1521: 数据库名。例 如
我要连接 IP 地址为 192.168.88.88 的 Oracle 服务器上的名字为 afa 的数据库,
那么正确的连接字符串即为: jdbc:oracle:thin:@192.168.88.88:1521:afa 。
( 3 ) Microsoft SQLServer : jdbc:microsoft:sqlserver:// 数据库的主机名或者 IP 地
址 :1433;databaseName= 数据库名。例如我要连接 IP 地址为 192.168.88.88 的
Microsoft SQLServer 服务器上的名字为 afa 的数据库,那么正确的连接字符串即为: sqlserver://192.168.88.88:1433;databaseName=afa 。
( 4 ) DB2 : jdbc:db2:// 数据库的主机名或者 IP 地址 :6789/ 数据库名。例如我要连 接
IP 地址为 192.168.88.88 的 DB2 服务器上的名字为 afa 的数据库,那么正确 的
连接字符串即为: jdbc:db2://192.168.88.88:6789/afa 。
注意:如果要连接本机的数据库,则 “ 数据库的主机名或者 IP 地址 ” 一般填为 127.0. 0.1
或者 localhost 即可。
1.1.4 JDBC 的常见概念
连接( Connection ) : “ 连接 ” 是建立在 Java 程序和数据库服务器之间的一条通路,在 J ava
程序对数据库进行操作之前必须首先建立一个 “ 连接 ” ,在操作完成后需要关闭 “ 连接 ” 。
语句( Statement ): “ 语句 ” 是 Java 程序向数据库服务器发起的操作命令,也就是它代
表了 Java 程序要求数据库服务器执行的 SQL 语句。
结果集( ResultSet ): “ 结果集 ” 是数据库服务器执行 “ 语句 ” 的执行结果, Java 程序 可
以通过读取 “ 结果集 ” 来取得 SQL 语句的执行结果。
1.2 JDBC 实战
本节我们将以一个实例介绍如何通过 JDBC 访问 MySQL 数据库。
第一步、启动 MySQL 数据库,在 MySQL 数据库中创建一个数据库 afa ,并创建一张代表 人
员的表 :T_Person ,建表 SQL 语句为:
Create Create Create Create Table Table Table Table T_Person(FId Varchar Varchar Varchar Varchar ( 50 ) not not not not null null null null ,FName Varchar Varchar Varchar Varchar ( 50 ) not not not not
null null null null ,FAge int int int int not not not not null null null null , primary primary primary primary key key key key (FId));
在数据库中插入一条记录:
Insert Insert Insert Insert into into into into T_Person(FId,FName,FAge) values values values values ( '1' , 'tom' , 22 ) ;
第二步、将 MySQL 的 JDBC 驱动 Jar 包放到 CLASSPATH 中;
第三步、建立一个 Java 文件 JDBCTest :
public public public public class class class class JDBCTest
{
public public public public static static static static void void void void main(String[] args)
{
}
}
第四步、加载 MySQL 的 JDBC 驱动:
Class.forName("com.mysql.jdbc.Driver");
可以看到加载数据库驱动的方法就是: Class.forName( 驱动类名 );
由于加载数据库驱动的时候有可能会发生驱动找不到的异常,因此需要捕捉这个异常并且
将这个异常情况报告给客户,这里我们使用最简单的输出字符串的方式报告:
try try try try
{
Class. forName ( "com.mysql.jdbc.Driver" );
} catch catch catch catch (ClassNotFoundException e)
{
System. out .println( " 数据库驱动找不到! " );
return return return return ;}
第五步、建立和数据库的连接:
JDBC 中建立和数据库连接的方式非常简单,只要调用 java.sql.DriverManager 类的 静
态方法 getConnection 即可。 getConnection 接受三个字符串类型的参数:第一个参数为 连
接字符串;第二个参数为连接数据库的用户名;第二个参数为连接数据库的密码。
getConnection 的返回值为代表数据库连接的 java.sql.Connection 对象。
在这里,我们要建立 IP 地址为本地(即 localhost ),数据库名称为 afa 的 MySQL 数据库 ,
用户名为 root ,密码为空,因此如下建立连接:
Connection conn = null;
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/afa","root","");
第六步、创建查询 SQL 语句:
建立连接以后就可以创建要执行的 SQL 语句,调用数据库连接的 prepareStatement 方法
即得到代表 SQL 语句的 java.sql.PreparedStatement 对象, prepareStatement 的参数 为
要执行的 SQL 语句。这里要查询 T_Person 表中的所有数据,因此如下创建 SQL 语句对象:
PreparedStatement ps = null;
ps = conn.prepareStatement("select * from T_Person");
第七步、执行 SQL 语句对象:
PreparedStatement 有两个主要的方法: executeQuery 用于执行 Select 等有返回结
果集的 SQL 语句,而 execute 则用于执行 Delete 、 Update 语句等没有返回结果集的 SQL 语句。
这里我们要执行的是 select 语句,因此使用 executeQuery 方法执行:
ResultSet rs = null;
rs = ps.executeQuery();
executeQuery 方法的返回值类型为 java.sql.ResultSet ,它代表执行以后的结果集 ,
读取 ResultSet 即可得到所有的执行结果。
第八步、读取执行结果集
因为执行结果集数量非常大,为了减少资源占用, ResultSet 采用了类似于游标的处理方
式,也就是每次只处理一行结果集,当要处理其他行的时候必须移动游标到相应行上。游标可 以
位于结果集的任何一行,也可以位于结果集的第一行之前的位置,也可以位于结果集的最后一 行
之后的位置。初始状态时游标位于结果集的第一行之前的位置。
ResultSet 中提供了很多移动游标的方法,主要包括:
next() :向下一行游标。
beforeFirst () ;将游标移动到第一行之前的位置。
afterLast() :将游标移动到最后一行之后的位置。
first() :将游标移动到第一行。
last() :将游标移动到最后一行。
absolute( int row ) :将游标移动到第 row 行。
所有数据库都支持 next() 方法移动游标,而其他移动游标的方法在很多情况下不被支持,
因此我们通常只使用 next() 方法进行游标控制,而且实际业务中也通常是从上到下逐行进行 结
果集读取,因此 next() 方法一般也就够用了。 next() 方法的返回值表示是否已经到了结果 集
的最后一行之后的位置。
ResultSet 提供了读取当前行中各个列中数据值的方法:
� String getString(String columnName) :取得列名为 columnName 的值,返回类
型为 String 。� boolean getBoolean(String columnName) :取得列名为 columnName 的值,返回
类型为 boolean 。
� int getInt(String columnName) :取得列名为 columnName 的值,返回类型为 int 。
� java.sql.Date getDate(String columnName) :取得列名为 columnName 的值,
返回类型为 java.sql.Date 。
ResultSet 也提供了根据列索引号来取得值的方法,但是出于程序可读性和可维护性的考
虑,我们不推荐这种使用方式。
讲解了这些基础知识,下面就来显示第七步的执行结果:
while (rs.next())
{
StringBuffer sb = new StringBuffer();
sb.append(" 主键 :").append(rs.getString("FId"))
.append("; 姓名 :").append(rs.getString("FName"))
.append("; 年龄 :").append(rs.getInt("FAge"));
System.out.println(sb);
}
这里使用 ResultSet 的 next() 方法做为循环退出的判断条件。 next() 有两个作用,第 一
个作用是将游标下移一个位置,第二个作用就是判断是否已经处理到最后一行。执行结果如下:
主键 :1; 姓名 :tom; 年龄 :22
第九步、异常处理和资源回收
SQL 执行的过程中有可能发生各种异常,这些异常的类型通常是 SQLException ,我们需
要对这些异常进行处理,这里我们采用最简单的打印异常消息的处理方式:
catch (SQLException e)
{
System.out.println(" 数据库执行过程中发生异常情况 :" +
e.getMessage());
}
执行完数据库操作以后我们需要对数据库连接、 SQL 语句对象、结果集等进行资源关闭等 回
收操作,否则会造成数据库资源泄露。为了保证资源一定会被回收我们将资源回收的工作放到
finally 块中来执行:
finally
{
if (rs != null)
{
try
{
rs.close();
} catch (SQLException e)
{
}
}if (ps != null)
{
try
{
ps.close();
} catch (SQLException e)
{
}
}
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
}
}
}
需要注意的是,在调用 close 的方法中也有可能抛出 SQLException 异常,为了不影响后
续的资源回收操作,这里通常要对 close 方法抛出的异常捕获。
下面是这个例子的全部代码:
package com.test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCTest
{
public static void main(String[] args)
{
try
{
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e)
{
System.out.println(" 数据库驱动找不到! ");
return;}
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/afa", "root", "");
ps = conn.prepareStatement("select * from T_Person");
rs = ps.executeQuery();
while (rs.next())
{
StringBuffer sb = new StringBuffer();
sb.append(" 主键 :").append(rs.getString("FId")).append(" ;
姓名 :")
.append(rs.getString("FName")).append("; 年
龄 :").append(
rs.getInt("FAge"));
System.out.println(sb);
}
} catch (SQLException e)
{
System.out.println(" 数据库执行过程中发生异常情况 :" +
e.getMessage());
} finally
{
if (rs != null)
{
try
{
rs.close();
} catch (SQLException e)
{
}
}
if (ps != null)
{
try
{
ps.close();
} catch (SQLException e)
{}
}
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
}
}
}
}
}
对应的 Java 工程为: JDBCDemo.rar
1.3 JDBC 其他问题
1.3.1 执行没有结果集的 SQL
ps = conn.prepareStatement( " Update T_Person set F a ge=20 " );
rs = ps.execute();
1.3.2 参数化 SQL
在执行 SQL 的时候经常需要拼一些查询条件,比如查询名称等于用户输入的 name 值的人员 ,
我们可以采用拼 SQL 语句的方法来进行:
ps = conn.prepareStatement( "select * from T_Person where
F n ame= ’ " +name+ ”’” );
rs = ps.executeQuery();
这样有可能会被人采用注入 SQL 的方式进行攻击,而且也会有执行效率的问题。更好的方 式
是使用参数化 SQL 来解决。参数化 SQL 将 SQL 语句中需要在运行期才能确定的参数用?表示,并
且在运行时再通过 JDBC 提供的方法为这些参数赋值。
比如我们要查询名称等于用户输入的 name 值的人员,只要如下编写即可:
package com.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;import java.sql.ResultSet;
import java.sql.SQLException;
public class JDBCParamTest
{
public static void main(String[] args)
{
// 从控制台中读取用户输入的参数
System.out.print(" 请输入要查询的用户的名称: ");
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
String name = "";
try
{
name = br.readLine();
} catch (IOException e)
{
e.printStackTrace();
return;
}
try
{
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e)
{
System.out.println(" 数据库驱动找不到! ");
return;
}
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try
{
conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/afa", "root", "");
pspspsps = = = = conn.prepareStatement("select conn.prepareStatement("select conn.prepareStatement("select conn.prepareStatement("select * * * * from from from from T_Person T_Person T_Person T_Person where where where where
FName=?"); FName=?"); FName=?"); FName=?");
ps.setString(1, ps.setString(1, ps.setString(1, ps.setString(1, name); name); name); name);
rs = ps.executeQuery();
while (rs.next())
{
StringBuffer sb = new StringBuffer();sb.append(" 主键 :").append(rs.getString("FId")).append(" ;
姓名 :")
.append(rs.getString("FName")).append("; 年
龄 :").append(
rs.getInt("FAge"));
System.out.println(sb);
}
} catch (SQLException e)
{
System.out.println(" 数据库执行过程中发生异常情况 :" +
e.getMessage());
} finally
{
if (rs != null)
{
try
{
rs.close();
} catch (SQLException e)
{
}
}
if (ps != null)
{
try
{
ps.close();
} catch (SQLException e)
{
}
}
if (conn != null)
{
try
{
conn.close();
} catch (SQLException e)
{
}}
}
}
}
代码一开始从控制台中读取用户输入的值,并将输入的值赋值给字符串 name 。从控制台中
读取用户输入的值的代码涉及到了流操作,如果你目前不熟悉也无所谓,只要知道这段代码的 作
用就可以了。
这段代码的核心就是红色粗体字部分:
pspspsps = = = = conn.prepareStatement("select conn.prepareStatement("select conn.prepareStatement("select conn.prepareStatement("select * * * * from from from from T_Person T_Person T_Person T_Person where where where where
FName=?"); FName=?"); FName=?"); FName=?");
ps.setString(1, ps.setString(1, ps.setString(1, ps.setString(1, name); name); name); name);
这里采用了参数化的 SQL : "select "select "select "select * * * * from from from from T_Person T_Person T_Person T_Person where where where where FName=?" FName=?" FName=?" FName=?" , 可以看到采
用?为 F n ame 的值预留了位置;接着调用 ps 的 setString 方法为这个参数赋值,注意在这里 参
数的索引号是从 1 开始的,而非通常的 0 ,这是初学者经常犯错误的地方。还可以为参数赋予其
他类型的参数值,比如赋整数类型的 setInt 、赋日期类型的 setDate 等。
还需要特别注意的就是参数只适用于 where 语句以及计算列等部分,而不能将表名、字段
名等部分也用参数代替。比如根据用户输入的表名来查询某个表,很多初学者会这么写 ( 示例 代
码 ) :
pspspsps = = = = conn.prepareStatement("select conn.prepareStatement("select conn.prepareStatement("select conn.prepareStatement("select * * * * from from from from ? ? ? ? "); "); "); ");
ps.setString(1, ps.setString(1, ps.setString(1, ps.setString(1, “ “ “ “ T_Person T_Person T_Person T_Person ” ” ” ” ););););
这是不对的,在运行的时候会报语法错误。

标签:

给我留言