1:resultSet
当创建一个ResultSet时,你可以设置三个属性:
类型
ResultSet.TYPE_FORWARD_ONLY
该常量指示光标只能向前移动的 ResultSet 对象的类型。
ResultSet.TYPE_SCROLL_INSENSITIVE
该常量指示可滚动但通常不受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
ResultSet.TYPE_SCROLL_SENSITIVE
该常量指示可滚动并且通常受 ResultSet 底层数据更改影响的 ResultSet 对象的类型。
并发
ResultSet.CONCUR_READ_ONLY
该常量指示不可以更新的 ResultSet 对象的并发模式。
ResultSet.CONCUR_UPDATABLE
该常量指示可以更新的 ResultSet 对象的并发模式。
可保存性
ResultSet.HOLD_CURSORS_OVER_COMMIT
该常量指示提交当前事务时,具有此可保存性的打开的 ResultSet 对象将保持开放。
ResultSet.CLOSE_CURSORS_AT_COMMIT
该常量指示提交当前事务时,具有此可保存性的打开的 ResultSet 对象将被关闭。
在创建Statement或PreparedStatement时已经设置了这些值,如下所示:
Statement statement = connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_OVER_COMMIT ); PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_OVER_COMMIT );
1.1最基本的ResultSet.
最基本的ResultSet是因为,这个ResultSet他起到的作用就是完成了查询结果的存储功能,而且只能读去一次,不能够来回的滚动读取. 最常用的
1.2 可滚动的ResultSet类型
next(),previous(), first(),last() 移动绝对行 absolute(int n),移动相对行relative(int n),
ResultSet.TYPE_FORWARD_ONLY
只能向前滚动
ResultSet.TYPE_SCROLL_INSENSITIVE
实现任意的前后滚动, 对于修改不敏感
Result.TYPE_SCROLL_SENSITIVE
实现任意的前后滚动, 对于修改敏感.
1.3 可更新的ResultSet
ResultSet对象可以完成对数据库中表的修改,但是我知道ResultSet只是相当于数据库中表的视图,所以并不时所有的ResultSet只要设置了可更新就能够完成更新的,能够完成更新的ResultSet的SQL语句必须要具备如下的属性: 通过 并发下面属性设置
a,只引用了单个表.
b,不含有join或者group by子句.
c,那些列中要包含主关键字.
执行顺序UpdatXXX 更新操作执行必须执行
1:moveToInsertRow() 是把ResultSet移动到插入行 这个插入行是表中特殊的一行 moveToCurrentRow() 移动到插入行 如果之前Insert,那么就移动到之前Insert()0哪一行,没有Insert 就没有效果 2:UpdateXXX() 3:insertRow()
1.4 可保持的ResultSet
所有的Statement的查询对应的结果集是一个,如果调用Connection的commit()方法也会关闭结果集.
通过设置 HOLD_CURSORS_OVER_COMMIT 来保持数据
2:PrepareStatement
特点: 禁止了拼接SQL可以注入的现象,将会SQL传入数据库编译通过设置参数方式保证安全性
select * from user where name='aa' and password='bb' or 1=1 //类始于这种SQL的注入方式
2.1: 基本操作
executeQuery() 执行查询
executeUpdate() 执行CUD操作
execute() 执行DDL操作
executeLargeUpdate() 执行超大SQL语句
String sql = "select * from user"; PreparedStatement preparedStatement = connection.prepareStatement(sql); ResultSet resultSet = preparedStatement.executeQuery(); while (resultSet.next()) { int id = resultSet.getInt("id"); String username = resultSet.getString("username"); String birthday = resultSet.getString("birthday"); String sex = resultSet.getString("sex"); String address = resultSet.getString("address"); System.out.println(" " + username + " " + birthday + " " + sex + " " + address); }
2.2 复用pststemetn
即为一次创建多次使用, 通过connection创建prepareStatement 多次使用 prepareStatement
特点 参数可以变,但是SQl 是不变的
PreparedStatement preparedStatement = connection.prepareStatement(sql);//创建prepareStatement preparedStatement.setString(1,"Fant.J"); preparedStatement.setInt(2,27); int result = preparedStatement.executeUpdate(); // 第一次使用 preparedStatement.setString(1,"Fant.J reUseTest"); preparedStatement.setInt(2,27); preparedStatement.executeUpdate();//第二次使用 但是都是用的第一次创建ps 时的编译语句
2.3 性能分析
PreparedStatement是Statement的子类,区别:
PreparedStatement 编译一次,可以将多条SQL语句汇聚到一起执行,提高执行效率
Statement 是每一条SQL执行一次,100条SQL 就要执行100次
两个级别的复用:
JDBC驱动程序重新使用PreparedStatement。
数据库重用PreparedStatement。
3:执行批量SQL
用到 addBatch()和executeBatch()方法 用于 Insert Update Delete 等SQL的处理
3.1: statemet 方式
Statement statement = null; try{ statement = connection.createStatement(); statement.addBatch("update people set firstname='aaa' where id=123"); statement.addBatch("update people set firstname='bbb' where id=456"); statement.addBatch("update people set firstname='ccc' where id=789"); int[] recordsAffected = statement.executeBatch(); // 返回每个SQl执行后影响的元组数 } finally { if(statement != null) statement.close(); }
3.2: preparedstatement 方式
String sql = "update user set username=? where id=?"; PreparedStatement preparedStatement = null; try{ preparedStatement =connection.prepareStatement(sql); preparedStatement.setString(1, "aaa"); preparedStatement.setLong (2, 123); preparedStatement.addBatch(); preparedStatement.setString(1, "bbb"); preparedStatement.setLong (2, 456); preparedStatement.addBatch(); int[] affectedRecords = preparedStatement.executeBatch();// 返回每条语句执行影响的行数 }finally { if(preparedStatement != null) { preparedStatement.close(); } }
4: 事物transaction
对出现异常的SQL代码进行回退(可能系统异常),保证数据一致性
4.1 基本处理
Connection connection = ... try{ connection.setAutoCommit(false); // 这种处理方式 没有回滚点 出错将返回整个SQL代码 // create and execute statements etc. connection.commit(); } catch(Exception e) { connection.rollback(); } finally { if(connection != null) { connection.close(); } }
4.2 断点事物处理
Connection conn = JdbcUtils.getConnection(); PreparedStatement ps = null; Savepoint savepoint=null; //断点 try { conn.setAutoCommit(false); savepoint = conn.setSavepoint(); //设置当前断点1 当然可以有多个断点 ps = conn.prepareStatement("update account set balance = balance - ? where name=?"); ps.setInt(1, 500); ps.setString(2, "Jack"); ps.executeUpdate(); //出现异常 System.out.println(100 / 0); //给 rose 加钱 ps = conn.prepareStatement("update account set balance = balance + ? where name=?"); ps.setInt(1, 500); ps.setString(2,"Rose"); ps.executeUpdate(); //提交事务 conn.commit(); System.out.println("转账成功"); } catch (Exception e) { e.printStackTrace(); try { conn.rollback(savepoint); } catch (Exception e1) { e1.printStackTrace(); } }finally { JdbcUtils.close(conn, ps); } }
5 存储过程
DELIMITER // # 分割符号 默认是; 在多条语句时候需要进行改变
DELIMITER // # 分割符号 默认是; 在多条语句时候需要进行改变 CREATE PROCEDURE findStuById(IN pid INTEGER) BEGIN SELECT * FROM student WHERE id=pid; END // DELIMITER ;
通过Call关键字调用储存过程 CallableStatement处理存储过程 PreparedStatement ==处理DML DML DQL
@Test public void test_producer() throws SQLException { Connection conn = JdbcUtils.getConnection(); CallableStatement call = conn.prepareCall("CALL findStuByID(?)"); call.setInt(1, 1); ResultSet resultSet = call.executeQuery(); Student student=null; while(resultSet.next()) { int id = resultSet.getInt("id"); String name = resultSet.getString("name"); boolean gender = resultSet.getBoolean("gender"); Date birthday = resultSet.getDate("birthday"); student= new Student(id, name, gender, birthday); } System.out.println(student); }
6 元数据类型
6.1 DatabaseMetaData 数据库元数据
数据库基本信息
Connection conn = JdbcUtils.getConnection(); DatabaseMetaData metaData = conn.getMetaData(); int majorVersion = metaData.getDatabaseMajorVersion(); String productVersion = metaData.getDatabaseProductVersion(); String driverName = metaData.getDriverName(); String url = metaData.getURL(); String userName = metaData.getUserName(); System.out.println(majorVersion);//8 System.out.println(productVersion);//8.0.13 System.out.println(driverName);//MySQL Connector/J System.out.println(url);//jdbc:mysql://127.0.0.1:3306/day System.out.println(userName);//root@localhost
数据库所有信息的获取
getTableTypes() 方法 可以使用正则表达式
Connection conn = JdbcUtils.getConnection(); DatabaseMetaData metaData = conn.getMetaData(); // String catalog = "day"; //对应数据库名称 String schemaPattern = "*"; // mysql没有这个概念 sql server对应用户名称操作权限 String tableNamePattern = "student"; // 对应数据库名称 String[] types = {"TABLE"}; // 数据库中具体的类型 "TABLE"、"VIEW"、"SYSTEM TABLE"、"GLOBAL TEMPORARY"、"LOCAL TEMPORARY"、"ALIAS" 和 "SYNONYM"。 ResultSet result = metaData.getTables( catalog, schemaPattern, tableNamePattern, types ); while(result.next()) { String catalogName = result.getString(1); String schemaName = result.getString(2); String tableName = result.getString(3); String columName = result.getString(6); System.out.println(tableName); System.out.println(catalogName); System.out.println(columName); }
在表中列出列 getColumS()
Connection conn = JdbcUtils.getConnection(); DatabaseMetaData metaData = conn.getMetaData(); // String catalog = "day"; // 对应数据库名称 String schemaPattern = "*"; // mysql没有这个概念 sql server对应用户名称操作权限 String tableNamePattern = "student"; // 对应数据库名称 String columnNamePattern = null; ResultSet result = metaData.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); while (result.next()) { String columName = result.getString(4);// 列名称 String data_type = result.getString(5);// 列类型 System.out.println(columName); System.out.println(data_type); }
主键信息
getPrimaryKeys() 获取主键信息
getExportedKeys() 获取外键信息
Connection conn = JdbcUtils.getConnection(); DatabaseMetaData metaData = conn.getMetaData(); // String catalog = "day"; //执行库 String schemaPattern = null; // mysql为null String tableNamePattern = "student"; ResultSet result = metaData.getPrimaryKeys(catalog, schemaPattern, tableNamePattern); metaData.getExportedKeys(catalog, schema, table) while (result.next()) { String tablename = result.getString(3);// 表名 String keyname = result.getString(4);//主键名 System.out.println(tablename); System.out.println(keyname);
6.2 ParameterMetaData 参数元数据类型
对于传递的SQL中的参数(占位符? )的个数 数据进行处理
前提:
增加 &generateSimpleParameterMetadata=true
所有的参数认为是字符串(VARCHAR)类型
注意:ParameterMetaData许多方法MySQL并不友好支持,比如像获取指定参数的SQL类型的getParameterType方法,如果数据库驱动连接URL只是简单的“jdbc:mysql://localhost:3306/jdbcdemo”那么MyEclipse会抛出SQLException异常,必须要将URL修改为“jdbc:mysql://localhost:3306/jdbcdemo?generateSimpleParameterMetadata=true”才行。但是像getParameterType等等与其他的方法也没多好用,因为如下面的例子,这些方法好像只会将所有的参数认为是字符串(VARCHAR)类型
public void test_ParameterINFO() throws SQLException { Connection conn = JdbcUtils.getConnection(); String sql="SELECT * FROM STUDENT WHERE id=?"; PreparedStatement preparedStatement = conn.prepareStatement(sql); ParameterMetaData pMetaData = preparedStatement.getParameterMetaData(); preparedStatement.setInt(1, 1); int count = pMetaData.getParameterCount(); for(int i = 1; i <= count; i ++) { System.out.print(pMetaData.getParameterClassName(i) + " "); System.out.print(pMetaData.getParameterType(i) + " "); System.out.println(pMetaData.getParameterTypeName(i)); } //执行查询操作 preparedStatement.executeQuery(); //执行查询操作 ResultSet rs = preparedStatement.executeQuery(); while(rs.next()) { System.out.println(rs.getInt("id") + " " + rs.getString("name") + " " + rs.getBoolean("gender") + " " + rs.getDate("birthday")); } }
6.3 ResultSetMetaData 结果集元数据
通过 ResultSet.getMetaData();获取 ,主要对于表中的一些列进行获取,处理
Connection conn = JdbcUtils.getConnection(); String sql="SELECT * FROM STUDENT WHERE id=?"; PreparedStatement pStatement = conn.prepareStatement(sql); pStatement.setInt(1, 1); ResultSet reSet = pStatement.executeQuery(); ResultSetMetaData metaData = reSet.getMetaData(); int count = metaData.getColumnCount(); for (int i = 1; i <= count; i++) { String columnClassName = metaData.getColumnClassName(i);//类型 String columnName = metaData.getColumnName(i);//列名 int columnType = metaData.getColumnType(i);//列属性值 String typeName = metaData.getColumnTypeName(i);//列类型名 String label = metaData.getColumnLabel(i);//列名 System.out.println(columnClassName+" "+columnName+" "+columnType+" "+typeName+" "+label); }