精华内容
下载资源
问答
  • 描述websphere后台如何进行数据源配置的操作,自带详细截图说明,新手一看就懂
  • websphere服务器中(was)连接池属性

    万次阅读 2018-06-28 12:13:00
    WAS连接池属性 连接超时: 解释:连接超时是指,当对指定连接池进行请求时,池中没有可用连接(连接全部被使用,或者数据库请求超时),当请求时间到达指定之间时未响应,那麽这个时候就会产生超时异常,通过日志...

    WAS连接池属性


      



    连接超时:

     

    解释:连接超时是指,当对指定连接池进行请求时,池中没有可用连接(连接全部被使用,或者数据库请求超时),当请求时间到达指定之间时未响应,那麽这个时候就会产生超时异常,通过日志可以发现。指定间隔(以秒为单位)

    结果:这个间隔时间过后连接请求超时并抛出 ConnectionWaitTimeoutException。

    说明:达到连接特定连接池的最大值(最大连接数)或者数据库请求超时,等待是必需的。例如,如果连接超时设置为 300 并且达到了最大连接数,则池管理器为可用的物理连接等待 300 秒。如果物理连接在此时间内不是可用的,则池管理器抛出 ConnectionWaitTimeoutException。它通常不会重试 getConnection() 方法,因为如果必需更长的等待时间,您应该设置连接超时设置为更高的值。因此,如果应用程序捕捉了此异常,那么管理员应该复查应用程序的期待用法,并相应地调整连接池和数据库。

    注:如果连接超时设置为 0,则只要必需,池管理器就会一直等待直到分配一个连接为止(这在连接数下降到最大连接数值以下时发生)。

    如果最大连接数设置为 0,其允许无限多个物理连接数,则将忽略连接超时值。

    连接超时设置:

    数据类型: 整型 

    单位: 秒

    缺省: 180 

    范围 :0 到最大整数

    好处:连接超时的设置,可以让我们发现哪些程序点有响应速度问题,可能是数据库查询语句问题,也有可能是程序逻辑死循环,再有可能就是数据库表结构需要优化,还有可能是最大连接数到达最大值。

     

    未使用超时 

     

    解释:未使用的超时指池中的物理连接空闲未使用的时间间隔,每隔指定时间,系统会为连接标记,帮助收集时间在维护过程中进行关闭。未使用的超时应该小于实效超时时间,并且其以最小连接数为标准,当连接数超过最小连接数时,其才起作用。以秒为单位

     

    说明:这个参数指定一个空闲连接在连接池中能够存活的最大时间。因为在连接池中保持连接会消耗系统资源,因此超过最小连接数的空闲连接会被定时清除。(注:当连接数没有超过最小连接数时,该项不起作用)未使用超时设为0时就不清除空闲连接。

    数据类型: 整型 

    单位: 秒 

    缺省 :1800

    范围 :0 到最大整数 

     

    好处:未使用超时的设置,帮助我们关闭不必要的空闲连接,释放系统资源,并且减少数据库开销。根据现场环境使用情况,我们可以根据系统访问频繁程序,来定制合理的未使用超时,如果过小,当访问频繁程度大时,总需要重新创建,如果过大,当访问频繁程度不大时,连接池又空闲占用过多。


    最小连接数

     

    解释:最小连接数是指当前连接池要保留的最小物理连接,其决定未使用超时维护机制的下限,连接池的创建不是根据最小连接数而特意创建,而是根据用户请求而创建,系统会一直维护最小的连接数目。

    说明:   最小连接数使应用服务器保持一定数量的物理连接,利用应用服务器维护机制,合理分配服务器资源。当应用程序访问频繁,但访问人数少的情况下,最小连接数的合理配置,可以将有效的资源进行充分利用,满足特定应用需求。

    数据类型: 整型 

    单位: 个 

    缺省 :1

     

    好处:最小连接数使应用服务器保持一定数量的物理连接,利用应用服务器维护机制,合理分配服务器资源。当应用程序访问频繁,但访问人数少的情况下,最小连接数的合理配置,可以将有效的资源进行充分利用,满足特定应用需求。


    最大连接数

     

    解释:最大连接数是指当前连接池中允许创建的最大物理连接数,当到达指定值后,将不允许创建物理连接。和连接超时相对应,当达到最大值后,连接请求将等待,直到池中有空闲连接为止,否则报连接超时错误(ConnectionWaitTimeoutException)。当使用集群机制时,会同时存在多个相同连接池,这个时候需要考虑最大数量的设置。

    好处:最大连接数可以有效控制创建物理连接的数量,连接池的大小影响着服务器资源的占用情况,若连接池过大,则会长期占用服务器可利用资源,若连接池过小,无法满足现场环境应用高负载使用压力。最大连接数的设置应根据TPV观测数据进行合理配置。

    数据类型: 整型 

    单位: 个 

    缺省 :10

     

    获得时间(收集时间)

     

    解释:收集时间是连接池维护机制的核心,是指每次维护连接池的时间间隔。其有两个维护指标,分别为未使用超时和时效超时,其值应该小于两个指标中的任何一个。每一次维护周期中,连接池都会将连接池中超时的物理连接关闭,以减少系统占用资源。

    说 明:连接池中的连接由一个定时运行的线程进行维护。这个参数就是指定运行连接池维护线程之间的间隔。例如,如果“获得时间”设置为60,则池维护线程每 60秒运行一次。当池维护线程运行时,它废弃所有未使用的连接(未使用时间长于“不使用超时”中指定的时间值),直到它到达最小连接数中指定的连接数。池维护线程还废弃所有活动时间长于“时效超时”中指定的时间值的连接。获得时间间隔还影响性能,因为更短的间隔意味着池维护线程将更频繁的运行并降低性能。要禁用池维持线程,“获得时间”设置为0,或“不使用超时”和“时效超时”都设置为 0。

    好处:合理的收集时间设置,是帮助我们关闭不必要的连接,节省系统资源占用的有效途径。收集时间设置不易过大,因为时间间隔过长,会使很多未被使用的物理连接持续占用资源。若收集时间过小,则频繁的维护会带来很多系统开销,连接池的主要精力都放到了维护上。

    时效超时

     

    解释:实效超时指关闭物理连接的时间间隔,这个值是指到达指定的时间后,关闭满足时间条件的物理连接,若这个物理连接未使用,则直接关闭,若这个连接正在使用,则当前事务结束后,关闭此连接。这个值不受最小连接数的影响,若没有新创建的连接,此机制会关闭连接直到为0。

    说明:这个参数指应用在获得连接之后而不使用它的最大空闲时间。如果在放回到连接池之后,应用再去使用这个连接就会报StaleConnectionException异常。这个参数对事务处理中的连接不生效。时效超时设为0时这个参数就不生效。这里有一点要注意,虽然WebSphere应用服务器可以通过设置这个参数可以回收应用程序中忘记释放的数据库连接,但是在大并发量用户的时候还是会导致数据库连接不够用的异常。因此,尽量保证应用程序中使用完数据库连接之后及时放回到连接池中去。这个值不受最小连接数的影响,若没有新创建的连接,此机制会关闭连接直到为0。

    好 处:  时效超时的设置,是为了方式应用程序或者数据库造成的数据库连接持续占用,可能导致的原因包括程序逻辑错误,数据库宕机导致的错误等。还有一种情况为人为导致,就是若某个用户持续占用一个资源不放,会导致其他用户无法访问。所以时效超时的设置,是对不合理使用应用,或者链接错误等进行强行关闭,保证程序的稳定性和持久性。

     
    展开全文
  • WAS连接池配置(一)

    万次阅读 2014-10-29 18:39:51
    本文介绍WebSphere下Oracle、SQL Server、Sybase、MySQL数据库连接池的配置方法,并给出相应调用连接池的示例。相对于Weblogic,WebSphere连接池的配置要稍微复杂一些,因为缺少相关的文档,需要一定的技巧和经验。...
    本文介绍WebSphere下Oracle、SQL Server、Sybase、MySQL数据库连接池的配置方法,并给出相应调用连接池的示例。相对于Weblogic,WebSphere连接池的配置要稍微复杂一些,因为缺少相关的文档,需要一定的技巧和经验。特别是对于初学者,完整的配置好Websphere连接池还是有一定难度的。 
    

    一、系统准备

    1.在相应的数据库中建立本文用到的表

    create table TEST(C1 CHAR(10) )

    insert into TEST values('FromTest')

    2.准备环境变量,此部分往往会被初学者忽略。

    WAS连接池配置(一)

    点击“管理WebSphere变量”,ORACLE_JDBC_DRIVER_PATH的值输入操作系统中jar文件(classes12.jar)的位置。

    “确认”后,界面最上方,点击“保存”,会再提示“保存”还是“放弃”,再选“保存”。

    为方便起见,本文中,SQL Server的jar文件(msbase.jar、mssqlserver.jar、msutil.jar )、Sybase的jar文件(jconn2.jar)、mySQL的jar文件(mysql-connector-java-3.1.10-bin.jar)都放在同一目录(如:C:\oracle\ora92\jdbc\lib)。

    3.本文中的所有例子测试均通过,环境:Windows2003、WebShpere5.1、ORACLE9I、SQL Server 2000、SYBASE12.5、MySQL5.0。

    二、Oracle、SQL Server、Sybase、MySQL数据库连接池在WebSphere中的详细配置步骤

    (一)、Oracle连接池的配置

    1.进入管理控制台(http://localhost:9090/admin/)

    2.选择:资源->JDBC提供程序,点击“新建”,建立JDBC提供程序。

    WAS连接池配置(一)

    点击“应用”后,类路径中,输入“${ORACLE_JDBC_DRIVER_PATH}/classes12.jar”,再点击“应用”。

    3.定义数据源

    点击界面中“数据源后”再点击“新建”,建立数据源。

    WAS连接池配置(一)

    JNDI取名ORACLE_JNDI,点击“应用”。

    4.界面上点击“定制属性”,定义连接池的JDBC Driver、URL、用户名和口令等信息。

    点击“URL”,URL的值输入:jdbc:oracle:thin:@localhost:1521:MYHORA,其中,localhost可以为ORACLE的IP地址,MYHORA是ORACLE的服务名称。

    点击“确定”保存配置。

    同样的方法输入:

    driverType的值oracle.jdbc.driver.OracleDriver

    databasename的值MYHORA

    servername的值localhost

    preTestSQLString的值为SELECT COUNT(1) FROM TEST

    其余的取默认值。

    5.本部分比较关键,是初学着比较困惑的地方。

    我们看到,界面上并没有输入用户名、口令的地方,而没有用户名称、口令是无法连接数据库的。

    WAS连接池配置(一)

    在“定制属性”中点击“新建”,“名称”中输入user,“值”中输入数据库的用户名称,如:study,点击“确定”;

    在“定制属性”中点击“新建”,“名称”中输入password,“值”中输入数据库的口令,如:study,点击“确定”;

    我们看到,“定制属性”中多了两个我们自定义的属性user、password

    WAS连接池配置(一)

    6.保存配置,在“定制属性”界面的最上方点击“保存”。

    7.测试连接

    WAS连接池配置(一)

    系统提示:成功信息,表明,连接池配置成功。

    连接池配置成功后,WebSphere需要重新启动。

    展开全文
  • Mybatis中的dataSource使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源,有三种内建的... 不同的数据库在性能方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。...

    Mybatis中的dataSource使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源,有三种内建的数据源类型:

    • UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。虽然有点慢,但对于在数据库连接可用性方面没有太高要求的简单应用程序来说,是一个很好的选择。 不同的数据库在性能方面的表现也是不一样的,对于某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形。
    • POOLED:这个数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这是一种使得并发 Web 应用快速响应请求的流行处理方式。
    • JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。如,我们常在wildfly的standalone.xml 文件中集中配置 JNDI 数据源。

    DataSourceL类图
    接下来,我们分别看下三种数据源的实现方式。

    UnpooledDataSource 数据源创建过程

    上文提到,Mybatis 中的 dataSource 使用标准的 JDBC 数据源接口,因此 UnpooledDataSource 是实现了 DataSource 接口的,并重写了 DataSource 中的 getConnection 方法。
    看下 UnpooledDataSource 中 getConnection 方法实现:

    public Connection getConnection() throws SQLException {
        //调用 doGetConnection 获取连接
        return doGetConnection(username, password);
    }
    
    private Connection doGetConnection(String username, String password) throws SQLException {
        Properties props = new Properties();
        //获取数据库驱动配置
        if (driverProperties != null) {
            props.putAll(driverProperties);
        }
        if (username != null) {
            props.setProperty("user", username);
        }
        if (password != null) {
            props.setProperty("password", password);
        }
        return doGetConnection(props);
    }
    
    private Connection doGetConnection(Properties properties) throws SQLException {
        //初始化数据库驱动
        initializeDriver();
        //通过驱动代理类 DriverProxy 对象创建 connection
        Connection connection = DriverManager.getConnection(url, properties);
        //配置是否自动提交和事务隔离级别
        configureConnection(connection);
        return connection;
    }
    

    UnpooledDataSource 的创建连接过程相对还是简单的。通过以下几步:

    1. 获取数据库驱动配置。
    2. 初始化数据库驱动。
    3. 通过 DriverManager 获取连接。
    4. 配置连接是否自动提交和事务隔离级别。

    PooledDataSource 数据源创建过程

    从 PooledDataSource 的代码中可以看出, PooledDataSource 同样继承 DataSource 接口,同时保存了一个 UnpooledDataSource 类的引用,还有一个 PoolState 对象用于保存空闲连接和活跃连接。我们看下获取连接代码:

    public Connection getConnection() throws SQLException {
        //获取真实连接的代理连接 proxyConnection
        return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
    }
    
    private PooledConnection popConnection(String username, String password) throws SQLException {
        boolean countedWait = false;
        //PooledConnection 是 Connection 真实连接的代理类,用于关闭时特殊处理,下面会分析如何处理关闭情形
        PooledConnection conn = null;
        long t = System.currentTimeMillis();
        int localBadConnectionCount = 0;
    
        while (conn == null) {
            //state 是 连接池状态,防止多线程操作,所以加锁
            synchronized (state) {
                //当空闲池中存在连接时,则从空闲池中取出连接,取列表的一个连接
                if (state.idleConnections.size() > 0) {
                    // Pool has available connection
                    conn = state.idleConnections.remove(0);
                    if (log.isDebugEnabled()) {
                        log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
                    }
                } else {
                    // 当活跃连接池数量小于最大活跃连接池数时,创建新的连接
                    if (state.activeConnections.size() < poolMaximumActiveConnections) {
                        // Can create new connection
          //这里是用 UnpooledDataSource 对象来创建连接
                        conn = new PooledConnection(dataSource.getConnection(), this);
                        @SuppressWarnings("unused")
                        //used in logging, if enabled
                                Connection realConn = conn.getRealConnection();
                        if (log.isDebugEnabled()) {
                            log.debug("Created connection " + conn.getRealHashCode() + ".");
                        }
                    } else {
                        // 当活跃连接池数量等于最大活跃连接池数时,从活跃连接池的列表取第一个连接
                        PooledConnection oldestActiveConnection = state.activeConnections.get(0);
                        long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
                        //当池中连接被检出时间大于配置时间(单位毫秒),则重新new一个新连接,并将原连接置为不可用
                        if (longestCheckoutTime > poolMaximumCheckoutTime) {
                            // Can claim overdue connection
                            state.claimedOverdueConnectionCount++;
                            state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
                            state.accumulatedCheckoutTime += longestCheckoutTime;
                            state.activeConnections.remove(oldestActiveConnection);
                            if (!oldestActiveConnection.getRealConnection().getAutoCommit()) {
                                oldestActiveConnection.getRealConnection().rollback();
                            }
                            conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
                            oldestActiveConnection.invalidate();
                            if (log.isDebugEnabled()) {
                                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
                            }
                        } else {
                            //活跃连接池已满,线程等待
                            // Must wait
                            try {
                                if (!countedWait) {
                                    state.hadToWaitCount++;
                                    countedWait = true;
                                }
                                if (log.isDebugEnabled()) {
                                    log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                                }
                                long wt = System.currentTimeMillis();
                                state.wait(poolTimeToWait);
                                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
                            } catch (InterruptedException e) {
                                break;
                            }
                        }
                    }
                }
                if (conn != null) {
                    if (conn.isValid()) {
                        if (!conn.getRealConnection().getAutoCommit()) {
                            conn.getRealConnection().rollback();
                        }
                        //设置连接类型编码,取url+username+password 三者拼接字符串的hashcode
                        conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
                        conn.setCheckoutTimestamp(System.currentTimeMillis());
                        conn.setLastUsedTimestamp(System.currentTimeMillis());
                        //将连接加入到活跃连接池列表
                        state.activeConnections.add(conn);
                        state.requestCount++;
                        state.accumulatedRequestTime += System.currentTimeMillis() - t;
                    } else {
                        //无法获取有效连接
                        if (log.isDebugEnabled()) {
                            log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
                        }
                        state.badConnectionCount++;
                        localBadConnectionCount++;
                        conn = null;
                        if (localBadConnectionCount > (poolMaximumIdleConnections + 3)) {
                            if (log.isDebugEnabled()) {
                                log.debug("PooledDataSource: Could not get a good connection to the database.");
                            }
                            throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
                        }
                    }
                }
            }
    
        }
    
        if (conn == null) {
            if (log.isDebugEnabled()) {
                log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
            }
            throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
        }
    
        return conn;
    }
    

    PooledDataSource 的获取连接过程相对复杂一点,可以先看下流程图,简单描述了下上述代码的逻辑过程:
    popConnection方法流程图
    接下来再通过文字描述下上述步骤:

    1. 首先检查 PoolState 中的空闲连接池 idleConnections 中是否有可用连接。如果有,则直接从空闲连接池中取出一个连接使用。
    2. 如果空闲连接池 idleConnections 中没有可用连接,那么继续检查 PoolState 中的活跃连接池 activeConnections 是否小于最大活跃连接池数。如果小于,则新建一个连接,新建连接是通过 dataSource.getConnection() 建立的,而 dataSourceUnpooledDataSource 对象,所以 PooledDataSource 中新建连接是通过 UnpooledDataSource 对象建立的,通过对象关联避免了重复代码。
    3. 如果 PoolState 中的活跃连接池 activeConnections 不小于最大活跃连接池数,则从活跃连接池 activeConnections 中取出第一个连接,并检查是否超过连接池最大检出时间 poolMaximumCheckoutTime。如果未超过,则移除第一个活跃连接(最老的活跃连接),并新建一个连接。否则,继续等待获取连接,直到超过最大检出时间 poolMaximumCheckoutTime。
    4. if (conn != null) 如果连接不为空且可获得,则将获取的连接添加到活跃连接池中。否则,当重试超过一定次数的坏连接后,抛出 SQLException 异常。

    接下来,谈另一话题。正常我们执行 SQL 语句,都会在执行前打开连接,执行结束后关闭连接。在 UnpooledDataSource 中确实是关闭了真实连接,那 PooledDataSource 是如何关闭的呢? 刚才说过,PooledDataSourcegetConnection 返回的是代理连接 proxyConnection,重点就在这个代理类中,它通过代理真实连接对象,并对真实连接对象的调用方法进行了增强。代理类 PooledConnection 使用的是 JDK 动态代理,即实现了 InvocationHandler 接口,并重写了 invoke 方法,我们来看下代理类中是如何处理 PooledDataSource 数据源的关闭操作的。

    private static final String CLOSE = "close";
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        //关键点,当真实连接调用的方法是 close 时,这里是将该连接从活跃连接池移除,并放到空闲连接池中
        if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
            dataSource.pushConnection(this);
            return null;
        } else {
            try {
                if (!Object.class.equals(method.getDeclaringClass())) {
                    // issue #579 toString() should never fail
                    // throw an SQLException instead of a Runtime
                    checkConnection();
                }
                return method.invoke(realConnection, args);
            } catch (Throwable t) {
                throw ExceptionUtil.unwrapThrowable(t);
            }
        }
    }
    
    protected void pushConnection(PooledConnection conn) throws SQLException {
        synchronized (state) {
            //将连接从活跃连接池移除
            state.activeConnections.remove(conn);
            if (conn.isValid()) {
                //当空闲连接池未达到最大空闲连接池数限制,则将真实连接加入空闲连接池
                if (state.idleConnections.size() < poolMaximumIdleConnections && conn.getConnectionTypeCode() == expectedConnectionTypeCode) {
                    state.accumulatedCheckoutTime += conn.getCheckoutTime();
                    //检查该连接是否提交,如果未提交,则执行回滚
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    //获取真实连接
                    PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
                    //添加到空间连接池中
                    state.idleConnections.add(newConn);
                    newConn.setCreatedTimestamp(conn.getCreatedTimestamp());
                    newConn.setLastUsedTimestamp(conn.getLastUsedTimestamp());
                    conn.invalidate();
                    if (log.isDebugEnabled()) {
                        log.debug("Returned connection " + newConn.getRealHashCode() + " to pool.");
                    }
                    state.notifyAll();
                } else {
                    //当空闲连接池数超过最大空闲连接池数限制,则将该真实连接关闭
                    state.accumulatedCheckoutTime += conn.getCheckoutTime();
                    if (!conn.getRealConnection().getAutoCommit()) {
                        conn.getRealConnection().rollback();
                    }
                    conn.getRealConnection().close();
                    if (log.isDebugEnabled()) {
                        log.debug("Closed connection " + conn.getRealHashCode() + ".");
                    }
                    conn.invalidate();
                }
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("A bad connection (" + conn.getRealHashCode() + ") attempted to return to the pool, discarding connection.");
                }
                state.badConnectionCount++;
            }
        }
    }
    

    PooledConnection 代理类中,我们看到了,代理类对连接的 close 方法做了特殊处理:

    1. 当空闲连接池未达到最大空闲连接池数限制,则将真实连接加入空闲连接池。
    2. 当空闲连接池数超过最大空闲连接池数限制,则将该真实连接关闭。
      这样保证了 PooledDataSource 数据源中的连接复用,也是 Mybatis 中连接池的实现机制。

    JNDI 数据源创建过程

    Mybatis 创建 JNDI 数据源的方式只用到了一个工厂类 JndiDataSourceFactory ,JNDI 数据源创建方式和上面 UNPOOL 和 POOL 方式不同,JNDI 主要是通过启动上下文 InitialContextJNDI 配置文件来完成。InitialContext 是执行命名操作的启动上下文,可以查找到配置文件中的 JNDI 配置:

    public void setProperties(Properties properties) {
        try {
            InitialContext initCtx = null;
            //获取 JNDI 配置信息
            Properties env = getEnvProperties(properties);
            //初始化启动上下文
            if (env == null) {
                initCtx = new InitialContext();
            } else {
                initCtx = new InitialContext(env);
            }
            // 从配置文件中获取 dataSource
            if (properties.containsKey(INITIAL_CONTEXT)
                    && properties.containsKey(DATA_SOURCE)) {
                Context ctx = (Context) initCtx.lookup(properties.getProperty(INITIAL_CONTEXT));
                dataSource = (DataSource) ctx.lookup(properties.getProperty(DATA_SOURCE));
            } else if (properties.containsKey(DATA_SOURCE)) {
                dataSource = (DataSource) initCtx.lookup(properties.getProperty(DATA_SOURCE));
            }
        } catch (NamingException e) {
            throw new DataSourceException("There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);
        }
    

    JNDI 获取数据源主要分三个步骤:

    1. 首先获取 JNDI 配置信息。
    2. 初始化启动上下文 initCtx。
    3. 上下文调用 lookup 方法获取数据源 dataSource。

    Mybatis 中的数据源类型和连接池实现原理就先介绍到这里,以备复习及其他小伙伴学习。

    展开全文
  • was配置db2数据连接池

    2009-12-11 10:54:44
    详细的讲述了在was中如何配置db2连接池,有截图,很适合入门的初学者!
  • Mybatis数据源连接池

    2021-06-02 11:03:25
    本文将从以下几个方面介绍Mybatis的数据源连接池: MyBatis数据源DataSource分类 数据源DataSource的创建过程 DataSource什么时候创建Connection对象 MyBatis数据源DataSource分类 MyBatis数据源实现是在以下...

    本文将从以下几个方面介绍Mybatis的数据源和连接池:

    • MyBatis数据源DataSource分类
    • 数据源DataSource的创建过程
    • DataSource什么时候创建Connection对象

    MyBatis数据源DataSource分类

    MyBatis数据源实现是在以下四个包中:


    MyBatis把数据源DataSource分为三种: 1、UNPOOLED:不使用连接池的数据源 2、POOLED: 使用连接池的数据源 3、JNDI:使用JNDI实现的数据源(JNDI是 Java 命名与目录接口(Java Naming and Directory Interface),在J2EE规范中是重要的规范之一。JNDI由j2ee容器提供,避免了程序与数据库之间的紧耦合,使应用更加易于配置、易于部署)

    DataSource的创建过程

    通过上一篇文章Mybatis初始化机制解析可以知道,在Mybatis初始化过程中,会将DataSource实例放到Configuration对象内的Environment对象中。在解析xml配置时:

    <dataSource type="POOLED">
      <property name="driver" value="${driver}"/>
      <property name="url" value="${url}"/>
      <property name="username" value="${username}"/>
      <property name="password" value="${password}"/>
    </dataSource>

    通过DataSourceFactory.getDataSource()方法来创建数据源DataSource。

    DataSource什么时候创建Connection对象

    当我们需要创建SqlSession对象并需要执行SQL语句时,这时候MyBatis才会去调用dataSource对象来创建java.sql.Connection对象。也就是说,java.sql.Connection对象的创建一直延迟到执行SQL语句的时候。例如:

    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    sqlSession.selectList("SELECT * FROM STUDENTS");

    前4句都不会导致java.sql.Connection对象的创建,只有当第5句sqlSession.selectList("SELECT * FROM STUDENTS"),才会触发MyBatis在底层执行下面这个方法来创建java.sql.Connection对象:

    //Transaction的实现类中创建,最终调用到DataSource的实现类
    protected void openConnection() throws SQLException {
        if (log.isDebugEnabled()) {
          log.debug("Opening JDBC Connection");
        }
        connection = dataSource.getConnection();
        if (level != null) {
          connection.setTransactionIsolation(level.getLevel());
        }
        setDesiredAutoCommit(autoCommmit);
      }

    UnpooledDataSource.getConnection()

    使用UnpooledDataSource的getConnection(),每调用一次就会产生一个新的Connection实例对象。

    public Connection getConnection() throws SQLException
    {
        return doGetConnection(username, password);
    }
     
    private Connection doGetConnection(String username, String password) throws SQLException
    {
        //封装username和password成properties
        Properties props = new Properties();
        if (driverProperties != null)
        {
            props.putAll(driverProperties);
        }
        if (username != null)
        {
            props.setProperty("user", username);
        }
        if (password != null)
        {
            props.setProperty("password", password);
        }
        return doGetConnection(props);
    }
     
    /*
     *  获取数据连接
     */
    private Connection doGetConnection(Properties properties) throws SQLException
    {
        //1.初始化驱动
        initializeDriver();
        //2.从DriverManager中获取连接,获取新的Connection对象
        Connection connection = DriverManager.getConnection(url, properties);
        //3.配置connection属性
        configureConnection(connection);
        return connection;
    }

    为什么要使用连接池?

    创建一个Connection对象的代价很大,因为创建一个Connection对象的过程,在底层就相当于和数据库建立的通信连接,在建立通信连接的过程,会消耗很多时间,而往往我们建立连接后(即创建Connection对象后),就执行一个简单的SQL语句,然后就要抛弃掉,这是一个非常大的资源浪费!

    对于需要频繁地跟数据库交互的应用程序,可以在创建了Connection对象,并操作完数据库后,可以不释放掉资源,而是将它放到内存中,当下次需要操作数据库时,可以直接从内存中取出Connection对象,不需要再创建了,这样就极大地节省了创建Connection对象的资源消耗。

    PooledDataSource.getConnection()

    PooledDataSource将java.sql.Connection对象包裹成PooledConnection对象放到了PoolState类型的容器中维护。 MyBatis将连接池中的PooledConnection分为两种状态: 空闲状态(idle)和活动状态(active),这两种状态的PooledConnection对象分别被存储到PoolState容器内的idleConnections和activeConnections两个List集合中。

    idleConnections:空闲(idle)状态PooledConnection对象被放置到此集合中,表示当前闲置的没有被使用的PooledConnection集合,调用PooledDataSource的getConnection()方法时,会优先从此集合中取PooledConnection对象。当用完一个java.sql.Connection对象时,MyBatis会将其包裹成PooledConnection对象放到此集合中。

    activeConnections:活动(active)状态的PooledConnection对象被放置到名为activeConnections的ArrayList中,表示当前正在被使用的PooledConnection集合,调用PooledDataSource的getConnection()方法时,会优先从idleConnections集合中取PooledConnection对象,如果没有,则看此集合是否已满,如果未满,PooledDataSource会创建出一个PooledConnection,添加到此集合中,并返回。

    public Connection getConnection() throws SQLException {
        return popConnection(dataSource.getUsername(), dataSource.getPassword()).getProxyConnection();
      }
     
      public Connection getConnection(String username, String password) throws SQLException {
        return popConnection(username, password).getProxyConnection();
      }

    现在让我们看一下popConnection()方法到底做了什么:

    1. 先看是否有空闲(idle)状态下的PooledConnection对象,如果有,就直接返回一个可用的PooledConnection对象;否则进行第2步。

    2. 查看活动状态的PooledConnection池activeConnections是否已满;如果没有满,则创建一个新的PooledConnection对象,然后放到activeConnections池中,然后返回此PooledConnection对象;否则进行第三步;

    3. 看最先进入activeConnections池中的PooledConnection对象是否已经过期:如果已经过期,从activeConnections池中移除此对象,然后创建一个新的PooledConnection对象,添加到activeConnections中,然后将此对象返回;否则进行第4步。

    4. 线程等待,循环2步

    private PooledConnection popConnection(String username, String password) throws SQLException
    {
        boolean countedWait = false;
        PooledConnection conn = null;
        long t = System.currentTimeMillis();
        int localBadConnectionCount = 0;
     
        while (conn == null)
        {
            synchronized (state)
            {
                if (state.idleConnections.size() > 0)
                {
                    // 连接池中有空闲连接,取出第一个
                    conn = state.idleConnections.remove(0);
                    if (log.isDebugEnabled())
                    {
                        log.debug("Checked out connection " + conn.getRealHashCode() + " from pool.");
                    }
                }
                else
                {
                    // 连接池中没有空闲连接,则取当前正在使用的连接数小于最大限定值,
                    if (state.activeConnections.size() < poolMaximumActiveConnections)
                    {
                        // 创建一个新的connection对象
                        conn = new PooledConnection(dataSource.getConnection(), this);
                        @SuppressWarnings("unused")
                        //used in logging, if enabled
                        Connection realConn = conn.getRealConnection();
                        if (log.isDebugEnabled())
                        {
                            log.debug("Created connection " + conn.getRealHashCode() + ".");
                        }
                    }
                    else
                    {
                        // Cannot create new connection 当活动连接池已满,不能创建时,取出活动连接池的第一个,即最先进入连接池的PooledConnection对象
                        // 计算它的校验时间,如果校验时间大于连接池规定的最大校验时间,则认为它已经过期了,利用这个PoolConnection内部的realConnection重新生成一个PooledConnection
                        //
                        PooledConnection oldestActiveConnection = state.activeConnections.get(0);
                        long longestCheckoutTime = oldestActiveConnection.getCheckoutTime();
                        if (longestCheckoutTime > poolMaximumCheckoutTime)
                        {
                            // Can claim overdue connection
                            state.claimedOverdueConnectionCount++;
                            state.accumulatedCheckoutTimeOfOverdueConnections += longestCheckoutTime;
                            state.accumulatedCheckoutTime += longestCheckoutTime;
                            state.activeConnections.remove(oldestActiveConnection);
                            if (!oldestActiveConnection.getRealConnection().getAutoCommit())
                            {
                                oldestActiveConnection.getRealConnection().rollback();
                            }
                            conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
                            oldestActiveConnection.invalidate();
                            if (log.isDebugEnabled())
                            {
                                log.debug("Claimed overdue connection " + conn.getRealHashCode() + ".");
                            }
                        }
                        else
                        {
     
                            //如果不能释放,则必须等待有
                            // Must wait
                            try
                            {
                                if (!countedWait)
                                {
                                    state.hadToWaitCount++;
                                    countedWait = true;
                                }
                                if (log.isDebugEnabled())
                                {
                                    log.debug("Waiting as long as " + poolTimeToWait + " milliseconds for connection.");
                                }
                                long wt = System.currentTimeMillis();
                                state.wait(poolTimeToWait);
                                state.accumulatedWaitTime += System.currentTimeMillis() - wt;
                            }
                            catch (InterruptedException e)
                            {
                                break;
                            }
                        }
                    }
                }
     
                //如果获取PooledConnection成功,则更新其信息
     
                if (conn != null)
                {
                    if (conn.isValid())
                    {
                        if (!conn.getRealConnection().getAutoCommit())
                        {
                            conn.getRealConnection().rollback();
                        }
                        conn.setConnectionTypeCode(assembleConnectionTypeCode(dataSource.getUrl(), username, password));
                        conn.setCheckoutTimestamp(System.currentTimeMillis());
                        conn.setLastUsedTimestamp(System.currentTimeMillis());
                        state.activeConnections.add(conn);
                        state.requestCount++;
                        state.accumulatedRequestTime += System.currentTimeMillis() - t;
                    }
                    else
                    {
                        if (log.isDebugEnabled())
                        {
                            log.debug("A bad connection (" + conn.getRealHashCode() + ") was returned from the pool, getting another connection.");
                        }
                        state.badConnectionCount++;
                        localBadConnectionCount++;
                        conn = null;
                        if (localBadConnectionCount > (poolMaximumIdleConnections + 3))
                        {
                            if (log.isDebugEnabled())
                            {
                                log.debug("PooledDataSource: Could not get a good connection to the database.");
                            }
                            throw new SQLException("PooledDataSource: Could not get a good connection to the database.");
                        }
                    }
                }
            }
     
        }
     
        if (conn == null)
        {
            if (log.isDebugEnabled())
            {
                log.debug("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
            }
            throw new SQLException("PooledDataSource: Unknown severe error condition.  The connection pool returned a null connection.");
        }
     
        return conn;
    }

    对应的处理流程图如下所示:

    Connection对象的回收
    这里使用了代理模式,为真正的Connection对象创建一个代理对象,代理对象所有的方法都是调用相应的真正Connection对象的方法实现。当代理对象执行close()方法时,要特殊处理,不调用真正Connection对象的close()方法,而是将Connection对象添加到连接池中。

    MyBatis的PooledDataSource的PoolState内部维护的对象是PooledConnection类型的对象,而PooledConnection则是对真正的数据库连接java.sql.Connection实例对象的包裹器。

    PooledConnection对象内持有一个真正的数据库连接java.sql.Connection实例对象和一个java.sql.Connection的代理:

    class PooledConnection implements InvocationHandler {
      
      //......
      //所创建它的datasource引用
      private PooledDataSource dataSource;
      //真正的Connection对象
      private Connection realConnection;
      //代理自己的代理Connection
      private Connection proxyConnection;
      
      //......
    }

    让我们看一下PooledConnection类中的invoke()方法定义:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        //当调用关闭的时候,回收此Connection到PooledDataSource中
        if (CLOSE.hashCode() == methodName.hashCode() && CLOSE.equals(methodName)) {
          dataSource.pushConnection(this);
          return null;
        } else {
          try {
            if (!Object.class.equals(method.getDeclaringClass())) {
              checkConnection();
            }
            return method.invoke(realConnection, args);
          } catch (Throwable t) {
            throw ExceptionUtil.unwrapThrowable(t);
          }
        }
      }
    展开全文
  • 一、数据源DataSource的分类Mybatis的数据实现都在datasource这个包内:即:Mybatis把数据源分为了三类: JNDI:使用JNDI实现数据源(这里不介绍这种) UNPOOLED:不使用连接池数据源() POOLED:使用连接池的...
  • WAS 数据源配置文件位置

    千次阅读 2020-07-19 13:10:42
    上周查了个问题:WAS启动卡在连接池初始化上,明显是数据源配置问题。 因为WAS起不来,所以进控制台排查肯定是不行了,好在服务器本地数据源配置是明文。 该配置在$WAS_HOME/***/PROFILE_NAME/config/***/resource...
  • 今天发现了这个问题,数据源连接池的配置方式dbcp c3p0 Druid 然后百度得到了第一个答案C3P0官方对于MySQL8小时问题的解决方案 The last packet successfully received from the server was x milliseconds ago ...
  • 项目DBCP配置内容如下###### DBCP连接池参数配置 ###### #######jdbc连接池初始连接数,设置后更好发挥连接池左右jdbc.initialSize=10#jdbc最大活动连接数,即连接池上限,要小于数据库连接上限,项目组根...
  • 《深入理解mybatis原理》 Mybatis数据源连接池

    万次阅读 多人点赞 2014-07-10 23:32:51
    本文将通过对MyBatis框架的数据源结构进行详尽的分析,并且深入解析MyBatis的连接池。  本文首先会讲述MyBatis的数据源的分类,然后会介绍数据源是如何加载和使用的。紧接着将分类介绍UNPOOLED、POOLED和JNDI类型...
  • WAS 5.x中数据源的配置使用及其常见问题数据源本文将介绍WAS5.X版本中数据源的配置和使用方法,并结合实际客户遇到的常 见问题进行一些讨论,以使更多用户能在WASH顺利的配置和使用数据源。1.简单原理和背景介绍1. 1...
  • 常见的数据源组件都实现了javax.sql.DataSource接口,MyBatis自身实现的数据源实现也不例外。MyBatis提供了两个javax.sql.DataSource接口实现,分别是PooledDataSource和UnpooledDataSource。MyBatis使用不同的...
  • Mybatis中的数据源连接池详解

    万次阅读 多人点赞 2017-05-14 15:05:15
    》中我们已经知道里面可以配置两个元素,一个是数据源连接池的配置,一个是事务管理器的配置。在上篇文章中我们只是简单的描述了一下,从这篇文章开始,我们将分两篇博文,分别对这两个问题进行详细说明。 这篇...
  • JNDI – 这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。这种数据源配置只需要两个属性: –这个属性用来在 InitialContext 中...
  • 本文主要针对以下三种连接池进行分析对比:C3P0DBCPJNDI1.com.mchange.v2.c3p0.ComboPooledDataSource定期使用连接池内的连接,使得它们不会因为闲置超时而被 MySQL 断开&lt;bean id="dataSource" ...
  • 本文将通过对MyBatis框架的数据源结构进行详尽的分析,并且深入解析MyBatis的连接池。 本文首先会讲述MyBatis的数据源的分类,然后会介绍数据源是如何加载和使用的。紧接着将分类介绍UNPOOLED、POOLED和JNDI类型的...
  • Mybatis数据源连接池

    千次阅读 2015-04-16 09:41:56
    原文链接:点击打开链接(http://blog.csdn.net/luanlouis/article/details/37671851?utm_source=tuicool) ...本文将通过对MyBatis框架的数据源结构进行详尽的分析,并且深入解析MyBatis的连接池。  本文
  • 数据源连接池

    千次阅读 2015-01-17 13:34:49
    数据源一般实现自javax.sql.DataSource接口,Spring、Struts、Hibernate等框架都有自己的数据源,Tomcat中也内置了数据源支持,Tomcat使用Jakarta-CommonsDatabase Connection Pool作为数据源的实现,使用时只需按照...
  • 上一篇介绍了 springboot集成mongodb 多数据库切换 源码demo 开发环境: windows 7 idea windows64 mongodb 如果没安装运行 点这里 navicat for mongodb 下面介绍用的是这个图形工具,命令行客户端或其他图形工具都...
  • 2004 年 6 月 24 日本文将介绍WAS 5.x版本中数据源的配置和使用方法,并结合实际客户遇到的常见问题进行一些讨论,以使更多用户能在WAS上顺利的配置和使用数据源。我们先来看一下使用JDBC1.0的时候,一般是怎样来...
  • 一般情况下我们操作数据库都是通过connection,但是频繁创建和删除connection会严重影响效率,因此在这种情况下我们一般会用到连接池,因为项目中用到的是mybatis,所以了解一下mybatis的默认的数据库连接池(大多数...
  • 1:DBCP数据源DBCP类包位于/lib/jakarta-commons/commons-dbcp.jar,DBCP是一个依赖Jakartacommons-pool对象池机制的数据库连接池,所以在类路径下还必须包括/lib/jakarta-commons/commons-pool.jar。下面是使用DBCP...
  • "" name/value pair was not found" + " in the Reference object. The reference Object is" + " " + ref.toString()); }} 其中红色的地方是你的数据库密码解密方法,当然对应的也要有加密算法,加密后的串放到...
  • DB数据源之SpringBoot+MyBatis踏坑过程(四)没有使用连接池的后果 liuyuhang原创,未经允许禁止转载 系列目录连接 DB数据源之SpringBoot+Mybatis踏坑过程实录(一) 1.环境说明  1.1.使用springboot...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,171
精华内容 2,868
关键字:

was数据源连接池