JDBC day01

JDBC day01

1 JDBC引言

1.1 JDBC简介

JDBC(Java DataBase Connectivity) :Java数据库连接技术:具体讲就是通过Java连接广泛的数据库,并对表中数据执行增、删、改、查等操作的技术。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PmL8NHSH-1631064881911)(JDBC day01.assets/image-20210513140744246.png)]

此前我们学习过SQL后,可以通过 NavicatSQLyog等图形化客户端发送SQL操作数据库。本质上,JDBC的作用和图形化客户端的作用相同,都是发送SQL操作数据库。差别在图形化界面的操作是图形化、傻瓜化的,而JDBC则需要通过编码(这时候不要思考JDBC代码怎么写,也不要觉得它有多难)完成图形操作时的效果。

总结:JDBC本质上也是一种发送SQL操作数据库的client技术,只不过需要通过Java编码完成。

为什么要学习JDBC?
既然说JDBC和 Navicat的作用相同,而 Navicat图形化操作很简单(我们也很熟练),那么为什么还要学习操作更复杂(需要编码)、更陌生的新的Java客户端技术呢?

Java是可编程的(可定制化),可以将普通用户输入的数据拼接成各种各样的可运行的SQL,从而降低普通用户使用数据库服务的难度。

举个例子:任何系统中都有登录功能,登录时需要从用户表中根据用户名查询然后比对密码,每个人的用户名密码肯定不同,执行的select语句的条件部分就不同,直接让用户通过 Navicat 操作数据库,就得由用户拼接SQL,这对于小白用户要求过高。而JDBC就可以通过Java代码将用户输入的用户名密码拼接到SQL中完成查询,普通小白用户通过JDBC程序操作数据库时,只要会输入用户名密码即可!!!

1.2 JDBC涉及的API

JDBC要通过Java代码操作数据库,JDBC中定义了操作数据库的各种接口和类型:

  • Driver 驱动接口 定义了Java如何和数据库获取连接
  • DriverManager 工具类 提供了管理驱动的便捷能力,可以获取和数据库的连接
  • Connection 连接接口 代表Java和数据库之间的联系
  • PreparedStatement 发送SQL的工具接口 该类型对象用于向数据库发送一条SQL
  • ResultSet 结果集接口 该类型的对象表示一条查询SQL返回的结果

注意:学习到这里不需要你掌握上述的任何一个类型(后续会逐步学习到每一个类型),只需要加深理解JDBC需要通过编码操作数据库(也就是JDBC的可编程属性)即可。

1.3 JDBC是规范不是实现

从根本上来说,JDBC 是一种规范,它提供了一套完整的接口,允许便携式访问到底层数据库,因此可以轻松的用 JDBC编写适用于各种数据库的程序。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zbjfxpFq-1631064881913)(JDBC day01.assets/1578018059416.png)]

为什么JDBC只有接口,没有提供实现?

不同数据库的底层技术不同,不少数据库是闭源的,源代码不公开的。Sun公司无力为所有数据库提供具体实现,只能提供接口而由数据库厂商提供具体实现,Sun公司只是制定JDBC标准,各个厂商准守标准提供具体的实现。JDBC和数据库实现的关系就好比List接口和ArrayList、LinkedList之间的关系。

面向JDBC接口规范编程,写出的JDBC代码可以在不同的数据库间轻松的迁移。

2 JDBC编程

2.1 JDBC的编程步骤

之前,我们已经反复强调JDBC是一种和 Navicat 相当的客户端程序,那么JDBC操作数据库的步骤和 Navicat 操作数据库步骤就大同小异,下面我们先回顾下 Navicat的操作步骤,然后分析出JDBC的步骤。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yYedvuB8-1631064881913)(JDBC day01.assets/image-20210513142741673.png)]

总结:开发步骤

1. 加载驱动

2. 获取链接

3. 准备SQL以及发送SQL的工具

4. 执行SQL

5. 处理结果集

6. 释放资源

2.2 第1个JDBC程序

需求:向t_person表中新增一行数据

create table t_person(
	person_id int primary key auto_increment,
    person_name varchar(20),
    age tinyint,
    sex enum('男','女','其他'),
    mobile varchar(20),
    address varchar(200)
);

-- 需求 向t_person表中插入一行数据
insert into t_person values(null,'王鹏',88,'其他','138383838','硅谷');
  1. 准备工作(搭建开发环境)

    需要在项目中引入数据库驱动jar包(jar文件:针对class文件的压缩格式包含了多个带包的class文件,类似于普通文件打包的zip、rar)

    • eclipse

      将mysql-connector-java.jar添加到项目环境中
      1. 右键选中项目,新建一个folder名为lib,将jar包复制到lib目录中
      2. 右键选中jar包,build path-->add to build path
      
    • idea

      将mysql-connector-java.jar添加到项目环境中
      1. 右键选中项目,新建一个Directory名为lib,将jar包复制到lib文件夹中
      2. 右键选中jar包,Add as Library --> OK
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EADekke-1631064881914)(JDBC day01.assets/image-20210513143446395.png)]

  2. 编码(JDBC6步)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yEGB46kj-1631064881914)(JDBC day01.assets/image-20210510130416220.png)]

    public class JDBCTest {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1 加载驱动
            /*
            	驱动版本8.0.x com.mysql.cj.jdbc.Driver
            	驱动版本5.1.x com.mysql.jdbc.Driver
            */
            Class.forName("com.mysql.cj.jdbc.Driver");
            
            //2 获取连接
            String username = "root";//用户名
            String password = "123456";//密码
            /*
                url参数用来确定连接的数据库信息: 数据库机器ip 端口号port 数据库名db_name 连接的参数,比如编解码集、时区...
                url格式:jdbc:mysql://ip:port/db_name?k=v参数 ,只需要了解url的组成,不需要记忆
            */
            String url = "jdbc:mysql://localhost:3306/baizhi?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai";
            Connection conn = DriverManager.getConnection(url, username, password);//通过DriverManager管理驱动获取连接
            
            //3 准备发送SQL的工具
            String sql = "insert into t_person values(null,'王月华',88,'其他','138383838','硅谷')";
            PreparedStatement pstm = conn.prepareStatement(sql);
            
            //4 发送执行SQL
            int update = pstm.executeUpdate();
            System.out.println("影响数据的条数:"+update);
            
            //5 处理结果集(如果有)
    
            //6 释放资源(反序关闭:后出现先关闭)
            pstm.close();
            conn.close();
        }
    }
    

课堂练习:

  1. 完成上课案例
  2. 使用JDBC,完成删除和修改(提示:只是sql语句不同)

3 结果集的处理

需求:查询t_person表中的数据

select * from t_person;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w83p75x8-1631064881915)(JDBC day01.assets/image-20210513145815920.png)]

开发步骤回顾

//1 加载驱动

//2 创建和数据库之间的连接

//3 准备一个发送SQL的工具

//4 发送并执行SQL

//5 处理结果集

//6 释放资源

案例演示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JVQh80PV-1631064881915)(JDBC day01.assets/image-20210510150147516.png)]

public class ResultSetTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1 加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2 创建和数据库之间的连接
        String url = "jdbc:mysql://localhost:3306/baizhi?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username, password);

        //3 准备一个发送SQL的工具
        String sql = "select * from t_person";
        PreparedStatement pstm = conn.prepareStatement(sql);

        //4 发送并执行SQL
        ResultSet rs = pstm.executeQuery();

        //5 处理结果集
        while(rs.next()){
            /*
                rs.getXxx(列顺序从1开始) 或者 rs.getXxx("列名") 获取指定列的数据,Xxx为数据类型
                实战中多使用列名,可读性强
             */
            int personId1 = rs.getInt("person_id");
            String personName1 = rs.getString("person_name");
            int age1 = rs.getInt("age");
            String sex1 = rs.getString("sex");
            String mobile1 = rs.getString("mobile");
            String address1 = rs.getString("address");
            System.out.println("personId="+personId1+",personName="+personName1
                    +",age="+age1+",sex="+sex1+",mobile="+mobile1+",address="+address1);

            int personId2 = rs.getInt(1);
            String personName2 = rs.getString(2);
            int age2 = rs.getInt(3);
            String sex2 = rs.getString(4);
            String mobile2 = rs.getString(5);
            String address2 = rs.getString(6);
            System.out.println("personId="+personId2+",personName="+personName2
                    +",age="+age2+",sex="+sex2+",mobile="+mobile2+",address="+address2);
        }

        //6 释放资源
        rs.close();
        pstm.close();
        conn.close();
    }
}

4 数据绑定

数据绑定:将用户输入的数据,绑定到要执行的SQL语句中。

JDBC执行的SQL中的数据要根据用户的输入发生变化,比如 登录功能背后的查询sql要根据用户名不同,执行不同的条件。这就需要将用户输入的数据绑定到执行的SQL中。

绑定数据的方式有2种:

  • 字符串拼接
  • ?占位符绑定

环境准备:

create table t_admin(
	admin_id int primary key auto_increment,
    admin_name varchar(20) unique not null,
    password varchar(50) not null
);

-- 添加测试数据
insert into t_admin values(null,'xiaohei','123456');

4.1 字符串拼接

字符串拼接方式,本质上就是通过Java字符串拼接语法构造出正确的可执行的SQL语句。拼接步骤如下:

  1. 在需要数据的地方,使用变量名替换
  2. 在变量名前添加"+,变量后添加+"
  3. 注意:如果拼接的是字符串,那么需要在"+之前添加’ 在+"后添加’

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fhWnoSwr-1631064881916)(JDBC day01.assets/image-20210510161811265.png)]

public class DataBindingStringJoinTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1 加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2 创建和数据库之间的连接
        String url = "jdbc:mysql://localhost:3306/baizhi?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username, password);

        //3 准备一个发送SQL的工具
        Scanner sc = new Scanner(System.in);
        String adminName = sc.nextLine();
        String adminPassword = sc.nextLine();
        /*
            ① 在需要绑定数据的地方,使用变量名替换
            ② 在变量名前追加( "+ )  在变量名后追加( +" )
            ③ 注意:如果拼接的数据是字符串,那么需要在"+前和+"后各添加一个'
         */
        String sql = "select * from t_admin where admin_name = '"+adminName+"' and password = '"+adminPassword+"'";
        System.out.println("sql = " + sql);
        PreparedStatement pstm = conn.prepareStatement(sql);

        //4 发送并执行SQL
        ResultSet rs = pstm.executeQuery();

        //5 处理结果集
        if(rs.next()){
            int adminId= rs.getInt("admin_id");
            String name = rs.getString("admin_name");
            String pwd = rs.getString("password");
            System.out.println("adminId="+adminId+",adminName="+name+",adminPassword="+pwd);
        }

        //6 释放资源
        rs.close();
        pstm.close();
        conn.close();
    }
}

4.2 ?占位符

?占位符是JDBC的一种特殊语法,专用于参数绑定。使用步骤:

  1. 在需要使用数据的地方,使用?代替(占位)
  2. 发送sql前,通过pstm.setXXX方法给?赋值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qnol5CGh-1631064881916)(JDBC day01.assets/image-20210510162739060.png)]

public class DataBindingPreparedStatementTest {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1 加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2 创建和数据库之间的连接
        String url = "jdbc:mysql://localhost:3306/baizhi?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai";
        String username = "root";
        String password = "123456";
        Connection conn = DriverManager.getConnection(url, username, password);

        //3 准备一个发送SQL的工具
        Scanner sc = new Scanner(System.in);
        String adminName = sc.nextLine();
        String adminPassword = sc.nextLine();

        /*
        	① sql中需要绑定数据的地方使用?占位
            ② 通过pstm.setXXX(?序号,数据)绑定数据;//序号从1开始,XXX为数据类型
         */
        String sql = "select * from t_admin where admin_name = ? and password = ?";
        PreparedStatement pstm = conn.prepareStatement(sql);
        pstm.setString(1,adminName);
        pstm.setString(2,adminPassword);

        //4 发送并执行SQL
        ResultSet rs = pstm.executeQuery();

        //5 处理结果集
        if(rs.next()){
            int adminId= rs.getInt("admin_id");
            String name = rs.getString("admin_name");
            String pwd = rs.getString("password");
            System.out.println("adminId="+adminId+",adminName="+name+",adminPassword="+pwd);
        }

        //6 释放资源
        rs.close();
        pstm.close();
        conn.close();
    }
}

4.3 字符串拼接和?占位符的区别

方式特点使用场景最佳实践
字符串拼接可能会被SQL注入攻击可以拼接表名、列名、SQL关键字动态的查询不同的表以及根据用户选择升序或者降序查询数据
?占位符可以防止SQL注入攻击绑定纯数值数据通常情况下使用占位符

5 异常

解决问题的步骤:

  1. 定位问题(哪一行出错)

    ① 添加打印语句

    ② 根据异常信息定位(找到异常信息中关于自己写的代码部分)

  2. 为什么出错

    根据异常信息和所学知识分析问题的原因

  3. 解决异常

    根据问题的原因,解决异常记录异常

5.1 根据异常日志分析

分析异常最高效的办法是阅读异常日志,根据异常日志的信息,可以快速定位问题的位置、问题的原因设置是问题的解决方案。举个例子:

Exception in thread "main" java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382) // 数字指的是代码行号
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:264)
	at com.baizhi.test.ResultSetTest.main(ResultSetTest.java:8)
  1. 先看异常类型:

    ClassNotFoundException: com.mysql.cj.jdbc.Driver,说明是驱动类文件没有找到

  2. 再看异常位置:

    自上而下看出现数字的行,找到自己写的代码。比如当前案例下:自己的代码 ResultSetTest.java第8行有问题,那么错误就在这里发生的

  3. 解决方案:

    oracle.jdbc.OracleDriver类没找到,这行代码是加载驱动类的,就一定要先找到对应的类。

    错误原因:① 类名写错了

    ​ ② 驱动jar包没有导入当前项目中

说明:阅读异常日志挑错是最有效的,但是对于初学者而言难度过高。刚开始不用急于求成,异常信息也非常有规范,在学习过程中慢慢提升异常阅读能力,最终掌握阅读异常信息的能力。

5.2 添加打印语句

笨但有效的办法:手动添加打印语句

可以在代码的关键位置处添加打印语句,通过语句的输出与否判定异常发生的问题。
打印输出尽量有意义,比如关键代码有返回值,则可以打印返回值。这样通过返回值可以判断程序运行的状态,为调错提供指导。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A2qm9D1B-1631064881917)(JDBC day01.assets/image-20210510172558318.png)]

5.3 掌握JDBC中的异常

JDBC的异常其实还是非常固定的,就那么几种:类加载问题、数据库用户名密码错误、sql语法错误、绑定数据错误、获取数据错误…
有1个办法可以快速的掌握JDBC中的异常:站在上帝视角,人为的造错,观察记录异常信息,日后出现时可以快速调错。

② 驱动jar包没有导入当前项目中

说明:阅读异常日志挑错是最有效的,但是对于初学者而言难度过高。刚开始不用急于求成,异常信息也非常有规范,在学习过程中慢慢提升异常阅读能力,最终掌握阅读异常信息的能力。

5.2 添加打印语句

笨但有效的办法:手动添加打印语句

可以在代码的关键位置处添加打印语句,通过语句的输出与否判定异常发生的问题。
打印输出尽量有意义,比如关键代码有返回值,则可以打印返回值。这样通过返回值可以判断程序运行的状态,为调错提供指导。

[外链图片转存中…(img-A2qm9D1B-1631064881917)]

5.3 掌握JDBC中的异常

JDBC的异常其实还是非常固定的,就那么几种:类加载问题、数据库用户名密码错误、sql语法错误、绑定数据错误、获取数据错误…
有1个办法可以快速的掌握JDBC中的异常:站在上帝视角,人为的造错,观察记录异常信息,日后出现时可以快速调错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值