Java学习总结之第十四章 数据库操作
一、JDBC基础
JDBC是Java应用与数据库管理系统进行交互的标准API,包括两个包:核心API---java.sql和扩展的API---javax.sql。应用程序通过核心API的接口实现数据库连接和数据处理,其主要接口如下:
接口名称 | 功能 |
java.sql.Driver | 驱动程序,连接应用程序和数据库,用于读取数据库驱动器的信息,提供连接方法,建立访问数据库所用的Connection对象。在加载某一Driver类时,它应该创建自己的实例并向DriverManager注册该实例。 |
java.sql.DriverManager | 驱动程序管理器,管理一组Driver对象,对程序中用到的驱动程序进行管理,包括加载驱动程序、获得连接对象、向数据库发送信息。在调用getConnection方法时,DriverManager会试着从初始化时加载的那些驱动程序以及使用与当前 applet 或应用程序相同的类加载器显式加载的那些驱动程序中查找合适的驱动程序。 |
java.sql.Connection | 连接Java数据库和Java应用程序之间的主要对象并创建所有的Statement对象。 不管对数据库进行什么样的操作,都需要创建一个连接,然后通过这个连接来完成操作。 |
java.sql.Statement | 语句对象,代表了一个特定的容器,对一个特定的数据库执行SQL语句。用于执行静态SQL语句并返回它所生成结果的对象。在默认情况下,同一时间每个 Statement 对象在只能打开一个ResultSet对象。因此,如果读取一个 ResultSet 对象与读取另一个交叉,则这两个对象必须是由不同的Statement对象生成的。如果存在某个语句的打开的当前ResultSet对象,则Statement接口中的所有执行方法都会隐式关闭它。 |
PreparedStatement | 表示预编译的SQL语句的对象。SQL语句被预编译并存储在PreparedStatement对象中。然后可以使用此对象多次高效地执行该语句。 |
java.sql.ResultSet | 用于控制对一个特定语句的行数据的存取,也就是数据库中记录或行组成的集合。 |
二、结果集及其常见方法
1. 结果集有三种类型,它的类型决定了能否对结果集中的游标进行操作,以及并发的数据源的改变能否反映到结果集中。具体描述如下:
类型 | 描述 |
TYPE_FORWARD_ONLY | 默认的结果集类型,这种类型的结果集对象的游标只能向前移动,从第1行的前面到最后一行的后面。 |
TYPE_SCROLL_INSENSITIVE | 这种类型的结果集对象的游标可以向前移动,也可以直接定位到某一行上,但是对结果集中对应数据的变化是不敏感的。 |
TYPE_SCROLL_SENSITIVE | 这种类型的结果集对象的游标可以向前移动,也可以直接定位到某一行上,并且对结果集中对应数据的变化是敏感的(如果)。 |
2. 结果集的并发性决定了结果集所支持的更新操作的层次,有两种并发性层次:
类型 | 描述 |
CONCUR_READ_ONLY | 默认的结果集并发类型,这种情况下的结果集对象不支持更新操作。 |
CONCUR_UPDATABLE | 这种情况下的结果集对象支持更新操作。 |
可以通过调用DatabaseMetaData的supportsResultSetConcurrency方法来看驱动是否支持结果集上的更新操作,该方法定义如下:
boolean supportsResultSetConcurrency(int type,int concurrency) throws SQLException 第一个数据表示结果集类型,第二个参数表示并发类型。 |
3. 结果集的延续性是指当事务提交时,在当前事务中创建的结果集是否关闭。默认情况下会关闭这个结果集对象。延续性可以通过如下两个静态属性来指定:
类型 | 描述 |
HOLD_CURSORS_OVER_COMMIT | 当提交事务时不关闭该结果集对象。 |
CLOSE_CURSORS_AT_COMMIT | 提交事务时关闭结果集对象,有时候会提高性能。 |
4. 结果集的类型、并发性和延续性可以通过Connection.createStatement、Connection.prepareStatement和Connection.prepareCall等方法指定,同时Statement、PreparedStatement和CallableStatement接口也提供了相应的setter方法和getter方法。如下代码是创建语句对象的时候指定结果集的类型、并发性和延续性。
Connection conn = ds.getConnection(user,passwd); Statement stmt = conn.createStatement(ResultSet. TYPE_SCROLL_INSENSITIVE, ResultSet. CONCUR_READ_ONLY, ResultSet. CLOSE_CURSORS_AT_COMMIT); |
5. 结果集常用的游标操作方法如下表所示:
返回值 | 方法名 | 功能描述 |
boolean | next() | 将游标从当前位置向前移一行,如果指向某行,返回true,如果指向最后一行的后面,返回false |
boolean | previous() | 将游标从当前位置向后移一行,如果指向某行,返回true,如果指向第一行的前面,返回false |
boolean | first() | 将游标移到此结果集的第一行。 |
boolean | last() | 将游标移到些结果集的最后一行。 |
void | beforeFirst() | 将游标移动到此结果集的开始处,正好位于第一行之前 |
void | afterLast() | 将游标移动到此结果集的末尾,正好位于最后一行之后 |
boolean | relative(int rows) | 按相对行数移动游标。如果参数为0,游标无变化。如果参数是正的,游标向前移动rows行,如果rows太大,游标指向最后1条记录的后面。如果参数是负数,游标向后移动rows行,如果rows太小,游标指向第1条记录的前面。如果游标指向一个有效行,方法返回true,否则返回false |
boolean | absolute(int row) | 将游标移动到参数所指定的行 |
6. 以下是示例代码:
//获取结果集中列的类型 ResultSet rs = stmt.executeQuery(sqlString); ResultSetMetaData rsmd = rs.getMetaData(); int [] colType = new int[ rsmd.getColumnCount() ]; for(int idx=0,int col=1;idx<colType.length;idx++,col++) colType[idx] = rsmd.getColumnType(col); //如果结果集支持更新操作,可以通过结果集完成更新、删除和插入操作。 Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery(“select author from booklist where isbn=111”); rs.next(); rs.updateString(“author”,”JerryChoi”); rs.updateRow(); //插入记录 ResultSet rs = stmt.executeQuery(“select author,title,isbn from booklist”); rs.moveToInsertRow(); //设置每一列的值 rs.updateString(1,”aaa”); rs.updateString(2,”bbb”); rs.updateLong(3,1234); //插入一行 rs.insertRow(); rs.moveToCurrentRow(); //删除记录 rs.absolute(4); rs.deleteRow(); |
三、连接数据库的基本过程
基本过程如下:
l 建立数据源
l 导入用到的包
l 加载驱动程序
l 创建与数据库的连接
l 创建语句对象
l 编写SQL语句
l 执行SQL语句
l 处理数据
l 关闭相关对象
l 处理异常
1. 建立数据源
假设已经存在名为bookstore的MySQL数据库。
2. 导入用到的包
import java.sql.*; |
3. 加载驱动程序
//如果驱动程序和名字是MyDriver,加载驱动程序的语句是: Class.forName(“MyDriver”); //或者 Class.forName(“MyDriver”).newInstance(); //本例中使用MySQL,刚加载的语句为: Class.forName(“com.mysql.jdbc.Driver”); |
4. 创建与数据库的连接
连接数据库需要知道如下信息:
l 数据库所在的主机,所使用的端口等
l 数据库的名字
l 用户信息,包括用户名和口令
//连接数据库的格式如下: //constr:连接字符串;user:用户名;passwd:口令 Connection con = DriverManager.getConnection(constr,user,passwd); //MySQL数据库的连接示例如下: Connection con = DriverManager.getConnection(“jdbc:mysql://localhost:3306/bookstore”,”root”,”root”); |
以下表格是常用的数据库驱动程序名字和URL格式:
数据库 | 驱动程序 | URL |
Oracle | oracle.jdbc.driver.OracleDriver | jdbc:oracle:thin:@dbip:port:databasename dbip :数据库服务器的 IP 地址,如果是本地可写 localhost 或 127.0.0.1 。 port :数据库的监听端口,需要看安装时的配置,缺省为 1521 。 databasename:数据库的 SID ,通常为全局数据库的名字。 |
SQL Server | com.microsoft.jdbc.sqlserver.SQLServerDriver | jdbc:microsoft:sqlserver://dbip:port;DatabaseName=databasename dbip :数据库服务器的 IP 地址,如果是本地可写 localhost 或 127.0.0.1 。 port :数据库的监听端口,需要看安装时的配置,缺省为 1433。 databasename:数据库的 SID ,通常为全局数据库的名字。 |
DB2 | com.ibm.db2.jdbc.app.DB2Driver | jdbc:db2://dbip:port/databasename dbip :数据库服务器的 IP 地址,如果是本地可写 localhost 或 127.0.0.1 。 port :数据库的监听端口,需要看安装时的配置。 databasename:数据库的 SID ,通常为全局数据库的名字。 |
Informix | com.informix.jdbc.IfxDriver | jdbc:infoxmix-sqli://dbip:port /testDB:INFORMIXSERVER= databasename;user=username;password=userpassword dbip :数据库服务器的 IP 地址,如果是本地可写 localhost 或 127.0.0.1 。 port :数据库的监听端口,需要看安装时的配置。 databasename:数据库的 SID ,通常为全局数据库的名字。 user:用户名 password:用户口令 |
Sybase | com.sybase.jdbc.SybDriver | jdbc:sybase:Tds:dbip:port/databasename dbip :数据库服务器的 IP 地址,如果是本地可写 localhost 或 127.0.0.1 。 port :数据库的监听端口,需要看安装时的配置。 databasename:数据库的 SID ,通常为全局数据库的名字。 |
MySQL | com.mysql.jdbc.Driver 或 org.gjt.mm.mysql.Driver | jdbc:mysql://dbip:port/databasename [?param1=value1][¶m2=value2]…… 注:[] 是可选的选项 dbip :数据库服务器的IP地址,如果是本地可写成 localhost 或 127.0.0.1 。 port:数据库的监听端口,需要看安装时的配置,缺省为 3306。 databasename:数据库的 SID ,通常为全局数据库的名字。 param1、param2、value1和value2:附加参数,常见参数如下: l user:用户名 l password:密码 l autoReconnect:联机失败时是否重新联机(true/false) l maxReconnect:尝试重新联机次数 l initialTimeout:尝试重新联机间隔 l maxRows:传回最大行数 l useUnicode:是否使用Unicode编码(ture/false) l characterEncoding:何种编码 l relaxAutocommit:是否自动提交(true/false) l capitalizeTypeNames:数据定义的名称以大写表示 |
PostgreSQL | org.postgresql.Driver | jdbc:postgresql://dbip:port/databasename dbip :数据库服务器的IP地址,如果是本地可写成 localhost 或 127.0.0.1 。 port:数据库的监听端口,需要看安装时的配置。 databasename:数据库的 SID ,通常为全局数据库的名字。 |
Access | sun.jdbc.odbc.JdbcOdbcDriver | jdbc:odbc:datasourcename datasourcename:数据库的 SID ,通常为全局数据库的名字。 注:该驱动只能工作在 Windows 系统中,首先需要在操作系统中建立一个可以访问 Access 数据库的本地数据源(ODBC) ,如果名字为 allandb ,那么 URL 写法如下:jdbc:odbc:allandb |
5. 创建语句对象
语句对象的作业就是执行SQL语句。语句对象的创建是通过连接对象创建的,所以在创建语句对象之前应该确保连接对象已经创建。以下代码是创建语句对象的代码,不管连接什么数据库,不管执行什么样的操作,这句代码不用改:
Statement stmt = con.createStatement(); |
6. 编写SQL语句
示例代码如下:
String sql = “select * from usertable”; |
7. 执行SQL语句
常用的执行SQL语句的方法有以下两个:
返回值 | 方法 | 说明 |
ResultSet | executeQuery(String sql) | 主要用于执行有结果集返回的SQL语句,典型的就是select查询语句。 |
int | executeUpdate(String sql) | 主要用于执行没有结果集返回的SQL语句,如果要在数据库中添加、修改或删除信息,它们都没有返回值,应该使用本方法。该方法的返回值是一个整数,表示影响数据库中记录的个数。 |
例如,要执行上面的查询语句,可以使用如下代码:
ResultSet rs = stmt.executeQuery(sql); |
8. 处理结果集
可参照上面的“结果集及其常见方法”
注:对行的遍历,使用结果集的next()方法。要获取某一列,可以使用getXXX(int columnIndex)或getXXX(String columnLabel)方法。以下是示例代码:
//以字符串的形式获取第1列或字段名为username的列 String userid = rs.getString(1); String userName = rs.getString(“username”); |
9. 关闭相关对象
代码如下:
//应该按以下顺序关闭相关对象,该顺序与创建对象的顺序相反 //关闭结果集 rs.close(); //关闭语句 stmt.close(); //关闭连接 con.close(); |
10. 异常处理
使用以下框架对异常进行处理:
try{ ……//要执行的可能出错的代码 }catch(Exception e){ ……//出错后的处理代码 }finally{ ……//不管是否出错都要执行的代码 } |
以下是综合示例代码:
String className = “com.mysql.jdbc.Driver”; String url = “jdbc:mysql://localhost:3306/bookstore”; String username = “root”; String userpass = “root”; String tableName = “usertable” Connection con = null; PreparedStatement pstmt = null; ResultSet rs = null; try{ Class.forName(className); con = DriverManager.getConnection(url,username,userpass); pstmt = con.prepareStatement(“select * from “ + tableName); rs = pstmt.executeQuery(); while(rs.next()) { for(int i=0;i<rs.getMetaDate().getColumnCount();++i) System.out.println(rs.getString(i+1)); System.out.println(); } }catch(Exception e){ System.out.println(e.toString); }finally{ try{ rs.close();}catch(Exception e){} try{ pstmt.close();}catch(Exception e){} try{ con.close();}catch(Exception e){} } |