因为要实现CICS的负载均衡(配置CTG/CICS Transaction Gateway工作负载管理器将在后续BLOG中介绍),当一台服务器A的CICS Server宕掉后,CTG自动调用另一台服务器B的CICS Server,但是因为环境的差异,在A上编译好的可执行程序复制到B,CICS调用时报错,需要在B上重新编译才行。
问题出现了:当A的CICS宕掉后,CICS客户端自动调用B的CICS,这时CICS调用访问DB2的应用程序,报SQL0818N错误,重新编译B上的应用程序(包括db2 prep和cicstcl),不再报错,但此时将A上的CICS恢复后,当客户端重新调用A时,A又报SQL0818N。
在网上找到一篇文章《
[Share]DB2返回SQLCODE -818 错误》(http://blog.csdn.net/caoxicao/archive/2006/11/15/1386165.aspx),描述的情况是相同的,但是没有给出解决方法。
这个错误的原因是,A
和B访问同一个DB2数据库,在预编译SQC文件时(db2 prep xxx.sqc),除了产生.c文件外,还产生一个package存放到DB2数据库中(syscat.packages表),.c文件和package有一个相同的时间戳,用.c文件编译连接生成的可执行程序继承了.c文件的时间戳,也就是说,可执行程序和package的时间戳也是相同的。
当可执行程序访问DB2时,DB2会检查两个时间戳是否一致,如果不一致,就报错:“SQL0818N A timestamp conflict occurred.”
所以在B上预编译了程序,更新了package的时间戳,A上的程序因为时间戳和package的不一致,就不能再运行。通过在IBM官网
DB2 Information Center搜索关键字:timestamp conflict,找到一篇文章《
Precompiler-Generated Timestamps》(http://publib.boulder.ibm.com/infocenter/db2luw/v8//topic/com.ibm.db2.udb.doc/ad/c0005565.htm),文章中提供了解决方法。
在db2 prep xxx.sqc时加上version参数。例如,在A上用db2 prep xxx.sqc version 1预编译,在B上用db2 prep xxx.sqc version 2预编译。用db2 "select substr(pkgname,1,8),pkgversion,EXPLICIT_BIND_TIME from syscat.packages where pkgname ='xxx'"查询,发现有两条package记录,pkgversion分别是1和2。
这样,当预编译B上的程序时,将不会影响到A上程序的package时间戳,就不会使A上的程序运行时报错。同样,预编译A上的程序时,也不会影响到B上的程序执行。
还有一种方法,就是只在一个地方预编译SQC文件:把A上预编译产生的.c文件拿到B上编译连接(在B上不执行db2 prep,也就不更新package的timestamp),产生的程序也拥有和A上的程序以及数据库里package相同的时间戳,执行时也不会报错。
附:db2 prep xxx.sqc,默认产生或者更新(如果package已存在)package(pkgname='xxx',长度为8,超过截取前8位),如果指定bindfile参数,即db2 prep xxx.sqc bindfile,则不产生或者更新package,而是产生xxx.bnd文件,在db2 bind xxx.bnd时产生或者更新package。