0
点赞
收藏
分享

微信扫一扫

JDBC介绍

落花时节又逢君to 2022-03-12 阅读 75

一、什么是JDBC

JDBC(Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

在这里插入图片描述

二、JDBC的原理

早期SUN公司的天才们想编写一套可以连接天下所有数据库的API,但是当他们刚刚开始时就发现这是不可完成的任务,因为各个厂商的数据库服务器差异太大了。后来SUN开始与数据库厂商们讨论,最终得出的结论是,由SUN提供一套访问数据库的规范(就是一组接口),并提供连接数据库的协议标准,然后各个数据库厂商会遵循SUN的规范提供一套访问自己公司的数据库服务器的API出现。SUN提供的规范命名为JDBC,而各个厂商提供的,遵循了JDBC规范的,可以访问自己数据库的API被称之为驱动!

在这里插入图片描述

JDBC是接口,而JDBC驱动才是接口的实现,没有驱动无法完成数据库连接!每个数据库厂商都有自己的驱动,用来连接自己公司的数据库。

当然还有第三方公司专门为某一数据库提供驱动,这样的驱动往往不是开源免费的!

三、程序员,JDBC,JDBC驱动的关系及说明

JDBC API

提供者:Sun公司

内容:供程序员调用的接口与类,集成在java.sql和javax.sql包中,如

1.DriverManager类 作用:管理各种不同的JDBC驱动

2.Connection接口

3.Statement接口

4.ResultSet接口

JDBC 驱动

提供者:数据库厂商

作用:负责连接各种不同的数据库

Java程序员

     JDBC对Java程序员而言是API,对实现与数据库连接的服务提供商而言是接口模型。

 

  • 1

三方关系

SUN公司是规范制定者,制定了规范JDBC(连接数据库规范)

数据库厂商微软、甲骨文等分别提供实现JDBC接口的驱动jar包

程序员学习JDBC规范来应用这些jar包里的类。

在这里插入图片描述

四、JDBC的总结

简单地说,JDBC 可做三件事:与数据库建立连接、发送 操作数据库的语句并处理结果。

在这里插入图片描述
DriverManager :依据数据库的不同,管理JDBC驱动

Connection :负责连接数据库并担任传送数据的任务

Statement :由 Connection 产生、负责发送执行SQL语句

ResultSet:负责保存Statement执行后所产生的查询结果

五、JDBC连接数据的步骤

1:注册一个Driver驱动(作用:告诉Java程序,即将要连接的是哪个品牌的数据库)

2:获取数据库连接(Connection)(表示JVM的进程和数据库进程之间的通道打开了,这属于进程之间的通信,重量级的,使用完后一定要关闭)

3 : 获取数据库操作对象(专门执行SQL语句的对象 )

4:执行SQL语句(DML、DQL、...)

5:处理查询结果集(只有当第四步执行的是select语句的时候,才有这第五步处理查询结果集)

6:关闭数据库资源(使用完资源后一定要关闭资源,Java和数据库属于进程间的通信,开启后一定要关闭),按以下顺序关闭:

ResultSet

Statement

Connection。

六、JDBC连接数据的详细步骤

1.注册驱动

注册JDBC驱动是通过调用方法java.lang.Class.forName(),下面列出常用的几种数据库驱动程序加载语句的形式 :

Class.forName(“oracle.jdbc.driver.OracleDriver”);//使用Oracle的JDBC驱动程序

Class.forName(“com.microsoft.jdbc.sqlserver.SQLServerDriver”);//使用SQL Server的JDBC驱动程序

Class.forName(“com.ibm.db2.jdbc.app.DB2Driver”);//使用DB2的JDBC驱动程序

Class.forName(“com.mysql.jdbc.Driver”);//使用MySql的JDBC驱动程序

2.创建数据库连接

与数据库建立连接的方法是调用DriverManager.getConnection(String url, String user, String password )方法

Connection conn=null;

String url=“jdbc:oracle:thin:@localhost:1521:orcl”;

String user=“scott";

String password=“tiger";

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

3.创建Statement并发送命令

Statement对象用于将 SQL 语句发送到数据库中,或者理解为执行sql语句

有三种 Statement对象:

Statement:用于执行不带参数的简单SQL语句;

PreparedStatement(从 Statement 继承):用于执行带或不带参数的预编译SQL语句;

CallableStatement(从PreparedStatement 继承):用于执行数据库存储过程的调用。
在这里插入图片描述

4.处理ResultSet结果

ResultSet对象是executeQuery()方法的返回值,它被称为结果集,它代表符合SQL语句条件的所有行,并且它通过一套getXXX方法(这些get方法可以访问当前行中的不同列)提供了对这些行中数据的访问。

ResultSet里的数据一行一行排列,每行有多个字段,且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。

ResultSet对象自动维护指向当前数据行的游标。每调用一次next()方法,游标向下移动一行。

初始状态下记录指针指向第一条记录的前面,通过next()方法指向第一条记录。循环完毕后指向最后一条记录的后面。

在这里插入图片描述

5.关闭数据库资源

作为一种好的编程风格,应在不需要Statement对象和Connection对象时显式地关闭它们。关闭Statement对象和Connection对象的语法形式为:

public void close() throws SQLException

用户不必关闭ResultSet。当它的 Statement 关闭、重新执行或用于从多结果序列中获取下一个结果时,该ResultSet将被自动关闭。

注意:要按先ResultSet结果集,后Statement,最后Connection的顺序关闭资源,因为Statement和ResultSet是需要连接是才可以使用的,所以在使用结束之后有可能其他的Statement还需要连接,所以不能先关闭Connection。

以上内容参考博客:[添加链接描述](https://blog.csdn.net/qq_43623447/article/details/106494077)


七、代码演示

1、注册驱动第一种方式(包含:插入/删除/更新)

  • JDBC执行插入
package com.zzz.jdbc;


import java.sql.*;

/**
 * JDBC完成insert
 */
public class JDBCTest01 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement statement = null;
        try {
            //1、注册驱动
            Driver driver = new com.mysql.jdbc.Driver(); //多态,父类引用指向子类对象
            DriverManager.registerDriver(driver);

            //2、获取连接
            /**
             * URL:统一资源定位符(网络中某个资源的绝对路径)
             * https://www.baidu.com/   这就是URL
             * URL包括哪几部分?
             * 协议
             * IP   计算机的代号
             * PORT    计算机上某个软件的代号
             * 资源名
             *
             * http://182.61.200.7:80/index.html
             * http://  通信协议
             * 182.61.200.7  服务器IP地址
             * 80   服务器上软件的端口
             * index.html   服务器上的某个资源名
             *
             * jdbc:mysql://localhost:3306/hive
             * jdbc:mysql://    协议
             * localhost    IP地址
             * 3306  mysql数据库端口号
             * hive   具体的数据库实例名
             *
             * 什么是通信协议?有什么用?
             * 通信协议是通信之前就提前定好的数据传送格式。数据包具体怎么传数据,格式提前定好的。
             */
            String url = "jdbc:mysql://localhost:3306/hive";
            String user = "root";
            String password = "111111";
            conn = DriverManager.getConnection(url, user, password);

            //3、获取数据库操作对象Statement来将SQL语句发送到数据库
            statement = conn.createStatement();

            //4、执行sql语句(JDBC的SQL语句结尾不需要写分号)
            String sql = "insert into people(name,age) values('Susan',20)";
            //executeUpdate方法是专门执行DML语句的(insert/delete/update),返回值是影响数据库中的记录的条数
            int count = statement.executeUpdate(sql);
            System.out.println(count==1? "保存成功" : "保存失败");

            //5、处理查询结果集

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //6、释放资源
            //为了保证资源一定释放,在finally语句块中关闭资源
            //并且要遵循从小到大一次关闭
            try {
                if (statement != null){
                    statement.close();
                }
            } catch (SQLException e) {
                    e.printStackTrace();
            }
            try {
                if (conn != null){
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
  • JDBC执行删除与更新
package com.zzz.jdbc;


import java.sql.*;

/**
 * JDBC完成delete, update
 */
public class JDBCTest02 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement statement = null;
        try {
            //1、注册驱动
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
            //3、获取数据库操作对象
            statement = conn.createStatement();
            //4、执行SQL语句
            //String sql = "delete from people where name = 'Susan'";
            String sql = "update people set name = 'Daming',age = 18 where name = 'Andy'";
            int count = statement.executeUpdate(sql);
            //System.out.println(count==1? "删除成功" : "删除失败");
            System.out.println(count==1? "更新成功" : "更新失败");
            //5、处理查询结果集
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            //6、关闭资源
            try {
                if (statement != null){
                    statement.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
            try {
                if (conn != null){
                    conn.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
}

2、注册驱动的第二种方式(类加载方式,常用方式)

package com.zzz.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * 注册驱动的另一种方式:类加载的方式注册驱动(这种方式常用)
 */
public class JDBCTest03 {
    public static void main(String[] args) {
        try {
            //1、注册驱动
            //这是注册驱动的第一种写法,用的少
            //DriverManager.registerDriver(new com.mysql.jdbc.Driver());

            /**
             * 这是注册驱动的第二种写法,
             * 通过反射机制完成类加载,进而执行该类中静态代码块里的内容,该静态代码块里的内容就是注册驱动。
             *
             * 这是常用的写法,因为参数是字符串,字符串可以写到配置文件中
             *
             * 以下方法不需要接收返回值,因为我们只想用它的类加载动作
             */
            Class.forName("com.mysql.jdbc.Driver");

            //2、获取连接
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
            System.out.println(conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

3、从属性资源文件中读取连接数据库信息

package com.zzz.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ResourceBundle;

/**
 * 将连接数据库的所有信息配置到配置文件中。
 * 实际开发中不建议把连接数据库的信息写死到java程序中,一般都是将信息写到xxxx.properties文件中,使用资源绑定器ResourceBundle获取信息。
 */
public class JDBCTest04 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement statement = null;

        //使用资源绑定器绑定资源配置文件
        /**
         * 注意:这里需要把jdbc.properties文件放在src下,如果是放在package下,则程序的filename应该package/jdbc
         * 或者放在target文件下的classes文件夹下
         *
         * jdbc.properties文件中的内容为:
         * driver=com.mysql.jdbc.Driver
         * url=jdbc:mysql://localhost:3306/hive
         * user=root
         * password=111111
         *
         * 这样要改参数的话,只需要去jdbc.properties文件中去改就行了
         */
        //ResourceBundle是专门用来读取配置文件的工具类
        //bundle只能读取properties类型的文件, 读取的时候只需要文件名, 不需要后缀
        ResourceBundle bundle = ResourceBundle.getBundle("jdbc");
        String driver = bundle.getString("driver");
        String url = bundle.getString("url");
        String user = bundle.getString("user");
        String password = bundle.getString("password");

        try {
            //1、注册驱动
            Class.forName(driver);
            //2、获取连接
            conn = DriverManager.getConnection(url,user,password);
            //3、获取数据库操作对象
            statement = conn.createStatement();
            //4、执行SQL语句
            int count = statement.executeUpdate("update people set age = 21 where name='Michael'");
            System.out.println(count==1? "更新成功"  : "更新失败");
            //5、处理查询结果集
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //6、关闭资源
            try {
                if (statement != null){
                    statement.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
            try {
                if (conn != null){
                    conn.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
}

4、JDBC执行查询操作(有处理查询结果集步骤)

package com.zzz.jdbc;

import java.sql.*;

/**
 * 处理查询结果集(遍历结果集)
 */
public class JDBCTest05 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive","root","111111");
            //3、获取数据库操作对象
            statement = conn.createStatement();
            //4、执行SQL语句
            String sql = "select name as na,age from people";
            /**
             * 注意:
             * 增删改使用executeUpdate (insert/delete/update) 返回的是变化的数量
             * 查询使用executeQuery (select)    返回结果集
             */
            //executeQuery方法是专门执行DQL语句的(select),返回单个ResultSet对象
            resultSet = statement.executeQuery(sql);

            //5、查询结果集
            while (resultSet.next()){ //判断光标指向的行有没有数据
                //若光标指向的行有数据就执行取出
                //getString方法的特点是:不管数据库中的数据类型是什么,都以String形式取出
                //JDBC所有下标从1开始,不是从0开始
                /*String name = resultSet.getString(1); //以列下标获取,取出第一列
                String age = resultSet.getString(2); //以列下标获取,取出第二列*/
                String name = resultSet.getString("na"); //以列名获取,若查询结果集的列名称有别名就填别名
                int age = resultSet.getInt("age"); //以列名获取,若查询结果集的列名称有别名就填别名
                System.out.println("name:" + name + ", age:" + age);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //6、关闭资源
            try {
                if (resultSet != null){
                    resultSet.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }

            try {
                if (statement != null){
                    statement.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }

            try {
                if (conn != null){
                    conn.close();
                }
            }catch(SQLException e){
                e.printStackTrace();
            }
        }
    }
}

5、通过模拟用户登录演示SQL注入现象

package com.zzz.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * 实现功能:
 *  1、需求:模拟用户登录功能的实现
 *  2、业务描述:
 *      程序运行的时候,提供一个输入的入口,可以让用户输入用户名和密码
 *      用户输入用户名和密码之后,提交信息,Java程序收集到用户信息
 *      Java程序连接数据库验证用户名和密码是否合法
 *      合法:显示登录成功
 *      不合法:显示登录失败
 *  3、数据的准备:
 *      在实际开发中,表的设计会使用专门的建模工具,这里需要安装一个建模工具:PowerDesigner
 *      使用PD工具来进行数据库表的设计(参见user-login.sql脚本)
 *  4、当前程序存在问题:
 *      请输入用户名:ijds
 *      请输入密码:fdsa' or '1'='1
 *      登录成功
 *  这种现象被称为SQL注入(安全隐患)。(黑客经常使用)
 *  5、导致SQL注入的根本原因是什么?
 *      用户输入的信息中含有sql语句的关键字,并且这些关键字参与sql语句的编译过程,导致sql语句的原意被扭曲,进而达到sql注入。
 *
 */
public class JDBCTest06 {
    public static void main(String[] args) {
        //初始化一个界面
        Map<String, String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean login = login(userLoginInfo);
        //最后输出结果
        System.out.println(login? "登录成功" : "登录失败");
    }

    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return false 登录失败   true 登录失败
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean loginSuccess = false;
        //JDBC代码
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        String loginName = userLoginInfo.get("loginName");
        String loginPwd = userLoginInfo.get("loginPwd");
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive","root","111111");
            //3、获取数据库操作对象
            statement = conn.createStatement();
            //4、执行sql语句
            //在字符串中拼一个变量,有固定格式: "+变量名+"
            String sql = "select * from t_user where loginName = '"+loginName+"' and loginPwd = '"+loginPwd+"'";
            /**
             * 以上正好完成了sql语句的拼接,以下代码的含义是:发送sql语句给DBMS,DBMS进行sql编译。
             * 正好将用户提供的“非法信息”编译进去,导致原sql语句的含义被扭曲了。进而发生了SQL注入现象。
             */
            resultSet = statement.executeQuery(sql);
            //5、处理结果集
            if (resultSet.next()){
                loginSuccess = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、关闭资源
            if (resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面,返回用户输入的用户名和密码等登录信息
     */
    private static Map<String,String> initUI() {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();
        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",username);
        userLoginInfo.put("loginPwd",password);
        return userLoginInfo;
    }
}

6、解决SQL注入问题(对比Statement和PreparedStatement)

package com.zzz.jdbc;

import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 *  1、解决sql注入问题
 *      只要用户提供的信息不参与SQL语句的编译过程,问题就解决了。
 *      即使用户提供的信息中含有SQL语句的关键字,但是没有参与编译,不起作用。
 *      要想用户信息不参与SQL语句的编译,那么必须使用java.sql.PreparedStatement
 *      PreparedStatement接口继承了java.sql.Statement
 *      PreparedStatement是属于预编译的数据库操作对象
 *      PreparedStatement的原理是:预先对SQL语句的框架进行编译,然后再给SQL语句传“值”。
 *  2、测试结果:
 *      请输入用户名:ijds
 *      请输入密码:fdsa' or '1'='1
 *      登录失败
 *  3、解决SQL注入的关键是什么?
 *      用户提供的信息中即使含有sql语句的关键字,但是这些关键字并没有参与编译,不起作用。
 *  4、对比Statement和PreparedStatement?
 *      - Statement存在sql注入问题,而PreparedStatement解决了sql注入问题。
 *      - Statement是编译一次执行一次,PreparedStatement是编译一次执行多次。PreparedStatement效率比Statement高。
 *      - PreparedStatement会在编译阶段做类型的安全检查。
 *  综上所述:PreparedStatement使用较多,只有极少数的情况下需要使用Statement
 *  5、什么情况下必须使用Statement呢?
 *      业务方面要求必须支持SQL注入的时候。
 *      Statement支持SQL注入,凡是业务方面要求是需要进行sql语句拼接的,必须使用Statement。
 *      如果是单纯地给sql语句传值,则使用PreparedStatement。
 */
public class JDBCTest07 {
    public static void main(String[] args) {
        //初始化一个界面
        Map<String, String> userLoginInfo = initUI();
        //验证用户名和密码
        boolean login = login(userLoginInfo);
        //最后输出结果
        System.out.println(login? "登录成功" : "登录失败");
    }

    /**
     * 用户登录
     * @param userLoginInfo 用户登录信息
     * @return false 登录失败   true 登录失败
     */
    private static boolean login(Map<String, String> userLoginInfo) {
        boolean loginSuccess = false;
        //JDBC代码
        Connection conn = null;
        PreparedStatement ps = null; //这里使用PreparedStatement(预编译的数据库操作对象)
        ResultSet resultSet = null;
        String loginName = userLoginInfo.get("loginName");
        String loginPwd = userLoginInfo.get("loginPwd");
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive","root","111111");

            //3、获取预编译的数据库操作对象
            //SQL语句的框架。其中一个 ? 表示一个占位符,一个 ? 将来接收一个“值”。注意:占位符不能使用单引号括起来!
            String sql = "select * from t_user where loginName = ? and loginPwd = ?";
            //程序执行到此处,会发送sql语句的框架给DBMS,然后DBMS进行sql语句的预先编译。
            ps = conn.prepareStatement(sql);
            //给占位符 ? 传值(第一个问号下标是1,第二个问号下标是2,JDBC中所有下标从1开始)
            ps.setString(1,loginName);
            ps.setString(2,loginPwd);

            //4、执行sql语句
            resultSet = ps.executeQuery();

            //5、处理结果集
            if (resultSet.next()){
                loginSuccess = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //6、关闭资源
            if (resultSet != null){
                try {
                    resultSet.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();
                }
            }

        }
        return loginSuccess;
    }

    /**
     * 初始化用户界面,返回用户输入的用户名和密码等登录信息
     */
    private static Map<String,String> initUI() {
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String username = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();
        Map<String,String> userLoginInfo = new HashMap<>();
        userLoginInfo.put("loginName",username);
        userLoginInfo.put("loginPwd",password);
        return userLoginInfo;
    }
}

7、演示Statement用途

package com.zzz.jdbc;

import java.sql.*;
import java.util.Scanner;

/**
 * 需要使用Statement完成SQL注入的例子
 */
public class JDBCTest08 {
    public static void main(String[] args) {
        //用户在控制台输入desc就是降序,输入asc就是升序
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入desc或asc(其中desc表示降序,asc表示升序): ");
        String keyWords = sc.nextLine();

        //执行SQL
        Connection conn = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
            //3、获取数据库操作对象
            statement = conn.createStatement();
            //4、执行sql语句
            String sql = "select name, age from people order by age " + keyWords; //进行sql语句的拼接,即注入
            resultSet = statement.executeQuery(sql);
            //5、处理结果集
            while (resultSet.next()){
                System.out.println(resultSet.getString("name") + "\t" + resultSet.getInt("age"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //6、关闭资源
            if (resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

8、PreparedStatement完成增删改

package com.zzz.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * PreparedStatement完成 insert delete update
 */
public class JDBCTest09 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取 连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
            //3、获取预编译的数据库操作对象
            //增 insert操作
            /*ps = conn.prepareStatement("insert into people(name,age) values (?,?)");
            ps.setString(1,"Lucy");
            ps.setInt(2,23);*/
            //改 update操作
            /*ps = conn.prepareStatement("update people set name=?,age=? where name = ?");
            ps.setString(1,"Cauthy");
            ps.setInt(2,20);
            ps.setString(3,"Lucy");*/
            //删 delete操作
            ps = conn.prepareStatement("delete from people where name=?");
            ps.setString(1,"Cauthy");

            //4、执行sql语句
            int count = ps.executeUpdate();

            System.out.println(count==1? "更新成功" : "更新失败");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //6、关闭资源
            if (ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9、JDBC的事务自动提交机制演示

package com.zzz.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * JDBC事务机制:
 *      1、JDBC中的事务是自动提交的,什么是自动提交?
 *          只要执行任意一条DML语句,则自动提交一次。这是JDBC默认的事务行为
 *          但是在实际的业务中,通常都是N条DML语句共同联合才能完成的,必须保证他们这些DML语句在同一个事务中同时成功或者同时失效。
 *      2、以下程序先来验证一下JDBC的事务是否是自动提交机制
 *          测试结果:JDBC的事务支持自动提交机制,即JDBC中只要执行任意一条DML语句,就提交一次。
 */
public class JDBCTest10 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取 连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
            //3、获取预编译的数据库操作对象
            ps = conn.prepareStatement("update people set name = ? where name = ?");

            //第一次给占位符传值
            ps.setString(1,"Stephen");
            ps.setString(2,"Daming");
            int count = ps.executeUpdate(); //执行第一条Update语句
            System.out.println(count);

            //重新给占位符传值
            ps.setString(1,"Alan");
            ps.setString(2,"Michael");
            count = ps.executeUpdate(); //执行第二条Update语句
            System.out.println(count);

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            //6、关闭资源
            if (ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

10、账户转账演示事务(手动提交事务)

package com.zzz.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 账户转账演示事务
 * 建表的sql脚本:
 *  drop table if exists t_act;
 *  create table t_act(
 *      act_no bigint,
 *      balance double(7,2)   //注意:7表示有效数字的个数,2表示小数位的个数
 *  );
 *  insert into t_act(act_no,balance) values (111,20000);
 *  insert into t_act(act_no,balance) values (222,0);
 *  commit;
 *  select * from t_act;
 *
 *  重点:事务的三行代码:
 *  conn.setAutoCommit(false); //关闭自动提交事务
 *  conn.commit(); //手动提交事务
 *  conn.rollback(); //回滚事务
 */
public class JDBCTest11 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        try {
            //1、注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2、获取连接
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
            //将自动提交机制改为手动提交
            conn.setAutoCommit(false); //开启事务

            //3、获取预编译的数据库操作对象
            ps = conn.prepareStatement("update t_act set balance = ? where act_no = ?");
            //给占位符 ? 传值
            ps.setDouble(1,10000);
            ps.setInt(2,111);
            int count = ps.executeUpdate();
            //给占位符 ? 传值
            ps.setDouble(1,10000);
            ps.setInt(2,222);
            count += ps.executeUpdate();

            System.out.println(count==2? "转账成功" : "转账失败");

            //程序能走到这里说明以上程序没有异常,事务结束,手动提交数据
            conn.commit(); //提交事务

        } catch (Exception e) {
            //回滚事务,保证数据的安全性
            if (conn != null){
                try {
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
            }
            e.printStackTrace();
        }finally{
            //6、关闭资源
            if (ps != null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

11、JDBC工具类的封装,并实现模糊查询

  • JDBC工具类的封装
package com.zzz.jdbc.utils;

import java.sql.*;

/**
 * JDBC工具类,简化JDBC编程
 */
public class DBUtil {
    /**
     * 工具类中的构造方法都是私有的,
     * 因为工具类当中的方法都是静态的,不需要new对象,直接采用类名调用。
     */
    private DBUtil(){}

    //静态代码块在类加载时执行,并且只加载一次
    static{
        //1、注册驱动
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    //获取连接,返回连接对象
    public static Connection getConnection() throws SQLException {
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/hive", "root", "111111");
        return conn;
    }

    /**
     * 关闭资源
     * @param connection 连接对象
     * @param statement 数据库操作对象
     * @param resultSet 结果集
     */
    public static void close(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
  • JDBC实现模糊查询
package com.zzz.jdbc;

import com.zzz.jdbc.utils.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

/**
 * 这个程序两个任务:
 *      1、测试封装的工具类DBUtil是否好用
 *      2、模糊查询怎么写
 */
public class JDBCTest12 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet resultSet = null;

        try {
            //获取连接
            conn = DBUtil.getConnection();
            //获取预编译的数据库操作对象
            String sql = "select name from people where name like ?";
            ps = conn.prepareStatement(sql);
            ps.setString(1,"_a%"); //第二个字母含有a的名字
            resultSet = ps.executeQuery();
            while (resultSet.next()){
                System.out.println(resultSet.getString("name"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //释放资源
            DBUtil.close(conn,ps,resultSet);
        }
    }
}
举报

相关推荐

0 条评论