有关数据库连接池的模拟实现——丑九怪

    xiaoxiao2022-07-07  169

    有关数据库连接池的模拟实现——丑九怪

    有关数据库连接池的概念以及存在意义
    概念:数据库连接池,顾名思义,是存放数据库连接的地方,当我们打开了一个数据库连接,就可以将他放在一个特有的“池子”里,当我们要使用的时候,就直接在这个“池子”里寻找链接使用。这个池子同时也实现了对数据库连接的添加,删除,监控等管理存在的意义:首先数据库连接是重要资源,同时大部分对数据库的操作持续时间都不是那么长,没有必要每次操作都打开新的连接,完毕之后在进行关闭(这个是很费时间的)这将会浪费很多资源,所以我们建立数据库连接池。这里暂且不实现多线程的问题,当两个或更多线程同时拥有同一个数据库连接,然后执行了不同的SQL语句。这种情况,我们可以让一个事物只占一个数据库连接,这样虽然使用了比较多的数据库连接资源,却也大大减小了对数据库连接管理的繁琐和复杂性
    数据库连接池的大概实现
    这里我用两个类去实现它,第一个用来创建最基本的连接,并且提供得到连接的方法,如下: static final List<Connection> connectionPool = new ArrayList<>(); // 创建列表存储连接 // 这里的connection是我们自己创建的connection类 private static String driver; private static String url; private static String user; private static String password; private static int minCount; // 最大以及最小连接个数 private static int maxCount; private static int deltaCount; // 当发现数据库连接池中没有连接时,要增加的连接个数 private static long timeOut; // 最长的连接空闲时间 // 初始化数据库连接池,当然要一个properties文件 static void initDatabase(String path) throws Exception { if (path.equals(null)) { PropertiesParser.loadProperties("/database.cfg.properties"); } else { PropertiesParser.loadProperties(path); } driver = PropertiesParser.value("driver"); url = PropertiesParser.value("url"); user = PropertiesParser.value("user"); password = PropertiesParser.value("password"); String minCountStr = PropertiesParser.value("minCount"); minCount = minCountStr == null ? 3 : Integer.valueOf(minCountStr); String maxCountStr = PropertiesParser.value("maxCount"); maxCount = maxCountStr == null ? 50 : Integer.valueOf(maxCountStr); String deltaCountStr = PropertiesParser.value("deltaCount"); deltaCount = deltaCountStr == null ? 3 : Integer.valueOf(deltaCountStr); String timeoutStr = PropertiesParser.value("timeout"); timeOut = timeoutStr == null ? 60000 : Long.valueOf(timeoutStr); try { Class.forName(driver); // 加载数据库驱动类 createConnection(minCount); // 创建数据库连接池 } catch (Exception e) { e.printStackTrace(); } }

    创建连接池以及对外提供获取连接的方法

    private static boolean createConnection(int count) throws Exception { int i = 0; while (connectionPool.size() < maxCount && i < count) { Connection connection = new Connection(); connection.setConnection(DriverManager.getConnection(url, user, password)); connectionPool.add(connection); i++; } return connectionPool.size() < maxCount; } // 对外提供的方法,取得数据库连接 Connection getConnection() throws Exception { for (int i = 0; i < connectionPool.size(); i++) { Connection connection = connectionPool.get(i); if (connection.isUsed()) { continue; } else { return connection; } } // 能走到这里说明已经没有可以用的链接了,所以创建新的链接之后,递归调用自己 if (createConnection(deltaCount)) { return getConnection(); } return null; // 返回null说明数据库连接池已经满了 }

    下面是有关连接超时的处理,我用一个私有方法处理,用到了之前我做过的工具:滴答滴答(这个工具在我之前的博文里有)(滴答滴答改良版本也可以实现)

    private static void scanPool() { new Didadida() { @Override public void doIt() { for (int index = 0; index < connectionPool.size(); index++) { Connection connection = connectionPool.get(index); System.out.println(connection); // 一个连接没有被使用,并且也已经超时 if (!connection.isUsed() && connection.isTimeOut(System.currentTimeMillis(), timeOut)) { if ((connectionPool.size() - 1) >= minCount) { connection.getConnection().close(); connectionPool.remove(connection); } } } } @Override public void beforeDida() { } @Override public void afterStopDida() { } }.setDelayTime(timeOut).start(); } 用另一个类处理连接应该处理的操作(类名称:connection) private java.sql.Connection connection; private boolean isUsed; private long time; // 这个时间用来记录 public Connection() { isUsed = false; } Connection getConnection() { time = System.currentTimeMillis(); isUsed = true; return this; }

    这里也提供了强制关闭,判断是否连接超时,执行sql语句的方法,一句对于连接的set方法

    // 可以超出的时间和当前时间都由外面提供,算出时间差,判断是否为超时连接(超出时间有默认值) void ForceClose(long timeOut, long curTime) { if (!isUsed) { // 如果没有被使用,呢么默认为空闲连接,也就无需关闭 return; } long delayTime = curTime - time; if (timeOut <= delayTime) { isUsed = false; } } // 判断是否超时 boolean isTimeOut(long timeOut, long curTime) { long delayTime = curTime - time; if (timeOut <= delayTime) { return true; } return false; } // 执行sql语句的方法 PreparedStatement preparedStatement(String SQLString) throws SQLException { return connection.prepareStatement(SQLString); } void setConnection(java.sql.Connection connection) { this.connection = connection; }

    这两个类之间的联系:第二个connection类,是第一个数据库连接池中的list成员,我们用自己写的connection将对数据库的连接封装起来,用于判断是否超时等等

    总结
    数据库连接池是对于重要的资源进行有效管理的方法,这本身并没有什么,重要的是我们要有工具思想,大量重复出现的代码要抽象成工具类,关键代码也要做成工具类,这将大大提高我们的注意力,让我们更关心业务本身的逻辑。
    最新回复(0)