JDBC | JDBC编码步骤及各个对象详解

目录

 

1.JDBC的概念

2.JDBC编码步骤

3.详解各个对象

1)DriverManager:驱动管理对象

2)Connection:数据库连接对象

3)Statement:执行sql的对象

4)ResultSet:结果集对象,封装返回结果的

5)reperPreparedStatement:也是执行sql对象,但比Statement功能强大


1.JDBC的概念

        JDBC=Java DataBase Connectivity,使用同样的Java代码操作不同的数据库。

        本质:是官方定义的一套操作关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动的jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

2.JDBC编码步骤

  1. 导入驱动jar包  (此处相关jar包见https://blog.csdn.net/weixin_44187963/article/details/104864821
  2. 编写代码注册驱动
  3. 获取数据库的连接对象 connection
  4. 定义SQL语句
  5. 获取SQL语句对象 statement
  6. 执行SQL,接收返回结果
  7. 处理返回结果
  8. 释放资源
public class JdbcDome01 {
    public static void main(String[] args) throws Exception {
        //1.导入JAR包
        //2.注册驱动,在mysql5版本之后可以省略这个步骤,因为jar包里配置,系统回会自动注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //3.获取数据库的连接对象
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC","root","123456");
        //4.定义sql语句
        String sql = "update person set id = 161004 where id = 4";
        //5.获取执行sql的对象  statement
        Statement stat = conn.createStatement();
        //6.执行sql
        int info = stat.executeUpdate(sql);
        //7.处理结果
        System.out.println(info);
        //8.释放资源
        conn.close();
        stat.close();
    }
}

当然,这块只是梳理流程,并没有去抓取异常。而且关闭资源的代码理应在异常处理的finally块中,才会不论前面是否异常最终都会执行到finally,这样以免产生内存的泄露。所以代码可以改为:

public class JdbcDome03 {
    public static void main(String[] args) {
        Connection con = null;
        Statement sta = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            con = DriverManager.getConnection("jdbc:mysql://localhost:3306/TestDB?serverTimezone=UTC","root","123456");
            String sql = "update person set id = 161005 where id = 5";//修改表sql
            sta = con.createStatement();
            int count = sta.executeUpdate(sql);
            if(count > 1){
                System.out.println("修改成功");
            }else{
                System.out.println("修改失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(sta != null){
                try {
                    sta.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(con != null){
                try {
                    con.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

这样一看,很明显每一个操作都是在重复获取连接、关闭资源等基础操作,所以这块我们可以在utils包封装一个工具类出来,至于工具类的使用放在后面实现登录的代码里:

/**
 * JDBC工具类要有两个方法,一是注册驱动获取链接,二是释放资源
 * 注意:工具类的方法一般都是静态方法
 */
public class JdbcUtils {
    private static String url;
    private static String user;
    private static String password;
    private static String driver;
    //读取配置文件:期望文件的读取只读取一次,而静态代码块随着类的加载而加载,所以用静态代码块读取配置文件中的资源
    static{
        Properties properties = new Properties();
        try {
            //获取src下文件路径---->Class.loader 类加载器
            ClassLoader classLoader = JdbcUtils.class.getClassLoader();
            URL res = classLoader.getResource("Jdbc.properties");
            String path = res.getPath();
            //加载文件
            properties.load(new FileReader(path));
            //获取属性,赋值
            url = properties.getProperty("url");
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            driver = properties.getProperty("Driver");
            //加载驱动
            Class.forName(driver);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,user,password);
    }

    //释放资源,因为有两种情况,所以写两个方法实现方法的重载
    public static void release(Statement state,Connection conn){
        if(state != null){
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
    public static void release(ResultSet res,Statement state,Connection conn){
        if(res != null){
            try {
                res.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(state != null){
            try {
                state.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

3.详解各个对象

1)DriverManager:驱动管理对象

       1. 注册驱动    static void registerDriver(Driver driver)

        注册与给定的驱动程序DriverManager

        但我们代码中用Class.forName("com.mysql.cj.jdbc.Driver");

        有什么关系呢?

        通过源码发现在com.mysql.cj.jdbc.Driver下有个静态代码块,代码块里使用了registerDriver

        2. 获取数据库连接    static Connection getConnection(String url,Stirng user,String password)

                                         这里url = jdbc:mysql://IP:端口号/数据库名

2)Connection:数据库连接对象

        1.获取执行sql的对象    Statement createStatement();

                                             PrepareStatement prepareStatement(String sql);

        2.管理事务

                   开启事务:setAutoCommit(boolean autuCommit);参数设置为false

                   提交事务:commit();

                   回滚事务:rollbacl();

3)Statement:执行sql的对象

        1. boolean execute(String sql);      可以执行任意的sql

        2. int executeUpdate(String sql);

            执行DML(insert,update,delete)语句、DLL(表的create、drop、alter)语句,返回值是影响的行数。

        3. ResultSet executeQuery(String sql);      执行DQL(select)语句

这块代码就不贴出来了,就是注意不同的sql语句后面执行的时候调用不同的方法就行了。

4)ResultSet:结果集对象,封装返回结果的

        next();      游标向下移动一行,最开始默认指向的是标题栏,所以就有下面代码中的res.next()

        getXxx(参数);      获取返回值,比如int getInt()

        get方法的参数有两种情况:

        int代表列的编号,从1开始,比如getString(1) 获取第一列的值;

        String代表列的名称,比如getString("name")

使用步骤:

1.游标向下移动一行

2.判断是否有数据

3.获取数据

此时熟悉前面这部分的使用,我们写一个实现登录逻辑的代码,其中数据库的连接及关闭资源都使用了工具类:

/**
 * 需求:通过键盘输入用户名和密码
 *       判断用户是否登录成功
 */
public class JdbcLogin {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = sc.next();
        System.out.println("请输入密码:");
        String password = sc.next();
        boolean flag = new JdbcLogin().logIn2(name, password);
        if(flag){
            System.out.println("登陆成功!");
        }else{
            System.out.println("登陆失败...");
        }
    }

    //登录方法
    public boolean logIn(String usename,String password){
        //连接数据库判断是否登陆成功
        Connection connection = null;
        Statement statement = null;
        ResultSet res = null;
        if(usename == null || password == null){
            return false;
        }
        try {
            connection = JdbcUtils.getConnection();
            String sql = "select * from user where username = '"+usename+"' and password = '"+password+"'";
            statement = connection.createStatement();
            res = statement.executeQuery(sql);
            return res.next();//返回的就是一个Boolean类型值,代替了if语句
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(res,statement,connection);
        }
        return false;
    }
}

5)reperPreparedStatement:也是执行sql对象,但比Statement功能强大

1.SQL注入问题:在拼接sql时会有sql的特殊关键字参与字符串的拼接,会造成安全性问题

2.解决SQL注入问题:使用PreparedStatement对象来解决

3.预编译SQL:参数使用?作为占位符

4.使用步骤在sql语句时:

        1)用?作为占位符写sql语句

        2)在PreparedStatement(sql)方法中要传入sql作为参数

        3)给占位符?赋值:setXxx(参数1,参数2);

参数1---?的位置编号(从1开始)

参数2---?的值

        4)在下一步执行sql接收返回结果时就不需要传递sql参数了

之前写的sql语句是静态sql,用reperPreparedStatement获取执行对象后是这样的:对比上一个登录实现代码来理解:

public class JdbcLogin {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = sc.next();
        System.out.println("请输入密码:");
        String password = sc.next();
        boolean flag = new JdbcLogin().logIn2(name, password);
        if(flag){
            System.out.println("登陆成功!");
        }else{
            System.out.println("登陆失败...");
        }
    }

    /**
     * 使用preparedstatement的登录方法的实现
     */
    public boolean logIn2(String username,String password){
        //连接数据库判断是否登陆成功
        Connection connection = null;
        PreparedStatement  statement = null;
        ResultSet res = null;
        if(username == null || password == null){
            return false;
        }
        try {
            connection = JdbcUtils.getConnection();
            String sql = "select * from user where username = ? and password = ?";
            statement = connection.prepareStatement(sql);//此处传参
            //注意给?赋值
            statement.setString(1,"username");
            statement.setString(2,"password");

            res = statement.executeQuery();//此处不需要传参
            return res.next();

        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.release(res,statement,connection);
        }
        return false;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章