简体   繁体   English

将行插入Postgres时出现空指针异常

[英]Null pointer exception when inserting row into Postgres

I am querying a table in Postgres to see if a row with primary key values match those in a given Map exists. 我在Postgres中查询表,以查看是否存在具有主键值匹配给定Map的行的行。 If there are no results, I want to insert a new row. 如果没有结果,我想插入一个新行。 I can do this just fine when I go the standard JDBC route of creating a prepared statement and explicitly setting all the column values, but I want a more generic approach with the help of Groovy's Sql class. 当我使用创建准备好的语句并显式设置所有列值的标准JDBC路线时,可以做到这一点,但是我希望在Groovy的Sql类的帮助下使用更通用的方法。

This is my insert statement (the primary key columns are the first three): 这是我的插入语句(主键列为前三列):

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)

The issue is that I'm getting a NullPointerException from the Postgres driver as soon as I insert a row: 问题是,我在插入一行后就从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)

Digging into it, I find that an object called ProtoConnection is null in the org.postgresql.core.v3.SimpleParameterList class. 深入研究它,我发现在org.postgresql.core.v3.SimpleParameterList类中一个名为ProtoConnection的对象为null。 What am I doing wrong? 我究竟做错了什么?

This is the wrapping code which creates the Sql object: 这是创建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
            }
          }
        }
      }
    }
  }

And this is the database logic. 这就是数据库逻辑。 The error occurs at the very last line: 错误发生在最后一行:

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)
    }

There were a few things I was doing wrong with my code. 我的代码在某些方面做错了。 First of all, I wasn't converting the string objects in the record map into the appropriate JDBC types. 首先,我没有将记录映射中的字符串对象转换为适当的JDBC类型。 This explains why I was able to insert records via the standard prepared statement route, as I originally did the conversion there, and overlooked it when transitioning to Groovy's API. 这解释了为什么我能够像以前一样在此处进行转换,并通过标准的准备好的语句路由插入记录,而在过渡到Groovy的API时却忽略了它。

After fixing this, I then got an error that the hstore extension was not supported. 解决此问题后,我得到一个错误, hstore不支持hstore扩展。 This was simply solved by executing create extension hstore in Postgres. 这可以通过在Postgres中执行create extension hstore来解决。

Finally, I received an index out of bounds error. 最后,我收到索引超出范围错误。 This was due to a silly bug in my code where I was setting the values in my insert statement, rather than letting the API fill in the parameters. 这是由于我的代码中存在一个愚蠢的错误,我在我的插入语句中设置了值,而不是让API填充了参数。 You can see this fix in the final line of the insert statement now: 您现在可以在插入语句的最后一行中看到此修复程序:

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