zoukankan      html  css  js  c++  java
  • JDBC总结

    JDBC总结

    概述

    JDBC是一组能够执行SQL语句的API
    1.    连接数据库的步骤:
    1)       注册驱动  
        JDBC类库向DriverManager注册数据库驱动·
    2)       建立连接

        使用DriverManager提供的getConnection()方法连接到数据库
    3)       创建语句

        通过数据库的连接对象的createStatement方法建立SQL语句对象
    4)       执行语句

        执行SQL语句,并将结果集合返回到ResultSet中
    5)       处理结果

        使用while循环读取结果
    6)       释放资源(注意关闭的顺序)

    demo

     DriverManager.registerDriver(newcom.mysql.jdbc.Driver());

          

           System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");

              

            //加载驱动方式

            Class.forName("com.mysql.jdbc.Driver");//推荐方式

           //2.建立连接

            String url = "jdbc:mysql:localhost:3306/jdbc";

            String user = "root";

            String password = "mysql";

            Connection conn = DriverManager.getConnection(url,user,password);

          

           //3.创建语句

           Statement st = conn.createStatement();

          

           //4.执行语句

           ResultSet rs = st.executeQuery("select * from user");

           //5.处理结果

           while(rs.next()){//按行来遍历

            System.out.println(rs.getObject(1) + " " + rs.getObject(2) + " " +rs.getObject(3) + " " + rs.getObject(4)        );

           }

           //6.释放资源(注意关闭的顺序)

           rs.close();

           st.close();

           conn.close();

    JDBC的使用方法

    1.建立连接:

    建立连接分为两个关键步骤:①加载驱动程序;②建立连接。此处所涉及到的Java类有:ClassDriverDriverManager

    建立连接,要提供3个必不可少的参数:①数据库名称;②数据库账号;③数据库密码。

    关键代码:

    ① 加载驱动程序:Class.forName(com.mysql.jdbc.Driver);

    ② 建立连接:

    Connection conn=DriverManager.getConnection(url,name,pwd);

    此处,String url=”jdbc:mysql://localhost:3306/”+数据库名称

    String name=数据库账号

     String pwd=数据库密码

    需要说明的是,这两句关键代码所用的方法都会抛出异常,故应将这两句放在try-catch块里

     

    import java.sql.*;

    public class TestConnection{

    static {

    try{

    //加载驱动程序

    Class.forName(com.mysql.jdbc.Driver);

    }

    catch(Exeception e){

    e.printStackTrace();

    }

    }

     

    public static void main(String[] args){

    String url=”jdbc:mysql://localhost:3306/lt_atm”;

    String name=”admin”;

    String pwd=”lt11235”;

    Connection conn=null;

    try{

    //建立数据库连接

    conn=DriverManager.getConnection(url,name,pwd);

    }

    catch(SQLExeception e){

    e.printStackTrace();

    }

    finally{

    try{

    conn.close();

    }

    catch(SQLException e){

       e.printStackTrace();

    }

     

    }

    }

    }

    一般,我们在静态代码块里加载驱动程序,不需要每次调用时都重新加载一次驱动。

    建立连接过程——流程图总结:

     

    2.执行SQL命令:

    ①在建立起来的连接线上创建Statement对象;②用新建的Statement对象传送SQL命令;③接收Statement对象返回过来的结果。

    管理系统将所接受的SQL命令分为两类:①写,具体来说就是增删改;②读,即查。对于写性质的SQL命令,管理系统会将受到影响的记录条数交给信使Statement;对于读性质的SQL命令,管理系统会将满足条件的所有记录封装在一个对象里交给信使Statement,而这个对象就是ResultSet类的对象。现在我们来看一些这些动作的关键代码:

     

    增删改:stmt.executeUpdate(sql)返回修改的记录条数

    查:stmt.executeQuery返回结果对象

     

    关键代码:

    创建信使

    Statement stmt=conn.createStatement();

    传送SQL命令&接收返回结果

    添加记录:        

    String sql=”INSERT INTO account VALUES (‘1132’,’金龙’,’’,10000) ”;

    int count=stmt.executeUpdate(sql);

     

    修改记录:

    String sql=”UPDATE account SET name=’无花’ WHERE accId=’1132’”;

    int count=stmt.executeUpdate(sql);

     

    删除记录:

    String sql=”DELETE FROM account WHERE accId=’1132’”;

    int count=stmt.executeUpdate(sql);

    读性质的命令:

    查询记录:

    String sql=”SELECT * FROM account”;

    ResultSet rs=stmt.executeQuery(sql);

     

    接下来,我们以具体的程序例子来说明传送SQL命令的过程;再以流程图来总结该过程:

    传送SQL命令过程——代码示例:

    import java.sql.*;

    public class TestExecute{

    static {

    try{

    //加载驱动程序

    Class.forName(com.mysql.jdbc.Driver);

    System.out.println(Success loading Driver!);

    }

    catch(Exeception e){

    e.printStackTrace();

    }

    }

     

    public static void main(String[] args){

    String url=”jdbc:mysql://localhost:3306/lt_atm”;

    String name=”admin”;

    String pwd=”lt11235”;

    Connection conn=null;

    try{

    //建立数据库连接

    conn=DriverManager.getConnection(url,name,pwd);

    Statement stmt=conn.createStatement();

    //添加记录的SQL命令

    String sql_1=INSERT INTO account VALUES

    (1132,金龙,,10000) ;

    //修改记录的SQL命令

    String sql_2=UPDATE account SET name=无花’ 

    WHERE accId=1132’”;

    //删除记录的SQL命令

    String sql_3=DELETE FROM account WHERE accId=1132’”;

     

    //查询记录的SQL命令

    String sql_4=SELECT * FROM account;

     

    //传送SQL命令

    int count_1=stmt.executeUpdate(sql_1);

    int count_2= stmt.executeUpdate(sql_2);

    int count_3= stmt.executeUpdate(sql_3);

    ResultSet rs=stmt.executeQuery(sql_4);

     

    }

    catch(SQLExeception e){

    e.printStackTrace();

    }

    finally{

    try{

    conn.close();

    }

    catch(SQLException e){

       e.printStackTrace();

    }

    }

    }

    }

     

    传送SQL命令过程——流程图总结:

     

    3.从返回的对象结果集中读取数据:

    当是查找数据时,返回的是结果对象集合。

    如何从返回的ResultSet对象中读取数据

    ResultSet对象中,除了每一条记录各占用一个位置,还有一些特殊作用的位置,其中有两个分别是:beforeFirstafterLast。他们分别是第一条记录的前一个位置、最后一条记录的下一个位置。当我们用ResultSet对象封装了查询到的记录,游标初始位置置为beforeFirst

    ResultSet类中有一个next()方法,其作用就是移动游标,使其指向下一个位置。该方法的返回值是一个boolean类型变量,当移动游标后能指向一个有效记录,返回true,否则(比如说移动到了afterLast位置)返回falseResultSet类还有一系列方法,可以统一写成getXXX()。其作用是从游标指向的记录中读取数据。其中XXXStringIntDouble类的变量类型,取决于所要读取的字段的数据类型。

    思路:①用得到的ResultSet对象调用next()方法,若返回true转向②,否则转向③;②调用getXXX方法,从游标当前指向的记录中读取各个字段的数值;然后调用next方法,若返回true,转向②,否则转向③。③读取过程完成,正常结束。

    读取数据的过程——代码示例:

    import java.sql.*;

    public class TestExecute{

    static {

    try{

    //加载驱动程序

    Class.forName(com.mysql.jdbc.Driver);

    System.out.println(Success loading Driver!);

    }

    catch(Exeception e){

    e.printStackTrace();

    }

    }

    public static void main(String[] args){

    String url=”jdbc:mysql://localhost:3306/lt_atm”;

    String name=”admin”;

    String pwd=”lt11235”;

    Connection conn=null;

    try{

    //建立数据库连接

    conn=DriverManager.getConnection(url,name,pwd);

    System.out.println(Success eastablishing the Connection…”);

    Statement stmt=conn.createStatement();

     

    //查询记录的SQL命令

    String sql=SELECT * FROM account;

    //传送SQL命令

    ResultSet rs=stmt.executeQuery(sql);

    //读取数据

    while(rs.next()){

    String accId=rs.getString(1); //或者 rs.getString(accId);

    String name=rs.getString(2);//或者 rs.getString(name);

    Char sex=rs.getChar(3);//或者 rs.getChar(sex);

    int count=rs.getInt(4);//或者 rs.getInt(count);

    System.out.println(accId+/t+name+/t+sex+/t+count);

    }

    }

    catch(SQLExeception e){

    e.printStackTrace();

    }

    finally{

    try{

    conn.close();

    }

    catch(SQLException e){

       e.printStackTrace();

    }

    }

    }

    }

    读取数据的过程——流程图总结:

     

    二 动态执行SQL命令

    动态SQL程序运行时根据条件执行具体的内容。

    1、条件动态化:

             编写一个方法,他从外界接收一个参数,并用这个参数使方法内部的SQL条件具体化,然后return一个结果。具体代码如下:

    public static ResultSet sqlQuery(String accName){

    String sql=SELECT * FROM account WHERE name=’”+ accName +”’”;

    .............................

    return ResultSet

    }  

     

     

    2、字段动态化:

      承上所述,此处所谓的字段动态化,就是我们不仅能按姓名来查询记录,还能根据其他字段来查询:比如说根据编号,根据身份,甚至是根据性别。在上文sqlQuery方法的基础上继续扩展,其代码如下:

     

    public static ResultSet sqlQuery(String column,String value){

    String sql=SELECT * FROM account WHERE

    ’”column +”’=’”value +”’”;

    .............................

    return ResultSet

    }

     

     

       3、数据表动态化:

     目标是使他能不受具体数据表的限制传入一个数据表参数,而是根据我们不同的需要,访问不同的数据表。代码:

     

         public static ResultSet sqlQuery(String table,String column,String value){

    String sql=SELECT * FROM ’”+ table +”’ WHERE

    ’”column +”’=’”value +”’”;

    .............................

    .............................

    return ResultSet

    }

    4PreparedStatement类的介绍:

    PreparedStatement是继承自Statement的类

    PreparedStatement拥有Statement所有的特性和方法。但是与Statement不同在于PreparedStatement可以将SQL命令事先编译,并存储在PreparedStatement对象中,当需要执行多次相似的SQL命令时,能够比较高效地执行。

    另外,PreparedStatement最主要的功能就是能够输入条件式的SQL命令   

         import java.sql.*;

    public class VisitDB{

    static {

    try{

    //加载驱动程序

    Class.forName(com.mysql.jdbc.Driver);

    }

    catch(Exeception e){

    e.printStackTrace();

    }

    }

    //负责建立与数据库管理系统之间的连接

    public static Connection getCon(){

    String url=”jdbc:mysql://localhost:3306/lt_atm”;

    String name=”admin”;

    String pwd=”lt11235”;

    Connection conn=null;

    try{

    //建立数据库连接

    conn=DriverManager.getConnection(url,name,pwd);

       }

    catch(SQLExeception e){

        conn=null;

    e.printStackTrace();

    }

          return conn;

    }

    //负责动态执行查询语句

    public static ResultSet sqlQuery(String table,String column,String value){

    Connection conn= VisitDB.getCon();

    //条件式SQL命令,?表示待定参数

    String sql=SELECT * FROM ? WHERE ?=?;

    try{

    //创建pstmt时就将sql命令传过去,使其预先编译

    PreparedStatement pstmt=conn.prepareStatement(sql);

    //表示第1个?的值为String类型的table

    pstmt.setString(1,table);

        //表示第2个?的值为String类型的column

    pstmt.setString(2, column);

    //表示第3个?的值为String类型的value

    pstmt.setString(3, value);

    //pstmt对象执行将编译好的SQL命令传过去,并接收结果

    ResultSet rs=pstmt.executeQuery();

    return rs;

    }

    catch(Exception e){

    return null;

    e.printStackTrace();

    }

    }

    //负责关闭不再用的对象,释放系统资源

    public static void close(ReaultSet rs,Statement stmt,Connection conn){

    try{

    rs.close();

    stmt.close();

    conn.close();

    }

    catch(Exception e){

    e.printStackTrace();

    }

    }

    }

        

      好了,此时我们的三个动态扩展也用PreparedStatement实现了。不得不提的是PreparedStatement类的setXXX系列的方法并不是只有setString一种,只是上例中我们只用到了这一种而已

    三 批处理SQL命令

    1Statement的批处理功能

            Statement提供了批处理的功能,批处理多用在执行写操作的SQL命令时,如果一次要增删改很多条记录,使用批处理会减少对象在程序与数据库系统之间的交互,从而提高其性能。批处理的流程如下所示:

    方法说明:

    1public void clearBatch() throws SQLException

     作用:将Statement对象的Batch中的所有SQL命令清空

    2public void addBatch(String sql) throws SQLException

     作用:插入一个SQL命令到Statemen对象中的Batch

    3public int[] executeBatch() throws SQLException

    作用:将Statement对象的Batch中的所有SQL命令传给数据库系统

    代码示例:

    Import java.sql.*;

    public class TestBatch{

    String[] sqls={INSERT INTO account VALUES(13579’ ’云飞’ ‘男’ , 100),

    DELETE FROM account WHERE name=’无花’”,

    UPDATE account SET name=’铁手’ WHERE accId=2468’”,}

    public void testBatch(){

    Connection conn=null;

    try{

    conn= VisitDB.getCon();

    Statement stmt=conn.createStatement();

    stmt.clearBatch();

    for(int i=0;i<sqls.length;i++){

    stmt.addBatch(sqls[i]);

    }

    stmt.executeBatch();

    }

    catch(Exception e){

    e.printStackTrace();

    }

     

    }

    }

     

    2PreparedStatement的批处理功能:

        PreparedStatementStatement的子类,所以他也有批处理功能,其流程如下所示:

    图中所涉及到的方法都已说过,就不再赘述了。现在我们直接来看一下代码示例:

    public void testPreBatch(){

    try{

    Connection conn= VisitDB.getCon();

    PreparedStatement  pstmt=conn.prepareStatement(

    DELETE FROM account WHERE name=?);

    pstmt.clearBatch();

    pstmt.setString(金龙);

    pstmt.addBatch();

    pstmt.setString(无花);

    pstmt.addBatch();

    pstmt.setString(楚香帅)

    pstmt.addBatch();

     

    pstmt.executeBatch();

    }

    catch(Exception e){

    e.printStachTrace();

    }

    }

    四 事务机制

    事务最主要的功能是用来确保多个连续的数据库操作,能作为一个整体被对待。即在执行时,要么全部执行成功,否则全部执行失败——回到最初状态。

    流程说明:

    1Connection对象调用setAutoCommit()方法,将AutoCommit设置为false,以取消自动提交事务机制(自动提交事务机制将每一条SQL命令看做是一个事务,每做一次数据库操作,会自动提交一次)。

        2、当一个逻辑事务所包含的SQL命令都被执行后,调用commit()方法,向数据库系统提交事务;这条语句通常是try块里最后一句。

    3、中途如果发生任何错误或不明原因导致操作中断,调用rollback()方法,要求数据库系统执行Rollback操作。

     

    方法说明:

    public void setAutoCommit(boolean autoCommit) throws SQLException

        说明:设置是否自动提交事务。当true时,每执行一条SQL命令,数据库系统自动提交一次事务,即对数据库里的数据进行操作;当为false时,数据库系统不自动提交事务,知道遇到调用的commit()方法。

        

    public boolean getAutoCommit() throws SQLException

    说明:获得当前的Commit方式

     

    public void commit() throws SQLException

    说明:指示数据库系统提交事务,将结果写进数据库

     

    public void rollback() throws SQLException

    说明:指示数据库执行恢复操作,将数据恢复到最初状态

     

    流程图:

    代码示例:

    public void testTransaction(){

    try{

    Connection conn= VisitDB.getCon();

    conn.setAutoCommit(false);

    Statement stmt=con.createStatement();

    String sql_1=UPDATE account SET balance=balance-1000 

    WHERE accId=A’”;

    String sql_1=UPDATE account SET balance=balance+1000 

    WHERE accId=B’”;

    conn.commit();

    }

    catch(SQLException ex){

    ex.printStackTrace();

    try{

    conn.rollback();

    }

    catch(SQLException e){

    e.printStackTrace();

    }

    }

     

    }

     

    SQL注入PreparedStatementStatement 

    PreparedStatement(从Statement扩展而来)相对Statement的优点:

    1、没有SQL注入的问题。

    2Statement会使数据库频繁编译SQL,可能会造成数据库缓冲区溢出。

    3、数据库和驱动可以对PreparedStatement进行优化(只有在相关联的数据库连接没有关闭的情况下有效)。

     

    为什么要始终使用PreparedStatement代替Statement?

    代码可维护性

    辨别: Statement使用 +  PreparedStatement使用?)
    stmt.executeUpdate("insert into tb_name (col1,col2,col2,col4) values       ('"+var1+"','"+var2+"',"+var3+",'"+var4+"')");

    注意StatementPreparedStatement语句上的区别:Statement是在执行的时候才传入SQL语句,而PreparedStatement在创建的时候就已经传入了SQL语句。
    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();

     

    防止SQL注入
    对于JDBC而言,SQL注入攻击只对Statement有效,PreparedStatement是无效的,这是因为PreparedStatement不允许在插入时改变查询的逻辑结构.

    SQL注射原理

    SQL 注射能使攻击者绕过认证机制,完全控制远程服务器上的数据库

    登陆验证

    假如后台的sql语句时这样拼接的

    select id from test where username='"+myname+"' and password='"+mypasswd+"' ";

    表面上看,如果用户名和口令对匹配,那么该用户通过认证;否则,该用户不会通过认证——但是,事实果真如此吗?这里并没有对SQL命令进行设防,所以攻击者完全能够在用户名或者口令字段中注入SQL语句,从而改变SQL查询 。为此,我们仔细研究一下上面的SQL查询字符串:

    上述代码认为字符串username和password都是数据,不过,攻击者却可以随心所欲地输入任何字符 。如果一位攻击者输入的用户名为

    ‘’OR 1=1—

    而口令为

    x

    双划符号--告诉SQL解析器,右边的东西全部是注释,所以不必理会。这样,查询字符串相当于:

    select id from test where username='' or 1=1;

    因为现在只要用户名为长度为零的字符串''或1=1这两个条件中一个为真,就返回用户标识符ID——我们知 道,1=1是恒为真的。所以这个语句将返回user_table中的所有ID。在此种情况下,攻击者在username字段放入的是SQL指令 'OR1=1--而非数据。

    更为严重的情况是当username对应的是'OR1=1;DROPTABLEuser_table;--

    数据库中执行的sql语句就变成了:

    select id from test where username='' or 1=1;drop table test

    这个语句将执行句法上完全正确的SELECT语句,并利用drop命令清空test表。

    应对策略

    问题的关键就是不要用string构造sql语句,这样就不会利用输入的参数构造sql语句了。所以要用PreparedStatement替换Statement,即用占位符作为实参定义sql语句,从而避免sql注入攻击。

    不管什么框架,还是纯JDBC,只用Preparedstatement,一定要用占位符作为实参来构造sql(或hql)语句。

    String sql= "select * from test where usernmae=? and password=? " ;
    PreparedStatement psm=conn.preparedStatement(sql);
    psm.setString(1,myname);
    psm.setString(2,mypasswd);
    Result rs=psm.executeQuery(); 
    if (rs.next){
    rs.close();
    con.close();
    return false ;
    }
    else {
    rs.close();
    con.close();
    return true ;
    }

     

     





  • 相关阅读:
    一个printf(结构体指针)引发的血案
    C语言指针从底层原理到花式技巧,用图文和代码帮你讲解透彻
    利用C语言中的setjmp和longjmp,来实现异常捕获和协程
    提高代码逼格的利器:宏定义从入门到放弃
    我最喜欢的进程之间通信方式消息总线
    推荐一个阅读代码、文档的利器:屏幕贴图工具
    计算机网络基础知识总结
    vi指令总结
    LVS 负载均衡器理论基础及抓包分析
    Linux命令总结大全,包含所有linux命令
  • 原文地址:https://www.cnblogs.com/baixl/p/4483312.html
Copyright © 2011-2022 走看看