JDBC 基本使用

目录

一. JDBC 基本概念
二. 快速入门
三. 详解JDBC中各个接口和类
四. 抽取JDBC工具类

内容

一. JDBC 基本概念

概念:Java DataBase Connectivity:Java数据库连接,是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。
JDBC本质:其实是官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库服务商去实现这套接口,提供数据库驱动jar包。我们可以使用这套JDBC接口编程,真正执行的代码是驱动jar包中的实现类。

二. 快速入门

步骤:
1. 导入驱动jar包 mysql-connector-java-8.0.15.jar
2. 注册驱动
3. 获取数据连接对象 Connection
4. 定义SQL语句
5. 获取执行SQL语句的对象 Statement(后期我们不会再使用该类,须使用 PreparedStatement)
6. 执行SQL语句,接收返回结果
7. 处理结果
8. 释放资源:倒序释放,先获取的资源后释放,后获取的资源先释放。

代码实现:

// 1. 导入驱动jar包 jar包版本:8.0.15
// 2. 注册驱动。com.mysql.cj.jdbc.Driver加载进字节码文件时,Driver类中的静态代码被执行:注册驱动。
// MySQL 5之后注册驱动的逻辑可以不用写。
Class.forName("com.mysql.cj.jdbc.Driver");
// 3. 获取数据库连接
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "root", "88888888");
// 4. 定义SQL语句,语句后面不可以加分号
String sql = "UPDATE account SET balance = 500 WHERE id = 1";
// 5. 获取sql对象,Statement
Statement stmt = connection.createStatement();
// 6. 执行SQL语句,接收返回结果
int count = stmt.executeUpdate(sql);
// 7. 处理结果
System.out.println("count = " + count);
// 8. 释放资源
stmt.close();
connection.close();

三. 详解JDBC中各个接口和类

1、DriverManager:驱动管理对象

① 注册驱动:加载指定的【数据库驱动jar包】

static synchronized void registerDriver(java.sql.Driver driver)

开发中我们使用如下代码注册驱动:

Class.forName("com.mysql.cj.jdbc.Driver");

因为,Driver 中存在如下静态代码块,静态代码会随着Driver类的加载而加载,注册驱动。
Driver中的静态代码块:

static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }

注意:MySQL5之后的驱动jar包可以省略注册驱动的步骤。建议仍然注册,兼容老版本。

②获取数据库连接
方法:

public static Connection getConnection(String url, String user, String password);

参数:
url:指定连接的路径
语法:jdbc:mysql://ip地址(域名):端口号/数据库名称

  • jdbc:mysql://是固定写法。
  • ip地址(域名)可以找到指定的计算机
  • 端口号:可以找到指定计算机上安装的mysql服务器
  • user:数据库登录用户名
  • password:数据库登录密码

示例:jdbc:mysql://localhost:3306/db2:连接本机db2数据库

  • 细节:如果连接的是本机的mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称

2、Connection:数据库连接对象
功能
① 获取执行 sql 的对象

Statement createStatement()
PreparedStatement prepareStatement(String sql)

②管理事务:

  • 开启事务:void setAutoCommit(boolean autoCommit); 设置参数为false,即开启事务。
  • 提交事务:void commit()
  • 回滚事务:void rollback()

3、Statement
执行SQL的对象。用于执行静态SQL语句并返回其生成的结果的对象。静态sql容易产生sql注入问题。

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

① 执行sql

// 可以执行任意的sql,了解即可。
boolean execute(String sql)
// 执行DML(update、insert、delete)语句、DDL(对数据库和表操作 create、alter、drop)语句
// DDL不常用。因为为了更方便的设计数据库和表,我们一般不使用JDBC来完成。
// 返回值为INT类型:表示执行sql语句影响的行数。执行DDL语句,没有返回结果,默认0。
// 返回值作用:可以通过影响的行数,判断DML语句是否执行成功,返回值>0则执行成功;返回,执行失败。
int executeUpdate(String sql)
// 执行DQL(select)语句
ResultSet executeQuery(String sql)

4、ResultSet
结果集对象,封装查询的结果

next 方法:ResultSet光标最初位于第一行之前,第一次调用方法next使第一行成为当前行,第二行调用使第二行称为当前行,以此类推。当返回false时,表示光标位于最后一行之后;返回true时,表示新的当前行有效。

// 游标向下移动一行,判断当前行是否最后一行末尾。
boolean next();

调用 next()方法后,若返回值为true,那么,我们就可以使用诸如:String getString(int columnIndex)int getInt(int columnIndex)String getString(String columnLabel)int getInt(String columnLabel)等等 getXXX 方法,获取当前行的记录数据。
其中:
若方法参数传 int,代表列的编号,默认从1开始。
若方法参数传 String,代表列的名称,即数据库对应的字段。

例如:

while (resultSet.next()) { // 判断当前行是否有效
       int id = resultSet.getInt(1);
        String name = resultSet.getString("name");
        BigDecimal balance = resultSet.getBigDecimal("balance");
}

实现功能:查询db1数据库中employee表,将查询结果封装为对象,然后装载集合。然后打印。

public List<Employee> findAll() {

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        List<Employee> list = new ArrayList<>();

        try {
            // 1. 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2. 获取mysql服务器连接对象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "root", "88888888");
            // 3. 定义sql语句
            String sql = "SELECT * FROM employee";
            // 4. 获取sql执行对象
            stmt = conn.createStatement();

            // 5. 执行sql语句
            rs = stmt.executeQuery(sql);
            // 6. 处理数据
            Employee emp = null;
            while (rs.next()) {

                int pk_id = rs.getInt("pk_id");
                String name = rs.getString("name");
                double salary = rs.getDouble("salary");
                String gender = rs.getString("gender");
                Date join_date = rs.getDate("join_date");
                int department_id = rs.getInt("department_id");


                emp = new Employee();
                emp.setPk_id(pk_id);
                emp.setName(name);
                emp.setSalary(salary);
                emp.setJoin_date(join_date);
                emp.setDepartment_id(department_id);
                if (gender != null) {
                    emp.setGender(gender.toCharArray()[0]);
                }

                list.add(emp);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 7. 释放资源
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

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

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

        return list;
    }

5、PreparedStatement
用于执行预编译SQL语句并返回其生成的结果的对象。以后开发中使用 PreparedStatement 替代 Statement,来完成增删改查的所有操作,因为其解决了SQL注入问题,且效率高于 Statement 。后起都使用PreparedStatement

① 预编译sql:参数使用 ? 作为占位符。
② 使用步骤:

  1. 导入驱动jar包 mysql-connector-java-8.0.15.jar
  2. 注册驱动
  3. 获取数据连接对象 Connection
  4. 定义SQL语句
    • 注意:sql的参数使用 ? 作为占位符。如: SELECT * FROM user WHERE username = ? AND password = ?;
  5. 获取执行sql语句的对象 PreparedStatement prepareStatement(String sql);
  6. 给 ? 赋值
    • 方法:使用 setXXX(参数1, 参数2)
      • 参数1:?的位置编号,从1开始;
      • 参数2:?的值;
  7. 执行sql语句,不需要传递sql语句参数。
  8. 处理结果
  9. 释放资源

四. 抽取JDBC工具类: JDBCUtils

通过练习,我们发现,在注册驱动、获取mysql服务连接、释放资源等代码实现,存在冗余。因为开发中,我们可以封装JDBC的工具类,简化代码。

① 我们可以在工具类中,在静态代码块中完成驱动的注册;
② 封装获取连接对象,url/user/password参数的获取,我们通过配置文件jdbc.properties来获取,保证工具类的通用性;
③ 释放资源,根据需求,重载即可。

配置文件:jdbc.properties

url=jdbc:mysql://localhost:3306/db1
user=root
password=88888888
driver=com.mysql.cj.jdbc.Driver

JDBCUtils.java:

public class JDBCUtils {
    // 定义三个静态私有属性(为什么是静态:只有静态属性才能被静态代码块访问)
    private static String url;
    private static String user;
    private static String password;
    private static String driver;

    // 文件的读取,只需要读取一次即可,获取到配置文件中的值。使用静态代码块(随着类的加载而加载,只执行一次)!
    static {

        try {
            // 1. 创建 Properties 集合类
            Properties pro = new Properties();

            // 获取 src路径下的文件的方式 ---> ClassLoader 类加载器
            ClassLoader classLoader = JDBCUtils.class.getClassLoader();
            // 动态获取指定的配置文件路径。直接src为根路径,统一资源定位符,[配置文件在src下创建]
            URL resUrl = classLoader.getResource("jdbc.properties");
            String path = resUrl.getPath();
            System.out.println("path = " + path);

            // 2. 加载文件
            pro.load(new FileReader(path));

            // 3. 获取属性赋值
            url = pro.getProperty("url");
            user = pro.getProperty("user");
            password = pro.getProperty("password");
            driver = pro.getProperty("driver");

            try {
                // 4. 注册驱动
                Class.forName(driver);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /** 
     * @description: 获取连接对象 
     * @param 
     * @return: java.sql.Connection 
     * @author: King
     * @date: 2019-03-01 17:18 
     */ 
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, user, password);
    }
    
    /** 
     * @description: 释放资源 
     * @param stmt sql执行对象
     * @param conn mysql服务连接对象
     * @return: void 
     * @author: King
     * @date: 2019-03-01 17:20 
     */ 
    public static void close(Statement stmt, Connection conn) {
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /** 
     * @description: 释放资源
     * @param rs 结果集对象
     * @param stmt sql执行对象
     * @param conn mysql服务连接对象
     * @return: void 
     * @author: King
     * @date: 2019-03-01 17:21 
     */ 
    public static void close(ResultSet rs, Statement stmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

    /**
     * @description:  释放资源
     * @param rs 结果集对象
     * @param pstmt sql执行对象
     * @param conn mysql服务连接对象
     * @return: void
     * @author: King
     * @date: 2019-03-01 19:21
     */
    public static void close(ResultSet rs, PreparedStatement pstmt, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (pstmt != null) {
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

猜你喜欢

转载自blog.csdn.net/weixin_41463971/article/details/88067347