【问题标题】:Null pointer exception when inserting row into Postgres将行插入 Postgres 时出现空指针异常
【发布时间】:2015-10-05 04:07:07
【问题描述】:

我正在 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)

深入研究,我发现ProtoConnection 的对象在org.postgresql.core.v3.SimpleParameterList 类中为空。我做错了什么?

这是创建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)
    }

【问题讨论】:

  • 您的堆栈跟踪不完整,但我猜想您的记录映射中字段“NOT NULL”的值为空。
  • 由于 Groovy 关闭的疯狂,我缩写了堆栈跟踪。但是,所有非空列的值都存在。
  • 感谢您的意见,@hotzst。经过几次失误(主要是我自己),设法解决了这个问题!
  • 我在使用 param-name 而不是问号 sql 时遇到了同样的问题。

标签: java postgresql groovy


【解决方案1】:

我的代码有几处做错了。首先,我没有将记录映射中的字符串对象转换为适当的 JDBC 类型。这就解释了为什么我能够通过标准的prepared statement 路径插入记录,因为我最初在那里进行了转换,但在转换到Groovy 的API 时忽略了它。

修复此问题后,我收到不支持 hstore 扩展的错误消息。这可以通过在 Postgres 中执行 create extension hstore 来解决。

最后,我收到一个索引越界错误。这是由于我的代码中有一个愚蠢的错误,我在插入语句中设置值,而不是让 API 填充参数。您现在可以在插入语句的最后一行看到此修复:

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

【讨论】:

    猜你喜欢
    • 2016-03-31
    • 1970-01-01
    • 2013-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多