JDBC从0到1的学习 (提供JDBC 工具类,数据库连接池工具类)

2022-05-14 09:50:17 浏览数 (1)

目录

  • 1 jdbc概念
  • 2 jdbc原理
  • 3 jdbc加载驱动代码
    • 3.1 看源码
    • 3.2 为什么不需要我们自己注册
  • 4 类对象介绍
    • 4.1 DriverManager
    • 4.2 Connection
    • 4.3 statement
    • 4.4 ResultSet
  • 5 JDBC 工具类
  • 6 解决sql注入问题
  • 7 JDBC 管理事务
  • 8 jdbc 获取数据库连接对象connection
  • 9 使用statement接口实现crud
  • 10 数据库连接池
    • 10.1 概念
    • 10.2 DataSource
  • 11 自定义jdbc框架
    • 11.1 需求
    • 11.2 数据库源信息

1 jdbc概念

2 jdbc原理

也就是,jdbc是基准,其他公司,比如mysql,oracle这些公司,基于这个jdbc基本,封装jdbc基准里面的api,变为自己的,也就是变为自己的东西,这个就是驱动类;

我们连接mysql,需要mysql的驱动类driver;连接oracle,需要oracle的驱动类,这些驱动类就是各个数据库厂家提供的;

3 jdbc加载驱动代码

我们创建一个maven,导入mysql的依赖

代码语言:javascript复制
    <!--mysql驱动包-->
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>
    </dependencies>

以上这个是mysql的驱动包,这个就是mysql数据库公司封装了jdbc之后,自己的东西,以后我们使用这个驱动包,就可以在代码里面连接mysql数据库,并且操作数据库了;

以上在maven项目的pom文件里面写了这个,就相当于引入了mysql的驱动

mysql的驱动名称是com.mysql.jdbc.Driver

这个是mysql公司定的,我们使用就可以,我们在项目里面看看,能不能拿到这个对应的驱动

以上说明,只要添加了驱动,我们就可以在代码里面获取到驱动;

3.1 看源码

首先我们导入mysql的jar包,这个jar包就是mysql公司,封装了jdbc接口实现的一个项目,一个jar包就是一个项目,因为这个项目实现了java的jdk给提供的jdbc的接口,所以,我们就可以使用这个项目进行操作数据库,首先,每一个项目都有一个项目的入口,mysql的这个jar包也有,现在就是叫做驱动类,只要我们自己的项目,加载了这个驱动类,那么就有了mysql这个jar包的入口了;

1 我们看mysql的jar包的源码

找到驱动类

看这个类里面的代码

就相当于,我们一创建这个驱动类的对象,或者加载这个类,那么当前的jar包就和我们的jdk关联了;

3.2 为什么不需要我们自己注册

因为人家的jar包,已经有一个配置文件,这个里面配置了驱动类,直接读取这个配置文件,直接就可以进行注册,不需要我们自己注册

4 类对象介绍

4.1 DriverManager

这个类是jdk里面的,

4.2 Connection

这个类的对象,就是获取到了对应数据库的对象,之后根据这个对象,就可以操作数据库

4.3 statement

4.4 ResultSet

5 JDBC 工具类

这个工具类的作用就是,以后有人拿到这个代码,按照这个工具类里面的方法就可以操作数据库了

写一个配置文件

配置文件里面的内容是

代码语言:javascript复制
url=jdbc:mysql://localhost:3306/eshop
user=root
password=123456
driver=com.mysql.jdbc.Driver
代码语言:javascript复制
public class JDBCUtils {

// 1 私有构造方法
    private JDBCUtils(){};


//    2 声明所需要的配置变量
    private static String url ;
    private static String user ;
    private static String password ;
    private static String driver;


//    3 提供静态代码块,读取配置文件里面的信息为变量赋值,注册驱动
    static {
        Properties pro = new Properties();
        //这里是通过类加载器获取jdbc.propertise的绝对路径
        //首先获取类的加载器,然后通过类的加载器获取src路径下资源的绝对路径
        //这里的意思是不管模块如何移植,只要在模块当中,就能通过相对路径找到
        //绝对路径
        ClassLoader loader = JDBCUtils.class.getClassLoader();
        //通过类加载器获取scr路径下的资源的绝对路径
        URL res = loader.getResource("JDBC.properties");
        //获取绝对路径
        String path = res.getPath();

        try {
            pro.load(new FileReader(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        url = pro.getProperty("url");
        user = pro.getProperty("user");
        password = pro.getProperty("password");
        driver = pro.getProperty("driver");


        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


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


//    关闭statement对象   和   Connection对象
    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();
            }
        }
    }


//     关闭statement对象   和   Connection对象  和  ResultSet对象
    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();
            }
        }
    }


}

6 解决sql注入问题

就是使用预编译

7 JDBC 管理事务

如果多个方法都有事务,一个方法调用另一个方法,那么要保证多个方法使用的数据库的连接对象是同一个;

8 jdbc 获取数据库连接对象connection

我们在项目里面已经加载了驱动,之后根据驱动,就可以连接到mysql数据库了;这个驱动里面有很多的接口或者类,我们在代码里面只要操作这些,就可以操作数据库了;

我们首先要使用驱动获取到数据库连接,就是相当于获取到一个数据库对象,以后就可以拿这个对象进行操作数据库了;

代码语言:javascript复制
package com.jing;/**
 * @author jing
 * @date 2022/3/29  --  19:13
 */

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

/**
 * @author jing
 * @date 2022年03月29日 19:13
 */
public class jdbctest02 {

//    我要连接哪个数据库
    private static String dbUrl="jdbc:mysql://localhost:3306/eshop";
//    数据库的用户名
    private static String username = "root";
//    数据库的密码
    private static String password = "123456";
//    使用哪个驱动进行连接数据库
    private static String jdbcName = "com.mysql.jdbc.Driver";

    public static void main(String[] args) {
        try {
//            当前项目加载驱动
            Class.forName(jdbcName);
            System.out.println("加载成功");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("加载失败");
        }
        Connection connection =null;
        try {
//            DriverManager 是驱动包里面的类,使用这个类里面的各种各样的方法进行操作数据库
            connection = DriverManager.getConnection(dbUrl, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

我们获取到connection对象,以后就在项目里面,就可以使用这个去操作数据库;

9 使用statement接口实现crud

我们以上已经获取到了数据库连接对象connection,使用这个获取statement接口对象,使用里面的方法就可以执行sql语句了,这个sql语句和我们在Navicat里面执行一样;

就是使用statement去操作sql语句;

代码语言:javascript复制
public class jdbctest02 {

//    我要连接哪个数据库
    private static String dbUrl="jdbc:mysql://localhost:3306/eshop";
//    数据库的用户名
    private static String username = "root";
//    数据库的密码
    private static String password = "123456";
//    使用哪个驱动进行连接数据库
    private static String jdbcName = "com.mysql.jdbc.Driver";

    public static void main(String[] args) {
        try {
//            当前项目加载驱动
            Class.forName(jdbcName);
            System.out.println("加载成功");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            System.out.println("加载失败");
        }
        Connection connection =null;
        Statement statement =null;
        try {





//            DriverManager 是驱动包里面的类,使用这个类里面的各种各样的方法进行操作数据库
            connection = DriverManager.getConnection(dbUrl, username, password);
            statement = connection.createStatement();
            String sql = "select *  from product";
            boolean execute = statement.execute(sql);
            System.out.println(execute);



        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            try {
                statement.close();
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}

10 数据库连接池

10.1 概念

10.2 DataSource

这个是一个接口,java的jdk提供的,所以我们想要创建一个数据库连接池,就得自己写一个类,实现这个接口;

或者直接自己写一个类

代码语言:javascript复制
package com.jing.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 *
 *
 */
public class DataSourcePool {
    /**
     * 最大连接数
     */
    private static final int COUNT = 10;
    /**
     * 存放数据库
     */
    private static final LinkedList<Connection> connections = new LinkedList<Connection>();
    /**
     * 创建锁
     */
    private static final ReentrantLock lock = new ReentrantLock();
    private static final Condition notEmpty = lock.newCondition();
    private static final Condition notFull = lock.newCondition();
    /**
     * 数据库连接
     */
    private static String URL;
    /**
     * 用户名
     */
    private static String USER_NAME;
    /**
     * 密码
     */
    private static String PASS_WORD;
    /**
     * 驱动类型
     */
    private static String DRIVER_CLASS_NAME;
    /**
     * 存放属性信息
     */
    private static Properties properties = new Properties();

    /**
     * 初始化信息
     */
    static {
        InputStream is = DataSourcePool.class.getResourceAsStream("JDBC.properties");
        try {
            properties.load(is);
            URL = (String) properties.get("url");
            USER_NAME = (String) properties.get("userName");
            PASS_WORD = (String) properties.get("passWord");
            DRIVER_CLASS_NAME = (String) properties.get("driver");
            //加载驱动
            Class.forName(DRIVER_CLASS_NAME);
            Connection connection = null;
            for (int i = 0; i < 10; i  ) {
                connection = DriverManager.getConnection(URL, USER_NAME, PASS_WORD);
                connections.add(connection);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取Connection
     */
    public static Connection getConnection() {
        final ReentrantLock reentrantLock = lock;
        reentrantLock.lock();
        try {
            //如果没有连接了,则等待着新放入的连接
            if (connections.isEmpty()) {
                notEmpty.await();
            }
            Connection connection = connections.removeFirst();
            notFull.signalAll();
            return connection;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
        return null;
    }

    /**
     * 释放连接
     *
     * @param connection
     */
    public static void release(Connection connection) {
        final ReentrantLock reentrantLock = lock;
        reentrantLock.lock();
        try {
            if (connections.size() == COUNT) {
                notFull.await();
            }
            if (connection == null || connection.isClosed()) {
                connections.add(DriverManager.getConnection(URL, USER_NAME, PASS_WORD));
                notEmpty.signalAll();
                return;
            }
            //恢复默认值
            if (connection.getAutoCommit() == false) {
                connection.setAutoCommit(true);
            }
            connections.add(connection);
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

}

11 自定义jdbc框架

之后我们使用的mybatis,就是封装了jdbc,把之前我们使用jdbc的语句封装了一下,因为我们就是要一个sql语句块,那些获取连接对象,关闭连接对象,都是公共的,我们不想操作,所以我们也要进行封装,可以这样说,这个自定义的jdbc的框架,就是mybatis框架的简化版;

11.1 需求

11.2 数据库源信息

0 人点赞