2015-10-04 31 views
0

我正在查詢Postgres中的表以查看是否存在具有主鍵值的行匹配給定Map中的行。如果沒有結果,我想插入一個新行。當我使用創建預準備語句的標準JDBC路由並明確設置所有列值時,我可以很好地做到這一點,但是我希望Groovy的Sql類可以提供更通用的方法。向Postgres插入行時出現空指針異常

這是我的INSERT語句(主鍵列的前三個):

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) 

挖掘到它,我發現一個名爲ProtoConnection的對象在org.postgresql.core.v3.SimpleParameterList類中爲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) 
    } 
+0

你的堆棧跟蹤是不完整的,但我猜想,對於一個'NOT NULL」 fieldd在你的記錄圖的值爲空。 – hotzst

+0

由於Groovy關閉的瘋狂,我縮寫了stacktrace。儘管存在所有非空列的值。 – lealand

+0

感謝您的輸入,@hotzst。在經過幾次失敗後(主要在我身上)管理解決問題! – lealand

回答

0

有幾件事我做錯了我的代碼。首先,我沒有將記錄映射中的字符串對象轉換爲適當的JDBC類型。這就解釋了爲什麼我能夠通過標準準備好的語句路由插入記錄,就像我最初在那裏進行轉換一樣,並在轉換到Groovy的API時忽略了它。

修復此問題後,我得到一個錯誤,不支持hstore擴展名。這只是通過在Postgres中執行create extension hstore來解決的。

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

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