当前位置:首页 > 文章列表 > 数据库 > MySQL > 用Java手动封装JDBC连接池(一)

用Java手动封装JDBC连接池(一)

来源:SegmentFault 2023-01-13 08:30:02 0浏览 收藏

IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《用Java手动封装JDBC连接池(一)》,聊聊MySQL、Java、jdbc,我们一起来看看吧!

JDBC存在的问题

  1. 代码的冗余:在对数据库进行增删改查时,每个操作的JDBC流程和SQL执行代码的流程都一样,造成代码的冗余,所以我们可以把冗余的部分封装起来,封装之后,我们就不用再去写JDBC流程,只需要些SQL语句---这一部分的封装下一篇文章描述
  2. 性能问题:每一次对数据库的操作都要建立连接,操作完之后又要释放连接,如果数据库访问次数不多时性能还可以,但当我们的程序有很多人使用时,对数据库的操作次数也会越来越多,每一次操作都要建立和关闭连接,势必会降低性能,本篇文章主要解决这部分的问题

如何解决性能问题

我们先用一个例子来描述一下这个JDBC性能问题。

  • 比如说,当两个地方本来互相不通,分别是A和B两个地方。这时我们就需要在A和B之间修一条路能让他们连通,有人在这条路上通行的时候就处于连接状态,但是当这条路可能有段时间没人走了我们就把它炸掉了。但是每当有人需要从A去到B时,又需要再修一条路,而每一次修一条路的时间都需要非常久。所以我们不能一不用这条路就把它炸掉,这样非常浪费时间和资金。那我们该怎么解决呢?我们在A和B两地之间多修几条路,在每条路的路口设置关卡,当有人在其中一条路上通行时,那么这个关卡就不允许其他人在这条路上通行,当路上没人通行时那么关卡允许其他人通行。(可能这举的例子和实际生活不是特别恰当,但也希望大家能够理解,实在想不到一个更为贴切的例子)
  • 解决JDBC性能问题也是这个道理,一开始我们就创建几个连接通道,用完之后不关闭,而是用一个标志位来表示当前通道是否可用,建立的这几条通道放在统一的一个地方进行管理,看起来就像个池子一样,所以就叫JDBC连接池

封装JDBC的步骤

  • 1、为了更好的管理项目,我们把连接数据库用到的驱动类、url地址、用户名和密码都放到一个properties文件里,之后改起来也方便,一处改动全部都跟着改动。需要一个类来帮我们读取配置文件的信息
  • 配置信息如下(Configuration.properties)

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/bank?serverTimezone=CST
    user=root
    password=123456
    minConnectCount=5
    waitTime=5
  • ConfigReader类

    package util;

    import java.io.IOException;
    import java.io.InputStream;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;

    public class ConfigReader {

        private static Properties properties;
        //用Map集合存放properties文件下的配置信息
        private static Map configMap;

        //配置文件只加载一次
        static {
            properties = new Properties();
            configMap = new HashMap();
            InputStream inputStream = null;
            try {
                inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("configuration.properties");
                properties.load(inputStream);
                Enumeration en = properties.propertyNames();
                while (en.hasMoreElements()){
                    String key = (String) en.nextElement();
                    String value = properties.getProperty(key);
                    configMap.put(key, value);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (inputStream != null){
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        //获取配置文件里面的value值
        public static String getPropertyValue(String key){
            return configMap.get(key);
        }
    }
  • 2、在连接JDBC的时候我们用DriverManager.getConnection()方法获取连接,返回了Connection对象,成功获取后也表明和数据库连接成功,当我们不需要用的时候调用close()方法关闭连接。为了实现用完之后不关闭连接,我们需要自己封装一个类,这个类下有一个Connection属性,还有一个标志位,用来判断该连接可用还是不可用。为了能够让自己封装的类和Connection类的使用起来是一样的,我们自己创建一个AdapterConnection抽象类,这个类实现了Connection接口,我们自己封装的Connection类继承了这个抽象类,并重写了其中的三个方法,分别用来创建状态参数以及关闭连接。(这部分的设计思想体现出缺省适配器模式)
  • AdapterConnection类

    package pool;

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

    public abstract class AdapterConnection implements Connection {
        //这里将这三个写为抽象方法,是为了当子类继承这个抽象类的时候提示子类必须重写这个三个方法
        @Override
        public abstract Statement createStatement() throws SQLException;

        @Override
        public abstract PreparedStatement prepareStatement(String sql) throws SQLException ;

        @Override
        public abstract void close() throws SQLException;


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

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

        @Override
        public void setAutoCommit(boolean autoCommit) throws SQLException {

        }

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

        @Override
        public void commit() throws SQLException {

        }

        @Override
        public void rollback() throws SQLException {

        }



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

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

        @Override
        public void setReadOnly(boolean readOnly) throws SQLException {

        }

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

        @Override
        public void setCatalog(String catalog) throws SQLException {

        }

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

        @Override
        public void setTransactionIsolation(int level) throws SQLException {

        }

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

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

        @Override
        public void clearWarnings() throws SQLException {

        }

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

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

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

        @Override
        public Map> getTypeMap() throws SQLException {
            return null;
        }

        @Override
        public void setTypeMap(Map> map) throws SQLException {

        }

        @Override
        public void setHoldability(int holdability) throws SQLException {

        }

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

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

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

        @Override
        public void rollback(Savepoint savepoint) throws SQLException {

        }

        @Override
        public void releaseSavepoint(Savepoint savepoint) throws SQLException {

        }

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

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

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

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

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

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

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

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

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

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

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

        @Override
        public void setClientInfo(String name, String value) throws SQLClientInfoException {

        }

        @Override
        public void setClientInfo(Properties properties) throws SQLClientInfoException {

        }

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

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

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

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

        @Override
        public void setSchema(String schema) throws SQLException {

        }

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

        @Override
        public void abort(Executor executor) throws SQLException {

        }

        @Override
        public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {

        }

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

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

        @Override
        public boolean isWrapperFor(Class> iface) throws SQLException {
            return false;
        }
    }
  • MyConnection类

    package pool;

    import util.ConfigReader;
    import java.sql.*;

    public class MyConnection extends AdapterConnection{

        private Connection conn;
        //标志位,true表示被占用,false表示该通道可用
        private boolean used = false;

        private static String driver;
        private static String url;
        private static String user;
        private static String password ;

        //静态块,让加载类的步骤只执行一次,并初始化四个属性
        static {
            try {
                driver = ConfigReader.getPropertyValue("driver");
                url = ConfigReader.getPropertyValue("url");
                user = ConfigReader.getPropertyValue("user");
                password = ConfigReader.getPropertyValue("password");
                Class.forName(driver);
            }catch (ClassNotFoundException e){
                e.printStackTrace();
            }
        }

        //用来初始化连接通道,每一次被创建时都进行初始化
        {
            try {
                conn = DriverManager.getConnection(url, user, password);
            }catch (SQLException e){
                e.printStackTrace();
            }
        }

        //获取连接通道
        public Connection getConn() {
            return conn;
        }

        //判断该连接通道是否可用
        public boolean isUsed() {
            return used;
        }

        //设置标志位
        public void setUsed(boolean used) {
            this.used = used;
        }

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

        //重写了继承自AdapterConnection类的方法
        //该方法是为了获取状态参数,本质上还是调用了PreparedStatement
        @Override
        public PreparedStatement prepareStatement(String sql) throws SQLException {
            PreparedStatement pstate = this.conn.prepareStatement(sql);
            return pstate;
        }

        //重写了继承自AdapterConnection类的方法
        //该方法的目的是为了将连接通道设置为可用,看起来就像关闭流一样
        @Override
        public void close() throws SQLException {
            this.used = false;
        }
    }
  • 3、我们需要一个连接池对象来帮我们管理连接对象,我们需要把连接对象放到一个List集合中,当我们需要的时候就从集合里取。连接对象的个数我们也放置在properties文件里,便于管理。由于连接对象有限,当有多个用户同时访问时,可能有的用户拿不到连接对象,这里用了一个等待机制,当用户拿不到连接对象时,就让它等一会,如果超出等待时间还拿不到,就抛出一个异常通知用户。
  • ConnectionPool类

    package pool;

    import util.ConfigReader;

    import javax.swing.*;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.util.ArrayList;
    import java.util.List;

    public class ConnectionPool {

        //将ConnectionPool设计成单例模式
        private ConnectionPool(){}

        private static volatile ConnectionPool connectionPool;

        public static ConnectionPool getInstance(){
            if (connectionPool == null){
                synchronized (ConnectionPool.class){
                    if (connectionPool == null){
                        connectionPool = new ConnectionPool();
                    }
                }
            }
            return connectionPool;
        }

        //获取最小连接个数以及等待时间
        private int minConnectCount = Integer.parseInt(ConfigReader.getPropertyValue("minConnectCount"));
        private int waitTime = Integer.parseInt(ConfigReader.getPropertyValue("waitTime"));

        //属性---List集合,用来存储连接对象
        private List pool = new ArrayList();

        //往pool集合里面存放连接对象
        {
            for (int i = 1; i 

自定义异常类SystemBusyException
    package pool;

    public class SystemBusyException extends RuntimeException {

        public SystemBusyException(){}

        public SystemBusyException(String msg){
            super(msg);
        }
    }

这样整个JDBC连接池就封装好了,整体的功能也比较简单,代码是经过测试的了,所以运行起来应该是没有什么问题,如果有什么问题还望指正。

以上就是本文的全部内容了,是否有顺利帮助你解决问题?若是能给你带来学习上的帮助,请大家多多支持golang学习网!更多关于数据库的相关知识,也可关注golang学习网公众号。

版本声明
本文转载于:SegmentFault 如有侵犯,请联系study_golang@163.com删除
MySQL定时备份方案MySQL定时备份方案
上一篇
MySQL定时备份方案
直播系统源码常见安全问题及防护措施
下一篇
直播系统源码常见安全问题及防护措施
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    542次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    508次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    497次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    484次学习
查看更多
AI推荐
  • 笔灵AI生成答辩PPT:高效制作学术与职场PPT的利器
    笔灵AI生成答辩PPT
    探索笔灵AI生成答辩PPT的强大功能,快速制作高质量答辩PPT。精准内容提取、多样模板匹配、数据可视化、配套自述稿生成,让您的学术和职场展示更加专业与高效。
    14次使用
  • 知网AIGC检测服务系统:精准识别学术文本中的AI生成内容
    知网AIGC检测服务系统
    知网AIGC检测服务系统,专注于检测学术文本中的疑似AI生成内容。依托知网海量高质量文献资源,结合先进的“知识增强AIGC检测技术”,系统能够从语言模式和语义逻辑两方面精准识别AI生成内容,适用于学术研究、教育和企业领域,确保文本的真实性和原创性。
    22次使用
  • AIGC检测服务:AIbiye助力确保论文原创性
    AIGC检测-Aibiye
    AIbiye官网推出的AIGC检测服务,专注于检测ChatGPT、Gemini、Claude等AIGC工具生成的文本,帮助用户确保论文的原创性和学术规范。支持txt和doc(x)格式,检测范围为论文正文,提供高准确性和便捷的用户体验。
    30次使用
  • 易笔AI论文平台:快速生成高质量学术论文的利器
    易笔AI论文
    易笔AI论文平台提供自动写作、格式校对、查重检测等功能,支持多种学术领域的论文生成。价格优惠,界面友好,操作简便,适用于学术研究者、学生及论文辅导机构。
    39次使用
  • 笔启AI论文写作平台:多类型论文生成与多语言支持
    笔启AI论文写作平台
    笔启AI论文写作平台提供多类型论文生成服务,支持多语言写作,满足学术研究者、学生和职场人士的需求。平台采用AI 4.0版本,确保论文质量和原创性,并提供查重保障和隐私保护。
    35次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码