简体   繁体   English

使用准备好的语句将Spring批处理插入/更新到postgres

[英]Spring batch insert/update to postgres using prepared statement

I am trying to insert records to postgres table using prepared statements but I am getting following errors while using insert statements: 我试图使用准备好的语句将记录插入到postgres表中,但是使用插入语句时出现以下错误:

[main] ERROR org.springframework.batch.core.step.AbstractStep - Encountered an error executing step someStep in job someJob
org.springframework.dao.EmptyResultDataAccessException: Item 0 of 1 did not update any rows: [[com.abc.abc.abc.dao.orm.SomeORM@6653en,com.abc.abc.abc.dao.orm.SomeORM@75f04e]
   at org.springframework.batch.item.database.JdbcBatchItemWriter.write(JdbcBatchItemWriter.java:202)

My writer is : 我的作家是:

package com.somepackage.writer;

public class trialClass implements ItemPreparedStatementSetter<List<someORM>> {

    @Override
    public void setValues(List<someORM> itemList,java.sql.PreparedStatement ps) throws SQLException,EmptyResultDataAccessException {
         try {
    for (ORM item : itemList) {
    for (int i = 0;i<itemList.size();i++)
        {
    ps.setInt(1, itemList.get(i).getPropOne());                         
    ps.setString(2, itemList.get(i).getPropTwo());
     ps.setInt(3, itemList.get(i).getPropThree());
     ps.setInt(4, itemList.get(i).getPropFour());
    ps.addBatch();
}
int[] rs = ps.executeBatch();
       } catch (Exception e) {
     e.printStackTrace();
    }}}

My xml file is something like this: 我的xml文件是这样的:

<beans:bean id="beanId" scope="step"
              class="org.springframework.batch.item.support.CompositeItemWriter">
              <beans:property name = "delegates">
                     <util:list>
                     <beans:ref bean= "someId"/>
                     <beans:ref bean= "someOtherId"/>
                     </util:list>
              </beans:property>
              </beans:bean>

<beans:bean id = "someId" scope = "step" 
              class="org.springframework.batch.item.database.JdbcBatchItemWriter">
              <beans:property name="dataSource" ref="someSource" />
              <beans:property name="sql" value = "${fetch.somequery.sql}" >  
              </beans:property>
              <beans:property name="itemPreparedStatementSetter" ref="someRef" />
       </beans:bean>

I am getting error only while inserting the records, updates are working fine (postgres table has primary key on first column) (In both the cases the records are getting inserted/updated in the postgres table but still getting this error in case of insert) 我仅在插入记录时遇到错误,更新工作正常(postgres表在第一列上具有主键)(在两种情况下,记录都已在postgres表中插入/更新,但在插入的情况下仍然出现此错误)

and I am using query as : 我正在使用查询为:

fetch.somequery.sql =INSERT INTO table1 (col1, col2, col3) SELECT ?,?,? WHERE NOT EXISTS (SELECT 1 FROM table1 WHERE col1= ?);

but when I am using plain insert query I am getting error as : 但是,当我使用普通插入查询时,出现以下错误:

Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key violates unique constraint "table1_pkey"  (seg576 sdw24:40000 pid=398877)
   at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2062)

I have made sure that the records are not duplicate but still getting this error 我确保记录不是重复的,但仍然收到此错误

Where am I doing it wrong? 我在哪里做错了? Can I use ORM to update data to postgres. 我可以使用ORM将数据更新到Postgres。 If yes the how? 如果是的话如何? Can I use jdbc template to update data to postgres. 我可以使用jdbc模板将数据更新到Postgres。 If yes the how? 如果是的话如何?

How to handle this exception? 如何处理此异常?

The entire record doesn't necessarily have to be a duplicate in order to violate a unique constraint . 为了违反唯一约束 ,整个记录不必重复。 The only column(s) that need to be the same are the ones which comprise the constraint. 唯一需要相同的列就是构成约束的列。 Here, the error you provided says it's the table1_pkey constraint that's involved, so you would need to reference the DDL for that constraint to determine the columns. 在这里,您提供的错误表明所涉及的是table1_pkey约束,因此您需要引用该约束的DDL来确定列。

From the code provided it's not possible to tell for sure, but I suspect what's happening is that two items in your list, for whichever property is referenced in table1_pkey , are the same. 从提供的代码中无法确定,但是我怀疑正在发生的事情是列表中的两个项目(对于table1_pkey引用的哪个属性)都是相同的。

It's generally best to use sequences for this sort of thing (assuming it's a single column), which Postgres will populate itself, as long as you just let it use the default value (and have the default value properly increment the sequence -- the serial type is syntactic sugar that does this automatically). 通常最好对此类事情使用序列 (假设它是单列),只要您让它使用默认值(并让默认值适当地递增序列- serial ), Postgres就会自行填充类型是自动执行此操作的语法糖 )。

Also, when there's only one column involved, and it's meant to be the primary key, it can be declared as such inline, so something like this in the DDL : id serial primary key 另外,当只涉及一列并且要作为主键时,可以将其声明为内联,因此在DDL中是这样的: id serial primary key

If multiple columns are involved, the same general concept applies, but you wouldn't define the primary key quite the same way (it would defined later as a constraint, as it would be comprised of a column tuple), and you would need to make sure multiple sequences are used. 如果涉及多个列,则应用相同的一般概念,但是您将不会以完全相同的方式定义主键 (稍后将其定义为约束,因为它将由列元组组成),并且您需要确保使用了多个序列

Response to comment from OP: 对OP评论的回应:

If the records are already present, trying to insert them again will definitionally violate the unique constraint. 如果记录已经存在,则尝试再次插入它们将在定义上违反唯一约束。 Are you mixing insert and update cases under a single insert operation? 您是否在单个插入操作下混合插入和更新案例? That will not work. 那不管用。 Updates and inserts need to be separate. 更新和插入需要分开。 You can help guard against existence in an insert by adding a where exists sub-select in the insert, such that when it exists, the insert is a no-op. 您可以通过在插入中添加一个where exists子选择来帮助防止插入where exists ,这样,当插入存在时,该插入为空操作。 The updates would still need to occur separately. 更新仍然需要单独进行。

The exception to that is the upsert , which is new to Postgres in 9.5 and fit what you're looking for here. 例外是upsert ,它是9.5中的Postgres的新功能,适合您在这里寻找的内容。

From the doc: 从文档中:

ON CONFLICT DO UPDATE guarantees an atomic INSERT or UPDATE outcome; ON CONFLICT DO UPDATE保证原子的INSERT或UPDATE结果; provided there is no independent error, one of those two outcomes is guaranteed, even under high concurrency. 如果没有独立的错误,即使在高并发情况下,也可以保证这两个结果之一。 This is also known as UPSERT — "UPDATE or INSERT". 这也称为UPSERT-“ UPDATE或INSERT”。

I had a similar problem once and it's not caused by the writer bean. 我曾经有过类似的问题,这不是由writer bean引起的。

The problem, in my case, was because I'm was using a non thread safe reader, so my source read (aleatory) some itens more than one time. 就我而言,问题是因为我使用的是非线程安全的读取器,所以我的源代码多次读取(尝试)了一些内容。

In your example sources I can see only the writers declarations. 在示例资源中,我只能看到writers声明。

I recomend you to check the reader and if you need a parallel reader, use the proper one or consider to use sequencial reader. 我建议您检查阅读器,如果需要并行阅读器,请使用适当的阅读器或考虑使用顺序阅读器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM