《Java程序设计-15-访问数据.ppt》由会员分享,可在线阅读,更多相关《Java程序设计-15-访问数据.ppt(34页珍藏版)》请在三一办公上搜索。
1、Java程序设计,第15章 访问数据库,学习目标,了解JDBC发展历史能够用不同的方式建立到数据库的连接利用Statement访问数据能够在对象和数据库的记录之间进行转换,了解ORM技术掌握批量更新能够调用存储过程了解连接池技术,15.1.1什么是JDBC,JDBC(Java Database Connectivity)一种用于执行SQL 语句,和数据库进行交互的技术,它由一组用 Java 编程语言编写的类和接口组成。,JDBC的历史JDBC1.X API规范遵循的是SQL2/SQL92标准,对它的支持的类都定义在java.sql包中。JDBC2.0规范发布时,增加了对SQL3的支持,并且重点
2、扩展了在应用服务器端访问数据库的功能,相关扩展的类包含在javax.sql中。目前JDBC已经发布了4.0的版本,其重要的变化集中在丰富的数据类型、元数据的支持、支持标注和应用服务器端编程的特性如数据源、连接池、分布式的事务等。,15.1.2 JDBC 驱动程序类型,JDBC-ODBC 桥加 ODBC 驱动程序必须提供ODBC驱动程序 本地 API-部分用 Java 来编写的驱动程序 一种用Java实现的,替代JDBC-ODBC 桥产品的驱动程序JDBC 网络纯 Java 驱动程序一种和具体数据库无关的驱动程序。本地协议纯 Java 驱动程序 一种支持将JDBC调用直接转换为某个具体DBMS的
3、驱动程序,通常由数据库厂家提供,实践中常用,15.2基本的数据库存取过程,实现简单的数据库存取操作是一件很轻松的事情。实现基本的数据存取操作包括三个步骤:连接到数据库存取数据关闭连接。,连接到数据库连接到数据库需要由驱动程序的支持,在保证已经将驱动程序文件复制到可被运行环境搜索到的位置后,开发对数据库进行存取操作的第一步是建立到指定数据库的连接,这一过程可以细分为两个操作:加载指定的驱动程序(可选)获得到指定数据库的连接,public class SqlServerDemo public static void main(String args)String url=jdbc:sqlserve
4、r:/localhost:1433;databaseName=bank;user=sa;password=123456;Connection con=null;try con=DriverManager.getConnection(url);/获得到数据库的连接/获得连接数据库的元数据对象metaData DatabaseMetaData metaData=con.getMetaData();/输出连接数据库的产品名称 System.out.println(metaData.getDatabaseProductName();/输出连接数据库的产品版本号 System.out.println(m
5、etaData.getDatabaseProductVersion();con.close();/关闭到数据库的连接,释放资源 catch(SQLException e)e.printStackTrace();,1.加载驱动程序(可选)检查数据库厂商提供的JDBC驱动程序,可以在对应的位置发现其提供的驱动程序类。通过调用方法 Class.forName(),将显式地加载驱动程序类。,加载SQLServer驱动程序类Class.forName(com.microsoft.sqlserver.jdbc.SQLServerDriver);加载Oracle驱动程序类Class.forName(orac
6、le.thin.Driver);Class.forName(oracle.jdbc.driver.OracleDriver);加载MySQL驱动程序类Class.forName(org.gjt.mm.mysql.Driver);,2 建立连接加载 Driver 类之后,应用程序还需显式的获得到数据库的一个连接。当调用 DriverManager.getConnection()方法发出连接请求时,DriverManager 将检查每个驱动程序,查看它是否可以建立连接。该方法的返回值类型是Connection。,连接所需的URL分析,jdbc:例如:url=jdbc:microsoft:sqlse
7、rver:/localhost:1433;+databasename=score;User=sa;Password=123456;这里的subprotocol是microsoft,除此之外,根据情况还有odbc、oracle、mysql等。而subname则指定了数据源。,Connection,表示了与特定数据库的连接(会话),在连接上下文中执行 SQL 语句并返回结果。,15.3使用Statement访问数据库,Statement对象用于将 SQL 语句发送到数据库系统中。实际上有三种 Statement 对象,它们都作为在给定连接上执行 SQL 语句的包容器:StatementPrepar
8、edStatement(继承 Statement)CallableStatement(继承PreparedStatement)它们都专用于发送特定类型的 SQL 语句:Statement 对象用于执行不带参数的简单 SQL 语句;PreparedStatement 对象用于执行带或不带 IN 参数的预编译 SQL 语句;CallableStatement 对象用于执行对数据库已存储过程的调用。,1 创建 Statement 对象 建立了到特定数据库的连接之后,要想用该连接发送 SQL 语句,首先需要创建一个Statement 对象,可用 Connection 的方法 createStateme
9、nt 创建。Statement stmt=con.createStatement();,2 使用 Statement 对象执行语句ResultSet rs=stmt.executeQuery(select sid,name,gender from student);Statement 接口提供了四种执行 SQL 语句的方法。方法addBatch和executeBatch结合起来使用,执行命令的顺序以添加到批中的顺序为主。方法 executeQuery 用于产生单个结果集的语句,例如 SELECT 语句。方法 executeUpdate 用于执行 INSERT、UPDATE 或 DELETE 语
10、句以及 SQL DDL(数据定义语言)语句。方法 execute 用于执行返回多个结果集、多个更新计数或二者组合的语句。,ResultSet rs=null;rs=stmt.executeQuery(select sid,name,gender from student);,3 语句完成 当连接处于自动提交模式时,其中所执行的语句在完成时将自动提交或还原。语句在已执行且所有结果返回时,即认为已完成。对于返回一个结果集的 executeQuery 方法,在检索完 ResultSet 对象的所有行时该语句完成。对于方法 executeUpdate,当它执行时语句即完成。但在少数调用方法 execu
11、te 的情况中,在检索所有结果集或它生成的更新计数之后语句才完成。有些 DBMS 将已存储过程中的每条语句视为独立的语句;而另外一些则将整个过程视为一个复合语句。在启用自动提交时,这种差别就变得非常重要,因为它影响什么时候调用 commit 方法。在前一种情况中,每条语句单独提交;在后一种情况中,所有语句同时提交。,4 关闭 Statement 对象 Statement 对象将由 Java 垃圾收集程序自动关闭。而作为一种好的编程风格,应在不需要 Statement 对象时显式地关闭它们。这将立即释放 DBMS 资源,有助于避免潜在的内存问题。如上述程序中的finally代码块中的语句:stm
12、t.close();con.close();,15.4ResultSet,ResultSet 包含数据库中存储的符合 SQL 语句中条件的所有记录,并且它通过一套 get 方法(这些 get 方法可以访问当前行中的不同列)提供了对这些记录中数据的访问。定位记录获得此记录对应属性的值,15.4.1行和光标,行和光标ResultSet 对象具有指向其当前数据行的指针。最初,指针被置于第一行之前。next 方法将指针移动到下一行,因为该方法在 ResultSet 对象中没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集。默认的 ResultSet 对象不可更新,仅有一个向
13、前移动的指针。因此,只能迭代它一次,并且只能按从第一行到最后一行的顺序进行。可更新结果集Statement stmt=con.createStatement(intresultSetType,intresultSetConcurrency);参数resultSetType表示结果集类型。它是 esultSet.TYPE_FORWARD_ONLY、ResultSet.TYPE_SCROLL_INSENSITIVE 或 ResultSet.TYPE_SCROLL_SENSITIVE 之一参数resultSetConcurrency 表示并发类型。它是 ResultSet.CONCUR_READ_O
14、NLY 或 ResultSet.CONCUR_UPDATABLE 之一,15.4.2获取列的值,2 访问列方法 getXXX 提供了获取当前行中某列值的途径。在每一行内,可按任何次序获取列值。但为了保证可移植性,应该从左至右获取列值,并且一次性地读取列值。列名或列号可用于标识要从中获取数据的列。通过下标获得当前记录指定列的列值通过字段名获得当前记录指定列的列值通过字段名或下标获得当前记录未知类型的指定列的列值,String sql=select id,name,balance from tb_account;ResultSet rs=stmt.executeQuery(sql);while(r
15、s.next()String id=rs.getString(1);String name=rs.getString(2);int balance=rs.getInt(3);System.out.printf(id:%s,name:%s,balance:%drn,id,name,balance);rs.close();,String sql=select id,name,balance from tb_account;ResultSet rs=stmt.executeQuery(sql);while(rs.next()String id=rs.getString(id);String name
16、=rs.getString(name);int balance=rs.getInt(balance);System.out.printf(id:%s,name:%s,balance:%drn,id,name,balance);rs.close();,Object id=rs.getObject(id);Object name=rs.getObject(name);Object balance=rs.getObject(balance);,15.4.3插入新行,插入新行直接利用Statement执行 insert语句。当Statement对象的结果集类型是可更新的时候,ResultSet对象具有
17、一个与其关联的特殊行,该行用作构建要插入的行的暂存区域(staging area),利用它可以完成向数据表的插入操作。,rs.moveToInsertRow();/定位插入行位置,然后更新每个字段的值rs.updateString(id,uuid.toString();rs.updateNString(name,name);rs.updateInt(balance,balance);rs.insertRow();/将插入行的内容插入到此 ResultSet 对象和数据库,15.4.4更新列值,更新列值同样地批量的修改可以用Statement执行SQL来确定 ResultSet提供了针对一条记录
18、某个字段进行修改的方法updateXXX;,ResultSet rs=stmt.executeQuery(select id,name,balance+from tb_account where name=张华);if(rs.next()/假如找到这样符合条件的记录rs.updateInt(balance,100);rs.updateRow();,15.4.5删除记录行,删除记录同样地批量的删除可以用Statement执行SQL来确定 ResultSet提供了删除一条记录的方法deleteRow();,ResultSet rs=stmt.executeQuery(select*from tb_
19、account where balance=0);while(rs.next()/逐个删除每条记录 rs.deleteRow();rs.close();,6 数据类型和转换对于 getXXX 方法,JDBC 驱动程序试图将基本数据转换成指定 Java 类型,然后返回适合的 Java 值。例如,如果 getXXX 方法为 getString,而基本数据库中数据类型为 VARCHAR,则 JDBC 驱动程序将把 VARCHAR 转换成 Java String。getString 的返回值将为 Java String 对象。,7 对非常大的行值使用I/O流JDBC API 具有三个获取流的方法,分别
20、具有不同的返回值:getBinaryStream 返回只提供数据库原字节而不进行任何转换的流。getAsciiStream 返回提供单字节 ASCII 字符的流。getCharacterStream(返回提Reader类型字符的流。,8 NULL 结果值在读取字段值时,一般而言要对一些不明确值是否存在的字段值进行空值判断。要确定给定结果值是否是 JDBC NULL,必须先读取该列,然后使用 ResultSet.wasNull 方法检查该次读取是否返回 JDBC NULL。,15.5 PreparedStatement,PreparedStatement继承于Statement,它允许使用可替代
21、的参数修改最终执行的SQL语句,,PreparedStatement pstmt=con.prepareStatement(insert into tb_account(id,name,balance)values(?,?,?);,UUID uuid=UUID.randomUUID();pstmt.setString(1,uuid.toString();/设置id字段的值pstmt.setString(2,王军);/设置name字段的值pstmt.setInt(3,1000);/设置balance字段的值pstmt.executeUpdate();/用前面的实参值,替代原来的参数,执行SQL语
22、句,PreparedStatement pstmt=con.prepareStatement(select id,name,balance from tb_account where name=?,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);pstmt.setString(1,张华);ResultSet rs=pstmt.executeQuery();,15.6 CallableStatement,CallableStatementJDBC中提供了CallableStatement 对象为所有的 DBMS 实现了一种以
23、标准形式调用储存过程的方法。对储存过程的调用是 CallableStatement对象所含的主要内容。,CREATE procedure sumBalance low int,high intasbegindeclare total intselect total=sum(balance)from tb_account where balance=low and balance=highreturn totalend;,CallableStatement cstmt=con.prepareCall(?=call sumBalance(?,?);,Connection con=null;try(
24、01)con=DriverManager.getConnection(url);(02)String procName=?=call sumBalance(?,?);(03)CallableStatement cstmt=con.prepareCall(procName);(04)cstmt.setInt(2,1000);(05)cstmt.setInt(3,10000);(06)cstmt.registerOutParameter(1,Types.INTEGER);(07)cstmt.execute();(08)System.out.println(cstmt.getInt(1);(09)c
25、stmt.close();(10)con.close();catch(SQLException e)e.printStackTrace();,15.7 JDBC事务,事务数据库的事务就是对现实生活中事务的模拟,它由一组在业务逻辑上相互依赖的SQL语句组成。为了保证事务的完整性,JDBC提供了相应的事务控制机制。事务提交模式在JDBC编程模型中,一个数据库连接建立时,就处于一个自动提交模式,每一个SQL语句被执行完成后就会被自动提交,反映至数据库中。当需要把几条逻辑上相关的SQL组成一个事务执行时,就需要关闭事务自动提交模式。如下面的语句所示:con.setAutoCommit(false);/
26、关闭自动提交模式一旦关闭了事务自动提交模式,不会有任何SQL语句被提交至数据库系统执行,除非显式的调用提交方法。,public void transfer(Account a,Account b,int amount)throws SQLException PreparedStatement pstmt=null;String sql=update tb_account set balance=?where id=?;try pstmt=con.prepareStatement(sql,ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDAT
27、ABLE);/关闭自动提交模式,以下语句直到commit()前都作为一个完整的事务执行con.setAutoCommit(false);/开始处理转账,将账户a上减少amount元pstmt.setInt(1,a.getBalance()-amount);pstmt.setString(2,a.getId();pstmt.executeUpdate();/将账户b上增加amount元pstmt.setInt(1,b.getBalance()+amount);pstmt.setString(2,b.getId();pstmt.executeUpdate();mit();/提交上面的两次操作 ca
28、tch(SQLException e)con.rollback();/回滚操作,取消本次事务中的所有已执行SQL语句throw e;/继续抛出异常,告诉调用者转账没有成功,15.8数据源和连接池,通过数据源对象也可以获得到数据库的连接。连接池技术是一项能够极大提升数据库访问性能的技术,其本质是将实现建立好的若干连接存放于集合中,利用代理技术提供连接的获取和释放。,SQLServerDataSource ds=new SQLServerDataSource();ds.setUser(sa);ds.setPassword(123456);ds.setServerName(localhost);ds
29、.setPortNumber(1433);ds.setDatabaseName(bank);con=ds.getConnection();,SQLServerConnectionPoolDataSourceds=new SQLServerConnectionPoolDataSource();PooledConnection pool=ds.getPooledConnection();ds.setUser(sa);ds.setPassword(123456);ds.setServerName(localhost);ds.setPortNumber(1433);ds.setDatabaseName(bank);con=pool.getConnection();/通过连接池获得对象,