自己封装dbc连接池,支持并发,多数据源

package com.shuidi.common.mypool;

import org.apache.log4j.Logger;

import com.shuidi.common.myException.MyException;
import com.shuidi.common.spring.BeanFactory;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

ConnectionManager.java


/**
 * jdbc连接管理类
 * @Author 李修睿 
 * @Param
 * @return  
 * 2018-08-15 下午 4:06
 **/
public enum  ConnectionManager {
    /**
     * 使用枚举单例对象
     * @Author 李修睿 
     * @Param 
     * @return  
     * 2018-08-15 下午 4:07
     **/
    MANAGER;
    private final Logger log = Logger.getLogger(ConnectionManager.class);


    /** 
     * 加载的驱动器名称集合 
     */  
    private Set<String> drivers = new HashSet<String>(); 

    /**
     * 数据库连接池字典
     * 为每个数据库创建一个连接池(可配置多个数据库)
     */
    private ConcurrentHashMap<String, IConnectionPool> pools = new ConcurrentHashMap<String, IConnectionPool>();

   
    private ConnectionManager() {
       // createPools();
    }


    /**
     * 装载JDBC驱动程序,并创建连接池
     * @throws ClassNotFoundException 
     */
    private synchronized IConnectionPool createPools(String poolname) throws ClassNotFoundException{
        if(pools.containsKey(poolname)){
            return pools.get(poolname);
        }
        DataSource db= (DataSource) BeanFactory.getBean(poolname);
        db.setDbName(poolname);
        if (db.getUrl() == null) {
                log.error(poolname+"数据库的连接字符串为空,请检查配置文件");
                //抛出一个异常,说明数据库为空
                return null;
            }    
        if (db.getDriverName() == null) {
                log.error(poolname+"数据库的driver驱动为空,请检查配置文件");
                return null;
            }
      
            if (db.getUsername() == null) {
                log.error(poolname+"数据库的用户名设置为空,请检查配置文件");
                return null;
            }
            if (db.getPassword() == null) {
                log.error(poolname+"数据库的密码设置为空,请检查配置文件");
                return null;
            }
        
            //验证最小连接数配置正确性
            if (db.getMinConnections() <1) {
                log.error(poolname+"数据库的最小连接数配置不正确,设置为默认值5");
                db.setMinConnections(5);
            }
         
            //验证初始连接数配置正确性          
            if (db.getInitConnections() <db.getMinConnections()) {
                log.error(poolname+"数据库的初始连接数配置不正确,设置为最小连接数"+db.getMinConnections());
                db.setInitConnections(db.getMinConnections());
            }

            //验证最大连接数配置正确性
            if (db.getMaxConnections() <db.getInitConnections()) {
                log.error(poolname+"数据库的最大连接数配置不正确,设置为初始连接数"+db.getInitConnections());
                db.setInitConnections(db.getInitConnections());
            }

            //验证conninterval配置正确性
            if (db.getConninterval() <1) {
                log.error(poolname+"数据库的等待时间配置不正确,设置为默认值500毫秒");
                db.setConninterval(500);
            }
            //验证timeout配置正确性
            if (db.getTimeout() <0) {
                log.error(poolname+"数据库的超时重连配置不正确,设置为默认值2000毫秒");
                db.setTimeout(2000);
            }

            //创建驱动
            if(!drivers.contains(db.getDriverName())){
                try {
                    Class.forName(db.getDriverName());
                    log.info("加载JDBC驱动"+db.getDriverName()+"成功");
                    drivers.add(db.getDriverName());
                } catch (ClassNotFoundException e) {
                    log.error("未找到JDBC驱动" + db.getDriverName() + ",请引入相关包");
                    throw e;
                }
            }
            log.warn("初始化连接:"+db.getInitConnections());
            //创建连接池。这里采用同步方法实现的连接池类ConnectionPool。
            //(如果后面我们还有别的实现方式,只需要更改这里就行了。)
            IConnectionPool cp = ConnectionPool.createConnectionPool(db);
            if (cp.getFreeNum()>0) {
                pools.put(poolname, cp);
                cp.checkPool();
                log.info("创建" + poolname + "数据库连接池成功");
            } else {
                log.info("创建" + poolname + "数据库连接池失败");
                throw new MyException("创建" + poolname + "数据库连接池失败");
            }
      return cp;
    }

    /**
     * 从指定连接池中获取可用连接
     * 
     * @param poolName 要获取连接的连接池名称
     * @throws SQLException 
     * @return 连接池中的一个可用连接或null
     * @throws ClassNotFoundException 
     */
    public  MyConnection getConnection(String poolName) throws SQLException, ClassNotFoundException {
        IConnectionPool pool =  pools.get(poolName);
        if(pool==null){
            pool = createPools(poolName);
        }
       
        return  pool.getCurrentConnection();
    }


    /**
     * 回收指定连接池的连接
     * 
     * @param poolName 连接池名称
     * @param conn  要回收的连接
     * @throws SQLException 
     */
    public void closeConnection(String poolName, MyConnection conn) throws SQLException{
        IConnectionPool pool = pools.get(poolName);
        if (pool != null) {
            if(isAutoCommit(conn.getConnection())){//自动提交状态才释放,非自动提交状态可能是开启了事务管理
                pool.releaseConn(conn);
            }
                     
        }else{
            log.error("找不到"+poolName+"连接池,无法回收"); 
            throw new MyException("找不到"+poolName+"连接池,无法回收");
        }
    }

    private boolean isAutoCommit(Connection conn) throws SQLException{
        boolean b =false;
        try {
            b = conn.getAutoCommit();
        } catch (SQLException e) {    
            log.error("判断连接是否自动提交出错!");
            throw e;
        }
        return b;
    }
    /**
     * 关闭所有连接,撤销驱动器的注册
     */
    public void destroy() {
        for (Map.Entry<String, IConnectionPool> poolEntry : pools.entrySet()) {
            IConnectionPool pool = poolEntry.getValue();
            pool.destroy();
        }
        log.info("已经关闭所有连接");
    }
    /**
     * 关闭resultSet
     * @Author 李修睿
     * @Param [rs]
     * @return void
     * 2018-08-03 上午 9:21
     **/
    public void closeResultSet(ResultSet rs){
        try {
            if(null!=rs){
                rs.close();    
            }else{
                log.error("ResultSet是null");
            }
        } catch (SQLException e) {
            log.error("关闭ResultSet出错!");
            throw new MyException("关闭ResultSet出错!");
        }
    }


    /**
     * 关闭statement
     * @Author 李修睿
     * @Param [stm]
     * @return void
     * 2018-08-03 上午 9:20
     * @throws SQLException 
     **/
    public void closeStatement(Statement stm) throws SQLException {
        try {
            if(null!=stm){
                stm.close();
            }else{
                log.error("关闭Statement出错!Statement是null");    
                throw new MyException("关闭Statement出错!Statement是null");
            }
            
        } catch (SQLException e) {
            log.error("关闭ResultSet出错!");
            throw e;
        }
    }
}

 

ConnectionPool.java

package com.shuidi.common.mypool;

import org.apache.log4j.Logger;

import com.shuidi.common.myException.DBException;

import java.sql.*;
import java.util.LinkedList;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/** 
 * 类说明 :友元类,包内可见,不提供给客户程序直接访问。
 */
class ConnectionPool implements IConnectionPool {

    private static final Logger log = Logger.getLogger(ConnectionPool.class);

    /**
     * 最长空闲时间,超过就要校验连接是否可用
     * @Author 李修睿 
     * @Param 
     * @return  
     * 2018-08-06 下午 1:59
     **/
    private static final long FREE_TIME = 18000000;
    private DataSource propertyBean=null;

   /**
    * 连接池可用状态
    * @Author 李修睿
    * @Param
    * @return
    * 2018-08-06 上午 10:39
    **/
    private Boolean isActive = true;

    /**
     * 空闲连接池 。由于List读写频繁,使用LinkedList存储比较合适
     * @Author 李修睿
     * @Param
     * @return
     * 2018-08-06 上午 10:39
     **/
    private LinkedList<MyConnection> freeConnections = new LinkedList<>();
    /**
     * 活动连接池。活动连接数 <= 允许最大连接数(maxConnections)
     * @Author 李修睿
     * @Param
     * @return
     * 2018-08-06 上午 10:39
     **/
    private LinkedList<MyConnection> activeConnections = new LinkedList<>();

    /**
     * 当前线程获得的连接
     * @Author 李修睿
     * @Param
     * @return
     * 2018-08-06 上午 10:39
     **/
    private ThreadLocal<MyConnection> currentConnection= new ThreadLocal<>();

    /**
     * 构造方法无法返回null,所以取消掉。在下面增加了CreateConnectionPool静态方法。
     * @Author 李修睿
     * @Param
     * @return
     * 2018-08-06 上午 10:40
     **/
    private ConnectionPool(){
        super();
    }

    public static ConnectionPool createConnectionPool(DataSource propertyBean) {
        ConnectionPool connpool=new ConnectionPool();
        connpool.propertyBean = propertyBean;

        //基本点2、始使化时根据配置中的初始连接数创建指定数量的连接
        for (int i = 0; i < connpool.propertyBean.getInitConnections(); i++) {
          Connection con =  connpool.newConnection();
            if (con!=null){
                MyConnection conn = new MyConnection(con) ;
                connpool.freeConnections.add(conn);
            }


        }

        connpool.isActive = true;
        return connpool;
    }

    /**
     * 检测连接是否有效
     * @param conn 数据库连接对象
     * @return Boolean
     */
    private Boolean isValidConnection(Connection conn){
        try {
            if(conn==null || conn.isClosed()){
                return false;
            }
        } catch (SQLException e) {
            log.error("检测连接出错"+e.getMessage(),e);
            return false;
        }
        return true;
    }

    /**
     * 创建一个新的连接
     * @return 数据库连接对象
     */
    private Connection newConnection(){

        Connection conn = null;
        try {
            if (this.propertyBean != null) {

                conn = DriverManager.getConnection(this.propertyBean.getUrl(),
                        this.propertyBean.getUsername(),
                        this.propertyBean.getPassword());
            }
        } catch (SQLException e) {
           log.error(this.propertyBean.getDbName()+"创建新连接出错!"+e.getMessage(),e);
           throw new DBException("创建新连接出错!",e);
        }
        return conn;
    }


    private synchronized  MyConnection getConnection() {
        MyConnection conn;
        if (this.getActiveNum() < this.propertyBean.getMaxConnections()) {
            // 分支1:当前使用的连接没有达到最大连接数  
            // 基本点3、在连接池没有达到最大连接数之前,如果有可用的空闲连接就直接使用空闲连接,如果没有,就创建新的连接。
            if (this.getFreeNum() > 0) {
                // 分支1.1:如果空闲池中有连接,就从空闲池中直接获取
                log.info("分支1.1:如果空闲池中有连接,就从空闲池中直接获取");
                conn = this.freeConnections.pollFirst();

                //连接闲置久了也会超时,因此空闲池中的有效连接会越来越少,需要另一个进程进行扫描监测,不断保持一定数量的可用连接。
                //在下面定义了checkFreepools的TimerTask类,在checkPool()方法中进行调用。

                //基本点5、由于数据库连接闲置久了会超时关闭,因此需要连接池采用机制保证每次请求的连接都是有效可用的。
                
                    if(this.isValidConnection(conn.getConnection())){
                        //闲置小于5个小时,不检测 能否连接上
                        long now = System.currentTimeMillis();
                        if((now - conn.getRefreshTime()) < FREE_TIME){
                            this.activeConnections.add(conn);
                            currentConnection.set(conn);
                            //刷新使用时间
                            conn.setRefreshTime(now);
                        }else{//闲置大于5小时
                            if(testConn(conn.getConnection())){
                                //能连上
                                this.activeConnections.add(conn);
                                currentConnection.set(conn);
                                conn.setRefreshTime(now);
                            }else{
                                //连接不上
                              Connection con=conn.getConnection();
                              try {
                                con.close();
                              } catch (SQLException e) {
                                log.error("关闭连接出错!"+e.getMessage());
                                e.printStackTrace();
                              }
                              conn.setConnection(this.newConnection());
                              conn.setRefreshTime(now);
                            }
                        }                        
                    }else{
                        //如果连接不可用
                        //同步方法是可重入锁
                        conn = getCurrentConnection();
                    }
             
            } else {
                // 分支1.2:如果空闲池中无可用连接,就创建新的连接
                log.info("分支1.2:如果空闲池中无可用连接,就创建新的连接");
                conn = new MyConnection(newConnection());
                this.activeConnections.add(conn);
              
            }
        } else {
            // 分支2:当前已到达最大连接数  
            // 基本点4、当连接池中的活动连接数达到最大连接数,新的请求进入等待状态,直到有连接被释放。
            log.info("分支2:当前已到达最大连接数 ");
            long startTime = System.currentTimeMillis();

            //进入等待状态。等待被notify(),notifyALL()唤醒或者超时自动苏醒  
            try{
                this.wait(this.propertyBean.getConninterval());  
            }catch(InterruptedException e) {  
                log.error("线程等待被打断");  
            }

            //若线程超时前被唤醒并成功获取连接,就不会走到return null。
            //若线程超时前没有获取连接,则返回null。
            //如果timeout设置为0,就无限重连。
            if(this.propertyBean.getTimeout()!=0){
                if(System.currentTimeMillis() - startTime > this.propertyBean.getTimeout()) {
                    return null;
                }
            }
            conn = this.getConnection();

        }
        return conn;
    }


    @Override
    public  MyConnection getCurrentConnection() {
        
        MyConnection conn=currentConnection.get();
        if(null==conn || !isValidConnection(conn.getConnection())){
             conn=this.getConnection();
        }
      
        return conn;
    }


    @Override
    public synchronized void releaseConn(MyConnection conn){

        log.info(Thread.currentThread().getName()+"关闭连接:activeConnections.remove:"+conn.getConnection());
        this.activeConnections.remove(conn);
        this.currentConnection.remove();
        //活动连接池删除的连接,相应的加到空闲连接池中
       if(isValidConnection(conn.getConnection())){
            freeConnections.add(conn);
         }else{
            freeConnections.add(new MyConnection(this.newConnection()));
         }
        //唤醒getConnection()中等待的线程
        this.notifyAll();
    }

    @Override
    public synchronized void destroy() {
        for (MyConnection conn : this.freeConnections) {  
            try {
                if (this.isValidConnection(conn.getConnection())) { 
                    conn.getConnection().close();
                   //释放掉连接
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }   
        }  
        for (MyConnection conn : this.activeConnections) {  
            try {
                if (this.isValidConnection(conn.getConnection())) { 
                     conn.getConnection().close();
                    //释放掉连接
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } 
        }
        this.isActive = false;
        this.freeConnections.clear();
        this.activeConnections.clear();
    }

    @Override
    public boolean isActive() {
        return this.isActive;
    }


    @Override
    public void checkPool() {

        ScheduledExecutorService ses=Executors.newScheduledThreadPool(1);
        //功能一:开启一个定时器线程输出状态
        ses.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                //当活跃连接数较少时 ,空余连接数较多时关闭空余连接释放资源
              if(getActiveNum()<propertyBean.getInitConnections()){               
                
                    if(getFreeNum()>propertyBean.getInitConnections()){
                      MyConnection conn= freeConnections.pollLast();
                      if(conn!=null){
                        try {
                           conn.getConnection().close();
                          
                           log.warn("当前空余连接"+getFreeNum()+"个,删除一个空余连接...");
                        } catch (SQLException e) {                            
                            e.printStackTrace();
                        }
                    }
                 }
              }
            }
        }, 5, 5, TimeUnit.SECONDS);

        //功能二:开启一个定时器线程,监测并维持空闲池中的最小连接数
        //代码已维护,永远不会小于最小
       // ses.scheduleAtFixedRate(new checkFreepools(this), 1, 5, TimeUnit.SECONDS);
    }

    @Override
    public synchronized int getActiveNum() {
        return this.activeConnections.size();
    }

    @Override
    public synchronized int getFreeNum() {
        return this.freeConnections.size();
    }


   static class checkFreepools extends TimerTask {
        private ConnectionPool conpool = null;

        public checkFreepools(ConnectionPool cp) {
            this.conpool = cp;
        }

        @Override
        public void run() {
            if (this.conpool != null && this.conpool.isActive()) {
                int poolstotalnum = conpool.getFreeNum()
                        + conpool.getActiveNum();                
                int subnum = conpool.propertyBean.getMinConnections()
                        - poolstotalnum;

                if (subnum > 0) {
                    log.warn(conpool.propertyBean.getDbName()
                            + "扫描并维持空闲池中的最小连接数,需补充" + subnum + "个连接");
                    for (int i = 0; i < subnum; i++) {
                        conpool.freeConnections.add(new MyConnection(this.conpool.newConnection()));                       
                    }

                }
            }

        }

    }

    /**
     *
     * @Author 李修睿
     * @Param
     * @return
     * 2018-08-06 下午 2:03
     **/
    @Override
    public boolean testConn(Connection conn) {
        String sql = "select 1 from dual";      
        PreparedStatement pstmt=null;
        ResultSet resultSet=null;
        try {
            pstmt = conn.prepareStatement(sql);
            resultSet =pstmt.executeQuery();
        } catch (SQLException e) {
            log.error("连接数据库"+this.propertyBean.getDbName()+"失败!"+e.getMessage());
            return false;
        }finally{
            try {
                if(pstmt!=null) {
                    pstmt.close();
                }
                if(resultSet!=null) {
                    resultSet.close();
                }
           } catch (SQLException e) {              
               e.printStackTrace();
           }
        }
        return true;
    }

}

 

DataBaseExecutor.java

package com.shuidi.common.mypool;

import org.apache.log4j.Logger;

import com.shuidi.common.myException.ParamIsNullException;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 */
public class DataBaseExecutor {

    private static final Logger log = Logger.getLogger(DataBaseExecutor.class);

    /**
     * 查询操作
     * @Author 李修睿
     * @Param [sql, poolName, params]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     * 2018-08-16 上午 10:08
     * @throws SQLException 
     * @throws ClassNotFoundException 
     **/
    public static List<Map<String, Object>> executorQuery(String sql, String poolName, Object[] params) throws SQLException, ClassNotFoundException{
          if(sql==null||sql.trim()==""){
              throw new ParamIsNullException("sql");
          }
        if(poolName==null||poolName.trim()==""){
            throw new ParamIsNullException("poolName");
        }
         ResultSet rs=null;
         List<Map<String, Object>> mapList = new ArrayList<>();
         MyConnection conn=null;
        //使用预处理防止sql注入
         PreparedStatement preparedStatement =null;

        try {
             conn = ConnectionManager.MANAGER.getConnection(poolName);
             preparedStatement = conn.getConnection().prepareStatement(sql);
             if (params!=null&&params.length>0) {

                 for (int i=0;i<params.length;i++) {preparedStatement.setObject(i + 1, params[i]);}
              }
              rs = preparedStatement.executeQuery();
              
              while (rs.next()) {
                  Map<String,Object> map= new HashMap<>();
                  ResultSetMetaData md = rs.getMetaData();          
                  int size = md.getColumnCount();
                for (int i = 0; i <size; i++) {
                    map.put((md.getColumnLabel(i+1)).toLowerCase(),rs.getObject(i+1));
                }            
                mapList.add(map);
              }
             
        } catch (SQLException e) {
            String s=  preparedStatement.toString();
            String rsql = s.substring(s.indexOf(":")+1);
            log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
            throw e;
        } finally {
            ConnectionManager.MANAGER.closeResultSet(rs);
            ConnectionManager.MANAGER.closeStatement(preparedStatement);
            ConnectionManager.MANAGER.closeConnection(poolName,conn);
        }
        return mapList;
        
    }


    /**
     * 、插入、删除、更新操作
     * @Author 李修睿
     * @Param [sql, poolname, params]
     * @return int
     * 2018-08-16 上午 10:08
     * @throws SQLException 
     * @throws ClassNotFoundException 
     **/
    public static int executorUpdate(String sql, String poolname,Object[] params) throws SQLException, ClassNotFoundException{
        if(sql==null||sql.trim()==""){
            throw new ParamIsNullException("sql");
        }
        if(poolname==null||poolname.trim()==""){
            throw new ParamIsNullException("poolName");
        }
         MyConnection conn=null;
         PreparedStatement preparedStatement =null;

          int res =0;        
        try {

             conn = ConnectionManager.MANAGER.getConnection(poolname);
             preparedStatement = conn.getConnection().prepareStatement(sql);             
             if (params!=null&&params.length>0) {
                    for (int i=0;i<params.length;i++) {
                        preparedStatement.setObject(i+1, params[i]);
                    }
              }
             res = preparedStatement.executeUpdate();    
            ;
            
        } catch (SQLException e) {
            String s=  preparedStatement.toString();
            String rsql = s.substring(s.indexOf(":")+1);
            log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
            throw e;
        } finally{
            ConnectionManager.MANAGER.closeStatement(preparedStatement);
            ConnectionManager.MANAGER.closeConnection(poolname,conn);
        }
        return res;
    }


    /**
     * 批量处理
     * @Author 李修睿
     * @Param [sql, poolname, params]
     * @return int
     * 2018-08-16 上午 10:22
     * @throws SQLException 
     * @throws ClassNotFoundException 
     **/
    public static int executorBatch(String sql, String poolname,List<Object[]> params) throws SQLException, ClassNotFoundException{
        if(sql==null||sql.trim()==""){
            throw new ParamIsNullException("sql");
        }
        if(poolname==null||poolname.trim()==""){
            throw new ParamIsNullException("poolName");
        }
        MyConnection conn=null;
        PreparedStatement preparedStatement =null;
        int res = 0;
        try {

            conn = ConnectionManager.MANAGER.getConnection(poolname);
            preparedStatement = conn.getConnection().prepareStatement(sql);
            if (params!=null&&params.size()>0) {
                for (Object [] pars:params) {
                    for (int j=0, length =pars.length;j<length;j++) {
                        preparedStatement.setObject(j + 1,pars[j]);
                    }
                    preparedStatement.addBatch();
                }
            }
            int[] result= preparedStatement.executeBatch();
            if(result==null || (result!=null && result.length==0) ){
               return res;
            }
            for (int re:result) {
                res+=re;
            }
            
        } catch (SQLException e) {
            String s=  preparedStatement.toString();
            String rsql = s.substring(s.indexOf(":")+1);
            log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
            throw e;
        } finally{
            ConnectionManager.MANAGER.closeStatement(preparedStatement);
            ConnectionManager.MANAGER.closeConnection(poolname,conn);
        }
        return res;
    }
}
 

package com.shuidi.common.mypool;

import org.apache.log4j.Logger;

import com.shuidi.common.myException.ParamIsNullException;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 */
public class DataBaseExecutor {

    private static final Logger log = Logger.getLogger(DataBaseExecutor.class);

    /**
     * 查询操作
     * @Author 李修睿
     * @Param [sql, poolName, params]
     * @return java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     * 2018-08-16 上午 10:08
     * @throws SQLException 
     * @throws ClassNotFoundException 
     **/
    public static List<Map<String, Object>> executorQuery(String sql, String poolName, Object[] params) throws SQLException, ClassNotFoundException{
          if(sql==null||sql.trim()==""){
              throw new ParamIsNullException("sql");
          }
        if(poolName==null||poolName.trim()==""){
            throw new ParamIsNullException("poolName");
        }
         ResultSet rs=null;
         List<Map<String, Object>> mapList = new ArrayList<>();
         MyConnection conn=null;
        //使用预处理防止sql注入
         PreparedStatement preparedStatement =null;

        try {
             conn = ConnectionManager.MANAGER.getConnection(poolName);
             preparedStatement = conn.getConnection().prepareStatement(sql);
             if (params!=null&&params.length>0) {

                 for (int i=0;i<params.length;i++) {preparedStatement.setObject(i + 1, params[i]);}
              }
              rs = preparedStatement.executeQuery();
              
              while (rs.next()) {
                  Map<String,Object> map= new HashMap<>();
                  ResultSetMetaData md = rs.getMetaData();          
                  int size = md.getColumnCount();
                for (int i = 0; i <size; i++) {
                    map.put((md.getColumnLabel(i+1)).toLowerCase(),rs.getObject(i+1));
                }            
                mapList.add(map);
              }
             
        } catch (SQLException e) {
            String s=  preparedStatement.toString();
            String rsql = s.substring(s.indexOf(":")+1);
            log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
            throw e;
        } finally {
            ConnectionManager.MANAGER.closeResultSet(rs);
            ConnectionManager.MANAGER.closeStatement(preparedStatement);
            ConnectionManager.MANAGER.closeConnection(poolName,conn);
        }
        return mapList;
        
    }


    /**
     * 、插入、删除、更新操作
     * @Author 李修睿
     * @Param [sql, poolname, params]
     * @return int
     * 2018-08-16 上午 10:08
     * @throws SQLException 
     * @throws ClassNotFoundException 
     **/
    public static int executorUpdate(String sql, String poolname,Object[] params) throws SQLException, ClassNotFoundException{
        if(sql==null||sql.trim()==""){
            throw new ParamIsNullException("sql");
        }
        if(poolname==null||poolname.trim()==""){
            throw new ParamIsNullException("poolName");
        }
         MyConnection conn=null;
         PreparedStatement preparedStatement =null;

          int res =0;        
        try {

             conn = ConnectionManager.MANAGER.getConnection(poolname);
             preparedStatement = conn.getConnection().prepareStatement(sql);             
             if (params!=null&&params.length>0) {
                    for (int i=0;i<params.length;i++) {
                        preparedStatement.setObject(i+1, params[i]);
                    }
              }
             res = preparedStatement.executeUpdate();    
            ;
            
        } catch (SQLException e) {
            String s=  preparedStatement.toString();
            String rsql = s.substring(s.indexOf(":")+1);
            log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
            throw e;
        } finally{
            ConnectionManager.MANAGER.closeStatement(preparedStatement);
            ConnectionManager.MANAGER.closeConnection(poolname,conn);
        }
        return res;
    }


    /**
     * 批量处理
     * @Author 李修睿
     * @Param [sql, poolname, params]
     * @return int
     * 2018-08-16 上午 10:22
     * @throws SQLException 
     * @throws ClassNotFoundException 
     **/
    public static int executorBatch(String sql, String poolname,List<Object[]> params) throws SQLException, ClassNotFoundException{
        if(sql==null||sql.trim()==""){
            throw new ParamIsNullException("sql");
        }
        if(poolname==null||poolname.trim()==""){
            throw new ParamIsNullException("poolName");
        }
        MyConnection conn=null;
        PreparedStatement preparedStatement =null;
        int res = 0;
        try {

            conn = ConnectionManager.MANAGER.getConnection(poolname);
            preparedStatement = conn.getConnection().prepareStatement(sql);
            if (params!=null&&params.size()>0) {
                for (Object [] pars:params) {
                    for (int j=0, length =pars.length;j<length;j++) {
                        preparedStatement.setObject(j + 1,pars[j]);
                    }
                    preparedStatement.addBatch();
                }
            }
            int[] result= preparedStatement.executeBatch();
            if(result==null || (result!=null && result.length==0) ){
               return res;
            }
            for (int re:result) {
                res+=re;
            }
            
        } catch (SQLException e) {
            String s=  preparedStatement.toString();
            String rsql = s.substring(s.indexOf(":")+1);
            log.error("执行sql异常:"+e.getMessage()+">>sql:"+rsql);
            throw e;
        } finally{
            ConnectionManager.MANAGER.closeStatement(preparedStatement);
            ConnectionManager.MANAGER.closeConnection(poolname,conn);
        }
        return res;
    }
}
 

package com.shuidi.common.mypool;
public class DataSource {

    private String dbName;
    //数据连接驱动
    private String driverName;
    //数据连接url
    private String url;
    //数据连接username
    private String username;
    //数据连接密码
    private String password;
    //连接池最大连接数
    private int maxConnections ;
    //连接池最小连接数
    private int minConnections;
    //连接池初始连接数
    private int initConnections;
    //重连间隔时间 ,单位毫秒
    private int conninterval ;
    //获取连接超时时间 ,单位毫秒,0永不超时
    private int timeout ;

    //构造方法
    public DataSource(){
        super();
    }

    //下面是getter and setter

    /**
     * 获取数据库连接节点名称
     * @return
     */
    public String getDbName() {
        return dbName;
    }

    /**
     * 设置数据库连接节点名称
     * @param nodeName
     */
    public void setDbName(String nodeName) {
        this.dbName = nodeName;
    }

    /**
     * 获取数据库驱动
     * @return
     */
    public String getDriverName() {
        return driverName;
    }

    /**
     * 设置数据库驱动
     * @param driverName
     */
    public void setDriverName(String driverName) {
        this.driverName = driverName;
    }

    /**
     * 获取数据库url
     * @return
     */
    public String getUrl() {
        return url;
    }

    /**
     * 设置数据库url
     * @param url
     */
    public void setUrl(String url) {
        this.url = url;
    }

    /**
     * 获取用户名
     * @return
     */
    public String getUsername() {
        return username;
    }

    /**
     * 设置用户名
     * @param username
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * 获取数据库连接密码
     * @return
     */
    public String getPassword(){
        return password;
    }

    /**
     * 设置数据库连接密码
     * @param password
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * 获取最大连接数
     * @return
     */
    public int getMaxConnections() {
        return maxConnections;
    }

    /**
     * 设置最大连接数
     * @param maxConnections
     */
    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

    /**
     * 获取最小连接数(也是数据池初始连接数)
     * @return
     */
    public int getMinConnections() {
        return minConnections;
    }

    /**
     * 设置最小连接数(也是数据池初始连接数)
     * @param minConnections
     */
    public void setMinConnections(int minConnections) {
        this.minConnections = minConnections;
    }

    /**
     * 获取初始加接数
     * @return
     */
    public int getInitConnections() {
        return initConnections;
    }

    /**
     * 设置初始连接数
     * @param initConnections
     */
    public void setInitConnections(int initConnections) {
        this.initConnections = initConnections;
    }

    /**
     * 获取重连间隔时间,单位毫秒
     * @return
     */
    public int getConninterval() {
        return conninterval;
    }

    /**
     * 设置重连间隔时间,单位毫秒
     * @param conninterval
     */
    public void setConninterval(int conninterval) {
        this.conninterval = conninterval;
    }

    /**
     * 获取连接超时时间,单位毫秒
     * @return
     */
    public int getTimeout() {
        return timeout;
    }

    /**
     * 设置连接超时时间 ,单位毫秒,0-无限重连
     * @param timeout
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

}

 

IConnectionPool.java

package com.shuidi.common.mypool;
import java.sql.Connection;
import java.sql.SQLException;

public interface IConnectionPool {
   

    /**
     * 获得当前线程的连接库连接,如果为空则获取一个空闲的连接,如果等待超时则返回null
     * @return 数据库连接对象
     */
    public MyConnection getCurrentConnection();

    /**
     * 释放当前线程数据库连接
     * @param conn 数据库连接对象
     * @throws SQLException
     */
    public void releaseConn(MyConnection conn);

    /**
     * 销毁清空当前连接池
     */
    public void destroy();

    /**
     * 连接池可用状态
     * @return 连接池是否可用
     */
    public boolean isActive();

    /**
     * 定时器,检查连接池
     */
    public void checkPool();

    /**
     * 获取线程池活动连接数
     * @return 线程池活动连接数
     */
    public int getActiveNum();

    /**
     * 获取线程池空闲连接数
     * @return 线程池空闲连接数
     */
    public int getFreeNum();
    /**
     * 测试连接是否真实可用
     * @return
     */
    public boolean testConn(Connection conn);
}

 

MyConnection.java

 

package com.shuidi.common.mypool;

import java.sql.Connection;


public class MyConnection {
    
    private Connection connection;//连接
    private long refreshTime;//刷新时间
    
    public MyConnection(Connection conn){
        this.connection = conn;
        this.refreshTime = System.currentTimeMillis();
    }
    public Connection getConnection() {
        return connection;
    }
    public void setConnection(Connection connection) {
        this.connection = connection;
    }
    public long getRefreshTime() {
        return refreshTime;
    }
    public void setRefreshTime(long refreshTime) {
        this.refreshTime = refreshTime;
    }
}
 

TransactionAspect.java

package com.shuidi.common.mypool;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;

import com.shuidi.common.myException.UnKonwException;
import com.shuidi.common.myanotation.Transaction;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;

@Aspect
public class TransactionAspect {
    private static final Logger log = Logger.getLogger(TransactionAspect.class);

    /**
     * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码. 使用 @Pointcut 来声明切入点表达式.
     * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
     */
    @Pointcut("@annotation(com.shuidi.common.myanotation.Transaction)")
    public void declareJointPointExpression() {
    }

    // /**
    // * 前置通知
    // * 在 com.atguigu.spring.aop.ArithmeticCalculator
    // * 接口的每一个实现类的每一个方法开始之前执行一段代码
    // * 用通配符*来表示所有
    // */
    //// @Before("execution(public double
    // com.spring2.lee.aop.impl.ArithmeticCalculator.plus(int, int))")
    // @Before("declareJointPointExpression()")
    // public void beforeMethod(JoinPoint joinPoint) {
    // String methodName = joinPoint.getSignature().getName();
    // Object[] args = joinPoint.getArgs();
    // System.out.println("@Before: before method " + methodName + " begin
    // with:" + Arrays.asList(args));
    // }
    //
    // /**
    // * 后置通知
    // * 在方法执行之后执行的代码. 无论该方法是否出现异常
    // * @param joinPoint
    // */
    //
    // @After("declareJointPointExpression()")
    // public void afterMethod(JoinPoint joinPoint) {
    // String methodName = joinPoint.getSignature().getName();
    // Object[] args = joinPoint.getArgs();
    // System.out.println("@After:after method " + methodName +
    // " end " + Arrays.asList(args));
    // }
    //
    // /**
    // * 返回通知
    // * 在方法法正常结束受执行的代码
    // * 返回通知是可以访问到方法的返回值的!
    // */
    // @AfterReturning(value = "declareJointPointExpression()",
    // returning = "result")
    // public void afterReturning(JoinPoint joinPoint,
    // Object result) {
    // String methodName = joinPoint.getSignature().getName();
    // System.out.println(" @AfterReturning:The method " + methodName +
    // " ends with " + result);
    // }
    //
    // /**
    // * 异常通知
    // * 在目标方法出现异常时会执行的代码.
    // * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
    // */
    // @AfterThrowing(value = "declareJointPointExpression()", throwing = "e")
    // public void afterThrowing(JoinPoint joinPoint, Exception e) {
    // String methodName = joinPoint.getSignature().getName();
    // System.out.println("@AfterThrowing:The method " + methodName +
    // " occurs excetion:" + e);
    // }

    /**
     * 环绕通知需要携带 ProceedingJoinPoint 类型的参数. 环绕通知类似于动态代理的全过程: ProceedingJoinPoint
     * 类型的参数可以决定是否执行目标方法. 且环绕通知必须有返回值, 返回值即为目标方法的返回值
     * @throws SQLException 
     */

    @Around("declareJointPointExpression()")
    public Object aroundMethod(ProceedingJoinPoint pjd) throws SQLException {

        Object result = null;
        Signature sig = pjd.getSignature();
        MethodSignature msig;
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        msig = (MethodSignature) sig;
        Object target = pjd.getTarget();
        MyConnection myconn =null;
        Connection conn = null;
        String poolname = "";
        String className = "";
        String methodName = "";
        try {
            Method currentMethod = target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
        
            Transaction permission = currentMethod.getAnnotation(Transaction.class);
        
            className = target.getClass().getName();
            methodName = currentMethod.getName();
            poolname = permission.value();
            myconn = ConnectionManager.MANAGER.getConnection(poolname);
            conn =myconn.getConnection();

            log.warn(className + ":" + methodName + "方法的" + poolname + "连接池启用事务管理");
            conn.setAutoCommit(false);

            result = pjd.proceed();// 执行方法

            conn.commit();
            
            log.warn(className + ":" + methodName + "方法的" + poolname + "连接池提交事务");
        } catch (Throwable e) {
            result = null;
            //ConnectionManager.rollbackTransaction(conn);
            try {
                if(conn!=null)
                conn.rollback();
            } catch (SQLException e1) {
                log.error(className + ":" + methodName + "方法的连接池执行事务回滚失败",e);
                throw e1;
            }
            log.error(className + ":" + methodName + "方法的" + poolname + "连接池执行事务失败,事务回滚",e);
            throw new UnKonwException("事务管理异常!"+e.getMessage());
        } finally {
            try {
                if(conn!=null)
                conn.setAutoCommit(true);
            } catch (SQLException e) {
                log.error(className + ":" + methodName + "方法的"+conn+"设置事务自动提交失败",e);
                throw e;
            }
            log.warn(className + ":" + methodName + "方法的" + poolname + "事物结束,释放连接..");
            ConnectionManager.MANAGER.closeConnection(poolname, myconn);
        }

        return result;
    }

}

Transaction.java

package com.shuidi.common.myanotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义事务管理注解
 * @author 李修睿
 * @date 2018年4月23日 下午1:58:37
 */
@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取    
@Target(ElementType.METHOD)//目标是方法    
@Documented//文档生成时,该注解将被包含在javadoc中,可去掉
public @interface Transaction {
  String value() default "companyadvertisement";
}
 

上一篇:20201128-中国朝代表


下一篇:Autoloading Classes