Question

Let's say we have a REST service with accepts List of sales orders from manager. (we know managerId and it's the same for all orders he sends)

class SalesOrder {
   String id;
   String managerId;
   //some other data
}

And this service must:

if SalesOrder not exists - save object
if object exists - update it

What is the most efficient way (in terms of working with db) to saveOrUpdate this list using Spring jdbcTemplate?

First approach I was thinking about is:

public void saveOrUpdate(Iterable<SalesOrder> orders, String managerId) {
    Set<String> presentInDbOrderIds = findOrderIds(managerId);

    List<SalesOrder> ordersToInsert = new ArrayList<>();
    List<SalesOrder> ordersToUpdate = new ArrayList<>();

    for (SalesOrder ord : orders) {
        if(presentInDbRecOrderHeaderIds.contains(ord.getId())) {
            ordersToUpdate.add(ord);
        } else {
            ordersToInsert.add(ord);
        }
    }

    batchInsertOrders(recOrdersToInsert);
    batchUpdateOrders(recOrdersToUpdate);
}

And the second one:

public void saveOrUpdate(Iterable<SalesOrder> orders) {
    for (SalesOrder ord : orders) {
        if(!update(ord)) { // returns true if object was updated
            save(ord);
        }
    }
}

Updated:

Actually (in my case) each order has a collection of orderLines which must go through the same procedure, so I am looking for the most painless way (to DB) to accomplish this operation.

Was it helpful?

Solution

Taking your ownership on checking whether it needs check or update is not a good idea. What if another thread modified data in DB after you prepared findOrderIds() .. etc. I dont see whether you have implemented synchronised or not.

Also, if you add synchronised for the whole process, you are adding extra block. DB handles much better synchronisation and with indexed data.

I will go with something like this with batch prepared statements :

class SalesOrder {
    String id;
    String managerId;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getManagerId() {
        return managerId;
    }

    public void setManagerId(String managerId) {
        this.managerId = managerId;
    }

}

public void saveOrUpdate(List<SalesOrder> orders, String managerId) {
    String example_query = "insert into table(id, managerID,col2) values (?,?,?) on duplicate key update managerID= ? , col2 =?";
    final int batchSize = 500;

    for (int j = 0; j < orders.size(); j += batchSize) {
        final List<SalesOrder> pickedOrders = orders.subList(j,
                j + batchSize > orders.size() ? orders.size() : j + batchSize);
        getJdbcTemplate().batchUpdate(example_query, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                SalesOrder order = pickedOrders.get(i);
                ps.setString(1, order.getId());
                ps.setString(2, order.getManagerId());
                // so on
            }
            @Override
            public int getBatchSize() {
                return pickedOrders.size();
            }
        });

    }

} 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top