JDBC核心API
来源:互联网 发布:德国香肠 知乎 编辑:程序博客网 时间:2024/06/05 10:30
1. JDBC核心API
1.1. Statement
1.1.1. Statement执行查询
通过Connection对象创建Statement的方式:
- Connection.createStatement();
Connection.createStatement();
执行INSERT, UPDATE和DELETE等DML操作:
- Statement.executeUpdate();
Statement.executeUpdate();
执行SELECT:
- Statement.executeQuery();
Statement.executeQuery();
通过Statement对象返回SQL语句执行后的结果集:
- String sql = "select empno, ename, sal, hiredate from emp";
- Statement stmt = con.createStatement();
- ResultSetrs = stmt.executeQuery(sql);
- //对rs的处理
- //代码略
- stmt.close();
String sql = "select empno, ename, sal, hiredate from emp";Statement stmt = con.createStatement();ResultSetrs = stmt.executeQuery(sql);//对rs的处理//代码略stmt.close();
1.1.2. Statement执行插入
Statement.executeUpdate(sql)方法将返回SQL语句执行后影响的记录数:
- String sql = "insert into emp(empno, ename, job, sal) values(1001, ‘张三丰’,‘Manager’9500)";
- int flag = -1;
- try {
- con = ConnectionSource.getConnection();
- stmt = con.createStatement();
- flag = stmt.executeUpdate(sql);
- //处理结果
- }catch(SQLException e){
- //处理异常
- }
String sql = "insert into emp(empno, ename, job, sal) values(1001, ‘张三丰’,‘Manager’9500)";int flag = -1;try {con = ConnectionSource.getConnection();stmt = con.createStatement();flag = stmt.executeUpdate(sql); //处理结果}catch(SQLException e){ //处理异常}
1.1.3. Statement执行更改
和INSERT操作完全相同,只是SQL语句不同:
- String sql = "update emp set sal = 9900 where empno = 1001";
- int flag = -1;
- try {
- con = ConnectionSource.getConnection();
- stmt = con.createStatement();
- flag = stmt.executeUpdate(sql);
- //处理结果
- }catch(SQLException e){
- //处理异常
- }
String sql = "update emp set sal = 9900 where empno = 1001";int flag = -1;try {con = ConnectionSource.getConnection();stmt = con.createStatement();flag = stmt.executeUpdate(sql); //处理结果}catch(SQLException e){ //处理异常}
1.2. PreparedStatement
1.2.1. PreparedStatement原理
Statement主要用于执行静态SQL语句,即内容固定不变的SQL语句。Statement每执行一次都要对传入的SQL语句编译一次,效率较差。
某些情况下,SQL语句只是其中的参数有所不同,其余子句完全相同,适用于PreparedStatement。
PreparedStatement的另外一个好处就是预防sql注入攻击。
PreparedStatement是接口,继承自Statement接口。
使用PreparedStatement时,SQL语句已提前编译,三种常用方法 execute、executeQuery和executeUpdate已被更改,以使之不再需要参数。
图-1 PreparedStatement原理
PreparedStatement实例包含已事先编译的 SQL 语句,SQL 语句可有一个或多个 IN 参数,IN参数的值在 SQL 语句创建时未被指定。该语句为每个 IN 参数保留一个问号(“?”)作为占位符。
每个问号的值必须在该语句执行之前,通过适当的setInt或者setString等方法提供。
由于PreparedStatement对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为PreparedStatement对象,以提高效率。
通常批量处理时使用PreparedStatement。
- //SQL语句已发送给数据库,并编译好为执行作好准备
- PreparedStatementpstmt = con.prepareStatement(
- "UPDATE emp SET job= ? WHERE empno= ?");
- //对占位符进行初始化
- pstmt.setLong(1, "Manager");
- pstmt.setInt(2,1001);
- //执行SQL语句
- pstmt.executeUpdate();
//SQL语句已发送给数据库,并编译好为执行作好准备PreparedStatementpstmt = con.prepareStatement( "UPDATE emp SET job= ? WHERE empno= ?");//对占位符进行初始化pstmt.setLong(1, "Manager");pstmt.setInt(2,1001);//执行SQL语句pstmt.executeUpdate();
1.2.2. 通过PreparedStatement提升性能
图-2 数据库执行SQL语句过程
在数据库执行SQL语句过程中,制定执行计划开销巨大。
数据库本身具备SQL缓存功能,可以对statement的执行计划进行缓存,以免重复分析。其缓存原理是使用statement本身作为key并将执行计划存入与statement对应的缓存中,对曾经执行过的statements,再运行时执行计划将重用。
举例:
- SELECT a, b FROM t WHERE c = 1;
SELECT a, b FROM t WHERE c = 1;
再次向数据库发送相同的statement时,数据库会对先前使用过的执行计划进行重用,降低开销。
但是,如下两条语句被视作不同的SQL语句,执行计划不可重用:
- SELECT a, b FROM t WHERE c = 1;
- SELECT a, b FROM t WHERE c = 2;
SELECT a, b FROM t WHERE c = 1;SELECT a, b FROM t WHERE c = 2;
这就是为什么要使用PreparedStatement:
- //执行计划可重用
- String sql ="select a,b from t where c = ?";
- PreparedStatementps = conn.prepareStatement(sql);
- for (inti = 0; i< 1000; i++) {
- ps.setInt(1, i);
- ResultSetrs = ps.executeQuery();
- //处理rs,省略
- rs.close();
- }
- ps.close();
//执行计划可重用String sql ="select a,b from t where c = ?";PreparedStatementps = conn.prepareStatement(sql);for (inti = 0; i< 1000; i++) {ps.setInt(1, i);ResultSetrs = ps.executeQuery(); //处理rs,省略rs.close();}ps.close();
1.2.3. SQL Injection简介
场景:如下SQL语句被发送到数据库中:
- String sql = "select * from t where username = '" + name + "' and password = '" + passwd + "'";
String sql = "select * from t where username = '" + name + "' and password = '" + passwd + "'";
输入用户名和密码参数后,数据库接受到的完整sql语句将是这种形式:
- select * from t where username = 'scott' and password = 'tiger';
select * from t where username = 'scott' and password = 'tiger';
如果用户输入的passwd参数是:' or '1'='1, 则数据库收到的SQL语句将是:
- select * from t where username = 'scott' and password = '' or '1'='1’;
select * from t where username = 'scott' and password = '' or '1'='1’;
此SQL语句的where条件将永远为true。即用户不需要输入正确的帐号密码,也能登录。这种现象称作SQL注入(SQL Injection)。
1.2.4. 通过PreparedStatement防止SQL Injection
对JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement无效,因为PreparedStatement不允许在插入参数时改变SQL语句的逻辑结构。
使用预编译的语句对象时,用户传入的任何数据不会和原SQL语句发生匹配关系,无需对输入的数据做过滤。
如果用户将' or '1'='1传入赋值给占位符,下述SQL语句将无法执行:
- select * from t where username = ? and password = ?;
select * from t where username = ? and password = ?;
1.3. ResultSet
1.3.1. 结果集遍历
结果集常用的遍历方式(使用rs.getXXX方法):
- String sql = "select empno, ename, sal, hiredate from emp";
- rs = stmt.executeQuery(sql);
- while (rs.next()) {
- intempno = rs.getInt("empno");
- String ename = rs.getString("ename");
- doublesal = rs.getDouble("sal");
- Date hiredate = rs.getDate("hiredate");
- }
- rs.close();
String sql = "select empno, ename, sal, hiredate from emp";rs = stmt.executeQuery(sql);while (rs.next()) {intempno = rs.getInt("empno");String ename = rs.getString("ename");doublesal = rs.getDouble("sal"); Date hiredate = rs.getDate("hiredate");}rs.close();
1.3.2. ResultSetMetaData
ResultSetMetaData: 数据结果集的元数据,和查询出来的结果集相关,从结果集(ResultSet)中获取。
下列代码获得ResultSetMetaData对象后,从中获取数据表的所有列名:
- ResultSetMetaDatarsm = rs.getMetaData();
- intcolumnCount = rsm.getColumnCount();
- String columnName = null;
- for (int i = 1; i<=columnCount; i++) {
- columnName = rsm.getColumnName(i);
- }
ResultSetMetaDatarsm = rs.getMetaData();intcolumnCount = rsm.getColumnCount();String columnName = null;for (int i = 1; i<=columnCount; i++) {columnName = rsm.getColumnName(i);}
1.3.3. 可滚动结果集
常用的ResultSet,返回后,其初始指针在第一行之前(Before First),并且只能使用next()方法将指针向后移动,不能反向,一次移动一行,不能跳行。
可滚动的结果集:指针可以在结果集中任意移动。使用在需要指针移动的场合,比如分页。
获得可滚动的ResultSet,Statement或者PreparedStatement的创建有所不同:
- Statement stmt = conn.createStatement(type, concurrency);
- PreparedStatementstmt = conn.prepareStatement(sql, type, concurrency);
Statement stmt = conn.createStatement(type, concurrency);PreparedStatementstmt = conn.prepareStatement(sql, type, concurrency);
其中type取值:
- TYPE_FORWARD_ONLY:只能向前移动,默认参数
- TYPE_SCROLL_INSENSITIVE:可滚动,不感知数据变化
- TYPE_SCROLL_SENSITIVE:可滚动,感知数据变化
concurrency取值:
- CONCUR_READ_ONLY:只读
- CONCUR_UPDATABLE:可更新
获得可滚动结果集后,常用方法如下:
- first:指针移动到第一条
- last:指针移动到最后一条
- beforeFirst:指针移动到第一条之前
- afterLast:指针移动到最后一条之后
- isFirst:判断指针是否指向第一条
- isLast:判断指针是否指向最后一条
- isBeforeFirst:判断指针是否在第一条之前
- isAfterLast:判断指针是否在最后一条之后
- relative:移动到当前指针的相对位置
- next:移动到下一条
- previous:移动到前一条
- absolute:移动到绝对位置
- JDBC Unit02 JDBC核心API
- JDBC核心API
- JDBC核心API
- JDBC核心API
- jdbc接口核心的API
- JDBC基础编程、核心API
- jdbc连接数据库和jdbc的核心api
- JDBC(一)--JDBC核心API/JDBC工具类/Statement/PreparedStatement/CallableStatement
- JDBC接口核心的API、Statement接口详解
- java基础巩固---JDBC的接口核心API
- JDBC接口核心的API、Statement接口详解
- JDBC核心
- 核心API
- JDBC API
- JDBC API
- JDBC API
- JDBC API
- JDBC API
- 备忘录(CSS)
- 解决 MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk.
- acquia dev desktop开发第六天
- python关于石头剪刀布的一道题
- 安装windows系统
- JDBC核心API
- rz命令乱码失败问题
- 编码格式说明及Unicode与utf-8互转
- 安卓盒子运行摄像头提示VIDIOC_QUERYCTRL: I/O error
- Android一些http请求的问题
- 文章标题
- Spring JdbcTemplate详解
- JSON 基础知识总结
- Spring中Bean及@Bean的理解