`

一次做应用升级出现了一个问题,描述如下: 升级分为两块,一块是数据库结构变更(表结构增加新字段);一块是应用程序的升级。 应用环境为:jboss4.

 
阅读更多
一次做应用升级出现了一个问题,描述如下:
   升级分为两块,一块是数据库结构变更(表结构增加新字段);一块是应用程序的升级。
   应用环境为:jboss4.0.5 + ibatis + spring 数据源在jboss的oracle-ds.xml文件中进行配置,通过spring的jndi方式进行查找 。
   我先将数据库进行升级,更改表结构(增加字段),因为应用中的ibatis的查询采用的是ResultMap返回方式,返回定义的表结构字段,即使数据库发生变更,也不会产生影响。于是我大胆的进行脚本的执行。结果当我下午16:00数据库变更之后,几乎在同时就有人反应应用的一些查询功能无法使用,立刻查看出错日志:
Java代码  收藏代码

       Caused by: com.alibaba.generalorm.dao.DataAccessException: Data query error!    
    --- The error occurred in sqlmap/CiaDissension.xml.   
    --- The error occurred while applying a parameter map.   
    --- Check the QUERY_ALL_DISSENSION_CATEGORY-InlineParameterMap.   
    --- Check the statement (query failed).   
    --- Cause: java.sql.SQLException: OALL8 处于不一致状态 
        at com.alibaba.ibatis.BasicIBatisDao.query(BasicIBatisDao.java:315) 
        at com.alibaba.china.rcc.riskdc.dao.DissensionCategoryDAO.getAll(DissensionCategoryDAO.java:40) 
        at com.alibaba.china.rcc.riskdc.service.impl.DissensionServiceImpl.getCategoryMap(DissensionServiceImpl.java:495) 
        at com.alibaba.china.rcc.riskdc.service.impl.DissensionServiceImpl.getCategory(DissensionServiceImpl.java:188) 
        at com.alibaba.china.rcc.riskdc.web.action.DissensionAction.getCategory(DissensionAction.java:263) 
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
        at java.lang.reflect.Method.invoke(Method.java:597) 
        at com.alibaba.webx.action.invoker.AbstractModuleMethodInvoker.executeNoArgMethod(AbstractModuleMethodInvoker.java:401) 
        ... 33 more 


Java代码  收藏代码

       Caused by: com.alibaba.generalorm.dao.DataAccessException: Data query error!    
    --- The error occurred in sqlmap/CiaDissension.xml.   
    --- The error occurred while applying a parameter map.   
    --- Check the QUERY_ALL_DISSENSION_BUSINESS-InlineParameterMap.   
    --- Check the statement (query failed).   
    --- Cause: java.sql.SQLException: 违反协议 
        at com.alibaba.ibatis.BasicIBatisDao.query(BasicIBatisDao.java:315) 
        at com.alibaba.china.rcc.riskdc.dao.DissensionBusinessDAO.getAll(DissensionBusinessDAO.java:19) 
        at com.alibaba.china.rcc.riskdc.service.impl.DissensionServiceImpl.getBusiness(DissensionServiceImpl.java:178) 
        at com.alibaba.china.rcc.riskdc.web.action.DissensionAction.getBusiness(DissensionAction.java:249) 
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
        at java.lang.reflect.Method.invoke(Method.java:597) 
        at com.alibaba.webx.action.invoker.AbstractModuleMethodInvoker.executeNoArgMethod(AbstractModuleMethodInvoker.java:401) 
        ... 33 more 


为什么会出现违反协议的问题?马上google一下,有些人说是因为数据库的字段类型与java中使用的类型不一致导致,但查看了ibtais的map文件,老的应用代码根本还没有使用新的的字段!后来找pla共同排查,也没有发现应用程序哪里会出现问题,便打电话给DBA让他查下数据库,DBA咨询了一位资格较老的DBA,他说以前也出现过这种情况,只要将应用重启下,就好了。马上重启,果然问题解决了,违反协议的错误没有再报。

查找原因:
在做升级前,我自己在开发环境也做过模拟,并没有出现如果应用不重启,数据库变更而报“违反协议”的错误。而我看了下发布环境与开发环境差异,唯一的差异是开发环境没有采用jboss+jndi的方式获取数据源,而采用了tomcat+c3p0的方式获取数据源。

于是我开始实验。
Tomcat+C3P0启动方式:
1.准备好更改数据库脚本。
2.在开发环境用tomcat启动应用,并访问到涉及表结构变更的页面。
3.执行数据库脚本,确保表结构发生了变更。
4.刷新在步骤2的页面,查看后台输出和前台页面输出。
5.一切正常,没有抛出违反协议或处于不一致状态的错误日志。
JBoss4.0.5+JNDI启动方式
1.准备好更改数据库脚本。
2.在开发环境用jboss启动应用,并访问到涉及表结构变更的页面。
3.执行数据库脚本,确保表结构发生了变更。
4.刷新在步骤2的页面,查看后台输出和前台页面输出。
5.出现了违反协议和处于不一致状态的问题。

总结:

由此可以看出,出现这个问题与ibatis没有关系,而与数据源的获取方式有关,一种是通过Spring+c3p0直接注入DataSource;一种是在oracle-ds.xml文件中配置,然后在spring中通过jndi的方式进行查找,获取数据源。第二种在数据库变更的情况下,就必须进行应用重启,否则就会抛出违反协议或处于不一致的状态。

但根本原因到底是什么呢?我还在寻找。
===================================================
咨询了大少,并不是因为数据源配置模式没有关系,用c3p0或者jndi等,而是与数据源的配置方式有关:

在oracle-ds的配置如下:
Java代码  收藏代码

    <local-tx-datasource> 
         <jndi-name>rccBopsDataSource</jndi-name> 
         <use-java-context>false</use-java-context> 
         <connection-url>jdbc:oracle:thin:@xx.xx.xx.xx:1521:xx</connection-url> 
         <connection-property name="SetBigStringTryClob">true</connection-property> 
         <connection-property name="defaultRowPrefetch">50</connection-property> 
         <connection-property name="clientEncoding">GBK</connection-property> 
         <connection-property name="serverEncoding">ISO-8859-1</connection-property> 
         <driver-class>com.alibaba.china.jdbc.SimpleDriver</driver-class> 
         <min-pool-size>1</min-pool-size> 
         <max-pool-size>14</max-pool-size> 
         <prepared-statement-cache-size>20</prepared-statement-cache-size> 
         <metadata> 
             <type-mapping>Oracle9i</type-mapping> 
         </metadata> 
         <idle-timeout-minutes>15</idle-timeout-minutes> 
         <exception-sorter-class-name>org.jboss.resource.adapter.jdbc.vendor.OracleExceptionSorter</exception-sorter-class-name> 
         <user-name>xx</user-name> 
         <password>xx</password> 
     </local-tx-datasource> 



其中prepared-statement-cache-size参数解释为:
<prepared-statement-cache-size> - the number of prepared statements per connection to be kept open and reused in subsequent requests. They are stored in a LRU cache. The default is 0 (zero), meaning no cache.
为每个打开的数据库连接缓存了一定数量的prepared statement.他们是存在LRU cache中,如果设值为0,那么将不缓冲。这里我们设值了每个连接缓存20条prepared statment。

而在c3p0的配置中:
Xml代码  收藏代码

     <bean id="testDataSource" 
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="staticMethod"> 
        <value>com.mchange.v2.c3p0.DataSources.pooledDataSource</value> 
    </property> 
    <property name="arguments"> 
        <list> 
            <ref local="unpooledDataSource" /> 
            <props> 
                <prop key="acquireIncrement">1</prop> 
                <prop key="initialPoolSize">1</prop> 
                <prop key="minPoolSize">1</prop> 
                <prop key="maxPoolSize">5</prop> 
                <prop key="maxIdleTime">1800</prop>                  
                <prop key="maxIdleTimeExcessConnections">1000</prop> 
                <!-- 自动收缩连接用的,单位秒 --> 
                <!-- 自动重连需要的三个参数 --> 
                <prop key="acquireRetryAttempts">30</prop> 
                <prop key="acquireRetryDelay">1000</prop> 
                <prop key="breakAfterAcquireFailure">false</prop> 
                <!-- 获取一个connection需要的时间,单位毫秒 --> 
                <prop key="checkoutTimeout">5000</prop> 
            </props> 
        </list> 
    </property> 
    lt;/bean> 


上网查了下,影响到preparedStatment cache的参数有两个:maxStatements和maxStatementsPerConnection 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭,默认为0。

继续实验:

1、将c3p0配置增加maxStatements和maxStatementsPerConnection并都设值20。
修改数据库表结构,刷新访问页面。
后台抛出违反协议和处于不一致状态的错误提示。

2.将oracle-ds.xml文件配置更改prepared-statement-cache-size为0。
修改数据库表结构,刷新访问页面。
后台没有抛出违反协议和处于不一致状态的错误提示。

附参考文章:

http://community.jboss.org/wiki/configdatasources   讲解jboss中关于datasource的参数
http://msq.iteye.com/blog/60387   讲解c3p0的详细参数
分享到:
评论

相关推荐

    达梦数据库_SQL语言手册

    连续两个双引号转义为一个双引号 定界标识符的例子: 保留字的清单参见附录 语言的功能及语句 语言是一种介于关系代数与关系演算之间的语言,其功能主要包括数据定义、查询 操纵和控制四个方面,通过各种不同的...

    软件工程-理论与实践(许家珆)习题答案

    B) 图形工具能够极好地概括描述一个系统的信息,比文字叙述能够更好地表达重 要的细节 C) 图形能够更加直观地描述目标系统,便于用户理解和交流,有利于开发者与用 户之间达成一致的需求 D) 图形比文字描述简单、...

    软件测试教学文档 java test

     集成测试:一个应用系统的各个部件的联合测试,以决定他们能否在一起共同工作。部件可以是代码块、独立的应用、网络上的客户端或服务器端程序。这种类型的测试尤其与客户服务器和分布式系统有关。  功能测试:...

    Oraclet中的触发器

    database_event_list:一个或多个数据库事件,事件间用 OR 分开; 系统事件触发器既可以建立在一个模式上,又可以建立在整个数据库上。当建立在模式之上时,只有模式所指定用户的DDL操作和它们所导致的错误才激活...

    (完整)Android手机天气预报项目报告.doc

    一条SOAP消息就是一个包含有一个必需的SOAP的 封装包,一个可选的SOAP标头和一个必需的SOAP体块的XML文档. XML文档在Android平台上的解析可以通过SAX的方式方便快速的完成。解析Android 应用程序中获得的列表数据XML...

    二十三种设计模式【PDF版】

    你曾经多少次有过这种感觉—你已经解决过了一个问题但就是不能确切知道是在什么地 方或怎么解决的?如果你能记起以前问题的细节和怎么解决它的,你就可以复用以前的经验而不需要重新发现它。然而,我们 并没有很好...

    Oracle9i的init.ora参数中文说明

    否则就会启动一个值为双重货币符号的新会话。 值范围: 任何有效的格式名。。 默认值: 双重货币符号 nls_iso_currency: 说明: 为 C 数字格式元素指定用作国际货币符号的字符串。该参数的默认值由 NLS_TERRITORY ...

    高级软件架构师复习提纲

    //从源端复制数据到目标端,并检测和解决自上一次复制以来出现的任何更新冲突 //由位于源和目标之间、方向相反的两个复制链接组成的复制构造块 64、 下面哪些应用可以被称为Smart :A:能够利用本地资源 A:智能安装...

    Android手机天气预报项目报告.docx

    条SOAP消息就是一个包含有一个必需的SOAP的封装包,一个可选的SOAP标头和一个必需的SOAP体块的XML文档。 XML文档在Android平台上的解析可以通过SAX的方式方便快速的完成。解析Android应用程序中获得的列表数据XML...

    xheditor-1.1.14

    说明:这个函数执行时返回的值为上传程序返回的msg变量,可能为字符串或者数组,若为字符串则直接代表url,若是数组,则必需包含一个url的变量,其它可由可开发者自定义 备注:1.0.0 beta2新添加 plugins:自定义...

    asp.net知识库

    NET委托:一个C#睡前故事 [推荐] - [原创] Microsoft .NET策略及框架概述 卸载Class? Web Form 窗体 如何实现web页面的提示保存功能 在ASP.Net中两种利用CSS实现多界面的方法 如何在客户端调用服务端代码 页面一...

    sql2000 Log Explorer4.2(含注册码)+汉化

    服务器端代理是保存在SQLServer主机中的一个只读存储过程,他的作用是接受客户端请求,读取在线事物日志块并通过网络传给客户端软件,由客户端软件来读取这些原始的数据块来完成Log Explore所提供的所有功能。...

    Log Explorer4.2帮助文档

    服务器端代理是保存在SQLServer主机中的一个只读存储过程,他的作用是接受客户端请求,读取在线事物日志块并通过网络传给客户端软件,由客户端软件来读取这些原始的数据块来完成Log Explore所提供的所有功能。...

    Log Explorer for SQL Server v4.22 含注册机

    服务器端代理是保存在SQLServer主机中的一个只读存储过程,他的作用是接受客户端请求,读取在线事物日志块并通过网络传给客户端软件,由客户端软件来读取这些原始的数据块来完成Log Explore所提供的所有功能。...

    Log Explorer for SQL Server v4.22

    服务器端代理是保存在SQLServer主机中的一个只读存储过程,他的作用是接受客户端请求,读取在线事物日志块并通过网络传给客户端软件,由客户端软件来读取这些原始的数据块来完成Log Explore所提供的所有功能。...

    Oracle_Database_11g完全参考手册.part3/3

    第13章 当一个查询依赖于另一个查询时 13.1 高级子查询 13.1.1 相关子查询 13.1.2 并列的逻辑测试 13.1.3 EXISTS及其相关子查询的使用 13.2 外部连接 13.2.1 Oracle9i以前版本中的外部连接的语法 13.2.2 现在的外部...

    Oracle_Database_11g完全参考手册.part2/3

    第13章 当一个查询依赖于另一个查询时 13.1 高级子查询 13.1.1 相关子查询 13.1.2 并列的逻辑测试 13.1.3 EXISTS及其相关子查询的使用 13.2 外部连接 13.2.1 Oracle9i以前版本中的外部连接的语法 13.2.2 现在的外部...

    Sybase ASE 15.7 开发文档:系统管理指南(卷二)

    Sybase ASE 15.7 开发文档:系统管理指南(卷二)共两卷 第 1 章 限制对服务器资源的访问 第 2 章 镜像数据库设备 第 3 章 配置内存 第 4 章 配置数据高速缓存 第 5 章 管理多处理器服务器 第 6 章 创建和管理用户...

Global site tag (gtag.js) - Google Analytics