Java 核心技术 卷II (4章)--数据库编程
来源:互联网 发布:小米6怎么设置4g网络 编辑:程序博客网 时间:2024/05/21 02:20
Java 核心技术 卷II (4章)
---数据库编程
1、jdbc设计
1)Jdbc是java能够通过SQL访问数据库的一套javaAPI;
2)Jdbc是一套能与多种关系数据库提供统一访问Java接口方法;
2、核心API方法介绍
创建执行对象:
Stattement stat = conn.createStatement();
stat.executeUpdate():返回受SQL命令影响的行数,或者对不返回行数的语句(DDL语句)返回0
ResultSet rs = stat.executeQuery(String SQL)
结果集使用:
while(rs.next()){ . . . . . .}
如何取值?不同的参数类型有不同的访问器,可以通过下标和类名获取
rs.getDouble (1);rs.getDouble(“price”)
说明:
1)数据库索引与数组的索引不同,数据库的列序号从1开始计算的。
2)使用get方法的类型与列的数据类型不一致,get方法会尝试合理的类型转换,如rs.getString(“price”),会将price列的浮点值转换为字符串。
3)做通用话数据封装时,可以使用getObject进行通用取。
如何管理连接??
使用完ResultSet、Statement或Connection对象,应立即使用close方法关闭,调用顺序从里到外(ResultSet、Statement、Connection)
如何解析SQL异常
SQLWarning w = stat.getWarning();while(w != null){ do something with w w = w.nextWarning();}
说明:还有其他的很多方法,见书!!
相关其他方法:
Connection : Statement createStatement() voidcolse()Statement ResultSetexecuteQuery(String sql) intexecuteUpdate(String sql) booleanexecute(String sql) ResultSetgetResultSet() intgetUpdateCount() voidclose() booleanisColsed() void coseOncompleion()ResultSet booleannext() XxxgetXxx(int columnNumber) XxxgetXxx(String columnName) <T> TgetObject(int columnNumber,Class<T> type) <T> T getObject(intcolumnName,Class<T> type) int findColumn(String columnName) void close() boolean isClosed();
3、不同的执行对象
3.1预备语句(预编译语句)
如何进行参数化查询??
PreparedStatement stat = conn.prepareStatement(“select *from user where id = ?”);stat.serInt(1,12);ResultSet rs = stat.executeQuery();
许多数据库通常都会有自动缓存预备语句,如果相同的查询被预备两次,数据库通常会直接重用查询策略。
不使用Statement:
1)使用Statement,若是进行参数化查询,每次查询都会建立新的查询语句,消耗查询性能;
2)使用Statement,如果进行参数化查询,需要拼接SQL,容易造成SQL注入。
使用statement:
如果进行的查询是不带参数的,使用Statement比PrepredStatement更高校,
相关其他方法:
Connection PreparedStatementprepareStatement(String sql)PreparedStatement voidsetXxx(int n, Xxx x); voidclearParameters(); ResultSetexecuteQuery() intexecuteUpdate() 【如果执行的是数据定义语句(DDL),如CREATE TABLE,则返回0】
3.2 CallableStatement执行存储过程
n CALL pro_findById2(5,@NAME);
(1)存储过程
mysql> DELIMITER $mysql> CREATE PROCEDURE pro_findById2(IN eidINT,OUT vname VARCHAR(20))-> BEGIN-> SELECT empname INTO vname FROM employeeWHERE id = eid;-> END $;
(2)测试
String sql = "CALL pro_findById2(?,?)"; //第一个?是输入参数,第二个?是输出参数cstmt =conn.prepareCall(sql);//设置输入参数cstmt.setInt(1, 6);//设置输出参数(注册输出参数)cstmt.registerOutParameter(2,java.sql.Types.VARCHAR);//返回结果到输出参数中cstmt.executeQuery();//从输出参数的索引中,获取结果String result = cstmt.getString(2);
4、其他
4.1读写Lob
Lob分两种:一种字符型大对象Clob,二进制大对象Blob
Blob:
存入数据库:
String sql = " insert into test(img)values(?)";// 连接con = JdbcUtil.getConnection();// pstmt 对象pstmt = con.prepareStatement(sql);// 获取图片流InputStream in = App_text.class.getResourceAsStream("7.jpg");pstmt.setBinaryStream(1, in); // 执行保存图片pstmt.execute();
从数据库读取:
String sql = "select img from test where id=2;";// 连接con = JdbcUtil.getConnection();pstmt = con.prepareStatement(sql);rs = pstmt.executeQuery();if (rs.next()) { // 获取图片流 InputStream in =rs.getBinaryStream("img"); // 图片输出流 FileOutputStream out = new FileOutputStream(new File("c://1.jpg")); int len = -1; byte b[] = new byte[1024]; while ((len = in.read(b)) != -1) { out.write(b, 0,len); }}
Clob:
存入数据库:
String sql = "insert into test(content)values(?)";con = JdbcUtil.getConnection();pstmt = con.prepareStatement(sql);// 设置参数// 先获取文件路径String path = App_text.class.getResource("tips.txt").getPath();FileReader reader = new FileReader(new File(path));pstmt.setCharacterStream(1,reader);// 执行sqlpstmt.executeUpdate();
从数据库读取:
String sql = "select * from test;";con = JdbcUtil.getConnection();pstmt = con.prepareStatement(sql);rs = pstmt.executeQuery();if (rs.next()) { // 获取长文本数据,方式1: //Reader r = rs.getCharacterStream("content"); // 获取长文本数据,方式2: System.out.print(rs.getString("content"));}
4.2获取主键
String sql = "insert into articlevalues(null,?,now(),?)";//执行语句的同时返回一个主键集合PreparedStatement pst =DB.prepareStmt(conn, sql,Statement.RETURN_GENERATED_KEYS);pst.setInt(1,0);pst.setInt(2, 0);pst.executeUpdate(); //得到主键集合ResultSet rsKey =pst.getGeneratedKeys();rsKey.next();rootId = rsKey.getInt(1);
4.3多结果集
若是执行存储过程或者在单个查询中提交了多个select语句,那么一个数据库能返回多个结果集。
关键点:重复调用getMoreResult方法移动到下一项结果集。
CREATE PROCEDURE proc_test()BEGINselect * from person;select * from person;END;
Connection conn = getConn();String sql = "{call proc_test()}"; CallableStatement ctmt = conn.prepareCall(sql);boolean hadResults = ctmt.execute(); int i=0; ResultSet rs = null; while (hadResults) { System.out.println("result No:----"+(++i)); rs = ctmt.getResultSet(); while (rs !=null && rs.next()){ int id1 = rs.getInt(1); String name1 = rs.getString(2); System.out.println(id1 +":" + name1); } hadResults = ctmt.getMoreResults(); //检查是否存在更多结果集 }
4.4可滚动&可更新结果集
可滚动结果集:
Connection conn = getConn();/* *conn.createStatement(type,concurrency) */// TYPE_SCROLL_SENSITIVE:结果集能滚动,对数据库变化敏感// CONCUR_UPDATABLE:结果集可以用于更新数据库Statement stat = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);ResultSet rs = stat.executeQuery("select * from user");// 移动游标方法rs.next();rs.relative(3);rs.previous();rs.relative(-1);rs.absolute(5); // 特殊位置rs.first();rs.last();rs.beforeFirst();rs.afterLast();
ps:因为在操作过程中,一直连接着数据库,可滚动结果集,消耗数据库资源巨大。
可更新结果集:
Connection conn = getConn();// TYPE_SCROLL_SENSITIVE:结果集能滚动,对数据库变化敏感// CONCUR_UPDATABLE:结果集可以用于更新数据库Statement stat = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);ResultSet rs = stat.executeQuery("select * from user");rs.next();rs.updateString("name","u-2");rs.updateInt("age", 22);rs.updateRow(); rs.insertRow();rs.deleteRow();
ps:
①更新数据库行,必须要updateRow(),这样可以将变化同步到数据库;插入数据库一行,使用updateXxx,之后要使用insertRow(),rs.moveToCurrentRow();deleteRow()直接将当前行删除。
②如果查询语句涉及到多个表的连接操作,那么它所产生的结果集将是不可更新的;若是利用主键连接表的,那么它还是可更新结果集。
4.5行集
RowSet接口扩展自ResultSet接口,却无需始终保持与数据库连接,可以完美解决可滚动结果集的,数据库资源消耗问题。
行集分几种:
CachedRowSet:缓存的行集。
WebRowSet:缓存的行集,可保存为XML文件,该文件可移动到Web应用。
FilteredRowSet和JoinRowSet:支持对行集的轻量级操作。
JdbcRowSet:是ResultSet接口的瘦包装器。
行集中的数据来源??
使用JDBC驱动程序从数据库检索的数据
从其他数据源获得的数据,如文件数据
行集(Row Set)的优点??
1)可以断开数据库连接操作数据;
2)可以在分布式系统中的不同组件之间传递;
3)默认可更新,可滚动,可序列化,可以方便的在网络间传输;
4)可以方便的使数据在行集与JavaBean对象之间进行转换。行集中的一行数据可以封装为一个JavaBean对象。
Connection conn = getConn();PreparedStatement pst=conn.prepareStatement("select * from user"); //必须设置非自动提交 conn.setAutoCommit(false); ResultSet rs=pst.executeQuery(); //创建行集实例 CachedRowSetImpl rowset=newCachedRowSetImpl(); //填充 rowset.populate(rs); //这里已经关闭结果集了!!!rs.close(); pst.close(); // 在关闭连接之前进行更新操作rowset.absolute(5); rowset.updateInt("English", 55); rowset.updateRow(); //更新 rowset.acceptChanges(conn); //提交 //输出结果集之前,关闭连接 conn.close(); //输出行集数据 while(rowset.next()){ System.out.print(rowset.getInt("id")+"\t"); System.out.print(rowset.getInt("Chinese")+"\t"); System.out.print(rowset.getInt("English")+"\t"); System.out.println(rowset.getInt("history")); }
5、元数据
元数据:描述数据库或者其组成部分的数据。
元数据分为:
关于数据库的元数据(DatabaseMetaData)
关于结果集的元数据(ResultSetMetaData)
关于预备语句参数的元数据(ParameterMetaData)
数据库元数据
// 获取连接Connection conn = JdbcUtil.getConnection();// 获取数据库元数据DatabaseMetaData metaData = conn.getMetaData();//alt + shift + L 快速获取方法返回值 System.out.println(metaData.getUserName());System.out.println(metaData.getURL());System.out.println(metaData.getDatabaseProductName());
参数元数据
// 获取连接Connection conn = JdbcUtil.getConnection();// SQLString sql = "select * from dept wheredeptid=? and deptName=?";// Object[] values = {"tom","888"}; PreparedStatement pstmt = conn.prepareStatement(sql);// 参数元数据ParameterMetaData p_metaDate = pstmt.getParameterMetaData();// 获取参数的个数int count = p_metaDate.getParameterCount();// 测试System.out.println(count);
结果集元数据
Connection conn = JdbcUtil.getConnection();PreparedStatement pstmt = conn.prepareStatement("select * from dept ");ResultSet rs = pstmt.executeQuery();// 得到结果集元数据(目标:通过结果集元数据,得到列的名称)ResultSetMetaData rs_metaData = rs.getMetaData(); // 迭代每一行结果while (rs.next()) { // 1. 获取列的个数 int count = rs_metaData.getColumnCount(); // 2. 遍历,获取每一列的列的名称 for (int i=0; i<count; i++) { // 得到列的名称 String columnName= rs_metaData.getColumnName(i + 1); // 获取每一行的每一列的值 ObjectcolumnValue = rs.getObject(columnName); // 测试 System.out.print(columnName +"=" + columnValue + ","); } System.out.println();}
说明:getObject可以拿到任意类型行的值
6、事务
事务:将一组语句构建成一个事务,当所有语句都顺利执行,事务可以被提交。否则,如果其中某个语句遇到错误,那么事务将被回滚。
事务:确保数据库万整性。
默认情况下,数据库连接处于自动提交模式。
Connection con;PreparedStatement pstmt;String sql_zs = "UPDATE account SETmoney=money-1000 WHERE accountName='张三';";String sql_ls = "UPDATE1 account SETmoney=money+1000 WHERE accountName='李四';";try { con = JdbcUtil.getConnection();// 默认开启的隐士事务 // 一、设置事务为手动提交 con.setAutoCommit(false); /*** 第一次执行SQL ***/ pstmt = con.prepareStatement(sql_zs); pstmt.executeUpdate(); /*** 第二次执行SQL ***/ pstmt = con.prepareStatement(sql_ls); pstmt.executeUpdate();} catch(Exception e) { try { // 二、出现异常,需要回滚事务 con.rollback(); } catch (SQLException e1) { e.printStackTrace();}} finally { try { // 三、所有的操作执行成功,提交事务 con.commit(); JdbcUtil.closeAll(con,pstmt, null); } catch (SQLException e) { }}
保存点:使用保存点可以更细粒度的控制回滚操作
. . .try { con = JdbcUtil.getConnection();// 默认开启的隐士事务 // 一、设置事务为手动提交 con.setAutoCommit(false); /*** 第一次执行SQL ***/ pstmt = con.prepareStatement(sql_zs); pstmt.executeUpdate(); Savepoint svpt = pstmt.setSavepoint(); /*** 第二次执行SQL ***/ pstmt = con.prepareStatement(sql_ls); pstmt.executeUpdate();} catch(Exception e) { // 二、出现异常,需要回滚到回滚点 con.rollback(svpt); . . .} finally { . . .}
Ps:当不需要回滚点时,可以释放回滚点:使用conn.releaseSavepoint(svpt)。
7、批量操作
当程序需要执行多条语句时,可以使用批量操作,如执行上万条insert语句,可以使用批量更新来提高程序性能。
// SQLString sql = "INSERT INTOadmin(userName,pwd) values(?,?)";try { // 获取连接 con = JdbcUtil.getConnection(); // 创建stmt pstmt = con.prepareStatement(sql); // 【预编译SQL语句】 for (int i=0; i<list.size(); i++) { Admin admin =list.get(i); // 设置参数 pstmt.setString(1,admin.getUserName()); pstmt.setString(2, admin.getPwd()); // 添加批处理 pstmt.addBatch(); // 【不需要传入SQL】 // 测试:每5条执行一次批处理 if (i % 5 == 0) { // 批量执行 pstmt.executeBatch(); // 清空批处理 pstmt.clearBatch(); } } // 批量执行 pstmt.executeBatch(); // 清空批处理 pstmt.clearBatch();} catch(Exception e) { e.printStackTrace();} finally { JdbcUtil.closeAll(con, pstmt, rs);}
- Java 核心技术 卷II (4章)--数据库编程
- 数据库编程(Java核心技术卷Ⅱ)
- JAVA2核心技术卷II:高级特性(原书第7版) -- 第4章. 数据库编程
- Java 核心技术卷2 第五章 数据库编程
- 读书笔记——JAVA核心技术-卷II
- Java核心技术卷II知识点总结
- Java核心技术卷(第4章 对象与类)
- 读《Java 核心技术 卷II》高级特性(原书第9版)
- Java核心技术 卷II 高级特性 第9版(中文).pdf 免费下载
- 《Java核心技术 卷II 高级特性(原书第9版)》
- Java核心技术 ( 卷 I ) 读书笔记(第一~三章)
- Java核心技术(卷I)读书笔记 第四~六章
- Java核心技术(卷I)读书笔记 第七~九章
- 《java核心技术_卷一:基础知识》(一)4-10章 思维导图
- java 核心技术 卷1 第四章 CalendarTest
- java 核心技术 卷1 第五章 EnumTest
- Java核心技术卷2---第二章 XML
- Java核心技术卷1 第十四章 多线程
- 接口隔离原则
- java笔记
- Nginx+Node:Proxy_pass路径设置
- XDebug安装配置教程
- 什么是精灵图?css Sprites怎么用?
- Java 核心技术 卷II (4章)--数据库编程
- 1000.加密算法
- 宝宝攻略(2) 神经网络向量化
- jquery选择器
- c++对负数取余的判定
- C#图片上传与下载
- javascript如何用递归写一个简单的树形结构
- mvn
- Ajax获取php返回json数据动态生成select下拉框