groovy-sql: doco for batching

Project: http://git-wip-us.apache.org/repos/asf/incubator-groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-groovy/commit/58ba4de1
Tree: http://git-wip-us.apache.org/repos/asf/incubator-groovy/tree/58ba4de1
Diff: http://git-wip-us.apache.org/repos/asf/incubator-groovy/diff/58ba4de1

Branch: refs/heads/GROOVY_2_4_X
Commit: 58ba4de16d21376fadc759c4f75b17fe38e0f072
Parents: 46db4bc
Author: Paul King <pa...@asert.com.au>
Authored: Sun Apr 19 21:26:19 2015 +1000
Committer: Paul King <pa...@asert.com.au>
Committed: Mon Apr 20 17:23:31 2015 +1000

----------------------------------------------------------------------
 .../groovy-sql/src/spec/doc/sql-userguide.adoc  | 46 +++++++++++-
 .../groovy-sql/src/spec/test/SqlTest.groovy     | 74 ++++++++++++++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/58ba4de1/subprojects/groovy-sql/src/spec/doc/sql-userguide.adoc
----------------------------------------------------------------------
diff --git a/subprojects/groovy-sql/src/spec/doc/sql-userguide.adoc 
b/subprojects/groovy-sql/src/spec/doc/sql-userguide.adoc
index b78d5d1..d0e4ff0 100644
--- a/subprojects/groovy-sql/src/spec/doc/sql-userguide.adoc
+++ b/subprojects/groovy-sql/src/spec/doc/sql-userguide.adoc
@@ -249,7 +249,51 @@ Even though the first sql execute succeeds initially, it 
will be rolled back and
 
 === Using batches
 
-(TBD)
+When dealing with large volumes of data, it can be more efficient to chunk the 
data into batches. This is done
+using the `withBatch` statement as shown in the following example:
+
+[source,groovy]
+.Batching SQL statements
+----
+include::{rootProjectDir}/subprojects/groovy-sql/src/spec/test/SqlTest.groovy[tags=sql_batch_statements,indent=0]
+----
+
+After executing these statements, there will be 7 new rows in the database. In 
fact, they will have been added in batches
+even though you can't easily tell that after that fact. If you want to confirm 
what is going on under the covers, you can
+add a little bit of extra logging into your program. Add the following lines 
before the `withBatch` statement:
+
+[source,groovy]
+.Logging additional SQL information
+----
+include::{rootProjectDir}/subprojects/groovy-sql/src/spec/test/SqlTest.groovy[tags=sql_batch_import_for_logging,indent=0]
+include::{rootProjectDir}/subprojects/groovy-sql/src/spec/test/SqlTest.groovy[tags=sql_batch_logging,indent=0]
+----
+
+With this extra logging turned on, and the changes made as per the above 
comment for the logging.properties file, you should see
+output such as:
+
+[source]
+.SQL logging output with batching enable
+----
+include::{rootProjectDir}/subprojects/groovy-sql/src/spec/test/SqlTest.groovy[tags=sql_batch_results,indent=0]
+----
+
+We should also note, that any combination of SQL statements can be added to 
the batch. They don't all have to be
+inserting a new row to the same table.
+
+We noted earlier that to avoid SQL injection, we encourage you to use prepared 
statements, this is achieved using the
+variants of methods which take GStrings or a list of extra parameters. 
Prepared statements can be used in combination
+with batches as shown in the following example:
+
+[source,groovy]
+.Batching prepared statements
+----
+include::{rootProjectDir}/subprojects/groovy-sql/src/spec/test/SqlTest.groovy[tags=sql_batch_prepared_statements,indent=0]
+----
+
+This provides a much safer option if the data could come from a user such as 
via a script or a web form. Of course, given
+that a prepared statement is being used, you are limited to a batch of the 
same SQL operation (insert in our example)
+to the one table.
 
 === Performing pagination
 

http://git-wip-us.apache.org/repos/asf/incubator-groovy/blob/58ba4de1/subprojects/groovy-sql/src/spec/test/SqlTest.groovy
----------------------------------------------------------------------
diff --git a/subprojects/groovy-sql/src/spec/test/SqlTest.groovy 
b/subprojects/groovy-sql/src/spec/test/SqlTest.groovy
index 070e2ac..f5b5c9b 100644
--- a/subprojects/groovy-sql/src/spec/test/SqlTest.groovy
+++ b/subprojects/groovy-sql/src/spec/test/SqlTest.groovy
@@ -428,6 +428,80 @@ class SqlTest extends GroovyTestCase {
         '''
     }
 
+    void testBatching() {
+        assertScript '''
+            import groovy.sql.Sql
+            // tag::sql_batch_import_for_logging[]
+            import java.util.logging.*
+
+            // end::sql_batch_import_for_logging[]
+
+            def url = 'jdbc:hsqldb:mem:yourDB'
+            def user = 'sa'
+            def password = ''
+            def driver = 'org.hsqldb.jdbcDriver'
+            Sql.withInstance(url, user, password, driver) { sql ->
+              sql.execute """
+              DROP TABLE Author IF EXISTS
+              """
+              sql.execute """
+              CREATE TABLE Author (
+                id          INTEGER GENERATED BY DEFAULT AS IDENTITY,
+                firstname   VARCHAR(64),
+                lastname    VARCHAR(64)
+              )
+              """
+
+              // tag::sql_batch_logging[]
+              // next line will add fine logging
+              Logger.getLogger('groovy.sql').level = Level.FINE
+              // also adjust logging.properties file in JRE_HOME/lib to have:
+              // java.util.logging.ConsoleHandler.level = FINE
+              // end::sql_batch_logging[]
+
+              // tag::sql_batch_statements[]
+              sql.withBatch(3) { stmt ->
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Dierk', 'Koenig')"
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Paul', 'King')"
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Guillaume', 'Laforge')"
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Hamlet', 'D''Arcy')"
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Cedric', 'Champeau')"
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Erik', 'Pragt')"
+                stmt.addBatch "INSERT INTO Author (firstname, lastname) VALUES 
('Jon', 'Skeet')"
+              }
+              // end::sql_batch_statements[]
+              assert sql.firstRow('SELECT COUNT(*) as num FROM Author').num == 
7
+              /*
+              // tag::sql_batch_results[]
+              FINE: Successfully executed batch with 3 command(s)
+              Apr 19, 2015 8:38:42 PM groovy.sql.BatchingStatementWrapper 
processResult
+
+              FINE: Successfully executed batch with 3 command(s)
+              Apr 19, 2015 8:38:42 PM groovy.sql.BatchingStatementWrapper 
processResult
+
+              FINE: Successfully executed batch with 1 command(s)
+              Apr 19, 2015 8:38:42 PM groovy.sql.Sql getStatement
+              // end::sql_batch_results[]
+              */
+              sql.execute('DELETE FROM Author')
+              assert sql.firstRow('SELECT COUNT(*) as num FROM Author').num == 0
+              // tag::sql_batch_prepared_statements[]
+              def qry = 'INSERT INTO Author (firstname, lastname) VALUES (?,?)'
+              sql.withBatch(3, qry) { ps ->
+                ps.addBatch('Dierk', 'Koenig')
+                ps.addBatch('Paul', 'King')
+                ps.addBatch('Guillaume', 'Laforge')
+                ps.addBatch('Hamlet', "D'Arcy")
+                ps.addBatch('Cedric', 'Champeau')
+                ps.addBatch('Erik', 'Pragt')
+                ps.addBatch('Jon', 'Skeet')
+              }
+              // end::sql_batch_prepared_statements[]
+              assert sql.firstRow('SELECT COUNT(*) as num FROM Author').num == 
7
+            }
+        '''
+    }
+
     void testDeletingRows() {
         assertScript '''
         import groovy.sql.Sql

Reply via email to