JDBC与Perl DBI数据库操作全解析
1. JDBC基础操作
在JDBC编程中,
rs.getString("team_name")
可以从指定列中获取数据。当
ResultSet.next()
方法返回
FALSE
时,意味着无法再获取下一行数据,此时程序会退出
while
循环,并调用
ResultSet.close()
方法释放资源并关闭队列。关闭连接也很简单,使用
Connection.close()
方法即可,示例代码如下:
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
2. 修改数据库示例
以下是一个修改数据库的完整示例代码:
import java.net.URL;
import java.sql.*;
class jex14_12
{
public static void main(String argv[])
{
Connection con;
String upstring;
try {
Class.forName ("org.gjt.mm.mysql.Driver");
con = DriverManager.getConnection (
"jdbc:mysql://localhost:3306/baseball",
"mylogin",
"mypassword" );
} catch( Exception e) {
e.printStackTrace();
return;
}
try {
/* create a table */
Statement stmt = con.createStatement();
stmt.executeUpdate ("CREATE TABLE mytmp (aval int)");
System.out.println ("created temp table");
stmt.close();
/* put some stuff into the table */
stmt = con.createStatement();
for (int i = 1 ; i < 5 ; i++)
{
upstring = "INSERT INTO mytmp values(" + i + ")";
stmt.executeUpdate (upstring);
System.out.println ("added value " + i);
}
stmt.close();
/* read the stuff back from the temporary table */
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery (
"SELECT aval FROM mytmp ORDER BY aval");
while(rs.next())
{
System.out.println(rs.getString(1));
}
stmt.close();
/* drop the temporary table */
stmt = con.createStatement();
stmt.executeUpdate("DROP TABLE mytmp");
System.out.println("dropped mytmp");
stmt.close();
} catch( Exception e) {
e.printStackTrace();
}
try {
con.close();
} catch( Exception e) {
e.printStackTrace();
}
}
}
运行该程序的命令为:
java jex14_12
,预期输出如下:
created temp table
added value 1
added value 2
added value 3
added value 4
1
2
3
4
dropped mytmp
该程序主要包含以下六个部分:
- 加载驱动并连接到数据源。
- 创建表。
- 向表中插入数据。
- 从表中读取数据。
- 删除表。
- 关闭与数据源的连接。
下面详细介绍各部分操作:
-
创建表
:
Statement stmt = con.createStatement();
stmt.executeUpdate ("CREATE TABLE mytmp (aval int)");
System.out.println ("created temp table");
stmt.close();
此代码通过
Connection.createStatement()
方法创建
Statement
对象,再使用
Statement.executeUpdate()
方法执行创建表的SQL语句,最后关闭
Statement
对象释放资源。
-
插入数据
:
stmt = con.createStatement();
for (int i = 1 ; i < 5 ; i++)
{
upstring = "INSERT INTO mytmp values(" + i + ")";
stmt.executeUpdate (upstring);
System.out.println ("added value " + i);
}
stmt.close();
使用
for
循环构建
INSERT
语句,通过
Statement.executeUpdate()
方法执行插入操作,循环结束后关闭
Statement
对象。
-
读取数据
:
stmt = con.createStatement();
ResultSet rs = stmt.executeQuery (
"SELECT aval FROM mytmp ORDER BY aval");
while(rs.next())
{
System.out.println(rs.getString(1));
}
stmt.close();
调用
Statement.executeQuery()
方法执行
SELECT
语句,将结果存储在
ResultSet
对象中,通过
while
循环遍历结果集并输出数据,最后关闭
Statement
对象。
-
删除表
:
stmt = con.createStatement();
stmt.executeUpdate("DROP TABLE mytmp");
System.out.println("dropped mytmp");
stmt.close();
使用
Statement.executeUpdate()
方法执行删除表的SQL语句,然后关闭
Statement
对象。
需要注意的是,JDBC默认自动提交事务,执行语句后其效果会直接修改数据库且无法回滚,但JDBC也提供了修改此默认行为和操作事务的方法。
3. 处理NULL数据
JDBC提供了多种判断数据是否为
NULL
的方法,最简单的是使用
ResultSet.wasNull()
方法。以下是一个处理
NULL
值的示例代码:
String team_name;
String home_team;
try {
stmt = con.createStatement();
ResultSet rs =
stmt.executeQuery (
"SELECT DISTINCT team.team_name, game.home_team " +
"FROM team " +
"LEFT JOIN game ON team.team_name = game.home_team " +
"WHERE city = 'Chicago' " +
"ORDER BY team_name"
);
while(rs.next())
{
team_name = rs.getString (1);
System.out.print (team_name + ":−");
/* get home_team; check if it's NULL */
home_team = rs.getString(2);
if (rs.wasNull())
{
System.out.println ("NO RECORD IN TABLE GAME'");
} else {
System.out.println (home_team);
}
System.out.println("");
}
stmt.close();
} catch (Exception e) {
e.printStackTrace();
}
编译和运行该程序的命令分别为:
javac 14_13.java
java jex14_13
预期输出如下:
Cubs:−NO RECORD IN TABLE GAME'
White Sox:−White Sox
if (rs.wasNull())
表达式用于测试之前获取的列是否包含
NULL
值。
4. 预准备语句
JDBC提供了预编译SQL语句的机制,即预准备语句。预准备语句可以避免每次执行语句时驱动解析和翻译的开销,还适用于处理二进制数据。JDBC有两个预准备接口,分别用于SQL语句和存储过程。
- 预准备SQL语句 :
PreparedStatement prepstmt =
con.prepareStatement("INSERT INTO mytmp values( ? )");
for (int i = 1; i < 5; i++)
{
prepstmt.setInt(1, i);
int rows = prepstmt.executeUpdate();
}
prepstmt.close();
使用
Connection.prepareStatement()
方法创建
PreparedStatement
对象,通过
PreparedStatement.setInt()
方法将变量与参数绑定,每次循环都需要调用该方法。
PreparedStatement.clearParameters()
方法可清除所有参数。
-
预准备存储过程
:
虽然MySQL不支持存储过程,但JDBC的预准备存储过程接口使用方法如下:
1. 使用
Connection.prepareCall()
方法构建
CallableStatement
对象:
CallableStatement callstate =
connection.prepareCall ("{call mystoredprocedure(?, ?) }");
-
使用
CallableStatement.registerOutParameter()方法告知JDBC驱动每个参数的SQL类型:
callstate.registerOutParameter(Types.INTEGER, 1);
callstate.registerOutParameter(Types.VARCHAR, 2);
- 执行存储过程调用:
callstate.executeUpdate();
-
调用相应的
getXXX方法从参数中检索数据:
Integer firstparam = callstate.getInt(1);
String secondparam = callstate.getString(2);
如果存储过程的所有参数都是
IN
类型,则可以通过普通的
Statement
对象执行。
5. 通用SQL语句处理
在某些情况下,可能无法确定SQL语句是否会修改数据库,此时可以使用
Statement.execute()
方法。该方法执行的SQL语句生成
ResultSet
则返回
true
,否则返回
false
。以下是一个Java版的SQL解释器示例代码:
import java.net.URL;
import java.sql.*;
class jex14_15
{
public static void main(String argv[])
{
Connection con;
Statement stmt;
byte sql_text[] = new byte[1000];
try {
Class.forName("org.gjt.mm.mysql.Driver");
con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/baseball",
"mylogin",
"mypassword");
} catch ( Exception e) {
e.printStackTrace();
return;
}
System.out.println ("Type an SQL statement, or 'quit' to exit\n");
/* do a query */
while (true)
{
try {
stmt = con.createStatement();
System.out.print ("Ok> ");
System.out.flush();
System.in.read (sql_text);
String sql_string = new String (sql_text);
if (sql_string.indexOf("quit") != −1)
{
break;
}
// if true, the executed statement generated a ResultSet
if (!stmt.execute(sql_string))
{
// the statement did not return a ResultSet; therefore,
// it is an UPDATE, INSERT, or DELETE statement
System.out.println ("Database modified");
continue;
}
// if we reach this point, the statement generated a
// ResultSet: get it
ResultSet rs = stmt.getResultSet();
// get the MetaResult object that describes this ResultSet
ResultSetMetaData mr = rs.getMetaData();
for (int i = 1 ; i <= mr.getColumnCount() ; i++)
{
int colwidth = mr.getColumnDisplaySize (i);
String colname = mr.getColumnName (i);
int strwidth = colname.length();
System.out.print (colname);
// pad the column with spaces
for (int j = 0 ; j < colwidth − strwidth ; j++)
{
System.out.print(" ");
}
}
System.out.println("");
while(rs.next())
{
for (int i = 1 ; i <= mr.getColumnCount() ; i++)
{
String colvalue;
int colwidth = mr.getColumnDisplaySize (i);
colvalue = rs.getString(i);
if (rs.wasNull())
{
colvalue = new String("NULL");
}
int strwidth = colvalue.length();
System.out.print (colvalue);
// pad the column with spaces
for (int j = 0 ; j < colwidth − strwidth ; j++)
{
System.out.print (" ");
}
}
System.out.println("");
}
} catch ( Exception e) {
e.printStackTrace();
return;
}
}
System.out.println ("\nGoodbye!");
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
return;
}
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
return;
}
}
}
运行该程序的示例会话如下:
java jex14_15
Ok> select city, team_name, stadium from team where city = 'Chicago'
city team_name stadium
Chicago White Sox Comiskey Park
Chicago Cubs Wrigley Field
Ok> quit
Goodbye!
该程序的核心在一个
while
循环中,具体步骤如下:
1. 显示
Ok>
提示并接收用户输入的SQL语句。
2. 检查用户是否输入
quit
,如果是则退出程序。
3. 调用
Statement.execute()
方法执行用户输入的语句,如果执行成功但未生成
ResultSet
,则打印 “Database modified” 并继续循环。
4. 如果生成了
ResultSet
,则使用
Statement.getResultSet()
方法获取结果集,再使用
ResultSet.getMetaData()
方法获取结果集的元数据。
5. 根据元数据构建表头并输出,然后遍历结果集,使用
ResultSet.wasNull()
方法处理
NULL
值,最后输出数据并进行适当的空格填充。
需要注意的是,
Statement.execute()
方法可能返回多个结果集,可以使用
Statement.getMoreResults()
方法获取下一个可用的结果集。
6. 元数据
JDBC定义了两个非常有用的元数据类:
DatabaseMetaData
和
ResultSetMetaData
。
-
数据库元数据(DatabaseMetaData) :
DatabaseMetaData类定义了许多方法,用于返回关于数据源的信息,包括数据库产品、驱动和数据库本身。以下是一些常用方法:
| 方法 | 描述 |
| ---- | ---- |
|getDataProductName()| 获取数据库产品名称 |
|getDataProductVersion()| 获取数据库产品版本 |
|getIdentifierQuoteString()| 获取SQL标识符的引号字符串 |
|getColumns()| 返回数据库中的列信息 |
|getTablePrivileges()| 返回每个表的权限信息 | -
结果集元数据(ResultSetMetaData) :
ResultSetMetaData类用于访问给定结果集的元数据,如列数、列名和列宽等。以下是一些常用方法:
| 方法 | 描述 |
| ---- | ---- |
|getPrecision()| 返回列的精度(适用于NUMERIC类型的列) |
|getTableName()| 返回列所属的表名 |
|isNullable()| 判断列是否可以返回NULL值 |
|isWritable()| 判断列是否可写入数据 |
7. 其他特性
本文仅介绍了JDBC的基础知识,JDBC还有许多高级特性,如直接处理对象和跨网络分块移动大二进制对象等。详细信息可参考Sun提供的在线JDBC文档。
8. Perl DBI简介
Perl DBI(Perl Database Interface)是一个Perl对象包,其属性和方法为Perl程序员提供了强大的数据操作能力。它基于X/Open标准设计,与ODBC和JDBC有相似的“外观和感觉”,同时还扩展了该标准,提供了实用的服务。
9. Perl DBI的结构
Perl DBI由驱动管理器和一个或多个驱动组成。驱动管理器内置于Perl DBI中,无需安装或配置。Perl DBI驱动以共享库的形式编写,在运行时加载。不同的Linux发行版默认包含的驱动套件有所不同,大多数包含MySQL驱动,部分还包含其他关系型数据库的驱动。
通过以上内容,我们对JDBC的数据库操作和Perl DBI有了较为全面的了解,这些知识将有助于我们在实际开发中更高效地处理数据库相关任务。
JDBC与Perl DBI数据库操作全解析
10. Perl DBI的基本使用流程
Perl DBI的使用流程与ODBC和JDBC有相似之处,下面为你详细介绍其基本使用步骤:
1.
加载DBI模块
:在Perl脚本中,首先需要加载DBI模块,示例代码如下:
use DBI;
-
连接数据库
:使用
DBI->connect()方法连接到数据库,示例代码如下:
my $dsn = "dbi:mysql:database=baseball;host=localhost;port=3306";
my $dbh = DBI->connect($dsn, "mylogin", "mypassword",
{ RaiseError => 1, PrintError => 0 }
) or die $DBI::errstr;
这里的
$dsn
是数据源名称(DSN),指定了数据库类型、数据库名、主机地址和端口等信息。
$dbh
是数据库句柄,用于后续的数据库操作。
3.
执行SQL语句
:可以使用数据库句柄的
do()
方法执行不返回结果集的SQL语句,如
INSERT
、
UPDATE
、
DELETE
等,示例代码如下:
my $sql = "INSERT INTO mytmp (aval) VALUES (1)";
$dbh->do($sql);
如果需要执行返回结果集的SQL语句,如
SELECT
,则可以使用
prepare()
和
execute()
方法,示例代码如下:
my $sql = "SELECT aval FROM mytmp";
my $sth = $dbh->prepare($sql);
$sth->execute();
while (my @row = $sth->fetchrow_array) {
print join("\t", @row), "\n";
}
这里的
$sth
是语句句柄,用于执行和处理SQL语句。
fetchrow_array()
方法用于逐行获取结果集的数据。
4.
关闭连接
:在完成数据库操作后,需要关闭数据库连接,示例代码如下:
$dbh->disconnect;
11. Perl DBI处理不同类型数据的方法
在实际应用中,我们可能会遇到各种类型的数据,Perl DBI提供了相应的方法来处理不同类型的数据。
-
处理字符串数据
:对于字符串数据,直接在SQL语句中使用即可,示例代码如下:
my $name = "John";
my $sql = "SELECT * FROM users WHERE name = '$name'";
$sth = $dbh->prepare($sql);
$sth->execute();
- 处理数字数据 :数字数据的处理与字符串类似,示例代码如下:
my $age = 25;
my $sql = "SELECT * FROM users WHERE age > $age";
$sth = $dbh->prepare($sql);
$sth->execute();
-
处理日期和时间数据
:Perl DBI本身没有专门处理日期和时间的方法,但可以使用Perl的日期和时间模块,如
DateTime,示例代码如下:
use DateTime;
my $dt = DateTime->now;
my $date_str = $dt->ymd;
my $sql = "SELECT * FROM events WHERE event_date = '$date_str'";
$sth = $dbh->prepare($sql);
$sth->execute();
12. Perl DBI的错误处理
在使用Perl DBI进行数据库操作时,可能会遇到各种错误,如连接失败、SQL语句执行错误等。可以通过检查
$DBI::err
和
$DBI::errstr
变量来处理错误,示例代码如下:
my $dsn = "dbi:mysql:database=baseball;host=localhost;port=3306";
my $dbh = DBI->connect($dsn, "mylogin", "mypassword")
or die "Connect failed: $DBI::errstr";
my $sql = "SELECT * FROM non_existent_table";
my $sth = $dbh->prepare($sql);
if (!$sth->execute()) {
print "Execute failed: $DBI::errstr\n";
}
在上述代码中,
$DBI::err
是错误代码,
$DBI::errstr
是错误信息。通过检查这些变量,可以及时发现并处理数据库操作中的错误。
13. Perl DBI与JDBC的对比
| 特性 | Perl DBI | JDBC |
|---|---|---|
| 语言支持 | Perl | Java |
| 设计标准 | 基于X/Open标准并扩展 | 基于X/Open标准 |
| 驱动加载 | 运行时加载共享库 | 类加载机制 |
| 代码风格 | 灵活、简洁,符合Perl哲学 | 结构化、面向对象 |
| 适用场景 | 脚本编写、快速开发 | 大型企业级应用 |
从这个对比表格可以看出,Perl DBI和JDBC在不同的场景下各有优势。Perl DBI适合快速开发和脚本编写,而JDBC则更适合大型企业级应用。
14. 总结与建议
通过对JDBC和Perl DBI的学习,我们了解了它们在数据库操作方面的基本功能和使用方法。在实际开发中,我们可以根据项目的需求和特点选择合适的工具。
如果项目是基于Java语言开发的大型企业级应用,建议使用JDBC,它可以充分发挥Java的面向对象特性和强大的企业级支持。如果项目是使用Perl语言编写的脚本或小型应用,Perl DBI是一个不错的选择,它的灵活性和简洁性可以提高开发效率。
同时,无论是使用JDBC还是Perl DBI,都需要注意数据库操作的安全性,如防止SQL注入等问题。在处理复杂的数据库操作时,合理使用预准备语句和事务管理等功能,可以提高数据库操作的性能和可靠性。
下面是一个简单的mermaid流程图,展示了选择JDBC或Perl DBI的决策过程:
graph TD;
A[项目需求] --> B{项目语言};
B -- Java --> C[使用JDBC];
B -- Perl --> D[使用Perl DBI];
B -- 其他 --> E{开发场景};
E -- 大型企业级 --> C;
E -- 小型脚本 --> D;
通过这个流程图,我们可以更直观地根据项目的语言和开发场景来选择合适的数据库操作工具。希望本文能帮助你更好地掌握JDBC和Perl DBI的使用,在数据库操作中取得更好的效果。
超级会员免费看
55

被折叠的 条评论
为什么被折叠?



