java数据库连接池_方便自己学习

Posted hongzm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java数据库连接池_方便自己学习相关的知识,希望对你有一定的参考价值。

1、利用的等待/通知实现超时取连接

package cn.enjoyedu.ch1.pool;

import java.sql.Connection;
import java.util.LinkedList;

/**
 *类说明:连接池的实现
 */
public class DBPool 

    /*容器用于存放连接*/
    private static LinkedList<Connection> pool = new LinkedList<Connection>();

    /*限制了连接池的大小*/
    public DBPool(int initialSize) 
        if (initialSize > 0) 
            for (int i = 0; i < initialSize; i++) 
                //模拟拿连接
                pool.addLast(SqlConnectImpl.fetchConnection());
            
        
    

    /*释放连接,通知其他的等待连接的线程*/
    public void releaseConnection(Connection connection) 
        if (connection != null) 
            synchronized (pool)
                pool.addLast(connection);
                //通知其他等待连接的线程
                pool.notifyAll();
            
        
    

    /*获取*/
    // 在mills内无法获取到连接,将会返回null 1S
    public Connection fetchConnection(long mills) throws InterruptedException 
        synchronized (pool)
            //永不超时
            if(mills<=0)
                while(pool.isEmpty())
                    pool.wait();
                
                return pool.removeFirst();
            else
                /*超时时刻*/
                long future = System.currentTimeMillis()+mills;
                /*等待时长*/
                long remaining = mills;
                while(pool.isEmpty()&&remaining>0)
                    pool.wait(remaining);
                    /*唤醒一次,重新计算等待时长*/
                    remaining = future-System.currentTimeMillis();
                
                Connection connection = null;
                if(!pool.isEmpty())
                    connection = pool.removeFirst();
                
                return connection;
            
        

    

            

测试

package com.pool;

import java.sql.Connection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *类说明:测试并发1000次从池拿连接
 */
public class DBPoolTest 
    static DBPool pool  = new DBPool(10);
    // 控制器:控制main线程将会等待所有Woker结束后才能继续执行
    static CountDownLatch end;

    public static void main(String[] args) throws Exception 
        // 线程数量
        int threadCount = 50;
        end = new CountDownLatch(threadCount);
        int count = 20;//每个线程的操作次数
        AtomicInteger got = new AtomicInteger();//计数器:统计可以拿到连接的线程
        AtomicInteger notGot = new AtomicInteger();//计数器:统计没有拿到连接的线程
        for (int i = 0; i < threadCount; i++) 
            Thread thread = new Thread(new Worker(count, got, notGot), 
                    "worker_"+i);
            thread.start();
        
        end.await();// main线程在此处等待
        System.out.println("总共尝试了: " + (threadCount * count));
        System.out.println("拿到连接的次数:  " + got);
        System.out.println("没能连接的次数: " + notGot);
    

    static class Worker implements Runnable 
        int           count;
        AtomicInteger got;
        AtomicInteger notGot;

        public Worker(int count, AtomicInteger got,
                               AtomicInteger notGot) 
            this.count = count;
            this.got = got;
            this.notGot = notGot;
        

        public void run() 
            while (count > 0) 
                try 
                    // 从线程池中获取连接,如果1000ms内无法获取到,将会返回null
                    // 分别统计连接获取的数量got和未获取到的数量notGot
                    Connection connection = pool.fetchConnection(1000);
                    if (connection != null) 
                        try 
                            connection.createStatement();
                            connection.commit();
                         finally 
                            pool.releaseConnection(connection);
                            got.incrementAndGet();
                        
                     else 
                        notGot.incrementAndGet();
                        System.out.println(Thread.currentThread().getName()
                                +"等待超时!");
                    
                 catch (Exception ex) 
                 finally 
                    count--;
                
            
            end.countDown();
        
    

结果

技术图片

2、利用信号量实现数据库连接池

package com.semaphore;

import java.sql.Connection;
import java.util.LinkedList;
import java.util.concurrent.Semaphore;

/**
 *类说明:Semaphore实现数据库连接池
 */
public class DBPoolSemaphore 
    
    private final static int POOL_SIZE = 10;
    //两个指示器,分别表示池子还有可用连接和已用连接
    private final Semaphore useful,useless;
    //存放数据库连接的容器
    private static LinkedList<Connection> pool = new LinkedList<Connection>();
    //初始化池
    static 
        for (int i = 0; i < POOL_SIZE; i++) 
            pool.addLast(SqlConnectImpl.fetchConnection());
        
    
    public DBPoolSemaphore() 
        this.useful = new Semaphore(10);
        this.useless = new Semaphore(0);
    
    
    /*归还连接*/
    public void returnConnect(Connection connection) throws InterruptedException 
        if(connection!=null) 
            System.out.println("当前有"+useful.getQueueLength()+"个线程等待数据库连接!!"
                    +"可用连接数:"+useful.availablePermits());
            useless.acquire();
            synchronized (pool) 
                pool.addLast(connection);
            
            useful.release();
        
    
    
    /*从池子拿连接*/
    public Connection takeConnect() throws InterruptedException 
        useful.acquire();
        Connection connection;
        synchronized (pool) 
            connection = pool.removeFirst();
        
        useless.release();
        return connection;
    
    

测试

package com.semaphore;

import java.sql.Connection;
import java.util.Random;

/**
 *类说明:测试数据库连接池
 */
public class AppTest 

    private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
    
    private static class BusiThread extends Thread
        @Override
        public void run() 
            Random r = new Random();//让每个线程持有连接的时间不一样
            long start = System.currentTimeMillis();
            try 
                Connection connect = dbPool.takeConnect();
                System.out.println("Thread_"+Thread.currentThread().getId()
                        +"_获取数据库连接共耗时【"+(System.currentTimeMillis()-start)+"】ms.");
                SleepTools.ms(100+r.nextInt(100));//模拟业务操作,线程持有连接查询数据
                System.out.println("查询数据完成,归还连接!");
                dbPool.returnConnect(connect);
             catch (InterruptedException e) 
            
        
    
    
    public static void main(String[] args) 
        for (int i = 0; i < 50; i++) 
            Thread thread = new BusiThread();
            thread.start();
        
    
    

结果

技术图片

 

package com.semaphore;

import java.sql.Connection;
import java.util.LinkedList;
import java.util.Random;
import java.util.concurrent.Semaphore;

/**
 *类说明:Semaphore实现数据库连接池
 */
public class DBPoolNoUseless 

    private final static int POOL_SIZE = 10;
    private final Semaphore useful;
    //存放数据库连接的容器
    private static LinkedList<Connection> pool = new LinkedList<Connection>();
    //初始化池
    static 
        for (int i = 0; i < POOL_SIZE; i++) 
            pool.addLast(SqlConnectImpl.fetchConnection());
        
    
    public DBPoolNoUseless() 
        this.useful = new Semaphore(10);
    
    
    /*归还连接*/
    public void returnConnect(Connection connection) throws InterruptedException 
        if(connection!=null) 
            System.out.println("当前有"+useful.getQueueLength()+"个线程等待数据库连接!!"
                    +"可用连接数:"+useful.availablePermits());
            synchronized (pool) 
                pool.addLast(connection);
            
            useful.release();
        
    
    
    /*从池子拿连接*/
    public Connection takeConnect() throws InterruptedException 
        useful.acquire();
        Connection connection;
        synchronized (pool) 
            connection = pool.removeFirst();
        
        return connection;
    

    private static DBPoolNoUseless dbPoolNoUseless = new DBPoolNoUseless();

    private static class BusiThread extends Thread
        @Override
        public void run() 
            Random r = new Random();//让每个线程持有连接的时间不一样
            long start = System.currentTimeMillis();
            try 
                System.out.println("Thread_"+Thread.currentThread().getId()
                        +"_获取数据库连接共耗时【"+(System.currentTimeMillis()-start)+"】ms.");
                SleepTools.ms(100+r.nextInt(100));//模拟业务操作,线程持有连接查询数据
                System.out.println("查询数据完成,归还连接!");
                dbPoolNoUseless.returnConnect(new SqlConnectImpl());
             catch (InterruptedException e) 
            
        
    

    public static void main(String[] args) 
        for (int i = 0; i < 50; i++) 
            Thread thread = new BusiThread();
            thread.start();
        
    
    

 

 

 

package cn.enjoyedu.ch1.pool;

import cn.enjoyedu.tools.SleepTools;

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

/**
 *类说明:
 */
public class SqlConnectImpl implements Connection
    
    /*拿一个数据库连接*/
    public static final Connection fetchConnection()
        return new SqlConnectImpl();
    

    //忽略其它    

 

以上是关于java数据库连接池_方便自己学习的主要内容,如果未能解决你的问题,请参考以下文章

个人总结-3-连接池学习

JDBC连接池

JAVA连接池技术

[原创]java WEB学习笔记80:Hibernate学习之路--- hibernate配置文件:JDBC 连接属性,C3P0 数据库连接池属性等

java数据库连接池详细操作

Java学习:数据库连接池DBCP的使用