zoukankan      html  css  js  c++  java
  • Java向PostgreSQL发送prepared statement 与 libpq 向PostgreSQL发送prepared statement之比较:

    Java 代码,在数据库端,并没有当成 prepared statetment 被处理。

    C代码通过libpq 访问数据库端,被当成了 prepared statement 处理。也许是因PostgreSQL对JDBC的支持毕竟是后期出现的:

    下面看代码和运行结果:

    Java 代码:

    import java.sql.*;
     
    public class Test01 {
     
            public static void main(String argsv[]){
            try
             {
               Class.forName("org.postgresql.Driver").newInstance();
               String url = "jdbc:postgresql://localhost:5432/postgres" ;
       
               Connection con = DriverManager.getConnection(url,"postgres","postgres" );
              
               ///Phase 1:-------------Select data from table-----------------------
     
              
               System.out.println("Phase 1------------------------start");
              
               String strsql = " select * from customers where cust_id = ?";
               PreparedStatement pst=con.prepareStatement(strsql);
     
               pst.setInt(1,3); //find the customer with cust_id of 3.
              
               ResultSet rs = pst.executeQuery();
              
               while (rs.next())
                {
                   System.out.print("cust_id:"+rs.getInt( "cust_id"));
                   System.out.println("...cust_name:"+rs.getString( "cust_name" ));
               }
               System.out.println("Phase 1------------------------end
    ");
              
              
              
               ///Phase 2:-------------Use connection again,to select data from data dictionary-----------------------
              
               System.out.println("Phase 2------------------------start");
              
               strsql = "select * from pg_prepared_statements";
               pst=con.prepareStatement(strsql);          
              
               rs = pst.executeQuery();
              
               while (rs.next())
               {
                  System.out.println("statement:"+rs.getString( "statement"));
               }          
               System.out.println("Phase 2------------------------end
    ");          
              
               ///Phase 3:-------------Use connection again,to select data from table-----------------------
     
               System.out.println("Phase 3------------------------start");          
               strsql = "select * from customers";
               pst=con.prepareStatement(strsql);          
              
               rs = pst.executeQuery();
              
               while (rs.next())
               {
                  System.out.print("cust_id:"+rs.getInt( "cust_id"));
                  System.out.println("...cust_name:"+rs.getString( "cust_name" ));
              }           
             
              System.out.println("Phase 3------------------------end
    ");           
              
              rs.close();          
              pst.close();
              con.close();
              
           }
            catch (Exception ee)
            {
               System.out.print(ee.getMessage());
           }
            }
     
    }

    运行:

    Phase 1------------------------start
    cust_id:3...cust_name:Taylor
    Phase 1------------------------end
     
    Phase 2------------------------start
    Phase 2------------------------end
     
    Phase 3------------------------start
    cust_id:1...cust_name:Smith
    cust_id:2...cust_name:Brown
    cust_id:3...cust_name:Taylor
    Phase 3------------------------end

    C 代码:

    [root@lex tst]# cat testprepared.c
    /*
     * testlibpq.c
     *  Test the C version of LIBPQ, the POSTGRES frontend library.
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include "libpq-fe.h"
    
    static void
    exit_nicely(PGconn *conn)
    {
     PQfinish(conn);
     exit(EXIT_SUCCESS);
    }
    
    int
    main()
    {
     int   nFields;
     int   i,
           j;
    
    #ifdef DEBUG
     FILE    *debug;
    #endif  /* DEBUG */
    
     ///////////////////////////////////////////////////////////////////////////////
     ///Step1: making connection
    
    
     PGconn    *conn;
     PGresult   *res;
    
     const char *conninfo="postgresql://postgres:postgres@localhost:5432/postgres";
    
     /* make a connection to the database */
     conn = PQconnectdb(conninfo);
    
     /* check to see that the backend connection was successfully made */
     if (PQstatus(conn) == CONNECTION_BAD)
     {
      fprintf(stderr, "Connection to database failed.
    ");
      fprintf(stderr, "%s", PQerrorMessage(conn));
      exit_nicely(conn);
     }
    
    #ifdef DEBUG
     debug = fopen("/tmp/trace.out", "w");
     PQtrace(conn, debug);
    #endif  /* DEBUG */
      
     ////////////////////////////////////////////////////////////////////////////////////
     ///Step 2, activating prepared statement
    
     /* start a transaction block */
     res = PQexec(conn, "BEGIN");
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
      fprintf(stderr, "BEGIN command failed
    ");
      PQclear(res);
      exit_nicely(conn);
     }
    
     PQclear(res);
    
     ////////////////////////////////////////////////////////////////////////////////////
     ///Step 2, activating prepared statement
     const char *stmt_name = "test_stmt";
     const char *stmt = "select * from customers where cust_id=$1";
    
     Oid param_types[1];
     param_types[0] = 0; ///let db to judge it.
    
     res = PQprepare(conn, stmt_name, stmt,1,param_types);
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
      fprintf(stderr, "PQprepare failed
    ");
      PQclear(res);
      exit_nicely(conn);
     }
    
     PQclear(res);
    
     const char* custid = "3";
     const char* param_values[1];
     param_values[0] =custid;
    
     int param_lengths[1];
     param_lengths[0] = 1;
    
     int param_formats[1];
     param_formats[0] = 0;
     
     res = PQexecPrepared(conn, stmt_name, 1, param_values, param_lengths,
                            param_formats, 0);
    
     if (PQresultStatus(res) != PGRES_TUPLES_OK)
     {
      fprintf(stderr, "PQexecPrepared statement didn't return tuples properly
    ");
      PQclear(res);
      exit_nicely(conn);
     }
    
     /* print out the attribute names */
     nFields = PQnfields(res);
     for (i = 0; i < nFields; i++)
      printf("%-15s", PQfname(res, i));
    
     printf("
    
    ");
    
     /* print out the instances */
     for (i = 0; i < PQntuples(res); i++)
     {
      for (j = 0; j < nFields; j++)
       printf("%-15s", PQgetvalue(res, i, j));
      printf("
    ");
     }
    
     PQclear(res);
    
     /* end the transaction */
     res = PQexec(conn, "END");
     PQclear(res);
    
     ////////////////////////////////////////////////////////////////////////////////////
     ///Step 3, looking for cached status of prepared statements
    
     /* start a transaction block */
     res = PQexec(conn, "BEGIN");
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
      fprintf(stderr, "BEGIN command failed
    ");
      PQclear(res);
      exit_nicely(conn);
     }
    
     PQclear(res);
     
     /* define cursor */
     res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_prepared_statements");
     if (PQresultStatus(res) != PGRES_COMMAND_OK)
     {
      fprintf(stderr, "DECLARE CURSOR command failed
    ");
      PQclear(res);
      exit_nicely(conn);
     }
     PQclear(res);
    
     /* fetch cursor */
     res = PQexec(conn, "FETCH ALL in myportal");
     if (PQresultStatus(res) != PGRES_TUPLES_OK)
     {
      fprintf(stderr, "FETCH ALL command didn't return tuples properly
    ");
      PQclear(res);
      exit_nicely(conn);
     }
    
     /* first, print out the attribute names */
     nFields = PQnfields(res);
     for (i = 0; i < nFields; i++)
      printf("%-15s", PQfname(res, i));
    
     printf("
    
    ");
    
     /* next, print out the instances */
     for (i = 0; i < PQntuples(res); i++)
     {
      for (j = 0; j < nFields; j++)
       printf("%-15s", PQgetvalue(res, i, j));
      printf("
    ");
     }
    
     PQclear(res);
    
     /* close the portal */
     res = PQexec(conn, "CLOSE myportal");
     PQclear(res);
    
     /* end the transaction */
     res = PQexec(conn, "END");
     PQclear(res);
    
     ////////////////////////////////////////////////////////////////////////////////////
     ///Step 4, close the connection
    
     /* close the connection to the database and cleanup */
     PQfinish(conn);
    
    #ifdef DEBUG
     fclose(debug);
    #endif  /* DEBUG */
    
     return 0;
    }
    [root@lex tst]# 

    编译与运行:

    [root@lex tst]# gcc -c -I/usr/local/pgsql/include testprepared.c
    [root@lex tst]# gcc -o testprepared testprepared.o -L/usr/local/pgsql/lib -lpq
    [root@lex tst]# ./testprepared
    cust_id        cust_name      
    
    3              Taylor         
    name           statement                      prepare_time         parameter_typesfrom_sql       
    
    test_stmt      select * from customers where cust_id=$   12013-06-17 16:28:31.70059+08{integer}      f 

     追记:

    为了解决Java中处理prepared statement 的问题。在Postgresql社区提问,得到的回答是:

    采用threadshold:这个算是PostgreSQL自己的扩展。修改代码如下:

    [root@lex src]# cat Test01.java
    import java.sql.*;
    
    public class Test01 {
    
            public static void main(String argsv[]) {
                    try {
                            Class.forName("org.postgresql.Driver").newInstance();
                            String url = "jdbc:postgresql://localhost:5432/postgres";
    
                            Connection con = DriverManager.getConnection(url, "postgres",
                                            "postgres");
    
                            // /Phase 1:-------------Select data from
                            // table-----------------------
    
                            System.out.println("Phase 1------------------------start");
    
                            String strsql = " select * from customers where cust_id = ?";
                            PreparedStatement pst = con.prepareStatement(strsql);
    
                            org.postgresql.PGStatement pgt = (org.postgresql.PGStatement)pst;
    
                            pgt.setPrepareThreshold(1);
    
                            pst.setInt(1, 3); // find the customer with cust_id of 3.
    
                            ResultSet rs = pst.executeQuery();
    
                            while (rs.next()) {
                                    System.out.print("cust_id:" + rs.getInt("cust_id"));
                                    System.out.println("...cust_name:" + rs.getString("cust_name"));
                            }
                            System.out.println("Phase 1------------------------end
    ");
    
                            // /Phase 2:-------------Use connection again,to select data from
                            // data dictionary-----------------------
    
                            System.out.println("Phase 2------------------------start");
    
                            strsql = "select * from pg_prepared_statements";
                            pst = con.prepareStatement(strsql);
    
                            rs = pst.executeQuery();
    
                            while (rs.next()) {
                                    System.out.println("statement:" + rs.getString("statement"));
                            }
                            System.out.println("Phase 2------------------------end
    ");
    
                            // /Phase 3:-------------Use connection again,to select data from
                            // table-----------------------
    
                            System.out.println("Phase 3------------------------start");
                            strsql = "select * from customers";
                            pst = con.prepareStatement(strsql);
    
                            rs = pst.executeQuery();
    
                            while (rs.next()) {
                                    System.out.print("cust_id:" + rs.getInt("cust_id"));
                                    System.out.println("...cust_name:" + rs.getString("cust_name"));
                            }
    
                            System.out.println("Phase 3------------------------end
    ");
    
                            rs.close();
                            pst.close();
                            con.close();
    
                    } catch (Exception ee) {
                            System.out.print(ee.getMessage());
                    }
            }
    
    }
    [root@lex src]# 

    因为加入了这两句:

    org.postgresql.PGStatement pgt = (org.postgresql.PGStatement)pst;

    pgt.setPrepareThreshold(1);

    所以,得到的运行结果不同了:

    Phase 1------------------------start
    cust_id:3...cust_name:Taylor
    Phase 1------------------------end
    
    Phase 2------------------------start
    statement: select * from customers where cust_id = $1
    Phase 2------------------------end
    
    Phase 3------------------------start
    cust_id:1...cust_name:Smith
    cust_id:2...cust_name:Brown
    cust_id:3...cust_name:Taylor
    Phase 3------------------------end

    不过,这么作的目的是什么呢,还是很让人困惑的。

    http://jdbc.postgresql.org/documentation/head/server-prepare.html

    The PostgreSQL™ server allows clients to compile sql statements that are expected to be reused to avoid the overhead of parsing and planning the statement for every execution. This functionality is available at the SQL level via PREPARE and EXECUTE beginning with server version 7.3, and at the protocol level beginning with server version 7.4, but as Java developers we really just want to use the standard PreparedStatement interface.
    There are a number of ways to enable server side prepared statements depending on your application's needs. The general method is to set a threshold for a PreparedStatement. An internal counter keeps track of how many times the statement has been executed and when it reaches the threshold it will start to use server side prepared statements.

    这里面最令我困惑的是这句话:

    The PostgreSQL™ server allows clients to compile sql statements that are expected to be reused to avoid the overhead of parsing and planning the statement for every execution.

    ...server allows client to compile sql statements

  • 相关阅读:
    MongoDB下配置用户权限
    (CF)Codeforces445A DZY Loves Chessboard(纯实现题)
    C语言概述
    C#中值类型和引用类型的差别浅记
    Qt5官方demo解析集30——Extending QML
    汉澳sinox通过ndis执行windows驱动程序
    linux设备驱动归纳总结(三):4.ioctl的实现【转】
    linux设备驱动归纳总结(三):3.设备驱动面向对象思想和lseek的实现【转】
    linux设备驱动归纳总结(三):2.字符型设备的操作open、close、read、write【转】
    linux设备驱动归纳总结(三):1.字符型设备之设备申请【转】
  • 原文地址:https://www.cnblogs.com/gaojian/p/3140624.html
Copyright © 2011-2022 走看看