Java学习笔记:基本JDBC编程

本文详细介绍了Java JDBC的基本概念,包括它作为Sun公司制定的数据库连接接口,以及面向接口编程的优势。讲解了JDBC编程的六步流程,强调了资源释放的重要性。同时,针对SQL注入问题,对比了Statement和PreparedStatement的区别,指出PreparedStatement能有效防止SQL注入并提高效率。此外,还探讨了JDBC事务管理,通过设置自动提交、提交和回滚事务来确保数据一致性。

1, JDBC是什么?

  • Java DataBase Connectivity ( java语言连接数据库 )

2, JDBC的本质是什么?

  • JDBC是sun公司制定的一套接口(interface)
    接口都有调用者和实现者。
    面向接口调用,面向接口写实现类,这都使属于面向接口编程。

2.1, 为什么要面向接口编程?

  • 解耦合:降低程序耦合度,提高程序的扩展力。
    多态机制机制就是非常典型的:面向接口编程。

驱动:所有数据库的驱动都是以.jar包的形式存在,jar包中含有多个.class文件,这些class文件就是对JDBC接口的实现。

3, JDBC编程六步

  • 1,注册驱动—告诉java程序,即将要连接的是哪个品牌的数据库。
  • 2,获取连接—表示JVM的进程和数据库进程之间的通道打开了 ,使用完需要关闭
  • 3,获取数据库操作对象—专门执行sql语句的对象
  • 4,执行sql语句—(DQL,DML…)
  • 5,处理查询结果集—只有当第4步执行的是select语句的时候,才有这第5步处理查询结果集
  • 6,释放资源—使用完后一定要关闭资源

4,注册驱动

  try{
      java.sql.Driver driver = new com.mysql.jdbc.Driver();
      DriverManager.registerDriver(driver);
  }catch(Exception e){
      e.printstackTrace();
  }

另一种方式

   String static jdbcName = "com.mysql.jc.jdbc.Driver";
   try{
         Class.forName(jdbcName);
   }catch(Exception e){
         e.printStackTrace();
   }

5,获取连接

     String static url = "jdbc:mysql://128.2.1.1:3306/bjpowernode";
     String static user = "root";
     String static password = "333";
     Connection conn = null;
     try{
     //数据库连接对象
     conn = DriverManager.getConnection(url, user, password);  
     }catch(Exception e){
            e.printStackTrace();
     }

URL: 统一资源定位符(网络中某个资源的绝对路径)
比如 https://www.baidu.com/ 这就是URL

URL包括哪几部分?
1,协议
2,IP
3,PORT
4,资源名

什么是通信协议,有什么用?

  • 通信协议是通信之前就定好的数据传送格式。
    数据包具体怎么传数据,格式提前定好的。

6,获取数据库操作对象

  Statement stmt = null;
  try{
      stmt = conn.createStatement();
  }catch(Exception e){
       e.printStackTrace();   
  }

7,处理查询结果集

  ResultSet rs = null;
  try{
      String sql = "select empno, ename, sal from emp";
      rs = stmt.executeQuery(sql);//专门处理DQL语句
      if(rs.next() ){
      //以最终查询的列的名字来获得查询结果
         String empno = rs.getString("empno");
         String sname = rs.getString("ename");
         int sal = rs.getInt("sal");
      }
  }catch(Exception e){
      e.printStackTrace();
  } 

注意:最开始时 ,结果集中的光标对象指向第0行.
在这里插入图片描述

8,执行SQL语句,释放资源

  • 为了保证资源一定释放,在finally语句块中关闭资源
    并且要遵循从小到大依次关闭,分别对其try…catch
  try{ 
       String sql = "insert into dept(deptno, dname, loc) values(50, '人事部', '北京')";
       int count = stmt.executeUpdate(sql);//执行DML语句
  }catch(Exception e){
       e.printStackTrace(); 
  }finally{
      try{//先关闭最后的查询结果集资源
          if(rs!=null){
             rs.close();
          }
      }catch(Exception f){
            f.printStackTrace();       
      }
      
      try{//再关闭的数据库操作对象资源
        if(stmt != null){
           stmt.close(); 
        }  
      }catch(Exception f){
         f.printStackTrace();
      }
     
      try{//再关闭数据库连接对象资源
        if(conn != null){
           conn.close(); 
        }  
      }catch(Exception g){
         g.printStackTrace();
      }
  }

9,SQL注入(安全隐患)

  • 导致sql注入的根本原因:用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入。

如下所示的代码执行,便会出现安全隐患!!!

//登录操作,传入Map集合
  private static boolean login(Map<String, String> userLoginInfo) {

        String url = "jdbc:mysql://localhost:3306/Learn_jdbc";
        String userName = "root";
        String passWord = "123456";
        Connection con = null;
        Statement stmt = null;
        ResultSet res = null;
        String username = userLoginInfo.get("username");//获得用户名
        String password = userLoginInfo.get("password");//获得密码
        
        try{
            Class.forName("com.mysql.cj.jdbc.Driver");//注册驱动
            con = DriverManager.getConnection(url, userName , passWord );//获得连接
            stmt = con.createStatement();//获得数据库操作对象

         
            String sql = "select * from t_user where username = '?' and password = '?'";//获得sql语句对象
            res = stmt.executeQuery(sql);//获得结果集
            if(res.next() ) {//判断是否找到
                return true;
            }

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(res!=null) {//关闭结果集
                try {
                    res.close();
                } catch (Exception f) {
                    f.printStackTrace();
                }
            }
            if(stmt!=null){
                try{//关闭数据库操作
                    stmt.close();
                }catch(Exception f){
                    f.printStackTrace();
               }
            }

            if(con!=null){
                try{//关闭数据库连接
                    con.close();
                }catch(Exception f){
                     f.printStackTrace();
               }
           }
        }
       return false;
    }
  • 如何解决sql注入问题?
    只要用户提供的信息不参与sql语句的编译过程,问题就解决了。
    即使用户提供的信息中含有sql语句的关键字,但是没有参与编译,不起作用。
    要想用户信息不参与sql语句的编译,那么必须使用java.sql.PreparedStatement。
    PreparedStatement接口继承了java.sql.Statement。
    PreparedStatement是属于预编译的数据库操作对象。
    PreparedStatement的原理是:预先对sql语句的框架进行编译,然后再给sql语句传"值"。

将上述代码改为:

//登录操作,传入Map集合
  private static boolean login(Map<String, String> userLoginInfo) {

        String url = "jdbc:mysql://localhost:3306/Learn_jdbc";
        String userName = "root";
        String passWord = "123456";
        Connection con = null;
        Statement stmt = null;
        ResultSet res = null;
        try{
            Class.forName("com.mysql.cj.jdbc.Driver");//注册驱动
            con = DriverManager.getConnection(url, userName , passWord );//获得连接
            stmt = con.createStatement();//获得数据库操作对象

            String username = userLoginInfo.get("username");//获得用户名
            String password = userLoginInfo.get("password");//获得密码
            String sql = "select * from t_user where username = '?' and password = '?'";//获得sql语句对象
            res = stmt.executeQuery(sql);//获得结果集
            if(res.next() ) {//判断是否找到
                return true;
            }

        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(res!=null) {//关闭结果集
                try {
                    res.close();
                } catch (Exception f) {
                    f.printStackTrace();
                }
            }
            if(stmt!=null){
                try{//关闭数据库操作
                    stmt.close();
                }catch(Exception f){
                    f.printStackTrace();
               }
            }

            if(con!=null){
                try{//关闭数据库连接
                    con.close();
                }catch(Exception f){
                     f.printStackTrace();
               }
           }
        }
       return false;
    }

10,对比 PreparedStatement与Statement

  • Statement存在SQL注入问题,而PreparedStatement不存在SQL注入问题.
  • Statement是编译一次执行一次,而PreparedStatement是执行一次,可执行N次,效率更高.
  • PreparedStatement 会在编译阶段做类型的安全检查.

若业务方面必须要求SQL注入的时候,必须使用Statement, 因此两者都有各自的用处。

11,JDBC事务机制

  • 单机事务,只需要记住以下三行代码和基本应用即可。
    • con.setAutoCommit(false);//开启事务
    • con.commit();//提交事务
    • con.rollback();//回滚事务
public class JDBCtest4 {

    public static void main(String args[]){
        String url = "jdbc:mysql://localhost:3306/Learn_jdbc";
        String username = "root";
        String password = "123456";
        String jdbc = "com.mysql.cj.jdbc.Driver";

        Connection con = null;
        PreparedStatement ps = null;

        try{
            //注册驱动
            Class.forName(jdbc);
            //获得连接
            con = DriverManager.getConnection(url, username, password);

            con.setAutoCommit(false);
            //获得sql语句对象
            String sql = "update t_user set username = ?, password = ? where id = ?";
            //获得数据库操作对象
            ps = con.prepareStatement(sql);

            ps.setString(1, "小里");
            ps.setString(2, "333");
            ps.setInt(3, 1);
            //获得操作影响结果
            int count = ps.executeUpdate();
            System.out.println(count);

            String s = null;
            s.toString();

            ps.setString(1, "小王");
            ps.setString(2, "444");
            ps.setInt(3, 2);
            //获得操作影响结果
            count = ps.executeUpdate();
            System.out.println(count);

            con.commit();
        }catch(Exception e){
            //回滚事务
            if(con!=null){
                try{
                    con.rollback() ;
                }catch(SQLException e1){
                    e1.printStackTrace();
                }
            }

        }finally{

            if(ps!=null){
                try{//关闭数据库操作
                    ps.close();
                }catch(Exception f){
                    f.printStackTrace();
                }
            }

            if(con!=null){
                try{//关闭数据库连接
                    con.close();
                }catch(Exception f){
                    f.printStackTrace();
                }
            }
        }
    }
}

注:集群式事务在此不作讨论。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值