透过连接池和字段索引,提升单点登录cas的性能

通过连接池和字段索引,提升单点登录cas的性能


    cas是多个系统的中心认证,认证的过程就是用户的登录信息和数据库中的信息匹对的过程,如果某一时刻登录的人数很多,需要频繁的读取数据库,数据库连接的管理就是问题。

    前天测试评教时无意之中把单点登录的问题暴露出来了,平时通过cas登录管理端是没有问题的,而200人同时通过cas登陆学生端时出现异常

    org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Listener refused the connection。。。

     

    而我在实现单点登录时,重点放在了实现,没有考虑具体应用的场景,所以说做的应用一定要投入到实际使用中,否则永远停留在理想的学习使用中。

     

    解决问题固然重要,更重要的是发现问题。看到错误提示信息,很明显的说明了Connection资源有限,于是做了如下优化:

  1. cas添加Connection Pool连接池。
  2. 配置OracleConnection Pool。(数据库使用的是Oracle,而Oracle默认是不开启连接池的)
  3. 为频繁的查询字段创建索引

 

cas添加Connection Pool连接池

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

 

无论是DBCP还是C3P0,配置都差不多,因为连接池的属性是通用的。这里以C3P0为例,配置在cas的deployerConfigContext.xml中

在tomcat的/webapps/cas/WEB-INF/deployerConfigContext.xml添加以下内容:

<span style="font-size:18px;"><bean id="casDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">  
        <property name="driverClass" value="${jdbc.driverClassName}" />  
        <property name="jdbcUrl" value="${jdbc.url}" />  
        <property name="user" value="${jdbc.username}" />  
        <property name="password" value="${jdbc.password}" />  
        <!-- 最大连接数 -->  
        <property name="maxPoolSize" value="${hibernate.c3p0.max_size}" />  
        <!-- 最小连接数 -->  
        <property name="minPoolSize" value="${hibernate.c3p0.min_size}" />  
        <!-- 初始化连接数 -->  
        <property name="initialPoolSize" value="${hibernate.c3p0.initial_pool_size}" />  
        <!-- 最大空闲时间 ,120秒内未使用则连接被丢弃。若为0则永不丢弃 -->  
        <property name="maxIdleTime" value="${hibernate.c3p0.max_idle_time}" />  
        <!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->  
        <property name="acquireIncrement" value="${hibernate.c3p0.acquire_increment}" /> 
        <!-- 最大的PreparedStatement的数量 -->  
        <property name="maxStatements" value="${hibernate.c3p0.max_statements}" />  
        <!-- 每隔120秒检查连接池里的空闲连接-->  
        <property name="idleConnectionTestPeriod" value="${hibernate.c3p0.idle_test_period}" />  
        <!-- 如果设为true那么在取得连接的同时将校验连接的有效性 。Default: false -->  
        <property name="testConnectionOnCheckin" value="${hibernate.c3p0.test_connection_on_checkin}" />  
        <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->  
        <property name="acquireRetryAttempts" value="${hibernate.c3p0.acquire_retry_attempts}" />  
        <!--连接关闭时默认将所有未提交的操作回滚。Default: false -->  
        <property name="autoCommitOnClose" value="${hibernate.c3p0.auto_commit_on_close}"/>  
        <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。  
            如果设为true,那么在尝试获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
        <property name="breakAfterAcquireFailure" value="${hibernate.c3p0.break_after_acquire_failure}" />  
        <!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能通过多线程实现多个操作同时被执行。Default: 3-->   
        <property name="numHelperThreads" value="${hibernate.c3p0.num_helper_threads}" />
        <!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。Default: 0 -->   
        <property name="checkoutTimeout" value="${hibernate.c3p0.checkout_timeout}" />  
    </bean>  </span>

 

在tomcat的\webapps\cas\WEB-INF目录下新建两个文件,分别是jdbc.properties和c3p0.properties,内容如下:

Jdbc.properties代码    

<span style="font-size:18px;">## MySQL  
  
#jdbc.driverClassName=com.mysql.jdbc.Driver  
#jdbc.url=jdbc:mysql://10.5.227.125:3306/dcsso?#useUnicode=true&characterEncoding=utf-8  
#jdbc.username=root  
#jdbc.password=root  
  
## Oracle  
  
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver  
jdbc.url=jdbc:oracle:thin:@192.168.24.46:1521:orcl  
jdbc.username=gxpt_jc
jdbc.password=gxpt_jc</span>

  

C3p0.properties代码  

透过连接池和字段索引,提升单点登录cas的性能

<span style="font-size:18px;">###########################  
### C3P0 Connection Pool###  
###########################  
hibernate.c3p0.max_size 60  
hibernate.c3p0.min_size 2  
hibernate.c3p0.initial_pool_size 3  
hibernate.c3p0.max_idle_time 120  
hibernate.c3p0.acquire_increment 2  
hibernate.c3p0.max_statements 100  
hibernate.c3p0.idle_test_period 120  
hibernate.c3p0.test_connection_on_checkin true  
hibernate.c3p0.acquire_retry_attempts 30  
hibernate.c3p0.auto_commit_on_close false  
hibernate.c3p0.break_after_acquire_failure false  
hibernate.c3p0.num_helper_threads 3  
hibernate.c3p0.checkout_timeout 30000  
hibernate.c3p0.validate true  </span>

 

c3p0需要jar包的支持,c3p0-0.9.1.jar、commons-collections-3.2.1.jar、commons-pool-1.5.4.jar

 

在tomcat的\webapps\cas\WEB-INF\spring-configuration目录下找到propertyFileConfigurer.xml文件,修改如下:

Propertyfileconfigurer.xml代码  

透过连接池和字段索引,提升单点登录cas的性能

<span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xmlns:p="http://www.springframework.org/schema/p"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
    <description>  
        This file lets CAS know where you've stored the cas.properties file which details some of the configuration options  
        that are specific to your environment.  You can specify the location of the file here.  You may wish to place the file outside  
        of the Servlet context if you have options that are specific to a tier (i.e. test vs. production) so that the WAR file   
        can be moved between tiers without modification.  
    </description>  
      
    <!--  
    <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"  
        p:location="/WEB-INF/cas.properties" /> -->  
  
    <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="locations">  
            <list>  
                <value>/WEB-INF/cas.properties</value>  
                <value>/WEB-INF/jdbc.properties</value>  
                <value>/WEB-INF/c3p0.properties</value>  
            </list>  
        </property>  
    </bean>  
</beans>  </span>

 让应用启动的时候加载jdbc.properties和c3p0.properties文件。

 

配置OracleConnection Pool

目前Oracle只支持一个连接池,pool name缺省为“SYS_DEFAULT_CONNECTION_POOL”,管理连接池信息的也就一个包“DBMS_CONNECTION_POOL”,也就意味着必须以DBA的角色来操作。

 

先看看DBMS_CONNECTION_POOL的相关说明:

<span style="font-size:18px;">SQL> desc DBMS_CONNECTION_POOL
Element          Type     
---------------- ---------
ALTER_PARAM      PROCEDURE
CONFIGURE_POOL   PROCEDURE
RESTORE_DEFAULTS PROCEDURE
START_POOL       PROCEDURE
STOP_POOL        PROCEDURE</span>

包括5个存储过程。

SYS_DEFAULT_CONNECTION_POOL,但是并没有被打开,需要显示的开启连接池。

第一步当然就是开启连接池:

<span style="font-size:18px;">exec DBMS_CONNECTION_POOL.START_POOL('SYS_DEFAULT_CONNECTION_POOL');</span>

打开了连接池之后可以通过系统视图dba_cpool_info进行查询:

<span style="font-size:18px;">SQL> select connection_pool,status from dba_cpool_info;
 
CONNECTION_POOL                                                                  STATUS
-------------------------------------------------------------------------------- ----------------
SYS_DEFAULT_CONNECTION_POOL                                                      ACTIVE</span>

当连接池启动了之后,可以通过DBMS_CONNECTION_POOL.CONFIGURE_POOL来查看连接池的相关配置项。

<span style="font-size:18px;">SQL> desc DBMS_CONNECTION_POOL.CONFIGURE_POOL
Parameter              Type           Mode Default?
---------------------- -------------- ---- --------
POOL_NAME              VARCHAR2       IN   Y       
MINSIZE                BINARY_INTEGER IN   Y       
MAXSIZE                BINARY_INTEGER IN   Y       
INCRSIZE               BINARY_INTEGER IN   Y       
SESSION_CACHED_CURSORS BINARY_INTEGER IN   Y       
INACTIVITY_TIMEOUT     BINARY_INTEGER IN   Y       
MAX_THINK_TIME         BINARY_INTEGER IN   Y       
MAX_USE_SESSION        BINARY_INTEGER IN   Y       
MAX_LIFETIME_SESSION   BINARY_INTEGER IN   Y       </span>

参数说明:

参数

说明

MINSIZE

在pool中最小数量的pooled servers,缺省为4

MAXSIZE

在pool中最大数量的pooled servers,缺省为40

INCRSIZE

这个参数是在一个客户端应用需要连接的时候,当pooled servers不可用的状态时候,每次pool增加pooled servers的数目。

SESSION_CACHED_CURSORS

缓存在每个pooled servers上的会话游标的数目,缺省为20

INACTIVITY_TIMEOUT

pooled server处于idle状态的最大时间,单位秒,超过这个时间,the server将被停止。缺省为300.

MAX_THINK_TIME

在一个客户端从pool中获得一个pooled server之后,如果在MAX_THINK_TIME时间之内没有提交数据库调用的话,这个pooled server将被释放,客户端连接将被停止。缺省为30,单位秒

MAX_USE_SESSION

pooled server能够在pool上taken和释放的次数,缺省为5000

MAX_LIFETIME_SESSION

The time, in seconds, to live for a pooled server in the pool. The default value is 3600.

一个pooled server在pool中的生命值。

 

可以使用DBMS_CONNECTION_POOL.CONFIGURE_POOL或DBMS_CONNECTION_POOL.ALTER_PARAM对连接池的设置进行修改。

先来看看参数信息:

<span style="font-size:18px;">SQL>  desc DBMS_CONNECTION_POOL.ALTER_PARAM
Parameter   Type     Mode Default?
----------- -------- ---- --------
POOL_NAME   VARCHAR2 IN   Y       
PARAM_NAME  VARCHAR2 IN           
PARAM_VALUE VARCHAR2 IN           
SQL> exec DBMS_CONNECTION_POOL.ALTER_PARAM ('','minsize','10');
 
PL/SQL procedure successfully completed
 
SQL> exec DBMS_CONNECTION_POOL.ALTER_PARAM ('','maxsize','100');
 
PL/SQL procedure successfully completed</span>

由于只有一个连接池,第一个参数的值可以省略。

系统中有几个系统视图比较有用:

DBA_CPOOL_INFO          这个视图包含着连接池的状态

V$CPOOL_STATS             这个视图包含着连接池的统计信息

V$CPOOL_CC_STATS       这个视图包含着池的连接类型级别统计

 

修改成功了之后可以查询下连接池信息:

<span style="font-size:18px;">SQL> select CONNECTION_POOL, STATUS,MINSIZE,MAXSIZE from DBA_CPOOL_INFO;
 
CONNECTION_POOL                                                                  STATUS              MINSIZE    MAXSIZE
-------------------------------------------------------------------------------- ---------------- ---------- ----------
SYS_DEFAULT_CONNECTION_POOL                                                      ACTIVE                   10        100</span>


到此,连接池的设置和相关修改已经完成。

 

为查询字段创建索引

首先,查看目前已经建立的索引

<span style="font-size:18px;">select * from user_indexes where table_name = ‘TB_STUDENT’; </span>

   可以看到只有系统给主键自动建立的索引:SYS_C55001

 

      为频繁的查询字段建立索引(学生表中有近3万条数据)。

<span style="font-size:18px;">create index student_code_idx on tb_student(student_code);  </span>

 

这里创建的非聚集索引,如果使用聚集索引的话,因为其中键值的逻辑顺序决定了表中相应行的物理顺序,查询的速度的确更快,但是对于增删改的操作会很慢,所以当创建聚集索引时要慎重。

索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。更多关于聚集索引可以参考http://www.cnblogs.com/aspnethot/articles/1504082.html

 

小结

无论是Oracle的连接池还是Java的连接池,说白了就是两块缓冲区,提前创建好对象或者保留已经创建的对象,用的时候少去了创建的时间,提高了复用性。

索引,就像一本书的目录,是快速锁定目标的有效途径,因为有了目录或者索引,查询时间的长短跟内容多少无关,只取决于找到索引的时间。

9楼wangyajin333昨天 21:55
对单点登录的映像很深。
8楼hejingyuan6昨天 21:13
学习了
7楼xiaoxian8023昨天 21:00
连接池到哪都是很有帮助的。缓冲区,延迟功能。。。。
6楼lishehe昨天 17:19
单点登录,这块,研究的深刻啊,哈哈,马上向你学习来了
5楼zuozuo1245昨天 14:57
索引,就像一本书的目录,是快速锁定目标的有效途径
4楼zhaohuanhuanjiuqi前天 19:12
无论是Oracle的连接池还是Java的连接池,说白了就是两块缓冲区,提前创建好对象或者保留已经创建的对象,用的时候少去了创建的时间,提高了复用性。
3楼tang_huan_11前天 08:04
提前来了解一下
2楼gelupu3天前 15:50
无论是Oracle的连接池还是Java的连接池,说白了就是两块缓冲区,提前创建好对象或者保留已经创建的对象,用的时候少去了创建的时间,提高了复用性。
1楼akkzhjj3天前 15:28
学习学习,刚了解到连接池