diff --git a/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLDeleteClause.java b/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLDeleteClause.java index c50ccf83d..d4aa986d2 100644 --- a/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLDeleteClause.java +++ b/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLDeleteClause.java @@ -8,7 +8,9 @@ package com.mysema.query.sql.dml; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -43,7 +45,11 @@ public class SQLDeleteClause extends AbstractSQLClause implements DeleteClause entity; - private final QueryMetadata metadata = new DefaultQueryMetadata(); + private final List batches = new ArrayList(); + + private QueryMetadata metadata = new DefaultQueryMetadata(); + + private transient String queryString; public SQLDeleteClause(Connection connection, SQLTemplates templates, RelationalPath entity) { this(connection, new Configuration(templates), entity); @@ -59,6 +65,12 @@ public class SQLDeleteClause extends AbstractSQLClause implements DeleteClause,Object>emptyMap()); + }else{ + SQLSerializer serializer = new SQLSerializer(configuration.getTemplates(), true); + serializer.serializeForDelete(batches.get(0), entity); + queryString = serializer.toString(); + logger.debug(queryString); + + // add first batch + stmt = connection.prepareStatement(queryString); + setParameters(stmt, serializer.getConstants(), Collections.,Object>emptyMap()); + stmt.addBatch(); + + // add other batches + for (int i = 1; i < batches.size(); i++){ + serializer = new SQLSerializer(configuration.getTemplates(), true); + serializer.serializeForDelete(batches.get(i), entity); + setParameters(stmt, serializer.getConstants(), Collections.,Object>emptyMap()); + stmt.addBatch(); + } + } + return stmt; + } @Override public long execute() { - SQLSerializer serializer = new SQLSerializer(configuration.getTemplates(), true); - serializer.serializeForDelete(metadata, entity); - String queryString = serializer.toString(); - logger.debug(queryString); - PreparedStatement stmt = null; try { - stmt = connection.prepareStatement(queryString); - setParameters(stmt, serializer.getConstants(), Collections.,Object>emptyMap()); - return stmt.executeUpdate(); + stmt = createStatement(); + if (batches.isEmpty()){ + return stmt.executeUpdate(); + }else{ + long rv = 0; + for (int i : stmt.executeBatch()){ + rv += i; + } + return rv; + } } catch (SQLException e) { throw new QueryException("Caught " + e.getClass().getSimpleName() + " for " + queryString, e); } finally { diff --git a/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLUpdateClause.java b/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLUpdateClause.java index a47f582aa..097086f68 100644 --- a/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLUpdateClause.java +++ b/querydsl-sql/src/main/java/com/mysema/query/sql/dml/SQLUpdateClause.java @@ -48,9 +48,15 @@ public class SQLUpdateClause extends AbstractSQLClause implements UpdateClause< private final RelationalPath entity; - private final List,?>> updates = new ArrayList,?>>(); + private final List batchMetadata = new ArrayList(); + + private final List,?>>> batchUpdates = new ArrayList,?>>>(); + + private List,?>> updates = new ArrayList,?>>(); - private final QueryMetadata metadata = new DefaultQueryMetadata(); + private QueryMetadata metadata = new DefaultQueryMetadata(); + + private transient String queryString; public SQLUpdateClause(Connection connection, SQLTemplates templates, RelationalPath entity) { this(connection, new Configuration(templates), entity); @@ -66,7 +72,14 @@ public class SQLUpdateClause extends AbstractSQLClause implements UpdateClause< metadata.addFlag(new QueryFlag(position, flag)); return this; } - + + public SQLUpdateClause addBatch() { + batchUpdates.add(updates); + batchMetadata.add(metadata); + updates = new ArrayList,?>>(); + metadata = new DefaultQueryMetadata(); + return this; + } protected void close(PreparedStatement stmt) { try { @@ -76,18 +89,51 @@ public class SQLUpdateClause extends AbstractSQLClause implements UpdateClause< } } - @Override - public long execute() { - SQLSerializer serializer = new SQLSerializer(configuration.getTemplates(), true); - serializer.serializeForUpdate(metadata, entity, updates); - String queryString = serializer.toString(); - logger.debug(queryString); - - PreparedStatement stmt = null; - try { + private PreparedStatement createStatement() throws SQLException{ + PreparedStatement stmt; + if (batchUpdates.isEmpty()){ + SQLSerializer serializer = new SQLSerializer(configuration.getTemplates(), true); + serializer.serializeForUpdate(metadata, entity, updates); + queryString = serializer.toString(); + logger.debug(queryString); stmt = connection.prepareStatement(queryString); setParameters(stmt, serializer.getConstants(), Collections.,Object>emptyMap()); - return stmt.executeUpdate(); + }else{ + SQLSerializer serializer = new SQLSerializer(configuration.getTemplates(), true); + serializer.serializeForUpdate(batchMetadata.get(0), entity, batchUpdates.get(0)); + queryString = serializer.toString(); + logger.debug(queryString); + + // add first batch + stmt = connection.prepareStatement(queryString); + setParameters(stmt, serializer.getConstants(), Collections.,Object>emptyMap()); + stmt.addBatch(); + + // add other batches + for (int i = 1; i < batchUpdates.size(); i++){ + serializer = new SQLSerializer(configuration.getTemplates(), true); + serializer.serializeForUpdate(batchMetadata.get(i), entity, batchUpdates.get(i)); + setParameters(stmt, serializer.getConstants(), Collections.,Object>emptyMap()); + stmt.addBatch(); + } + } + return stmt; + } + + @Override + public long execute() { + PreparedStatement stmt = null; + try { + stmt = createStatement(); + if (batchUpdates.isEmpty()){ + return stmt.executeUpdate(); + }else{ + long rv = 0; + for (int i : stmt.executeBatch()){ + rv += i; + } + return rv; + } } catch (SQLException e) { throw new QueryException("Caught " + e.getClass().getSimpleName() + " for " + queryString, e); } finally { diff --git a/querydsl-sql/src/test/java/com/mysema/query/DeleteBaseTest.java b/querydsl-sql/src/test/java/com/mysema/query/DeleteBaseTest.java index f5ca86564..9cc1fed3f 100644 --- a/querydsl-sql/src/test/java/com/mysema/query/DeleteBaseTest.java +++ b/querydsl-sql/src/test/java/com/mysema/query/DeleteBaseTest.java @@ -27,7 +27,7 @@ public abstract class DeleteBaseTest extends AbstractBaseTest{ private void reset() throws SQLException{ delete(survey).where(survey.name.isNotNull()).execute(); - Connections.getStatement().execute("insert into survey values (1, 'Hello World')"); + insert(survey).values(1, "Hello World").execute(); } @Before @@ -47,5 +47,16 @@ public abstract class DeleteBaseTest extends AbstractBaseTest{ assertEquals(0, delete(survey).where(survey.name.eq("XXX")).execute()); assertEquals(count, delete(survey).execute()); } + + @Test + public void batch() throws SQLException{ + insert(survey).values(2, "A").execute(); + insert(survey).values(3, "B").execute(); + + SQLDeleteClause delete = delete(survey); + delete.where(survey.name.eq("A")).addBatch(); + delete.where(survey.name.eq("B")).addBatch(); + assertEquals(2, delete.execute()); + } } diff --git a/querydsl-sql/src/test/java/com/mysema/query/UpdateBaseTest.java b/querydsl-sql/src/test/java/com/mysema/query/UpdateBaseTest.java index 03533650f..bfc3538c1 100644 --- a/querydsl-sql/src/test/java/com/mysema/query/UpdateBaseTest.java +++ b/querydsl-sql/src/test/java/com/mysema/query/UpdateBaseTest.java @@ -16,6 +16,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.mysema.query.sql.dml.SQLUpdateClause; import com.mysema.query.types.Path; public abstract class UpdateBaseTest extends AbstractBaseTest{ @@ -84,5 +85,16 @@ public abstract class UpdateBaseTest extends AbstractBaseTest{ long count = query().from(survey).count(); assertEquals(count, update(survey).set(survey.name, null).execute()); } + + @Test + public void batch() throws SQLException{ + insert(survey).values(2, "A").execute(); + insert(survey).values(3, "B").execute(); + + SQLUpdateClause update = update(survey); + update.set(survey.name, "AA").where(survey.name.eq("A")).addBatch(); + update.set(survey.name, "BB").where(survey.name.eq("B")).addBatch(); + assertEquals(2, update.execute()); + } }