• JDBC(六部)实现


    JDBC配置

    一、最基础的配置(6步)

    1、注册于实例化驱动(加载Driver驱动)

    (1) 利用反射机制(最常用)

    格式:

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

    注:因为Driver中用一个静态方法块(里面包含第二步),当执行反射动作时,就会执行静态代码块的代码,所以可以通过反射动作实例化驱动。

    (2) 通过多态创建driver对象(底层实现)

    格式:

    Driver(接口) driver=new Driver(类)( );

    DriverManager.registerDriver(driver);

    2、获取数据库对象(获取数据库的连接对象Connection)

    格式:

    Connection 数据库对象 = DriverManager.getConnection(url, name, psw);
    注:

    Url: 统一资源定位符

    Name:数据库账户名

    Psw:   数据库密码

    3、获取数据库操作对象(获取数据库的操作对象Statement(查询器);【执行增删改查】)

    例如:

    Statement 数据库操作对象 = 数据库对象.createStatement();

    备注:

    (1) sql注入:使用Statement会产生漏洞,也就是sql注入问题。

      (2)    sql注入产生的原因:  用户提供的信息,参与了sql语句的编译过程。

    (我们会在下面解决这种sql注入的问题)

    4、执行SQL语句

    (1)执行查询操作,并返回查询结果集

    ResultSet 查询结果集 = 数据库操作对象.executeQuery(sql);

    (2)执行增删改操作,并返回影响数据库的行数

    int 行数 = 数据库操作对象.executeUpdate(sql);

    5、处理查询结果集(转储Resultset查询结果集)

    Resultset结果集:

    存储结构:

                  

                

    (1)Rsesultset对象.next();(返回值为boolean类型)

    注:遍历结果集,next()当光标下一个行有元素,返回true,并移进下一行,如果没有行,则放回false。

    (2)取数据

    通过Resultset对象.getString(int dex)方法(JDBC中,所有的下表从1开始),通过while循环就可以迭代取出

    注:

    1)getString(int dex);

    方法的特点是:不管数据库中的数据类型是什么,都已String的形式取出(dex代表的是第几列,也可以换成列名  “username”)

    2)  对象.getint();       

    当数据内部int类型存储,可以用此方法

    3)  对象.getdouble();  

    当数据库内部的数据是double类型存储,可以用此方法

    6、释放资源(一定要在finally语句块中,一定会执行,首先判断是否为空)

    (1)将数据库操作对象和数据库对象关闭,通过close方法

    (2)优先级:从小到大

    (3)分别处理异常,判断是否为空

    代码:

    finally {
        try{
            if (查询结果集对象!=null){
                查询结果集对象.close();
            }
        }catch (Exception E){
            System.out.println(E);
        }


     try{
            if (数据库操作对象t!=null){
                数据库操作对象.close();
            }
        }catch (Exception E){
            System.out.println(E);
        }


        try{
            if (数据库对象!=null){
                数据库对象.close();
            }
        }catch (Exception E){
            System.out.println(E);
        }

    }

    二、JDBC的后续补充

    1、上文中sql注入问题:

    sql注入产生的原因:  用户提供的信息中存在着sql语句的关键字,并且这些关键字参与了sql语句的编译过程。

    如何解决:让用户提供的信息,不参与sql语句的编译过程

    要想用户提供的信息不参与sql语句的执行,那么必须使用PrepareStatement接口

    PsrparedStatement接口(java.sql.PreparedStatement):

    (1)

    如何使用PerparedStatement:

    (1)书写sql语句

    String sql="SELECT * FROM `userinfo` WHERE userName= ? And userPsw= ?";

    注:问号为占位符

    (2)获取PerparedStatement操作对象,并预编译sql语句

    PerparedStatement 数据库操作对象 = 数据库对象.prepareStatement(sql);

    注:对sql语句预编译,可以检错

    (3)对占位符进行赋值(JDBC的下标都是从1开始)

    PerparedStatement对象.setString(1,username);
    PerparedStatement对象.setString(2,userpsw);

    (4)获取数据库操作对象

    RequestSet对象 = PerparedStatement对象.executeQuery();

    Int 行数 = PerparedStatement对象.executeUpdate();

    代码实现:

    public static boolean login(String username, String userpsw) {
        boolean b = false;
        String url = "jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&characterEncoding=utf8&useUnicode=true&useSSL=false";
        String name = "root";
        String psw = "root";
        Connection conn = null;
        PreparedStatement pr = null;
        ResultSet re = null;
        String sql = "SELECT * FROM `userinfo`WHERE userName= ? AND userPsw= ? ";
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(url, name, psw);
            pr = conn.prepareStatement(sql);
            pr.setString(1,username);
            pr.setString(2,userpsw);
            re = pr.executeQuery();
            while (re.next()) {
                b = true;
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (re != null) {
                try {
                    re.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (pr != null) {
                try {
                    pr.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return b;
    }

    2、JDBC事务的处理

    JDBC的事务机制,默认是自动提交的(只要执行一条DML语句,则就会自动提交一次)

    在现实业务中,这种默认提交机制,不满足我们的需求,因为我们需要n条DML语句同时满足条件,我们才能够完成事务。(需求:在同一个事务中,同时成功,同时失败)

    将JDBC中自动提交变为手动提交(3步走)

    (1) 开启事务

    数据库对象.SetAutoCommit(false);

    (2) 提交事务

    在保证事务成功的时候,提交事务

    数据库对象.commit();

    (3) 回滚事务

    为了保证数据的安全性,在catch中添加上手动回滚

    If(数据库对象!=null){

    Try{

    数据库对象.rollback();

    }catch(SQLException e){

       e.printStackTrace();

    }

    }

    3、JDBC工具类

    工具类的静态方法一般是私有的。(因为工具类当中,不需要new对象,直接采用类名调用就可以)

    工具类的主要目的:为了代码的复用,减少的重复代码。

    (1)因为加载驱动只需要执行一次,可以把驱动的加载写在静态代码块中,当类加载的时候,去执行,也利用了静态代码块,只会被执行一次。

    (2)把建立连接用静态方法封装到“getconnection();”方法中,直接通过“类名.方法名();” (异常处理:因为我们调用这个方法的时候,就已经有了try-catch,我们只需要把异常直接抛出就可以,不需要再写try-catch)

    调用就可以。

    (3)可以把数据库对象、数据库操作对象、查询结果集对象的关闭,封装到一个类中,其中关闭,首先判断是否为空,在进行关闭。(异常处理:当我们在finally方法体内调用这个方法的时候,因为外面没有try-catch,所以我们需要在里面写上)

    (4)代码实现:

    //静态方法:实例化驱动
    static {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //构造方法私有化,不需要产生对象
    private JDBCdemo(){
    }
    //获取连接对象
    public static Connection getConnection() throws SQLException {
        Connection conn= DriverManager.getConnection("jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&characterEn" +
                "coding=utf8&useUnicode=true&useSSL=false","root","root");
        return conn;
    }

    //关闭对象
    public static void close(Connection conn, Statement ps, ResultSet re){
        if( re!=null){
            try {
                re.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( ps!=null){
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if( conn!=null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    4、悲观锁与乐观锁机制

    悲观锁:事务必须排队执行,数据锁住了,不允许并发(行级锁)

    乐观锁:支持并发,事务也不需要排队,只不过需要一个版本号,只有前后版本号相同时,才会提交事务,否则回滚事务。

    悲观锁:在sql语句最后面加上 “for update”

  • 相关阅读:
    <cf>Square
    运算符重载
    HDU 1231 最大连续子序列
    Biorhythms(poj1006)
    友元和友元函数
    <poj 1046>Color Me Less
    <cf> Funky Numbers
    VC++中窗口的最大化问题
    励志文章,没事看一下(网上摘录)
    VC多线程编程(转)
  • 原文地址:https://www.cnblogs.com/buhaohedeyouzicha/p/12653619.html
Copyright © 2020-2023  润新知