连接池(原生+常用)

连接池

 

涉及概念:设计模式:资源池(Resource Pool)百度一下,你就知道

 

数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,从“缓冲池”中取出一个,使用完毕之后再放回去。

 

Tomcat连接池

Tomcat默认使用的是DBCP数据库连接池,使用的tomcat-dbcp.jar包。

数据源可以给项目单独配置,也可以全局配置:

单独配置:在项目META-INF下新建context.xml,内容如下Resource

全局设置:在tomcat中conf目录下的context.xml文件 context节点下添加resource

 

<Resource name="jdbc/Mobile"

          auth="Container"

          type="javax.sql.DataSource"

          factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"

          testWhileIdle="true"

          testOnBorrow="true"

          testOnReturn="false"

          validationQuery="SELECT 1"

          validationInterval="30000"

          timeBetweenEvictionRunsMillis="30000"

          maxActive="100"

          minIdle="10"

          maxWait="10000"

          initialSize="10"

          removeAbandonedTimeout="60"

          removeAbandoned="true"

          logAbandoned="false"

          minEvictableIdleTimeMillis="30000"

          jmxEnabled="true"

          fairQueue="true"

          jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;

            org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"

          username="root"

          password='root'

          driverClassName="com.mysql.jdbc.Driver"

          url="jdbc:mysql://127.0.0.1:3306/hsdb?useUnicode=true&characterEncoding=utf-8&autoReconnect=true"/>

 

Spring框架常用的连接池C3P0

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定。c3p0所需jarc3p0-0.9.2.1.jar mchange-commons-java-0.2.3.4.jar

基本使用:

1.引入jar

2.编写配置文件

default-config

        <?xml version="1.0" encoding="UTF-8"?>

<c3p0-config>
    <default-config>
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">
            jdbc:mysql://localhost:3306/dbname?useSSL=true
        </property>
        <!--以上的user是数据库的用户,password是数据库的密码,driverClass是mysql的数据库驱动,jdbcUrl是连接数据库的url -->
        <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->
        <property name="acquireIncrement">5</property>
        <!--初始化时获取十个连接,取值应在minPoolSize与maxPoolSize之间 -->
        <property name="initialPoolSize">10</property>
        <!--连接池中保留的最小连接数 -->
        <property name="minPoolSize">10</property>
        <!--连接池中保留的最大连接数 -->
        <property name="maxPoolSize">50</property>
        <property name="maxStatements">20</property>
        <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
        <property name="maxStatementsPerConnection">5</property>
    </default-config>
    <named-config name="mysql">
        <property name="user">root</property>
        <property name="password">root</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/dbname?useSSL=true</property>
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">10</property>
        <property name="maxPoolSize">50</property>
        <property name="maxStatements">20</property>
        <property name="maxStatementsPerConnection">5</property>
    </named-config>

</c3p0-config>

3.实现操作

       C3P0中连接池的实现类名ComboPooledDataSource 加载配置文件可以加载默认配置也可以加载带名字的配置

      ComboPooledDataSource dataSource = new ComboPooledDataSource();

     //加载有名称的配置named-config

     //ComboPooledDataSource dataSource =

                           new ComboPooledDataSource("mysql");

       Spring中的使用:

       <!-- 配置c3p0数据源 -->

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">

 <property name="jdbcUrl" value="${jdbc.url}" />

 <property name="driverClass" value="${jdbc.driverClassName}" />

 <property name="user" value="${jdbc.username}" />

 <property name="password" value="${jdbc.password}" />

 <!--连接池中保留的最大连接数。Default: 15 -->

 <property name="maxPoolSize" value="100" />

 <!--连接池中保留的最小连接数。-->

 <property name="minPoolSize" value="1" />

 <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->

 <property name="initialPoolSize" value="10" />

 <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->

 <property name="maxIdleTime" value="30" />

 <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->

 <property name="acquireIncrement" value="5" />

 <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->

 <property name="maxStatements" value="0" />

 <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->

 <property name="idleConnectionTestPeriod" value="60" />

 <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->

 <property name="acquireRetryAttempts" value="30" />

 <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->

 <property name="breakAfterAcquireFailure" value="true" />

 <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提升连接测试的性能。Default: false -->

 <property name="testConnectionOnCheckout"  value="false" />  

</bean>

 

JDBC连接池的一种原生写法:

 

Jdbc.properties

 

driver=com.mysql.jdbc.Driver

url=jdbc:mysql://localhost:3306/dbname?useSSL=true

username=root

password=root

jdbcPoolInitSize=10

 

JdbcPool.java

 

package com.test0815;

 

import java.io.InputStream;

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

import java.sql.SQLException;

import java.sql.SQLFeatureNotSupportedException;

import java.util.LinkedList;

import java.util.Properties;

import java.util.logging.Logger;

 

import javax.sql.DataSource;

/**

 * 简单的的jdbc连接池实现

 */

 

public class JdbcPool implements DataSource {

 

    /**

     * 由于要频繁读写List集合,所以这里使用LinkedList存储数据库连接比较合适

     * ps:LinkedList在性能上插入、删除数据速度快。

     */

    private static LinkedList<Connection> listConnections = new LinkedList<Connection>();

    private static Connection conn;

 

    // 在静态代码块中加载jdbc.properties数据库配置文件

    static {

        InputStream in = JdbcPool.class.getResourceAsStream("/jdbc.properties");

        Properties prop = new Properties();

        try {

            prop.load(in);

            String driver = prop.getProperty("driver");

            String url = prop.getProperty("url");

            String username = prop.getProperty("username");

            String password = prop.getProperty("password");

            // 数据库连接池的初始化连接数大小

            int jdbcPoolInitSize = Integer.parseInt(prop

                    .getProperty("jdbcPoolInitSize"));

            // 加载数据库驱动

            Class.forName(driver);

            for (int i = 0; i < jdbcPoolInitSize; i++) {

                conn = DriverManager.getConnection(url, username, password);

                // System.out.println("获取到了连接" + conn);

                // 将获取到的数据库连接加入到listConnections集合中,listConnections集合此时就是一个存放了数据库连接的连接池

                listConnections.add(conn);

            }

        } catch (Exception e) {

            throw new ExceptionInInitializerError(e);

        }

    }

 

    /*

     *

     * 获取数据库连接

     */

    @Override

    public Connection getConnection() throws SQLException {

 

        // 如果数据库连接池中的连接对象的个数大于0

        if (listConnections.size() > 0) {

            // 从listConnections集合中获取一个数据库连接

            System.out.println("listConnections数据库连接池大小是:"

                    + listConnections.size());

            // 返回Connection对象的代理对象

            return (Connection) Proxy.newProxyInstance(JdbcPool.class

                    .getClassLoader(), conn.getClass().getInterfaces(),

                    new InvocationHandler() {

                        @Override

                        public Object invoke(Object proxy, Method method,

                                Object[] args) throws Throwable {

 

                            if (!method.getName().equals("close")) {

                                System.out.println("获取到连接池连接对象......" + conn);

                                return method.invoke(conn, args);

                            } else {

                                // 如果调用的是Connection对象的close方法,就把conn还给数据库连接池

                                listConnections.add(conn);

                                // System.out.println(conn+ ",还给数据库连接池了");

                                // System.out.println("listConnections数据库连接池大小为"+

                                // listConnections.size());

                                return null;

                            }

                        }

                    });

        } else {

            throw new RuntimeException("对不起,数据库忙");

        }

    }

   

    //Override方法

    @Override

    public PrintWriter getLogWriter() throws SQLException {

        return null;

    }

    @Override

    public int getLoginTimeout() throws SQLException {

        return 0;

    }

    @Override

    public Logger getParentLogger() throws SQLFeatureNotSupportedException {

        return null;

    }

    @Override

    public void setLogWriter(PrintWriter out) throws SQLException {

       

    }

    @Override

    public void setLoginTimeout(int seconds) throws SQLException {

       

    }

    @Override

    public boolean isWrapperFor(Class<?> iface) throws SQLException {

        return false;

    }

    @Override

    public <T> T unwrap(Class<T> iface) throws SQLException {

        return null;

    }

    @Override

    public Connection getConnection(String username, String password)

            throws SQLException {

        return null;

    }

}

 

 

 

JDBCUtil.java

 

package com.test0815;

 

import java.sql.Connection;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.ResultSetMetaData;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

 

public class JDBCUtil {

    private static JdbcPool pool = new JdbcPool();

 

    /**

     * 获取资源

     */

    public static Connection getConnection() throws SQLException {

        return pool.getConnection();

    }

 

    /**

     * 关闭资源

     */

    public static void close(ResultSet resultSet, Statement statement,

        Connection connection) {

            if (resultSet != null) {

                try {

                    resultSet.close();

                } catch (SQLException e) {

                    throw new RuntimeException(e);

                }

                resultSet = null;

            }

            if (statement != null) {

                try {

                    statement.close();

                } catch (SQLException e) {

                    throw new RuntimeException(e);

                }

                statement=null;

            }

            if (connection != null) {

                try {

                    connection.close();

                } catch (SQLException e) {

                    throw new RuntimeException(e);

                }

                connection = null;

            }

    }

   

    //插入数据操作

    public static void insertOrDeleteOrUpdate(String sql) {

 

        try {

            Connection connection = JDBCUtil.getConnection();

            PreparedStatement pst = connection.prepareStatement(sql);

            int execute = pst.executeUpdate();

            System.out.println("执行语句:" + sql + "," + execute + "行数据受影响");

            JDBCUtil.close(null, pst, connection);

        } catch (SQLException e) {

            System.out.println("异常提醒:" + e);

        }

 

    }

   

    //插入数据操作

    public static List<Map<String, Object>> select(String sql) {

 

        List<Map<String, Object>> returnResultToList = null;

 

        try {

            Connection connection = JDBCUtil.getConnection();

            PreparedStatement pst = connection.prepareStatement(sql);

            ResultSet resultSet = pst.executeQuery();

            returnResultToList = returnResultToList(resultSet);

            JDBCUtil.close(resultSet, pst, connection);

        } catch (SQLException e) {

            System.out.println("异常提醒:" + e);

        }

 

        return returnResultToList;

 

    }

 

    /**

     *

     * 数据返回集合

     * @param resultSet

     * @return

     * @throws SQLException

     */

    public static List<Map<String, Object>> returnResultToList(

            ResultSet resultSet) {

        List<Map<String, Object>> values = null;

        try {

 

            // 键: 存放列的别名, 值: 存放列的值.

            values = new ArrayList<>();

            // 存放字段名

            List<String> columnName = new ArrayList<>();

            ResultSetMetaData rsmd = resultSet.getMetaData();

 

            for (int i = 0; i < rsmd.getColumnCount(); i++) {

                // 字段名

                columnName.add(rsmd.getColumnLabel(i + 1));

            }

 

            System.out.println("表字段为:");

            System.out.println(columnName);

            System.out.println("表数据为:");

 

            Map<String, Object> map = null;

 

            // 处理 ResultSet, 使用 while 循环

            while (resultSet.next()) {

                map = new HashMap<>();

                for (String column : columnName) {

                    Object value = resultSet.getObject(column);

                    map.put(column, value);

                    System.out.print(value + "\t");

                }

                // 把一条记录的 Map 对象放入准备的 List 中

                values.add(map);

                System.out.println();

            }

        } catch (SQLException e) {

            System.out.println("异常提醒:" + e);

        }

        return values;

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值