Java-数据库系列(一)--JDBC链接数据库 手写连接池

JDBC链接数据库–mysql

以mysql为例 写一套 自定义数据库连接池

设计思路

java连接mysql 参数:driver,url,username,password
为什么使用连接池:数据库链接的创建和销毁需要花费相当的时间,节省时间;创建资源占用一定内存,节省内存;数据库可承受最大链接,数据库默认有个最大承受数,频繁的短时间创建大量链接,链接并未超时,会导致too many connections…
连接池功能:初始化指定数量链接,缓存起来,用的时候去取,用完了放回,销毁的时候统一销毁

废话不多说,上代码:

JdbcPoolConfig – 连接池参数管理 单例 线程安全

public class JdbcPoolConfig {
    private String driver = "com.mysql.jdbc.Driver";// 数据库驱动
    private String url = "jdbc:mysql://localhost:3306/test";// 连接数据库地址
    private String username = "root";// 数据库用户名
    private String password = "123456";// 数据库密码
    private int initSize = 3;// 初始化连接数
    private int maxSize = 10;// 最大连接数
    private long timeOut = 5000;// 超时时间(毫秒)

    private static JdbcPoolConfig config = null;

    protected JdbcPoolConfig() {
    }

    static {
        config = new JdbcPoolConfig();
    }

    /**
     * 单例获取数据库连接池参数
     * 
     * @return
     */
    public static JdbcPoolConfig getJdbcPool() {
        return config;
    }
    //get set 省略
}

JdbcPool– 连接池 单例 线程安全

package top.hahawa.pool;

import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Vector;

import com.mysql.jdbc.Connection;

public class JdbcPool {
    private JdbcPoolConfig config;//连接池参数
    private Vector<Connection> initConns;// 初始化连接池
    private Vector<Connection> freeConns;// 空闲连接池
    private static int activeNum = 0;//当前活动线程数量
    private static Hashtable<Integer, Long> timeOut = new Hashtable<>();//超时机制

    private JdbcPool(JdbcPoolConfig config) throws ClassNotFoundException, SQLException {
        this.config = config;
        init();
        timeOut();
    }

    private static JdbcPool pool;

    static {
        try {
            pool = new JdbcPool(JdbcPoolConfig.getConfig());
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

    public static JdbcPool getPool() {
        return pool;
    }

    private void init() throws ClassNotFoundException, SQLException {
        initConns = new Vector<>(config.getInitSize());
        for (int i = 0; i < config.getInitSize(); i++) {
            initConns.add(createConn());
        }
        freeConns = new Vector<>();
    }

    private Connection createConn() throws ClassNotFoundException, SQLException {
        Class.forName(config.getDriver());
        Connection conn = (Connection) DriverManager.getConnection(config.getUrl(), config.getUsername(),
                config.getPassword());
        return conn;
    }

    public synchronized Connection getConnection() throws ClassNotFoundException, SQLException {
        System.out.println("=======有人获取链接start ==========");
        System.out.println("当前空闲连接数:" + freeConns.size());
        System.out.println("当前固定连接数:" + initConns.size());
        System.out.println("当前活动连接数:" + activeNum);
        System.out.println();
        Connection conn = null;
        if (freeConns.size() > 0) {
            conn = freeConns.remove(0);
        } else {
            if (initConns.size() > 0) {
                conn = initConns.remove(0);
            } else {
                // 目前情况 分析 理论 只有一种 就是,链接都被拿出去使用了 ,没有归还
                if (activeNum + initConns.size() + freeConns.size() < config.getMaxSize()) {
                    conn = createConn();
                } else {
                    throw new RuntimeException("链接忙,稍后重试...");
                }
            }
        }
        addActiveNum();
        System.out.println("=======有人获取链接end ==========");
        System.out.println("当前空闲连接数:" + freeConns.size());
        System.out.println("当前固定连接数:" + initConns.size());
        System.out.println("当前活动连接数:" + activeNum);
        System.out.println();
        return conn;
    }

    public synchronized void colse(Connection conn) {
        System.out.println("=======有人释放链接 start==========");
        System.out.println("当前空闲连接数:" + freeConns.size());
        System.out.println("当前固定连接数:" + initConns.size());
        System.out.println("当前活动连接数:" + activeNum);
        System.out.println();

        if (initConns.size() < config.getInitSize()) {
            initConns.add(conn);
        } else {
            freeConns.add(conn);
            timeOut.put(conn.hashCode(), System.currentTimeMillis());
        }
        removeActiveNum();
        System.out.println("=======有人释放链接 end==========");
        System.out.println("当前空闲连接数:" + freeConns.size());
        System.out.println("当前固定连接数:" + initConns.size());
        System.out.println("当前活动连接数:" + activeNum);
        System.out.println();
    }

    private synchronized void addActiveNum() {
        activeNum++;
    }

    private synchronized void removeActiveNum() {
        activeNum--;
    }

    private void timeOut() {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    for (int i = 0; i < freeConns.size(); i++) {
                        int hc = freeConns.get(i).hashCode();
                        while (System.currentTimeMillis() - timeOut.get(hc) >= config.getTimeOut()) {
                            try {
                                if (freeConns.contains(freeConns.get(i))) {
                                    freeConns.remove(i).close();
                                }
                            } catch (SQLException e) {
                                e.printStackTrace();
                            }
                            timeOut.remove(hc);
                            System.out.println("检测到有限制链接超时..释放掉");
                        }
                    }
                }
            }
        });
        t.start();
    }
}

测试案例 使用线程池测试

package top.hahawa.pool;

import java.sql.SQLException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import com.mysql.jdbc.Connection;

public class PoolTest {

    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 200, TimeUnit.MILLISECONDS,
                new ArrayBlockingQueue<Runnable>(10));
        for (int i = 0; i < 20; i++) {
            AA a = new AA();
            executor.execute(a);
        }
    }
}

class AA extends Thread {
    @Override
    public void run() {
        try {
            JdbcPool pool = JdbcPool.getPool();
            Connection conn = pool.getConnection();
            System.out.println("conn:   " + conn);
            Thread.sleep(2000);
            pool.colse(conn);
        } catch (ClassNotFoundException | SQLException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

结果

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:3
当前活动连接数:0

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:1

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@124df
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:1

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:2

conn:   com.mysql.jdbc.JDBC4Connection@6307aef3
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:2

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:3

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@3e210adf
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:3

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:4

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@52b9009
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:4

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:5

conn:   com.mysql.jdbc.JDBC4Connection@3aa7cbac
=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:5

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:6

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@22e90f55
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:6

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:7

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@45c2443e
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:7

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:8

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@33da6329
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:8

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:9

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@41690a2e
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@3290af7e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@124df
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
conn:   com.mysql.jdbc.JDBC4Connection@3e210adf
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@6307aef3
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@52b9009
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@3aa7cbac
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@22e90f55
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@45c2443e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@33da6329
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@41690a2e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接start ==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人获取链接end ==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

conn:   com.mysql.jdbc.JDBC4Connection@3290af7e
=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:0
当前活动连接数:10

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:1
当前活动连接数:9

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8

=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:2
当前活动连接数:8

=======有人释放链接 end==========
当前空闲连接数:0
当前固定连接数:3
当前活动连接数:7

=======有人释放链接 start==========
当前空闲连接数:0
当前固定连接数:3
当前活动连接数:7

=======有人释放链接 end==========
当前空闲连接数:1
当前固定连接数:3
当前活动连接数:6

=======有人释放链接 start==========
当前空闲连接数:1
当前固定连接数:3
当前活动连接数:6

=======有人释放链接 end==========
当前空闲连接数:2
当前固定连接数:3
当前活动连接数:5

Exception in thread "Thread-20" java.lang.NullPointerException
    at top.hahawa.pool.JdbcPool$1.run(JdbcPool.java:118)
    at java.lang.Thread.run(Thread.java:748)
=======有人释放链接 start==========
当前空闲连接数:2
当前固定连接数:3
当前活动连接数:5

=======有人释放链接 end==========
当前空闲连接数:3
当前固定连接数:3
当前活动连接数:4

=======有人释放链接 start==========
当前空闲连接数:3
当前固定连接数:3
当前活动连接数:4

=======有人释放链接 end==========
当前空闲连接数:4
当前固定连接数:3
当前活动连接数:3

=======有人释放链接 start==========
当前空闲连接数:4
当前固定连接数:3
当前活动连接数:3

=======有人释放链接 end==========
当前空闲连接数:5
当前固定连接数:3
当前活动连接数:2

=======有人释放链接 start==========
当前空闲连接数:5
当前固定连接数:3
当前活动连接数:2

=======有人释放链接 end==========
当前空闲连接数:6
当前固定连接数:3
当前活动连接数:1

=======有人释放链接 start==========
当前空闲连接数:6
当前固定连接数:3
当前活动连接数:1

=======有人释放链接 end==========
当前空闲连接数:7
当前固定连接数:3
当前活动连接数:0

完结!注意点就是 单例 的线程安全问题 不然多线程环境下 并不是真正的单例
然后就是 连接池 缓存的线程安全 创建连接,提供连接,回收连接,

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用Java连接MySQL数据库,需要下载并安装MySQL Connector/J驱动程序。以下是安装步骤: 1. 访问MySQL官方网站,下载MySQL Connector/J驱动程序。当前最新版本为8.0.20,下载地址为:https://dev.mysql.com/downloads/connector/j/ 2. 下载后,将mysql-connector-java-8.0.20.jar文件复制到项目的classpath路径下。 3. 在Java代码添加连接MySQL数据库的代码,示例代码如下: ``` import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class MySQLConnect { public static void main(String[] args) { Connection conn = null; try { // 加载MySQL驱动程序 Class.forName("com.mysql.cj.jdbc.Driver"); // 获取数据库连接 String url = "jdbc:mysql://localhost:3306/test"; String user = "root"; String password = "root"; conn = DriverManager.getConnection(url, user, password); System.out.println("数据库连接成功!"); } catch (SQLException e) { System.out.println("数据库连接失败:" + e.getMessage()); } catch (ClassNotFoundException e) { System.out.println("找不到MySQL驱动程序:" + e.getMessage()); } finally { try { if (conn != null) { conn.close(); } } catch (SQLException e) { System.out.println("关闭数据库连接失败:" + e.getMessage()); } } } } ``` 以上代码演示了如何连接本地MySQL数据库,如果需要连接远程MySQL数据库,只需要将url的localhost改为远程MySQL服务器的IP地址即可。同时,需要确保远程MySQL服务器已经允许远程连接。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值