PostgreSQL JDBC的触发器第一次写入成功,之后失败

8qgya5xd  于 2023-02-12  发布在  PostgreSQL
关注(0)|答案(1)|浏览(166)

我有一个从IBM系统上的DB2发送数据到RHEL系统上的PostgreSQL服务器的项目,我使用一个触发器将信息发送到数据队列,然后读取数据队列,并使用SQL语句通过RPGLE上的JDBC连接发送到PostgreSQL服务器。
代码大致如下所示(出于安全原因,我不得不删除实际的列名和表名):

dcl-proc doPostgreConn export;
  dcl-pi doPostgreConn like(connection) end-pi;
  //Code to change and set CLASSPATH variable, if necessary is here
  //...

  prop = JDBC_Properties();
  JDBC_setProp(prop: 'user'         : 'user');
  JDBC_setProp(prop: 'password'     : 'password');
  JDBC_setProp(prop: 'databaseName' : 'database');
  JDBC_setProp(prop: 'loggerLevel'  : 'TRACE'     );
  JDBC_setProp(prop: 'loggerFile'   : '/home/PostgreSQL/log');

  pgconn = JDBC_ConnProp('org.postgresql.Driver'
                     :'jdbc:postgresql://[some_IP]:5432/database'
                     : prop );
  JDBC_freeProp(prop);
  return pgconn;
end-proc;

dcl-proc doPGWriteMyTable export;
  dcl-pi doPGWriteMyTable like(success);
    i#schm char(10);
    i#rec char(334);
  end-pi;

  dcl-ds record extname('MYTABLE') end-ds;
  dcl-s prepStmtTxt varchar(10000);

  record = i#rec;

  pgconn = doPostgreConn;
  if pgconn = *NULL;
    //Custom Error Handling
  endif;

  prepStmtTxt = 'INSERT INTO ' + %trim(i#schm) + '.MYTABLE ' +
    '  VALUES (?, ?, ?) ';

  if PGWriteMYTABLEPrep = *NULL;

    PGWriteMYTABLEPrep = JDBC_PrepStmt(pgconn:prepStmtTxt);

    if PGWriteMYTABLEPrep = *NULL;
        
    endif;
  endif;

  JDBC_setString (PGWriteMYTABLEPrep: 1: StrCol);
  JDBC_setDecimal (PGWriteMYTABLEPrep: 2: DecCol);
  JDBC_setDate (PGWriteMYTABLEPrep: 75: DateCol);

  if JDBC_execPrepUpd( PGWriteMYTABLEPrep ) < 0;
    //Custom Error Handling
  endif;

  JDBC_Close(pgconn);

  return *on;
end-proc;

dcl-proc doPGDeleteMYTABLE export;
  dcl-pi doPGDeleteMYTABLE like(success);
    i#schm char(10);
    i#rec char(334);
  end-pi;

  dcl-ds record extname('MYTABLE') end-ds;
  dcl-s sqlstmt varchar(32000);
  dcl-s deleteSuccess ind;

  record = i#rec;

  sqlstmt = 'DELETE FROM ' + %trim(i#schm) + '.MYTABLE WHERE '; //Basically the key

  pgconn = doPostgreConn;
  if JDBC_ExecUpd(pgconn:sqlstmt) < 0;
    //Custom error handling
  endif;

  DoPostgreClose(pgconn);

  return *on;
end-proc;

数据队列读取程序本质上依次调用DoPGDeleteMYTABLE和DoPGWriteMYTABLE(没有唯一键,因此我们只需要删除PostgreSQL服务器上所有匹配的记录,然后重新添加它们)。
问题是,当数据队列读取程序运行时,第一个循环工作得非常好,然后失败了,顺序如下:
1.更新记录
1.删除任何现有PG记录:成功的
1.准备写入语句:成功的
1.将任何现有DB2记录写入PG:成功的
1.更新记录
1.删除任何现有PG记录:成功的
1.准备语句:成功的
1.将任何现有DB2记录写入PG:* 不成功 *
1.重复5到8,直到数据队列作业重新启动
我收到的错误不是很有帮助。AS400上的作业日志只是告诉我

org.postgresql.util.PSQLException: This connection has been closed.

即使我可以看到PostgreSQL服务器上打开的连接,从RPGLE关闭它仍然有效。
JDBC作业日志没有告诉我写操作发生前后的任何信息,它只是说准备成功了,然后就什么都没有了。
版本信息:
IBM操作系统7.4
基于x86_64-redhat-linux-gnu的PostgreSQL 13.7,由gcc(GCC)11.2.1 20220127(红帽11.2.1 - 9)编译,64位
PostgreSQL JDBC驱动程序postgresql-42.2.19
RPGLE正在利用Scott Klement的JDBCR4
我在网上找到的任何东西都还没有帮助解决这个问题。如果有任何其他我可以提供或尝试,以获得更多信息,请让我知道。

jq6vz3qz

jq6vz3qz1#

我没有看到任何东西跳出来的代码,你已经张贴,但鉴于它的工作第一次失败的第二次,我猜有些东西是重置(或不重置)之间的循环。
就我个人而言,我建议在DELETE/WRITE过程之外打开连接;但我不认为这是个骗局。
“连接关闭”很有趣...可能值得运行通信跟踪,看看连接是否实际上正在关闭,如果是,从哪一边关闭。
注意,虽然我喜欢RPG,但我不喜欢从RPG调用Java。很久很久以前我做过一些基准测试,让一个小的Java应用程序处理JDBC比从RPG使用它要快得多。
您还可以考虑使用一种开放源代码的替代方法来直接从RPG调用Java。
AppServer4RPG
应用程序服务器使Java组件可用于IBM i RPG程序,运行在IBM i或任何其他Java平台上。与ArdGate打包,使用IBM i的所有本机SQL接口访问任何JDBC数据库。
ArdGate基本上将其自身注册为DRDA应用程序请求驱动程序(ARD),并允许您像与任何其他远程DRDA(aka Db2)数据库一样与任何JDBC数据库通信。
这意味着,您可以从绿色屏幕STRSQL读/写PostgreSQL。

相关问题