JDBC 入门

目录

  • 1 JDBC 快速入门
    • 1.1 JDBC 的概念
    • 1.2 JDBC 快速入门
  • 2 JDBC 功能类详解
    • 2.1 DriverManager
    • 2.2 Connection
    • 2.3 Statement
    • 2.4 ResultSet
  • 3 JDBC 工具类
  • 4 SQL 注入攻击
  • 5 JDBC 事务
    • 5.1 JDBC 管理事务
  • 6 连接池
    • 6.1 数据库连接池的概念
    • 6.2 自定义数据库连接池
      • 6.2.1 DataSource
      • 6.2.2 归还连接
        • 6.2.2.1 继承方式
        • 6.2.2.2 装饰设计模式
        • 6.2.2.3 适配器设计模式
        • 6.2.2.4 动态代理
        • 6.2.2.5 动态代理方式
    • 6.3 开源数据库连接池
      • 6.3.1 C3P0 数据库连接池的使用
      • 6.3.2 Druid 数据库连接池的使用步骤
      • 6.3.3 Druid 数据库连接池的工具类

1 JDBC 快速入门

1.1 JDBC 的概念

  1. JDBC的概念
    • JDBC(Java DataBase Connectivity java数据库连接)是一种用于执行SQL语句的 Java API,可以为多种关系型数据库提供统一访问,它是由一组用 Java 语言编写的类和接口组成
  2. JDBC的本质
    • 其实就是 Java 官方提供的一套规范(接口)。用于帮助开发人员快速实现不同关系型数据库的连接

1.2 JDBC 快速入门

  • 代码演示
public class JDBCDemo01 {
    public static void main(String[] args) throws Exception {
        //1. 导入jar包

        //2. 注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //3. 获取连接
        Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/girls?useSSL=false&serverTimezone=UTC","root","1234");

        //4. 获取执行者对象
        Statement stat = con.createStatement();

        //5.执行sql语句,并且接收结果
        String sql = "SELECT * FROM boys";
        ResultSet rs = stat.executeQuery(sql);

        //6.处理结果
        while (rs.next()){
            System.out.println(rs.getString("boyName") + "\t" + rs.getString("userCP"));
        }

        //7.释放资源
        con.close();
        stat.close();
        rs.close();

    }
}

2 JDBC 功能类详解

2.1 DriverManager

  1. DriverManager驱动管理对象
    ① 注册驱动

    • 注册给定的驱动程序:static void registerDriver(Driver driver);
    • 写代码使用:Class.forName(" com.mysql.cj.jdbc.Driver ");

    注意:
    我们不需要通过DriverManager调用静态方法registerDriver(),因为只要Driver类被使用,则会执行其静态代码块完成注册驱动
    mysql5之后可以省略注册驱动的步骤。在jar包中,存在一个 java.sql.Driver 配置文件,文件中指定了 com.mysql.cj.jdbc.Driver

    ②获取数据库连接

    • 获取数据库连接对象:static Connection getConnection(String url,String user,String password)
    • 返回值:Connection 数据库连接对着
    • 参数
      • url:指定连接路径。语法:jdbc:mysql://ip地址:端口号/数据库名称
      • user:用户名
      • password:密码

2.2 Connection

  1. Connection数据库连接对象
    ① 获取执行者对象
    + 获取普通执行者对象:Statement createStatement();
    + 获取预编译执行者对象:PreparedStatement prepareStatement(String sql);
    ② 管理事务
    + 开启事务:setAutoCommit(boolean autoCommit); 参数为false,则事务开启
    + 提交事务:commit();
    + 回滚事务:rollback();
    ③ 释放资源
    + 立即将数据库连接对象释放:void close();

2.3 Statement

  1. Statement执行sql语句的对象
    ① 执行DML语句:int executeUpdate(String sql);
    + 返回值 int:返回影响的行数
    + 参数sql:可以执行insert、update、delete语句
    ② 执行DQL语句:ResultSet executeQuery(String sql);
    + 返回值Result:封装查询的结果
    + 参数sql:可以执行select语句
    ③ 释放资源
    + 立即将数据库连接对象释放:void close();

2.4 ResultSet

  1. ResultSet结果集对象
    ① 判断结果集中是否还有数据:boolean next();
    + 有数据返回true,并将索引向下移动一行
    + 没有数据返回false
    ② 获取结果集中的数据:XXX getXxx(" 列名 “);
    + XXX代表数据类型(要获取某列数据,这一列的数据类型)
    + 例如:String getString(” name “); int getInt(” age ");
    ③ 释放资源
    + 立即将数据库连接对象释放:void close();

3 JDBC 工具类

  1. 编写配置文件
    在 src 目录下创建 config.properties 配置文件
    JDBC 入门_第1张图片
  2. 编写jdbc工具类
package com.txt02.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.PrimitiveIterator;
import java.util.Properties;

public class JDBCUtils {
    private JDBCUtils(){}

    private static String driverClass;
    private static String url;
    private static String username;
    private static String password;
    private static Connection con;

    static {

        try {
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("config.properties");
            Properties prop = new Properties();
            prop.load(is);

            driverClass = prop.getProperty("driverClass");
            url = prop.getProperty("url");
            username = prop.getProperty("username");
            password = prop.getProperty("password");

            Class.forName(driverClass);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getConnection(){
        try {
          con = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return con;
    }

    public static void close(Connection con, Statement stat, ResultSet rs){
        if (con != null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

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

    public static void close(Connection con, Statement stat){
        if (con != null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

    }
}

4 SQL 注入攻击

  1. 什么是SQL注入攻击
    • 就是利用sql语句的漏洞来对系统进行攻击
  2. 原理
    • 按正常道理来说,我们在密码处输入的所有内容,都应该认为是密码的组成
    • 但是现在Statement对象在执行sql语句时,将密码的一部分内容当做查询条件来执行了
  3. SQL 注入攻击的解决
    • PreparedStatement 预编译执行者对象
      • 在执行sql语句之前,将sql语句提前编译。明确sql语句的格式后,就不会改变了。剩余的内容都会认为是参数
      • SQL语句的参数使用 ? 作为占位符
    • 为 ? 占位符赋值的方法:setXxx(参数1,参数2)
      • Xxx代表:数据类型
      • 参数1:? 的位置编号(编号从1开始)
      • 参数2:? 的实际参数
        JDBC 入门_第2张图片

5 JDBC 事务

5.1 JDBC 管理事务

  1. JDBC 如何管理事务
    • 管理事务的功能类:Connection
      • 开启事务:setAutoCommit(boolean autoCommit);参数为false,则开启事务
      • 提交事务:commit();
      • 回滚事务:rollback();

6 连接池

6.1 数据库连接池的概念

  1. 数据库连接池
    • 数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个。这项技术能明显提高对数据库操作的性能

6.2 自定义数据库连接池

6.2.1 DataSource

  1. DataSource 接口概述
    • javax.sql.DataSource 接口:数据源(数据库连接池)。Java官方提供的数据库连接池规范(接口)
    • 如果想完成数据库连接池技术,就必须实现 Data 接口
    • 核心功能:互殴去数据库连接对象: Connection getConnection();
  2. 自定义数据库连接池
    ① 定义一个类,实现 DataSource 接口
    ② 定义一个容器,用于保存多个 Connection 连接对象
    ③ 定义静态代码块,通过 JDBC 工具类获取 10 个连接保存到容器中
    ④ 重写 getConnection 方法,从容器中获取一个连接并返回
    ⑤ 定义 getSize 方法,用于获取容器的大小并返回
    • 代码演示
package com.txt01;

import com.txt.utils.JDBCUtils;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

public class MyDataSource implements DataSource {
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    static {
        for (int i = 1; i <= 10; i++) {
            Connection con = JDBCUtils.getConnection();
            pool.add(con);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        if (pool.size() > 0 ){
            Connection con = pool.remove(0);
            return con;
        }else {
            throw new RuntimeException("连接数量已用尽!");
        }
    }

    /*
    获取连接池容器大小
    */
    public int getSize(){
        return pool.size();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

  1. 自定义数据池测试
package com.txt01;

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

public class MyDataSourceTest {
    public static void main(String[] args) throws Exception {
        //1. 创建连接池对象
        MyDataSource dataSource = new MyDataSource();

        System.out.println("数据池大小:" + dataSource.getSize());

        //2. 获取连接
        Connection con = dataSource.getConnection();

        //3. 查询学生全部信息
        String sql = "SELECT * FROM student";
        PreparedStatement pst = con.prepareStatement(sql);

        ResultSet rs = pst.executeQuery();

        while (rs.next()){
            System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + " \t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
        }

        rs.close();
        pst.close();
        con.close();

        System.out.println("数据池大小:" + dataSource.getSize());
    }
}

JDBC 入门_第3张图片

6.2.2 归还连接

归还数据库连接的方式

  • 继承方式
  • 装饰设计模式
  • 适配器设计模式
  • 动态代理方式

6.2.2.1 继承方式

  1. 继承方式归还数据库连接的思想
    • 通过打印连接对象,发现 DriverManager 获取的连接实现类是 JDBC4Connection
    • 那我们就可以自定义一个类,继承 JDBC4Connection 这个类,重写 close() 方法,完成连接对象的归还
  2. 继承方式归还数据库连接的实现步骤
    ① 定义一个类,继承 JDBC4Connection
    ② 定义 Connection 连接对象和连接池容器对象的成员变量
    ③ 通过有参构造方法完成对成员变量的赋值
    ④ 重写 close 方法,将连接对象添加到池中
    ⑤ 剩余方法,只需要调用 mysql 驱动包的连接对象完成即可
  3. 继承方法归还数据库无法使用

6.2.2.2 装饰设计模式

  1. 装饰设计模式归还数据库连接的思想
    • 我们可以自定义一个类,实现 Connection 接口。这样就具备了和 JDBC4Connection 相同的行为
    • 重写 close 方法,完成连接的归还。其余的功能还调用 mysql 驱动包实现类原有的方式即可
  2. 实现步骤
    ① 定义一个类,实现 Connection 接口
    ② 定义 Connection 连接对象和连接池容器对象的成员变量
    ③ 通过有参构造方法完成对成员变量的赋值
    ④ 重写 close 方法,将连接对象添加到吃中
    ⑤ 剩余方法,只需要调用 mysql 驱动包的连接对象完成即可
    ⑥ 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装
  3. 代码示例
package com.txt02;

/*
    ① 定义一个类,实现 Connection 接口
	② 定义 Connection 连接对象和连接池容器对象的成员变量
	③ 通过有参构造方法完成对成员变量的赋值
	④ 重写 close 方法,将连接对象添加到吃中
	⑤ 剩余方法,只需要调用 mysql 驱动包的连接对象完成即可
*/

import java.sql.*;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

public class MyConnection1 implements Connection {
    private Connection con;
    private List<Connection> pool;

    public MyConnection1(Connection con, List<Connection> pool){
        this.con = con;
        this.pool = pool;
    }

    @Override
    public void close() throws SQLException {
        pool.add(con);
    }

    @Override
    public Statement createStatement() throws SQLException {
        return con.createStatement();
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return con.prepareStatement(sql);
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return con.prepareCall(sql);
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        return con.nativeSQL(sql);
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        con.setAutoCommit(autoCommit);
    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return con.getAutoCommit();
    }

    @Override
    public void commit() throws SQLException {
        con.commit();
    }

    @Override
    public void rollback() throws SQLException {
        con.rollback();
    }

    @Override
    public boolean isClosed() throws SQLException {
        return con.isClosed();
    }

    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return con.getMetaData();
    }

    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        con.setReadOnly(readOnly);
    }

    @Override
    public boolean isReadOnly() throws SQLException {
        return con.isReadOnly();
    }

    @Override
    public void setCatalog(String catalog) throws SQLException {
        con.setCatalog(catalog);
    }

    @Override
    public String getCatalog() throws SQLException {
        return con.getCatalog();
    }

    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        con.setTransactionIsolation(level);
    }

    @Override
    public int getTransactionIsolation() throws SQLException {
        return con.getTransactionIsolation();
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        return con.getWarnings();
    }

    @Override
    public void clearWarnings() throws SQLException {
        con.clearWarnings();
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return con.createStatement(resultSetType,resultSetConcurrency);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return con.prepareStatement(sql,resultSetType,resultSetConcurrency);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return con.prepareCall(sql,resultSetType,resultSetConcurrency);
    }

    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return con.getTypeMap();
    }

    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
        con.setTypeMap(map);
    }

    @Override
    public void setHoldability(int holdability) throws SQLException {
        con.setHoldability(holdability);
    }

    @Override
    public int getHoldability() throws SQLException {
        return con.getHoldability();
    }

    @Override
    public Savepoint setSavepoint() throws SQLException {
        return con.setSavepoint();
    }

    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return con.setSavepoint(name);
    }

    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        con.rollback(savepoint);
    }

    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        con.releaseSavepoint(savepoint);
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return con.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return con.prepareStatement(sql,resultSetType,resultSetConcurrency,resultSetHoldability);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return con.prepareCall(sql,resultSetType,resultSetConcurrency,resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return con.prepareStatement(sql,autoGeneratedKeys);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return con.prepareStatement(sql,columnIndexes);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return con.prepareStatement(sql,columnNames);
    }

    @Override
    public Clob createClob() throws SQLException {
        return con.createClob();
    }

    @Override
    public Blob createBlob() throws SQLException {
        return con.createBlob();
    }

    @Override
    public NClob createNClob() throws SQLException {
        return con.createNClob();
    }

    @Override
    public SQLXML createSQLXML() throws SQLException {
        return con.createSQLXML();
    }

    @Override
    public boolean isValid(int timeout) throws SQLException {
        return con.isValid(timeout);
    }

    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {
        con.setClientInfo(name,value);
    }

    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {
        con.setClientInfo(properties);
    }

    @Override
    public String getClientInfo(String name) throws SQLException {
        return con.getClientInfo(name);
    }

    @Override
    public Properties getClientInfo() throws SQLException {
        return con.getClientInfo();
    }

    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return con.createArrayOf(typeName,elements);
    }

    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return con.createStruct(typeName,attributes);
    }

    @Override
    public void setSchema(String schema) throws SQLException {
        con.setSchema(schema);
    }

    @Override
    public String getSchema() throws SQLException {
        return con.getSchema();
    }

    @Override
    public void abort(Executor executor) throws SQLException {
        con.abort(executor);
    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
        con.setNetworkTimeout(executor,milliseconds);
    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return con.getNetworkTimeout();
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return con.unwrap(iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return con.isWrapperFor(iface);
    }
}

package com.txt01;

import com.txt.utils.JDBCUtils;
import com.txt02.MyConnection1;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

public class MyDataSource implements DataSource {
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    static {
        for (int i = 1; i <= 10; i++) {
            Connection con = JDBCUtils.getConnection();
            pool.add(con);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        if (pool.size() > 0 ){
            Connection con = pool.remove(0);

            MyConnection1 myCon = new MyConnection1(con,pool);
            return myCon;
        }else {
            throw new RuntimeException("连接数量已用尽!");
        }
    }

    /*
    获取连接池容器大小
    */
    public int getSize(){
        return pool.size();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

6.2.2.3 适配器设计模式

  1. 适配器设计模式归还数据库连接的思想
    • 我们可以提供一个适配器类,实现 Connection 接口,将所有方法实现(除了 close 方法)
    • 自定义连接类只需要继承这个适配器类,重写需要改进的 close 方法即可
  2. 实现步骤
    ① 定义一个适配器类,实现 Connection 接口
    ② 定义 Connection 连接对象的成员变量
    ③ 通过有参构造方法完成对成员变量的赋值
    ④ 重写 所有方法(除了 close 方法),调用 mysql 驱动包的连接对象完成即可
    ⑤ 定义一个连接类,继承适配器
    ⑥ 定义 Connection 连接对象和连接池容器对象的成员变量,并通过有参构造进行赋值
    ⑦ 重写 close 方法,完成归还连接
    ⑧ 在自定义连接池中,将获取的连接对象通过自定义连接对象进行包装
  3. 代码演示
package com.txt02;

import java.net.CookieHandler;
import java.sql.*;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;

/*
    ① 定义一个适配器类,实现 Connection 接口
	② 定义 Connection 连接对象的成员变量
	③ 通过有参构造方法完成对成员变量的赋值
	④ 重写 所有方法(除了 close 方法),调用 mysql 驱动包的连接对象完成即可
*/

public abstract class MyAdapter implements Connection {
    private Connection con;

    public MyAdapter(Connection con){
        this.con = con;
    }

    @Override
    public Statement createStatement() throws SQLException {
        return con.createStatement();
    }

    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return con.prepareStatement(sql);
    }

    @Override
    public CallableStatement prepareCall(String sql) throws SQLException {
        return con.prepareCall(sql);
    }

    @Override
    public String nativeSQL(String sql) throws SQLException {
        return con.nativeSQL(sql);
    }

    @Override
    public void setAutoCommit(boolean autoCommit) throws SQLException {
        con.setAutoCommit(autoCommit);
    }

    @Override
    public boolean getAutoCommit() throws SQLException {
        return con.getAutoCommit();
    }

    @Override
    public void commit() throws SQLException {
        con.commit();
    }

    @Override
    public void rollback() throws SQLException {
        con.rollback();
    }

    @Override
    public boolean isClosed() throws SQLException {
        return con.isClosed();
    }

    @Override
    public DatabaseMetaData getMetaData() throws SQLException {
        return con.getMetaData();
    }

    @Override
    public void setReadOnly(boolean readOnly) throws SQLException {
        con.setReadOnly(readOnly);
    }

    @Override
    public boolean isReadOnly() throws SQLException {
        return con.isReadOnly();
    }

    @Override
    public void setCatalog(String catalog) throws SQLException {
        con.setCatalog(catalog);
    }

    @Override
    public String getCatalog() throws SQLException {
        return con.getCatalog();
    }

    @Override
    public void setTransactionIsolation(int level) throws SQLException {
        con.setTransactionIsolation(level);
    }

    @Override
    public int getTransactionIsolation() throws SQLException {
        return con.getTransactionIsolation();
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        return con.getWarnings();
    }

    @Override
    public void clearWarnings() throws SQLException {
        con.clearWarnings();
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        return con.createStatement(resultSetType,resultSetConcurrency);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return con.prepareStatement(sql,resultSetType,resultSetConcurrency);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
        return con.prepareCall(sql,resultSetType,resultSetConcurrency);
    }

    @Override
    public Map<String, Class<?>> getTypeMap() throws SQLException {
        return con.getTypeMap();
    }

    @Override
    public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
        con.setTypeMap(map);
    }

    @Override
    public void setHoldability(int holdability) throws SQLException {
        con.setHoldability(holdability);
    }

    @Override
    public int getHoldability() throws SQLException {
        return con.getHoldability();
    }

    @Override
    public Savepoint setSavepoint() throws SQLException {
        return con.setSavepoint();
    }

    @Override
    public Savepoint setSavepoint(String name) throws SQLException {
        return con.setSavepoint(name);
    }

    @Override
    public void rollback(Savepoint savepoint) throws SQLException {
        con.rollback(savepoint);
    }

    @Override
    public void releaseSavepoint(Savepoint savepoint) throws SQLException {
        con.releaseSavepoint(savepoint);
    }

    @Override
    public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return con.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return con.prepareStatement(sql,resultSetType,resultSetConcurrency,resultSetHoldability);
    }

    @Override
    public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
        return con.prepareCall(sql,resultSetType,resultSetConcurrency,resultSetHoldability);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
        return con.prepareStatement(sql,autoGeneratedKeys);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
        return con.prepareStatement(sql,columnIndexes);
    }

    @Override
    public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
        return con.prepareStatement(sql,columnNames);
    }

    @Override
    public Clob createClob() throws SQLException {
        return con.createClob();
    }

    @Override
    public Blob createBlob() throws SQLException {
        return con.createBlob();
    }

    @Override
    public NClob createNClob() throws SQLException {
        return con.createNClob();
    }

    @Override
    public SQLXML createSQLXML() throws SQLException {
        return con.createSQLXML();
    }

    @Override
    public boolean isValid(int timeout) throws SQLException {
        return con.isValid(timeout);
    }

    @Override
    public void setClientInfo(String name, String value) throws SQLClientInfoException {
        con.setClientInfo(name,value);
    }

    @Override
    public void setClientInfo(Properties properties) throws SQLClientInfoException {
        con.setClientInfo(properties);
    }

    @Override
    public String getClientInfo(String name) throws SQLException {
        return con.getClientInfo(name);
    }

    @Override
    public Properties getClientInfo() throws SQLException {
        return con.getClientInfo();
    }

    @Override
    public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
        return con.createArrayOf(typeName,elements);
    }

    @Override
    public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
        return con.createStruct(typeName,attributes);
    }

    @Override
    public void setSchema(String schema) throws SQLException {
        con.setSchema(schema);
    }

    @Override
    public String getSchema() throws SQLException {
        return con.getSchema();
    }

    @Override
    public void abort(Executor executor) throws SQLException {
        con.abort(executor);
    }

    @Override
    public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
        con.setNetworkTimeout(executor,milliseconds);
    }

    @Override
    public int getNetworkTimeout() throws SQLException {
        return con.getNetworkTimeout();
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return con.unwrap(iface);
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return con.isWrapperFor(iface);
    }
}

package com.txt02;

/*
    ⑤ 定义一个连接类,继承适配器
	⑥ 定义 Connection 连接对象和连接池容器对象的成员变量,并通过有参构造进行赋值
	⑦ 重写 close 方法,完成归还连接
*/

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public class MyConnection2 extends MyAdapter{
    private Connection con;
    private List<Connection> pool;

    public MyConnection2(Connection con, List<Connection> pool){
        super(con);
        this.con = con;
        this.pool = pool;
    }

    @Override
    public void close() throws SQLException {
        pool.add(con);
    }
}

6.2.2.4 动态代理

  • 动态代理:在不改变目标对象方法的情况下对对方进行增强
  • 组成
    • 被代理对象:真实的对象
    • 代理对象:内存中的一个对象
  • 要求
    • 代理对象和被代理对象实现相同的接口
  • 代码演示
    学生类
package com.proxy;

public class Student implements StudentInterface{
    public void eat(String name){
        System.out.println("学生吃" + name);
    }

    public void study(){
        System.out.println("在家学习");
    }
}

接口

package com.proxy;

public interface StudentInterface {
    void eat(String name);
    void study();
}

测试

package com.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        Student stu = new Student();
        /*stu.eat("米饭");
        stu.study();*/

        StudentInterface studentInterface = (StudentInterface) Proxy.newProxyInstance(stu.getClass().getClassLoader(), new Class[]{StudentInterface.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (method.getName().equals("study")){
                    System.out.println("来学校学习");
                    return null;
                }else {
                    return method.invoke(stu,args);
                }
            }
        });

        studentInterface.eat("米饭");
        studentInterface.study();
    }
}

6.2.2.5 动态代理方式

  1. 动态代理方式归还数据库连接的思想
    • 我们可以通过 Proxy 来完成对 Connection 实现类对象的代理
    • 代理过程中判断如果执行的是 close 方法,就将连接归还池子中。如果其他方法调用连接对象原来的功能即可
  2. 实现步骤
    ① 定义一个类,实现 DataSource 接口
    ② 定义一个容器,用于保存多个 Connection 连接对象
    ③ 定义静态代码块,通过 JDBC 工具类获取 10 个连接保存到容器中
    ④ 重写 getConnection 方法,从容器中获取一个连接
    ⑤ 通过 Proxy 代理,如果是 close 方法,就将连接归还池中。如果是其他方法则调用原有功能
    ⑥ 定义getSize 方法,用于获取容器大小
  3. 存在问题
    • 我们自己写的连接池技术不够完善,功能也不够强大
  4. 代码演示
package com.txt01;

import com.txt.utils.JDBCUtils;
import com.txt02.MyConnection1;
import com.txt02.MyConnection2;

import javax.sql.DataSource;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

public class MyDataSource implements DataSource {
    private static List<Connection> pool = Collections.synchronizedList(new ArrayList<>());

    static {
        for (int i = 1; i <= 10; i++) {
            Connection con = JDBCUtils.getConnection();
            pool.add(con);
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        if (pool.size() > 0 ){
            Connection con = pool.remove(0);

            Connection proCon = (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (method.getName().equals("close")){
                        pool.add(con);
                        return null;
                    }else {
                        return method.invoke(con,args);
                    }
                }
            });
            return proCon;
        }else {
            throw new RuntimeException("连接数量已用尽!");
        }

    }

    /*
    获取连接池容器大小
    */
    public int getSize(){
        return pool.size();
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }
}

6.3 开源数据库连接池

6.3.1 C3P0 数据库连接池的使用

  1. C3P0 数据库连接池的使用步骤
    ① 导入 jar 包
    ② 导入配置文件到 src 目录下
    ③ 创建 C3P0 连接池对象
    ④ 获取数据库连接进行使用

    注意:C3P0 的配置文件会自动加载,但是必须叫 c3p0-config.xml 或 c3p0-config.properties。

  2. 代码演示

package com.txt03;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import javax.xml.crypto.Data;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class C3P0Test1 {
    public static void main(String[] args) throws Exception{
        DataSource dataSource = new ComboPooledDataSource();

        Connection con = dataSource.getConnection();

        String sql = "SELECT * FROM student";
        PreparedStatement pst = con.prepareStatement(sql);

        ResultSet rs = pst.executeQuery();

        while (rs.next()){
            System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + " \t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
        }

        rs.close();
        pst.close();
        con.close();
    }
}

JDBC 入门_第4张图片

6.3.2 Druid 数据库连接池的使用步骤

  1. 使用步骤
    ① 导入 jar 包
    ② 编写配置文件,放在 src 目录下
    ③ 通过 Properties 集合加载配置文件
    ④ 通过 Druid 连接池工厂类获取数据库连接池对象
    ⑤ 获取数据库连接进行使用

    注意:Druid 不会自动加载配置文件,需要我们手动加载,但是文件的名称可以自定义

  2. 代码演示

package com.txt04;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

public class DruidTest1 {
    public static void main(String[] args) throws Exception {
        //获取配置文件的流对象
        InputStream is = DruidTest1.class.getClassLoader().getResourceAsStream("druid.properties");

        Properties prop = new Properties();
        prop.load(is);

        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        Connection con = dataSource.getConnection();

        String sql = "SELECT * FROM student";
        PreparedStatement pst = con.prepareStatement(sql);

        ResultSet rs = pst.executeQuery();

        while (rs.next()){
            System.out.println(rs.getInt("sid") + "\t" + rs.getString("name") + " \t" + rs.getInt("age") + "\t" + rs.getDate("birthday"));
        }

        rs.close();
        pst.close();
        con.close();
    }
}

JDBC 入门_第5张图片

6.3.3 Druid 数据库连接池的工具类

  • 代码演示
package com.txt.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class DataSourceUtils {
    //1. 私有构造方法
    private DataSourceUtils(){}

    //2. 声明数据源变量
    private static DataSource dataSource;

    //3. 提供静态代码块,完成配置文件的加载和获取数据库连接池对象
    static {
        try {
            InputStream is = DataSourceUtils.class.getClassLoader().getResourceAsStream("druid.properties");

            Properties prop = new Properties();
            prop.load(is);

            dataSource = DruidDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //4. 提供一个获取数据库连接的方法
    public static Connection getConnection(){
        Connection con = null;

        try {
            con = dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        return con;
    }

    //5. 提供一个获取数据库连接池对象的方法
    public static DataSource getDataSource(){
        return dataSource;
    }

    //6. 释放资源
    public static void close(Connection con, Statement stat, ResultSet rs){
        if (con != null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

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

    public static void close(Connection con, Statement stat){
        if (con != null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

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

你可能感兴趣的:(数据库,mysql,java)