JDBC浅谈(二)

preparedstatment,resultset,resultsetmetadata
上个博文中我简单的梳理了jdbc的使用流程,jdbc的使用方法并没有什么神秘之处,但是运用jdbc时使用的接口和类跟实际项目应用有着巨大的联系,下面让我们来简单的分析一下。

preparedstatment 和statment
上一次jdbc应用时我们使用的statment来向处理数据库的查询,但是statment在实际应用的时候非常的不方便,这时候就要用到preparedstatment 了,那么这两者之间存在着怎样的差距呢?下面我们从几个方面一起来分析一下。
1.安全性:
preparedstatment 实行参数绑定方式来向sql语句中传入参数,而statment则是直接把参数拼接在sql语句当中,这就会出现sql注入的问题比如我们想向java_tab表查询一条数据,我们定义的

select * from java_tab where calssname=?

用statment处理这个sql 就是把输入的内容替换符号?,但是假如输入的内容为:

'2012003'; drop table java_tab

那么表后面的语句drop table java_tab将会直接生效删除java_tab表
而用preparedstatment将不会出现这种问题它会用绑定参数来替换符号?

PreparedStatement par=con.prepareStatement("select * from java_tab where calssname=?" )
par.setString(1,"2012003");

这样即使你再绑定特殊参数par.setString(1,”2012003; drop table java_tab”);也不会影响到整个sql,因为2012003; drop table java_tab是按一个整体传进去的。

2.效率性:
一般情况下preparedstatment 的运行效率要比statment高,因为一般情况下preparedstatment 会对输入sql语句进行预编译,在执行大量操作时不用每次都传入sql,只需传入一次sql多次传入参数即可,同时preparedstatment 只用传入一次sql大大减少了拼接sql的错误率节省了系统开销。下面通过一段程序来对比两种方法的执行效率:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class preparedstatment {
    String url="jdbc:mysql://localhost:3306/java?"+"user=root&password=root&useUnicode=true&characterEncoding=UTF8";
    Connection con=null;
    String sql=null;
    //使用perparedstatement执行sql
    public void perparedstatement(){
        Long start=System.currentTimeMillis();
        try {
            con=DriverManager.getConnection(url);
            PreparedStatement sta=con.prepareStatement("insert into java_tab(classname) values (?)");
            for(int i=0;i<=100;i++){ //循环传入参数
                sta.setInt(1,i);
                sta.executeUpdate();
            }
            System.out.print("pre"+(System.currentTimeMillis()-start)+"\n");

        } catch(SQLException e){
            e.printStackTrace();
        }
    }

    //使用statment执行
    public void statment(){
        Long start=System.currentTimeMillis();
        try {
            con=DriverManager.getConnection(url);
            Statement sta=con.createStatement();
            for(int i=0;i<=100;i++){//循环传入sql
                sta.executeUpdate("insert into java_tab(classname) values("+i+")");
            }
            System.out.print("sta"+(System.currentTimeMillis()-start));

        } catch(SQLException e){
            e.printStackTrace();
        }

    }


    public static void main(String arg[]) throws ClassNotFoundException{
        Class.forName("com.mysql.jdbc.Driver");
        preparedstatment par=new preparedstatment();
        par.statment();
        par.perparedstatement();


    }
}

查看输出结果可以看出PreparedStatement 总是用时较少,这就直接说明了PreparedStatement 的高效性。

resultset
上一个博客中只是简单的介绍了resultset而没有具体的对这个接口进行分析,下面就让我们来看看这个接口的主要功能
ResultSet 对象具有指向其当前数据行的指针。最初,指针被置于第一行之前。next 方法将指针移动到下一行;默认的 ResultSet 对象不可更新,仅有一个向前移动的指针。如果想创建可滚动和可更新的结果集需要则需要我们传入两个额外的参数
ResultSet.TYPE_SCROLL_INSENSITIVE 设置resultset为可滚动结果集,通过调用其他方法可使结果集指针更加灵活的滚动。
ResultSet.CONCUR_UPDATABLE 设置resultset可更新,通过resultset结果集可以直接对数据库的相应数据进行更新
具体代码如下:

PreparedStatement par=con.prepareStatement("select * from java2 "
                    , ResultSet.TYPE_SCROLL_INSENSITIVE//可滚动
                    , ResultSet.CONCUR_UPDATABLE);//resultset 可更新的动态

resultsetmetadata

执行完sql之后需要通过移动指针来遍历ResultSet,但是在实际应用的时候可能不知道表的具体结构,所以这里就要用到resultsetmetadata来对表结构进行分析。
ResultSetMetaData的对象可以根据ResultSet中的getMetaData()方法获取。其方法如下:
String getCatalogName(int column) 获取指定列的表目录名称。
String getColumnClassName(int column) 如果调用方法 ResultSet.getObject 从列中检索值,则返回构造其实例的 Java 类的完全限定名称。
int getColumnCount() 返回此 ResultSet 对象中的列数。
int getColumnDisplaySize(int column) 指示指定列的最大标准宽度,以字符为单位。
String getColumnLabel(int column) 获取用于打印输出和显示的指定列的建议标题。
String getColumnName(int column) 获取指定列的名称。
int getColumnType(int column) 检索指定列的 SQL 类型。
String getColumnTypeName(int column) 检索指定列的数据库特定的类型名称。
int getPrecision(int column) 获取指定列的小数位数。
int getScale(int column) 获取指定列的小数点右边的位数。
String getSchemaName(int column) 获取指定列的表模式。
String getTableName(int column) 获取指定列的名称。
boolean isAutoIncrement(int column) 指示是否自动为指定列进行编号,这样这些列仍然是只读的。
boolean isCaseSensitive(int column) 指示列的大小写是否有关系。
boolean isCurrency(int column) 指示指定的列是否是一个哈希代码值。
boolean isDefinitelyWritable(int column) 指示在指定的列上进行写操作是否明确可以获得成功。
int isNullable(int column) 指示指定列中的值是否可以为 null。
boolean isReadOnly(int column) 指示指定的列是否明确不可写入。
boolean isSearchable(int column) 指示是否可以在 where 子句中使用指定的列。
boolean isSigned(int column) 指示指定列中的值是否带正负号。
boolean isWritable(int column) 指示在指定的列上进行写操作是否可以获得成功。
使用DatabaseMetaData则是用来获得数据库的信息,下面介绍这个类的使用方法。

介绍完这三个接口后我们写一段代码对这三个方法进行运用,这段代码运用了preparedstatment,resultset,resultsetmetadata 对数据库进行查询及分析:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

public class resultsetmetadata {

    public static void main(String arg[]){
        Connection con=null;
        String url="jdbc:mysql://localhost:3306/java?"+"user=root&password=root&useUnicode=true&characterEncoding=UTF8";

        try {
            Class.forName("com.mysql.jdbc.Driver");
            con=DriverManager.getConnection(url);
            //PreparedStatement par=con.prepareStatement("select * from java2");
            PreparedStatement par=con.prepareStatement("select * from java2 "
                    , ResultSet.TYPE_SCROLL_INSENSITIVE//可滚动
                    , ResultSet.CONCUR_UPDATABLE);//resultset 可更新的动态
            ResultSet set =par.executeQuery();
            ResultSetMetaData meta=set.getMetaData();//对数据库表结构不清晰的时候可以用到resultsetmetadata
            for(int i=0;i<meta.getColumnCount();i++){
                System.out.print(meta.getColumnName(i+1)   +"   ");
                System.out.print(meta.getColumnType(i+1)   +"   ");
            }
            set.last();
            int rowcont =set.getRow();
                for(int k=rowcont;k>0;k--){
                set.absolute(k);
                System.out.print("\n"+set.getString(1)+"   "+set.getString(2)+"\n 更改之后");
                set.updateString(2, "he"+k);//通过ResultSet更新数据库内容
                set.updateRow();//提交更新
                System.out.print("\n"+set.getString(1)+"   "+set.getString(2));
                }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值