JDBC 入门

news2024/11/30 10:45:50

目录

  • 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 配置文件
    在这里插入图片描述
  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:? 的实际参数
        在这里插入图片描述

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());
    }
}

在这里插入图片描述

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();
    }
}

在这里插入图片描述

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();
    }
}

在这里插入图片描述

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();
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/84848.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式:ARM存储器组织、协处理器及片上总线

文章目录ARM存储器组织ARM存储数据类型和存储格式ARM的存储器层次简介存储器管理单元MMUARM协处理器ARM片上总线AMBAARM存储器组织 ARM存储数据类型和存储格式 ARM处理器支持以下6种数据类型 8位有符号和无符号字节。16位有符号和无符号半字&#xff0c;它们以两字节的边界定…

字符串匹配问题(KMP)

文章目录题目KMP 算法1&#xff09;例子演示2&#xff09;KMP算法思路3&#xff09;疑惑模型验证4&#xff09;求 next 数组5&#xff09;代码演示6&#xff09;复杂度分析题目 有字符串 str1 和 str2 &#xff0c;str1 中是否包含 str2&#xff0c;如果没有包含返回 -1&#…

电商行业用天翎低代码平台做客服管理系统

编者按&#xff1a;在市场竞争越来越激烈的今天&#xff0c;客服作为电商行业的重要组成部分&#xff0c;如何科学管理成为企业管理层不可避免的难题&#xff0c;做好客服管理对企业具有重要意义。本文通过唯品会金牌客服管理系统案例介绍了低代码平台在定制化和快速落地的特点…

python tkinter 登录 计算器

使用tkinter开发图形化小项目&#xff1a; 功能&#xff1a; 登录 &#xff1a;登录成功 跳转到 计算器 页面&#xff0c;否则登录失败计算器 &#xff1a;登录成功后&#xff0c;窗口标题栏显示当前登录的用户 技术&#xff1a; 面向对象标准模块SQLite数据库登录成功后页…

SpringCloud MQ介绍与使用

哈喽~大家好&#xff0c;这篇来看看SpringCloud MQ介绍与使用。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【微服务】 &#x1f949;与这篇相关的文章&#xff1a; SpringCloud Sentinel 使用…

基于Python+Django的银行取号排队系统 毕业设计

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

clickhouse集群搭建、SpringBoot集成及应用

前言 在日常工作中&#xff0c;日志查询是我们不可避免的业务场景&#xff0c;当项目访问量较小时&#xff0c;我们可以将日志存储在MySQL或其他行式数据库中&#xff0c;但是如果项目访问量很大&#xff0c;一次查询就会给数据库带来很大压力&#xff0c;也许你会采用elk等成…

测试框架Pytest-pytest测试用例的运行实操

一、单元测试框架 1、什么是单元测试框架 单元测试是指在软件开发当中&#xff0c;针对软件的最小单位&#xff08;函数、方法&#xff09;进行正确性的检查测试。 2、单元测试框架 java&#xff1a;junit和testing python:unittest和pytest 3、单元测试框架主要做什么&a…

基于JSON的SQL注入攻击触发需要更新Web应用程序防火墙

©网络研究院 安全研究人员开发了一种通用的 SQL 注入技术&#xff0c;可以绕过多个 Web 应用程序防火墙 (WAF)。问题的核心是 WAF 供应商未能在 SQL 语句中添加对 JSON 的支持&#xff0c;从而使潜在的攻击者可以轻松隐藏其恶意负载。 Claroty Team82 的研究人员发现的绕…

绿盟SecXOps安全智能分析技术白皮书 思路方案

安全数据资产 统一管理DataOps&#xff0c;即 Data 和 Operations 的集成&#xff0c;于 2014 年首次提出。Gartner 将 DataOps 定义为“一种协作性的数据管理 实践&#xff0c;专注于改进组织内数据管道的通信、集成和自动化”[7]。DataOps 是一种面向流程的自动化方法&#x…

【C++笔试强训】第六天

文章目录选择题编程题选择题 1.十进制变量i的值为100&#xff0c;那么八进制的变量i的值为&#xff08;&#xff09; A 146 B 148 C 144 D 142 进制之间的转化&#xff0c;这不用多说了把 2.执行下面语句后的输出为 int I1; if(I<0)printf("****\n") ; els…

大数据Kudu(四):Kudu集群搭建

文章目录 Kudu集群搭建 一、kudu 安装包 二、节点规划及安装 1、首先在每个节点上传安装包 2、在node1、node2节点上安装如下rpm安装包 3、在node3节点上安装如下rpm安装包 4、配置Master Server 5、配置Tablet Server 6、Master节点配置所有Master Server 7、Server…

对DataFrame中元素进行定位并修改的DataFrame.iat[]方法

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 根据指定的行和列的位置号 显示或修改DataFrame中相应位置的元素 DataFrame.iat[x,y] 选择题 关于以下python代码说法错误的一项是? import pandas as pd df pd.DataFrame({"A"…

手把手教你搭建自己的FTP文件服务器

大家好&#xff0c;我是小豪&#xff0c;今天我来给大家分享如何在虚拟机上搭建自己的文件服务器 文章目录Linux上安装文件服务器FTP安装VSFTP下载dnf下载VSFTP清除防火墙的iptables缓存下载FTP匿名访问模式本地用户模式Linux上安装文件服务器FTP 由于FTP、HTTP、Telnet等协议…

【阿里实践】基于深度学习的个性化推荐系统实时化改造与升级

省时查报告-专业、及时、全面的行研报告库省时查方案-专业、及时、全面的营销策划方案库【免费下载】2022年11月份热门报告盘点推荐技术在vivo互联网商业化业务中的实践.pdf推荐系统基本问题及系统优化路径.pdf大规模推荐类深度学习系统的设计实践.pdf荣耀推荐算法架构演进实践…

doom emacs如何安装新插件和自定义快捷键

doom emacs如何安装新插件和自定义快捷键 最近在学习和使用doom emacs&#xff0c;遇到了2个问题。 问题1: 虽然doom emacs已经配置了很多的三方插件&#xff0c;但是还有些个性化的插件如何按doom风格添加&#xff1f; 问题2: 有些快捷键自己已经熟悉&#xff0c;如何修改&am…

双目密集匹配及SGM算法

提示&#xff1a; 双目密集匹配及SGM算法前言一、双目密集匹配1、双目密集匹配概述2.、双目密集匹配四大步骤代价计算&#xff08;per-pixel-cost&#xff09;&#xff1a;释义&#xff1a;代价聚集&#xff08;cost-aggregation&#xff09;:释义&#xff1a;分类&#xff1a;…

以就业为目标,Python到底应该学什么?

前言 很多小伙伴知道Python火爆薪资高&#xff0c;开始自学&#xff0c;可是并不知道Python应该学哪些技术、学到什么程度才能找到工作。今天我们就来分析一下&#xff0c;Python学到什么程度才能找到工作。 相关&#xff1a;我是今年刚刚毕业的不入流大学的本科生&#xff0…

KingbaseES Create Index Concurrently 过程探究

前言&#xff1a; 我们知道Oracle 可以通过create index online 在线创建索引&#xff0c;而不影响其他会话修改数据&#xff0c;但Oracle 实际在online 创建索引的最后一步&#xff0c;实际还是需要进行锁升级&#xff0c;申请表级的S锁&#xff0c;因此&#xff0c;最后还是有…

STM32CUBEMX开发GD32F303(17)----内部Flash读写

概述 本章STM32CUBEMX配置STM32F103&#xff0c;并且在GD32F303中进行开发&#xff0c;同时通过开发板内进行验证。 本例程主要讲解如何对芯片自带Flash进行读写&#xff0c;用芯片内部Flash可以对一些需要断电保存的数据进行保存&#xff0c;无需加外部得存储芯片&#xff0c…