• 用JAVA实现无等待数据库连接池


    我们都知道数据库连接是一种有限和非常昂贵的应用资源,怎样对这些资源进行高效的管理,能有效的改善整个系统的性能和健壮性。数据库连接池正是针对这个问题而提出来的。

           数据库连接负责分配、释放和管理数据库连接。使数据库连接可以重复利用,而不是用一次建立一次数据库连接。

    基本思路

           建立一个容器

    每次到这个容器里得到连接,如果为空则建立一个新连接。

    当连接使用完后归还给这个容器

    这里就有二个难点

    1.  容器必需是同步的,线程安全的。

    2.  连接怎归还连接池

    方案:

          针对这二个难点,我们分别提出了二个解决方法

    1.使用ConcurrentLinkedQueue实现先进先出队列

    ConcurrentLinkedQueue无界线程安全队列介绍

    这个类在java.util.concurrent包中,我们来看看官方是怎描述这个类的
    一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。队列的头部 是队列中时间最长的元素。队列的尾部 是队列中时间最短的元素。新的元素插入到队列的尾部,队列获取操作从队列头部获得元素。当多个线程共享访问一个公共collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素.此实现采用了有效的“无等待 (wait-free)”算法

    2.动态代理实现连接归还连接池

           大家也可以参考刘冬在IBM发表的文章

    http://www.ibm.com/developerworks/cn/java/l-connpoolproxy/


    接下来我们来看看整体代码

    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.Driver;

    import java.sql.SQLException;

    import java.util.ArrayList;

    import java.util.List;

    import java.util.Properties;

    import java.util.concurrent.ConcurrentLinkedQueue;

    import java.util.concurrent.atomic.AtomicInteger;

    import java.util.concurrent.atomic.AtomicLong;

    import java.util.concurrent.locks.ReentrantLock;

     

    import javax.sql.DataSource;

     

    public class JavaGGDataSource implements DataSource {

        //连接队列

        private ConcurrentLinkedQueue<_Connection> connQueue = newConcurrentLinkedQueue<_Connection>();

        //存放所有连接容器

        private List<_Connection> conns = new ArrayList<_Connection>();

        private Driver driver = null;

     

        private String jdbcUrl = null;

        private String user = null;

        private String password = null;

        private int maxActive = -1;// -1为不限制连接数

        private String driverClass = null;

        private int timeout = 1000 * 60 * 60 * 4;// 默认为4小时,即4小时没有任何sql操作就把所有连接重新建立连接

        private AtomicLong lastCheckout = new AtomicLong(System.currentTimeMillis());

        private AtomicInteger connCount = new AtomicInteger();

        //线程锁,主要用于新建连接和清空连接时

        private ReentrantLock lock = new ReentrantLock();

     

        public void closeAllConnection() {

        }

     

        /**

         * 归还连接给连接池

         *

         * @param conn

         *@date 2009-8-13

         *@author eric.chan

         */

        public void offerConnection(_Connection conn) {

           connQueue.offer(conn);

        }

     

        @Override

        public Connection getConnection() throws SQLException {

           return getConnection(user, password);

        }

     

        /**

         * 从池中得到连接,如果池中没有连接,则建立新的sql连接

         *

         * @param username

         * @param password

         * @author eric.chan

         */

        @Override

        public Connection getConnection(String username, String password)

               throws SQLException {

           checkTimeout();

           _Connection conn = connQueue.poll();

           if (conn == null) {

               if (maxActive > 0 && connCount.get() >= maxActive) {

                  for (;;) {// 采用自旋方法 从已满的池中得到一个连接

                      conn = connQueue.poll();

                      if (conn != null)

                         break;

                      else

                         continue;

                  }

               }

               lock.lock();

               try {

                  if (maxActive > 0 && connCount.get() >= maxActive) {

                      // 处理并发问题

                      return getConnection(username, password);

                  }

                  Properties info = new Properties();

                  info.put("user", username);

                  info.put("password", password);

                  Connection conn1 = loadDriver().connect(jdbcUrl, info);

                  conn = new _Connection(conn1, this);

                  int c = connCount.incrementAndGet();// 当前连接数加1

                  conns.add(conn);

                  System.out.println("info : init no. " + c + " connectioned");

               } finally {

                  lock.unlock();

               }

           }

           lastCheckout.getAndSet(System.currentTimeMillis());

           return conn.getConnection();

        }

     

        /**

         * 检查最后一次的连接时间

         *

         * @throws SQLException

         *@date 2009-8-13

         *@author eric.chan

         */

        private void checkTimeout() throws SQLException {

           long now = System.currentTimeMillis();

           long lt = lastCheckout.get();

           if ((now - lt) > timeout) {

               _Connection conn = null;

               lock.lock();

               try {

                  if(connCount.get()==0)return;

                  while ((conn = connQueue.poll()) != null) {

                      System.out.println("connection " + conn + " close ");

                      conn.close();

                      conn = null;

                  }

                  for(_Connection con:conns){

                      con.close();

                  }

                  conns.clear();

                  System.out.println("info : reset all connections");

                  connCount.getAndSet(0);// 重置连接数计数器

                  lastCheckout.getAndSet(System.currentTimeMillis());

               } finally {

                  lock.unlock();

               }

           }

        }

     

        /**

         *

         * @return

         *@date 2009

    转载 http://my.oschina.net/javagg/blog/3357

  • 相关阅读:
    r.json和json.loads 区别,以及json和字符串转换
    HTTPIE 工具使用入门
    PyCharm 专业版 2018 永久有效
    linux 执行:pip3 install -r requirements.txt 报错
    fiddler过滤指定的请求
    fiddler抓取https的请求详解
    centos6.5 内核 :2.6.32 升级内核
    -bash: /usr/bin/yum: /usr/bin/python: bad interpreter: No such file or directory
    ODI中web service介绍
    Oracle GoldenGate 12c中的协同交付(Coordinated Delivery)
  • 原文地址:https://www.cnblogs.com/chenying99/p/3415956.html
Copyright © 2020-2023  润新知