【Java知识点整理】 MYSQL03 学习使用JDBC访问数据 以及 JDBC的优化和封装

通过JDBC 访问数据

一、使用Java访问数据库

JAVA 主动 提出接口 ,各种数据库适应 这些接口

  • 接口就是 JDBC Java Database Connector
  • 各种数据库都会提供一套对应的驱动程序(JAR文件
  • 即不同的数据库都有自己对应的JAR文件
1、导入mysql对应的JAR包
  1. 创建lib文件夹
  2. 将jar文件放入
  3. 右键jar包,点击 add as library导入包
2、访问数据库的步骤
  1. 加载驱动:涉及到反射

    • Class.forName 需要捕获异常
      • 快速添加异常的快捷键Alt + 回车,选第二个
  2. 连接数据库:查找db文件

    • 配置urljdbc:mysql://127.0.0.1:3306/zy_sys?useUnicode=true&characterEncoding=UTF-8&useSSL=false

      ip地址,数据库名字,编码unicode,不使用加密

      • zy_sys对应的是数据库名称
    • 创建连接Connection connection = DriverManager.getConnection(url , user , password);

      • 也需要异常捕获
  3. SQL语句

    • 创建一个字符串存储 SQL语句
    • 建议先在DBMS中测试一次
  4. 预编译SQL语句(判断语法错误,获取执行的对象)

    • 固定语法PreparedStatement preparedStatement = connection.prepareStatement(sql);
  5. 执行操作

  6. 获取执行结果

    • 增删改调用方法executeUpdate()

      • 返回类型int 表示受影响的条数
      • 获取执行结果只需要输出这个返回值即可
    • 查找调用方法executeQuery():

      • 返回值类型是ResultSet(结果集:类似对象列表)

      • 用 while 循环 遍历结果集.

        用到ResultSet.next()方法——向下移动一行,返回布尔值。默认是在空行,next一行才是第一行。举个例子如下:

          while (resultSet.next()){
                        // 使用对应的方法获得相应的数据类型
                        String sno = resultSet.getString("sno");
                        String sname = resultSet.getString("sname");
                        int sage = resultSet.getInt("sage");
                        // 按顺序输出结果即可
                        System.out.println(sno + "\t" + sname + "  \t" + sage);
                    }
        
  7. 关闭操作(关闭连接,关闭接口,关闭对象) 释放资源

    • 关闭顺序有大小之分,小的先关,大的后关
3、举个例子(增删改
package com.cykj.demo;

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

public class Test {
    public static void main(String[] args) {
        try {
            // 1、加载驱动  ——涉及到反射知识点
            Class.forName("com.mysql.jdbc.Driver"); // Driver类 驱动
            String url = "jdbc:mysql://127.0.0.1:3306/zy_sys?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
            // 2、连接数据库
            String user = "root";  // 账号
            String password = "root";   // 密码
            Connection connection = DriverManager.getConnection(url , user , password);     // 创建连接
            System.out.println("连接成功!");
            // 3、写SQL语句
            String sql = "INSERT INTO zy_student(sno,sname,ssex)  VALUES ('jx220501','老王',1)";
            // 4、预编译
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 5、执行操作
            int re = preparedStatement.executeUpdate();
            // sql的增删改都用executeUpdate() 返回类型int 表示受影响的条数
            // 6、获取执行结果
            System.out.println(re);
            // 7、关闭
            preparedStatement.close();  // 关闭编译
            connection.close();         // 关闭连接
            // 关闭顺序有大小之分,小的先关,大的后关
        } catch (ClassNotFoundException  e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
4、 查找例子
package com.cykj.demo;

import java.sql.*;

public class Test2 {
    public static void main(String[] args) {
        try {
            // 1、加载驱动  ——涉及到反射知识点
            Class.forName("com.mysql.jdbc.Driver"); // Driver类 驱动
            // 2、连接数据库
            String url = "jdbc:mysql://127.0.0.1:3306/zy_sys?useUnicode=true&characterEncoding=UTF-8&useSSL=false";
            String user = "root";  // 账号
            String password = "root";   // 密码
            Connection connection = DriverManager.getConnection(url , user , password);     // 创建连接
            System.out.println("连接成功!");
            // 3、写SQL语句
            String sql = "SELECT sno,sname,sage FROM zy_student WHERE sno LIKE 'AF%';";
            // 4、预编译
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            // 5、执行操作
            ResultSet resultSet = preparedStatement.executeQuery();  // 查找数据库用的是executeQuery()
            // 6、获取执行结果
            while (resultSet.next()){
                // 使用对应的方法获得相应的数据类型
                String sno = resultSet.getString("sno");        
                String sname = resultSet.getString("sname");
                int sage = resultSet.getInt("sage");
                // 按顺序输出结果即可
                System.out.println(sno + "\t" + sname + "  \t" + sage);
            }
            // 7、关闭
            resultSet.close();
            preparedStatement.close();  // 关闭编译
            connection.close();         // 关闭连接
            // 关闭顺序有大小之分,小的先关,大的后关

        } catch (ClassNotFoundException  e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

===输出结果===
AF121101	小王  	22
AF121102	小红  	22
AF121103	王思思  	23
AF121104	小灰  	30
AF121105	小林  	27
AF121106	小张  	26
AF121107	小丽  	32
AF121108	小花  	29
AF121109	小马  	26

JDBC优化

一、在预编译时拼接字符串

  • SQL语句的拼接,有什么缺点?

    • 写法麻烦
    • 不安全,留有SQL注入的风险
  • 如何解决呢?

    用问号?替代字符串中需要拼接的位置

    • 预编译时加入字符串,举个例子
    // 原字符串
    String sql = "SELECT * FROM tb_user WHERE userid = '" + useridText + "' OR username = '" + useridText + "'";
    
    • 修改后
                // 用问号替代拼接的字符串  意思类似挖坑
    String sql = "SELECT * FROM tb_user WHERE userid = ? OR username = ?";;
    ps = connection.prepareStatement(sql);  // 预编译
    // 利用setString()方法 插入字符串,计数从1开始
    ps.setString(1,useridText); 
    ps.setString(2,useridText);
    
    • 简单理解:这种方法类似挖坑和填坑
      1. 先挖坑:用问号?替代也要拼接的字符串
      2. 再填坑,利用setString()方法 插入字符串,计数从1开始
    • 注意:setString会自动给这个字符串加入单引号,无需再添加

二、优化关闭操作

  • 在JDBC操作中,如果编译出现报错,后续的关闭操作就不再执行了。这样会导致数据库负担较大

    • 要如何解决该问题呢?
      • 利用异常关键字finally的特点:异常处理中finally是最后必须执行一次的,可以把关闭操作写在这里!
  • 具体操作如下

    1. 将需要关闭的对象,设置为全局变量

    2. 目标**:在finally语句块里关闭对象**

    3. 关闭时也要加入异常捕获,注意:每次关闭都要分别捕获异常

    4. 在关闭前,也要加入一个if判断,判断对象不等于null,才进行关闭操作。举个例子

      try{
          。。。
      } catch{
          。。。
      } finally {
          try {
              if (connection != null){	// 判断连接是否为空
                  connection.close();		// 关闭连接
              }
          } catch (SQLException e) {	// 加入关闭操作的异常捕获
              e.printStackTrace();
          }
          try {
              if (ps != null) {
                  ps.close();
              }
          } catch (SQLException e) {
              e.printStackTrace();
          }
      }
      

三、封装

经过观察发现,1、2、7三步的基本类似,可以偷懒共同的方法,可以封装起来,甚至写成一个类,即:

共同的代码———> 方法 ———> 类

1、2、7三步的代码 ———> 分别封装成方法 ———> 放在同一个类中(工具层)

  • 这种类存放在工具层,这个类就成为"工具包"
1、 工具类 Utils
  • 用于存放各种封装起来的方法,提供给其他模块调用
2、封装第一步和第二步 加载驱动建立连接
  • 封装1+2步

    public Connection getConnection (){
        try {
            // 1、加载驱动
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql://127.0.0.1:3306/goods_db?" +
                    "useUnicode=true&" +
                    "characterEncoding=UTF-8&useSSL=false";
            String user = "root";
            String password = "root";
            // 2、建立连接
            Connection connection = DriverManager.getConnection(url,user,password);
            return connection;  // 连接成功则返回连接
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;        // 连接失败则返回空
    }
    
  • 但是存在一个问题,URL,用户名,密码都是不固定的,这时候就需要用到配置文件*.properties” 、 xmlyml

    • 如何使用配置文件?
3、properties配置文件的使用
  • 键值对格式 : key=value

    • 注意:等号的两边都不能有空格
  • 具体使用步骤

    1. 将配置文件 拷贝到 项目工程目录 下

    2. 读取配置文件的值

      • 要有对应的库 ——> 找到对应的或对象 ——> 方法

      • Java有对应的类 Properties,实现的思路如下:

        1. 读取文件 调用InputStream类 (IO流的内容 后续会接触到
        2. 实例化属性类 Properties
        3. 调用load(文件名)加载文件
        4. 取值 用getProperty(键名)来搜索对应的数据,返回值类型为String
      • 举个例子

        public static void main(String[] args) {
            try {
                // 用IO读取文件
                InputStream inputStream = new FileInputStream("db.properties");
                // 加载
                Properties pps = new Properties();
                pps.load(inputStream);
                // 获取字符串
                String driver = pps.getProperty("driver");
                System.out.println(driver);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
    3. 在工具类中,获取对应的驱动,url,用户名,密码存放在String

    4. 在执行连接数据库时,直接调用这些字符串进行登陆即可


  • 在实际应用场景中,只需要读取一次配置文件。那么,如何只读取一次配置文件?
    • 构造函数?实例化的时候只运行一次,但是多次实例化还会再次执行
    • 这里就需要用到静态代码块——
      • 语法:static {代码块}
      • 在类里的静态代码块,只会执行一次
      • 执行的时间是在构造函数之前,且需要实例化的时候才会运行

4、封装第七步:关闭操作
  • 举个例子

    public void closeJdbc(Connection con , PreparedStatement ps , ResultSet rs){
        try {
            if (rs != null){
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (con != null){	// 判断连接是否为空
                con.close();		// 关闭连接
            }
        } catch (SQLException e) {	// 加入关闭操作的异常捕获
            e.printStackTrace();
        }
        try {
            if (ps != null) {
                ps.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
5、调用思路
  • 思路如下:

    1. 先将工具类实例化为全局变量 (所有需要关闭的对象也要声明为全局变量)
    2. 调用工具类的方法 getConnection () 获取 连接 Connection
      • 对应的完成了第一步和第二步
    3. 继续完成 写SQL语句 预编译 执行和获取结果的步骤
    4. 在最后的finally的语句块中调用关闭的方法closeJdbc(),关闭掉对应的对象。
      • 由于关闭方法有多个对象,当不存在某个对象时,可以传入null
6、工具类的具体案例
  • 举个例子

    Connection connection = null;
    PreparedStatement ps = null;
    ResultSet resultSet = null;
    JdbcUtils jdbcUtils = new JdbcUtils();
    connection = jdbcUtils.getConnection();	// 调用方法获得连接
    try {
        String sql = "SELECT * FROM tb_user WHERE userid = ? OR username = ?";  // 预编译
        ps = connection.prepareStatement(sql);
        ps.setString(1, useridText);
        ps.setString(2, usernameText);
        resultSet = ps.executeQuery();
        if (resultSet.next()) {
            JOptionPane.showMessageDialog(null, "账号已重复!",
                    "注意", JOptionPane.WARNING_MESSAGE);
            return;
        } else {
            // 账号没有重复 可以继续执行操作 。。。
        }
    } catch (SQLException e) {
    	e.printStackTrace();
    } finally {
    	jdbcUtils.closeJdbc(connection, ps, resultSet);
        // 如果没有resultset,就传入null即可
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xcong_Zhu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值