JDBC操作笔记

JDBC规范下载链接
http://download.oracle.com/otndocs/jcp/jdbc-4_2-mrel2-spec/index.html

java数据库操作基本流程
1.得到数据库驱动程序 
2.创建数据库连接 
3.执行SQL语句 
4.得到结果集 
5.对结果集做相应的处理(增,删,改,查) 
6.关闭资源:这里释放的是DB中的资源

1、获取数据库连接
(1)用DriverManager取数据库连接
例子:

String className,url,uid,pwd;
className = "oracle.jdbc.driver.OracleDriver";
url = "jdbc:oracle:thin:@127.0.0.1:1521:orasvr;
uid = "system";
pwd = "manager";
Class.forName(className);
Connection cn = DriverManager.getConnection(url,uid,pwd);

(2)用jndi(java的命名和目录服务)方式
例子:

String jndi = "jdbc/db";
Context ctx = (Context) new InitialContext().lookup("java:comp/env");
DataSource ds = (DataSource) ctx.lookup(jndi);
Connection cn = ds.getConnection();

2、执行sql语句
(1)用Statement来执行sql语句

String sql;
Statement sm = cn.createStatement();
sm.executeQuery(sql); // 执行数据查询语句(select)
sm.executeUpdate(sql); // 执行数据更新语句(delete、update、insert、drop等)statement.close();

(2)用PreparedStatement来执行sql语句

String sql;
sql = "insert into user (id,name) values (?,?)";
PreparedStatement ps = cn.prepareStatement(sql);
ps.setInt(1,xxx);
ps.setString(2,xxx);
ResultSet rs = ps.executeQuery(); // 查询
int c = ps.executeUpdate(); // 更新

3、补充说明:
(1)对于oracle数据库,默认游标数为300,如果在执行过程中数据量较大会出现游标溢出的问题,解决方案为
        【1】每次使用完Statement、PreparedStatement、ResultSet等,每次使用这些对象时最好重新生成对象,使用后直接关闭。
        【2】对获得的结果集操作时,批量操作,比如100条数据一次进行操作。
        
    【问题原因:绝大部分情况下,open_cursors只需要设置一个比较小的值,就足够使用了,除非有非常特别的要求。
         如果你不使用连接池,那么就没有什么问题,一旦Connection关闭,数据库物理连接就被释放,所有相关Java资源也可以被GC回收了。
    但是如果你使用连接池,那么请注意,Connection关闭并不是物理关闭,只是归还连接池,所以PreparedStatement和ResultSet都被持有,并且实际占用相关的数据库的游标资源,在这种情况下,只要长期运行,往往就会报“游标超出数据库允许的最大值”的错误,导致程序无法正常访问数据库。】
     
(2)oracle游标相关知识:
        【1】获取当前数据库游标数:    show parameter open_cursors;
        【2】修改当前数据库游标数:   alter system set open_cursors=1000;
(3)默认无参Statement,对结果集ResultSet遍历一遍后,之后游标使用beforeFirst()移动到first位置,重新进行遍历,会报错java.sql.SQLException: 对只转发结果集的无效操作: first
解决方案:把preprepareStatemen修改成:pstm = con.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
    原因:
    缺省情况下创建的ResultSet 是一种只能访问一次(one-time-through),只能向前访问(forward-only),只读的对象。您只能访问数据一次,如果再次需要该数据,必须重新查询数据库。所以如果要再次查询,则需要设置resultSet的属性。

(4) ResultSet相关:
        【1】ResultSet的三种类型参数
        缺省情况下创建的ResultSet 是一种只能访问一次(one-time-through),只能向前访问(forward-only),只读的对象。您   只能访问数据一次,如果再次需要该数据,必须重新查询数据库。
        ResultSet.TYPE_SCROLL_SENSITIVE
        双向滚动,并及时跟踪数据库的更新,以便更改ResultSet中的数据。允许在记录中定位。这种类型受到其他用户所作更改的影响。如果用户在执行完查询之后删除一个记录,那个记录将从 ResultSet 中消失。类似的,对数据值的更改也将反映在 ResultSet 中。(其它人对记录的修改会反应到你打开的记录集   敏感)
        ResultSet.TYPE_SCROLL_INSENSITIVE
        双向滚动,但不及时更新,就是如果数据库里的数据修改过,并不在ResultSet中反应出来。允许在列表中向前或向后移动,甚至可以进行特定定位,例如移至列表中的第四个记录或者从当前位置向后移动两个记录。不会受到其他用户对该数据库所作更改的影响。(其它人对记录的修改不会反应到你打开的记录集   不敏感)
        TYPE_FORWORD_ONLY
        只可向前滚动。缺省类型,不会受到其他用户对该数据库所作更改的影响。只允许向前访问一次,并且不会受到其他用户对该数据库所作更改的影响。
       【2】ResultSet 和事务处理参数
        ResultSet 一般会被关闭,在事务的commit 或者 rollback被执行后.但是有时候你要保留ResultSet继续被使用怎么办?看下面参数:
        HOLD_CURSORS_OVER_COMMIT: ResultSet的数据仍然可以被存取在commit 或者 rollback之后.
        CLOSE_CURSORS_AT_COMMIT: ResultSet的数据被抛弃在 commits 或者 rollbacks执行后.
        【3】并发性参数
        ResultSet 的数据可以被更新的,为了达到这个目的要做的一件事情就是和数据库保持连接,然后就是使用一些锁机制在更新期间保护数据。并发等级参数有下面两个:
        CONCUR_READ_ONLY: 不允许更新
        CONCUR_UPDATABLE: 允许并发同步更新数据 

(5)应该使用PreparedStatement,原因如下:
       【1】jdbc(java database connectivity,java数据库连接)的api中的主要的四个类之一的java.sql.Statement要求开发者付出大量的时间和精力。在使用statement获取jdbc访问时所具有的一个共通的问题是输入适当格式的日期和时间戳:2002-02-05 20:56 或者 02/05/02 8:56 pm。 
    通过使用java.sql.preparedstatement,这个问题可以自动解决。
       【2】一个PreparedStatement是从java.sql.connection对象和所提供的sql字符串得到的,sql字符串中包含问号(?),这些问号标明变量的位置,然后提供变量的值,最后执行语句。preparedstatement不是动态创建的,这允许jvm(javavirtual machine,java虚拟机)和驱动/数据库缓存语句和字符串并提高性能。这样在代码的可读性和可维护性都更好。

stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");
        
perstmt = con.prepareStatement("insert into tb_name (col1,col2,col2,col4) values (?,?,?,?)"); 
perstmt.setString(1,var1);
perstmt.setString(2,var2);
perstmt.setString(3,var3);
perstmt.setString(4,var4);
perstmt.executeUpdate();

    【3】PreparedStatement也提供数据库无关性。当显示声明的sql越少,那么潜在的sql语句的数据库依赖性就越小。
    【4】PreparedStatement尽最大可能提高性能.
    每一种数据库都会尽最大努力对预编译语句提供最大的性能优化.因为预编译语句有可能被重复调用.所以语句在被DB的编译器编译后的执行代码被缓存下来,那么在整个DB中,下次调用时只要是相同的预编译语句就不需要编译。
    而statement的语句是动态创建的,同一操作由于每次操作的数据不同使整个语句相匹配的机会极小,几乎不太可能匹配,没有缓存语句的意义,几乎每次都要重新编译。事实是没有数据库会对普通语句编译后的执行代码缓存.
    当然并不是所以预编译语句都一定会被缓存,数据库本身会用一种策略,比如使用频度等因素来决定什么时候不再缓存已有的预编译结果.以保存有更多的空间存储新的预编译语句.
    【5】最重要的一点是极大地提高了安全性.
    Statement使用动态拼接的sql语句,不能有效组织SQL注入,而使用PreparedStatement可以有效避免。
    

发布了9 篇原创文章 · 获赞 4 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/juan190755422/article/details/84976134