簡體   English   中英

將行插入Postgres時出現空指針異常

[英]Null pointer exception when inserting row into Postgres

我在Postgres中查詢表,以查看是否存在具有主鍵值匹配給定Map的行的行。 如果沒有結果,我想插入一個新行。 當我使用創建准備好的語句並顯式設置所有列值的標准JDBC路線時,可以做到這一點,但是我希望在Groovy的Sql類的幫助下使用更通用的方法。

這是我的插入語句(主鍵列為前三列):

insert into MY_TABLE
  (contract_month, contract_year, publish_date, open, high, low)
values
  (10, 2015, 2015-09-15 00:00:00.0, 46.65, 46.9, 45.98)

問題是,我在插入一行后就從Postgres驅動程序中獲取了NullPointerException

Exception in thread "main" java.lang.NullPointerException
    at org.postgresql.core.v3.SimpleParameterList.setNull(SimpleParameterList.java:142)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.setNull(AbstractJdbc2Statement.java:1259)
    at org.postgresql.jdbc3.AbstractJdbc3Statement.setNull(AbstractJdbc3Statement.java:1499)
    at org.postgresql.jdbc4.AbstractJdbc4Statement.setNull(AbstractJdbc4Statement.java:85)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.setObject(AbstractJdbc2Statement.java:2092)
    at org.postgresql.jdbc3g.AbstractJdbc3gStatement.setObject(AbstractJdbc3gStatement.java:38)
    at org.postgresql.jdbc4.AbstractJdbc4Statement.setObject(AbstractJdbc4Statement.java:48)

深入研究它,我發現在org.postgresql.core.v3.SimpleParameterList類中一個名為ProtoConnection的對象為null。 我究竟做錯了什么?

這是創建Sql對象的包裝代碼:

  private Main() {    
    final def headers = new HashMap<Integer, String>()
    final def record = new HashMap<String, Object>()

    Sql.withInstance(/* my db */) { final Sql sql ->
      sql.withBatch {
        new URL(/* my url */).withReader {
          it.readLines().each {
            if (headers.isEmpty()) {
              setHeaders it, headers
            }
            else {
              processRecord it, headers, record
              storeRecord sql, record
            }
          }
        }
      }
    }
  }

這就是數據庫邏輯。 錯誤發生在最后一行:

def storeRecord = { final Sql sql, final Map<String, Object> record ->
    final def connection = sql.connection
    final def metadata = connection.metaData

    final def columns = metadata.getColumns(null, null, MY_TABLE, null).with {
      final def result = []
      while (it.next()) {
        result << it.getString(4)
      }
      result
    }

    final def primaryKeys = metadata.getPrimaryKeys(null, null, MY_TABLE).with {
      final def result = []
      while (it.next()) {
        result << it.getString(4)
      }
      result
    }

    final def whereClause = primaryKeys.collect { final String pk ->
      "$pk = ?.$pk"
    }

    final def select = """
        select ${columns.join(', ')}
          from MY_TABLE
         where ${whereClause.join(' and ')}
        """

    final def row = sql.firstRow(select, record)

    if (row) {
      println "Updating"
      // Not implemented yet
    }
    else {
      println "Inserting record: $record"
      final def insert = """
                insert into MY_TABLE
                  (${columns.findAll { null != record[it] }.join(", ")})
                 values
                  (${columns.findAll { null != record[it] }.collect { record[it] }.join(", ")})
                """
      println insert
      sql.executeInsert(insert, record)
    }

我的代碼在某些方面做錯了。 首先,我沒有將記錄映射中的字符串對象轉換為適當的JDBC類型。 這解釋了為什么我能夠像以前一樣在此處進行轉換,並通過標准的准備好的語句路由插入記錄,而在過渡到Groovy的API時卻忽略了它。

解決此問題后,我得到一個錯誤, hstore不支持hstore擴展。 這可以通過在Postgres中執行create extension hstore來解決。

最后,我收到索引超出范圍錯誤。 這是由於我的代碼中存在一個愚蠢的錯誤,我在我的插入語句中設置了值,而不是讓API填充了參數。 您現在可以在插入語句的最后一行中看到此修復程序:

final def insert = """
    insert into MY_TABLE
      (${columns.join(', ')})
     values
      (${columns.collect { "?.$it" }.join(', ')})
    """
sql.executeInsert(insert, record)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM