-- 作者:admin
-- 发布时间:2006/2/26 22:09:21
-- 课件21下载——JDBC
1 简介 Java的JDBC是Java应用访问数据库的通用编程接口,一个紧凑、简单的软件层,主要功能在于定义了应用程序如何打开数据库连接、如何与数据库通信、如何执行SQL语句和如何检索查询结果等,同时兼顾了通用性、速度和兼容性,即 1)通用:跨数据库、跨平台,通过对不同的数据库的客户端的抽象,提供统一的编程接口 2)速度:运用不同的JDBC驱动程序,可提高访问数据库的速度。通用性是速度的敌人,从底层实现JDBC接口可以提高速度。oracle thin driver从tcp层实现jdbc接口。所以速度的问题就是采用何种jdbc驱动的问题。 3)兼容性:适应主流数据库产品的通用特征,如是否支持可修改游标,所支持的二进制对象的最大长度是多少,在一个Connection里面能同时支持多少个语句,同时能打开多少个表等。JDBC充分支持兼容性问题。
具体来看,JDBC的特性有: 1)不限制传递到底层DBMS驱动程序的查询类型 2)JDBC机制易于理解和使用 3)提供与Java系统的其他部分保持一致的Java接口 4)JDBC可以在常见SQL层API的顶层实现
同时,JDBC具有SQL一致性,即JDBC在类Java.SQL.Types中定义了一组通用SQL类型标识符,并且JDBC还通过以下几种方式处理SQL一致性问题:JDBC API允许将任何查询字符串传递到底层DBMS驱动程序;提供内置功能,便于将包含转义序列的SQL查询转换为数据库可理解的格式;提供DatabaseMetaData接口,允许用户检索关于所使用的DBMS信息。
JDBC支持两种模型:二层模型和三层模型。二层模型表现为Java applet和应用程序直接与数据库交互,被称为客户端/服务器配置;三层模型 使用中间层,可以在不同语言中实现中间层。
2、JDBC驱动程序的类型 客户端访问数据库服务器(DBMS)从本质上来说,是一个网络通信应用:TCP应用。具体为首先客户端发送SQL语句,然后DBMS返回SQL语句的结果。如SQL Server通过1433端口,Oralce通过1521端口来进行TCP通信。一般情况下,不需要直接与DBMS进行TCP通信,也不可能,因为厂家通常没有公开访问方法的细节。相反,DBMS厂家提供了一些函数库,程序代码通过调用这些函数对DBMS进行访问。这些函数处理与DBMS的TCP通信,在Windows/Unix平台函数的定义接口是相同的。这些函数(DB API)以动态链接库进行提供,它们是DBMS客户端的核心部分。如.dll,.so等。不同的数据库产品的客户端,DB API的定义和使用方法不一样。如SQL Server是Msdblib3.dll,Oracle是OCI.dll等。 当然层次越高,速度越慢,通用性越好。
JDBC包含三个组件:应用程序、驱动程序管理器和驱动程序。其中JDBC驱动程序的类型可以分为JDBC-ODBC桥加ODBC驱动程序、本地API、JDBC网络纯Java驱动程序、本地协议纯Java驱动程序。
1)JDBC-ODBC桥加ODBC驱动程序 利用ODBC驱动程序提供JDBC的访问,优点在于易于实现,缺点在于客户端需要安装ODBC驱动
2)本地API 直接调用客户机上的数据库驱动程序(如DLL文件等),缺点依然是客户端需要安装二进制驱动
3)JDBC网络纯Java驱动程序 本质上不算是新的一种形式,只是利用各种容器中间件间接访问数据库
4)本地协议纯Java驱动程序 直接利用TCP通信与数据库通信,无需任何API(其实是绕过API直接来作),如Oracle中的Oracle thin连接
3 JDBC开发流程 3、1 加载JDBC驱动 注意早期版本需要注册JDBC驱动程序,现在通过驱动程序类中的静态块都能自动完成注册,所以不再需要了。 注册方法为: DriverManager.registerDriver(driver); 其中的driver就是要注册的新JDBC驱动程序
加载JDBC驱动的方法为: Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); (sun.jdbc.odbc.JdbcOdbcDriver类也可以实例化) 这是一个静态方法,用于指示JVM动态的查找、加载和链接指定类(如果没有加载),如果找不到这个类,则抛出ClassNotFoundException。
也可以使用加载: sun.jdbc.odbc.JdbcOdbcDriver dr = new sun.jdbc.odbc.JdbcOdbcDriver();
3、2 连接数据库(得到Connection) 通过DriverManager.getConnection方法进行连接,如 Connection conn = DriverManager.getConnection(URL,login_name, login_password); 其中JDBC连接由数据库URL标识jdbc:<subprotocol>:<subname>来表示。
3、3 执行查询 Statement对象能够将SQL语句发送到DBMS,创建方法为: Statement:执行SQL语句。conn.createStatement(); PreparedStatement:执行带参数SQL语句。conn.prepareStatement(“...”); CallableStatement:执行存储过程。conn.prepareCall(“...”);
3、4 得到结果集 Statement接口的executeQuery:得到结果集ResultSet Statement接口的executeUpdate:dml语句的执行结果 Statement接口的execute方法:底层方法,可得到多个结果集(如sql的compute by子句就能返回多个结果集)
3、5 处理结果集 利用ResultSet中的方法,如next(),getXXX(...);有些方法涉及到兼容性:first(),last()。
3、6 关闭Connection(关闭很重要)
一个简单的例子: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; Statement stm; ResultSet res; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); res=stm.executeQuery("select * from stu"); while (res.next()) { System.out.println(res.getString(1));//begin at 1 } con.close(); } catch(Exception ex) {} } } 说明: 运行这个程序,需要实现在“控制面板”——“管理工具”——“数据源(ODBC)”中注册一个新的数据源,名称为“StuSQL”,具体的数据库类型和名称自己可以定义,但数据库中一定存在一个名称为“stu”的表
显示所有记录的所有字段 import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; Statement stm; ResultSet res; ResultSetMetaData rsmd; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); res=stm.executeQuery("select * from stu"); rsmd = res.getMetaData(); while (res.next()) { for(int i=1;i<=rsmd.getColumnCount();i++) System.out.print(res.getObject(i)+"\\t"); System.out.println(); } con.close(); } catch(Exception ex) {} } }
说明: ResultSetMetaData和DatabaseMetaData类(通过Connection类的getMetaData方法获取)能够获取数据库的相关元数据信息。
下面的程序能够让用户输入学号,并显示的学生详细信息,如: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; Statement stm; ResultSet res; ResultSetMetaData rsmd; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); String str=javax.swing.JOptionPane.showInputDialog("Please input the SID:"); res=stm.executeQuery("select * from stu where number=\'"+str+"\'"); rsmd = res.getMetaData(); while (res.next()) { for(int i=1;i<=rsmd.getColumnCount();i++) System.out.print(res.getObject(i)+"\\t"); System.out.println(); } con.close(); System.exit(0); } catch(Exception ex) {} } }
下面是一个swing版本的数据库演示程序: import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.sql.*;
public class exec { public static void main(String args[]) { MyFrame m=new MyFrame("JDBC"); Toolkit theKit = m.getToolkit(); Dimension wndSize = theKit.getScreenSize(); m.setBounds(wndSize.width/4, wndSize.height/4, wndSize.width/2, wndSize.height/2); m.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); m.setVisible(true); m.pack(); } }
class MyFrame extends JFrame implements ActionListener { Connection con; Statement stm; ResultSet res; JLabel j1=new JLabel("学号"); JLabel j2=new JLabel("姓名"); JTextField jtf1=new JTextField(10); JTextField jtf2=new JTextField(10); JButton jb=new JButton("确定"); JPanel jp1=new JPanel(); JPanel jp2=new JPanel(); public MyFrame(String title) { super(title); jp1.setLayout(new FlowLayout()); jp1.add(j1); jp1.add(jtf1); jp1.setLayout(new FlowLayout()); jp1.add(j2); jp1.add(jtf2); getContentPane().setLayout(new FlowLayout()); getContentPane().add(jp1); getContentPane().add(jp2); getContentPane().add(jb); jb.addActionListener(this); try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); } catch(Exception ex) {} } public void actionPerformed(ActionEvent e) { try { res=stm.executeQuery("select name from stu where number=\'"+jtf1.getText()+"\'"); res.next(); jtf2.setText(res.getString(1)); con.close(); } catch(Exception ex) {} } }
一般的统计记录个数程序: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; Statement stm; ResultSet res; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); res=stm.executeQuery("select * from stu"); int count=0; while (res.next()) { count++; } System.out.println(count); con.close(); } catch(Exception ex) {} } }
更好的统计记录个数程序: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; Statement stm; ResultSet res; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); res=stm.executeQuery("select count(*) from stu");
res.next(); System.out.println(res.getInt(1)); con.close(); } catch(Exception ex) {} } }
4、执行DML语句 利用Statement对象的executeUpdate方法即可 import java.sql.*;
public class exec { public static void main(String [] args)throws Exception { Connection con; Statement stm; ResultSet res; Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQL" ); stm=con.createStatement(); stm.executeUpdate("insert into stu values(\'000111\',\'Ben\',1,\'1985-10-10\',1.76)");
con.close(); } }
5、调用存储过程(CallableStatement) 它是PreparedStatement子类,可以执行存储过程 如建立存储过程: create proc stu_proc1 as select count(*) from stu
create proc stu_proc2 @pname char(6) as select * from stu where number=@pname
create proc stu_proc3 @pname char(6), @result char(8) output as select @result=name from stu where number=@pname
一般的使用方法为: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; CallableStatement cstm; ResultSet res; ResultSetMetaData rsmd; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQLServer" ); cstm=con.prepareCall("{call stu_proc1}"); res=cstm.executeQuery(); rsmd = res.getMetaData(); while (res.next()) { for(int i=1;i<=rsmd.getColumnCount();i++) System.out.print(res.getObject(i)+"\\t"); System.out.println(); } con.close(); } catch(Exception ex) {} } } 说明:{call stu_proc1}为调用存储过程的语法,不是标准SQL的方法(所以不能用exec stu_proc1),而是JDBC的转义语法,它会自动将其转换成特定的DBMS格式
对于传入参数的使用方法为: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; CallableStatement cstm; ResultSet res; ResultSetMetaData rsmd; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQLServer" ); cstm=con.prepareCall("{call stu_proc2(?)}"); cstm.setString(1,"000001"); res=cstm.executeQuery(); rsmd = res.getMetaData(); while (res.next()) { for(int i=1;i<=rsmd.getColumnCount();i++) System.out.print(res.getObject(i)+"\\t"); System.out.println(); } con.close(); } catch(Exception ex) {} } } 注意此程序要求的数据库字符型字段为char,而不能是nvarchar
对于传出参数的使用方法为: SQLServer做法为 String pcall="{call stu_proc3(?,?)}"; CallableStatement cstmt=conn.prepareCall(pcall); cstmt.setString(1,"000001"); cstmt.registerOutParameter(2,Types.VARCHAR);//重要,指定传出参数的类型 cstmt.execute(); System.out.println(cstmt.getString(2));//重要,得到传出参数 如: import java.sql.*;
public class exec { public static void main(String [] args) { Connection con; CallableStatement cstm; ResultSet res; ResultSetMetaData rsmd; try { Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); con = DriverManager.getConnection("jdbc:odbc:StuSQLServer" ); cstm=con.prepareCall("{call stu_proc3(?,?)}"); cstm.setString(1,"000001"); cstm.registerOutParameter(2,Types.VARCHAR);//重要,指定传出参数的类型 cstm.execute(); System.out.println(cstm.getString(2));//重要,得到传出参数 con.close(); } catch(Exception ex) {} } } 注意此程序要求的数据库字符型字段为char,而不能是nvarchar
[此贴子已经被作者于2010-12-12 08:03:28编辑过]
|