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”

原文地址:https://www.cnblogs.com/buhaohedeyouzicha/p/12653619.html