From 24d5ed259064e53ebaae05c2534e407643089ba2 Mon Sep 17 00:00:00 2001 From: parthiv39731 <70740707+parthiv39731@users.noreply.github.com> Date: Mon, 21 Aug 2023 19:23:25 +0530 Subject: [PATCH] Bael 6870 (#14582) * BAEL-6801 (#4) Validate string length with Java validation annotations * Bael-6870, Executing SQL Script File in Java * Bael-6870, Fixed formatting on pom.xml * Bael-6870, Fixing Jenkins Build Failure * Bael-6870, PR Review comments * Bael-6870, PR Review comments --- .../core-java-persistence-2/pom.xml | 12 +++ .../baeldung/script/MyBatisScriptUtility.java | 13 ++++ .../baeldung/script/SpringScriptUtility.java | 29 +++++++ .../script/SqlScriptBatchExecutor.java | 74 ++++++++++++++++++ .../script/MyBatisScriptUtilityUnitTest.java | 46 ++++++++++++ .../script/SpringScriptUtilityUnitTest.java | 47 ++++++++++++ .../SqlScriptBatchExecutorUnitTest.java | 47 ++++++++++++ .../src/test/resources/employee.sql | 75 +++++++++++++++++++ 8 files changed, 343 insertions(+) create mode 100644 persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java create mode 100644 persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java create mode 100644 persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java create mode 100644 persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java create mode 100644 persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java create mode 100644 persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java create mode 100644 persistence-modules/core-java-persistence-2/src/test/resources/employee.sql diff --git a/persistence-modules/core-java-persistence-2/pom.xml b/persistence-modules/core-java-persistence-2/pom.xml index 0bec7a808f..2013bdb6af 100644 --- a/persistence-modules/core-java-persistence-2/pom.xml +++ b/persistence-modules/core-java-persistence-2/pom.xml @@ -70,6 +70,16 @@ ${assertj.version} test + + org.mybatis + mybatis + ${mybatis.version} + + + org.springframework + spring-jdbc + ${spring-jdbc.version} + @@ -80,6 +90,8 @@ 20220320 07.00.00-MS-GA 2.1.214 + 5.3.29 + 3.5.7 \ No newline at end of file diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java new file mode 100644 index 0000000000..8a9bbb6e20 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/MyBatisScriptUtility.java @@ -0,0 +1,13 @@ +package com.baeldung.script; + +import org.apache.ibatis.jdbc.ScriptRunner; +import java.sql.Connection; + +public class MyBatisScriptUtility { + public static void runScript(String path, Connection connection) throws Exception { + ScriptRunner scriptRunner = new ScriptRunner(connection); + scriptRunner.setSendFullScript(false); + scriptRunner.setStopOnError(true); + scriptRunner.runScript(new java.io.FileReader(path)); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java new file mode 100644 index 0000000000..cf70dfa890 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SpringScriptUtility.java @@ -0,0 +1,29 @@ +package com.baeldung.script; + +import org.springframework.core.io.PathResource; +import org.springframework.core.io.support.EncodedResource; +import org.springframework.jdbc.datasource.init.ScriptUtils; + +import java.sql.Connection; + +public class SpringScriptUtility { + public static void runScript(String path, Connection connection) { + boolean continueOrError = false; + boolean ignoreFailedDrops = false; + String commentPrefix = "--"; + String separator = ";"; + String blockCommentStartDelimiter = "/*"; + String blockCommentEndDelimiter = "*/"; + + ScriptUtils.executeSqlScript( + connection, + new EncodedResource(new PathResource(path)), + continueOrError, + ignoreFailedDrops, + commentPrefix, + separator, + blockCommentStartDelimiter, + blockCommentEndDelimiter + ); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java new file mode 100644 index 0000000000..b9da968abe --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/main/java/com/baeldung/script/SqlScriptBatchExecutor.java @@ -0,0 +1,74 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SqlScriptBatchExecutor { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutor.class); + private static final Pattern COMMENT_PATTERN = Pattern.compile("--.*|/\\*(.|[\\r\\n])*?\\*/"); + public static void executeBatchedSQL(String scriptFilePath, Connection connection, int batchSize) throws Exception { + List sqlStatements = parseSQLScript(scriptFilePath); + executeSQLBatches(connection, sqlStatements, batchSize); + } + private static List parseSQLScript(String scriptFilePath) throws IOException { + List sqlStatements = new ArrayList<>(); + + try (BufferedReader reader = new BufferedReader(new FileReader(scriptFilePath))) { + StringBuilder currentStatement = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + Matcher commentMatcher = COMMENT_PATTERN.matcher(line); + line = commentMatcher.replaceAll(""); + line = line.trim(); + + if (line.isEmpty()) { + continue; + } + + currentStatement.append(line).append(" "); + + if (line.endsWith(";")) { + sqlStatements.add(currentStatement.toString()); + logger.info(currentStatement.toString()); + currentStatement.setLength(0); + } + } + } catch (IOException e) { + throw e; + } + return sqlStatements; + } + + private static void executeSQLBatches(Connection connection, List sqlStatements, int batchSize) + throws SQLException { + int count = 0; + Statement statement = connection.createStatement(); + + for (String sql : sqlStatements) { + statement.addBatch(sql); + count++; + + if (count % batchSize == 0) { + logger.info("Executing batch"); + statement.executeBatch(); + statement.clearBatch(); + } + } + // Execute any remaining statements + if (count % batchSize != 0) { + statement.executeBatch(); + } + connection.commit(); + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java new file mode 100644 index 0000000000..98f82cfbd5 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/MyBatisScriptUtilityUnitTest.java @@ -0,0 +1,46 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class MyBatisScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(MyBatisScriptUtilityUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb1"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + MyBatisScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java new file mode 100644 index 0000000000..be6e39ca31 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SpringScriptUtilityUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SpringScriptUtilityUnitTest { + private static final Log logger = LogFactory.getLog(SpringScriptUtilityUnitTest.class); + + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb2"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SpringScriptUtility.runScript(path, connection); + + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } +} diff --git a/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java new file mode 100644 index 0000000000..3b1210fd00 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/java/com/baeldung/script/SqlScriptBatchExecutorUnitTest.java @@ -0,0 +1,47 @@ +package com.baeldung.script; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +public class SqlScriptBatchExecutorUnitTest { + private static final Log logger = LogFactory.getLog(SqlScriptBatchExecutorUnitTest.class); + private static Connection connection = null; + private static final String JDBC_URL = "jdbc:h2:mem:testdb3"; + private static final String USERNAME = "user"; + private static final String PASSWORD = "password"; + + @Before + public void prepareConnection() throws Exception { + connection = DriverManager.getConnection(JDBC_URL, USERNAME, PASSWORD); + } + + @AfterAll + public static void closeConnection() throws Exception { + connection.close(); + } + + @Test + public void givenConnectionObject_whenSQLFile_thenExecute() throws Exception { + String path = new File(ClassLoader.getSystemClassLoader() + .getResource("employee.sql").getFile()).toPath().toString(); + SqlScriptBatchExecutor.executeBatchedSQL(path, connection, 10); + Statement statement = connection.createStatement(); + ResultSet resultSet = statement.executeQuery("SELECT COUNT(1) FROM employees"); + + if (resultSet.next()) { + int count = resultSet.getInt(1); + Assert.assertEquals("Incorrect number of records inserted", 20, count); + } + } + +} diff --git a/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql new file mode 100644 index 0000000000..c532458163 --- /dev/null +++ b/persistence-modules/core-java-persistence-2/src/test/resources/employee.sql @@ -0,0 +1,75 @@ +/** +Script Name : Create employees script +Author: Parthiv Pradhan + +**/ + +-- Create the employees table if it doesn't exist +CREATE TABLE employees ( + id INT PRIMARY KEY, + first_name VARCHAR(50), + last_name VARCHAR(50), + department VARCHAR(50), + salary DECIMAL(10, 2) +); + +-- Insert employee records +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (1, 'John', 'Doe', 'HR', 50000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (2, 'Jane', 'Smith', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (3, 'Michael', 'Johnson', 'Finance', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (4, 'Emily', 'Williams', 'Marketing', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (5, 'David', 'Brown', 'IT', 65000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (6, 'Sarah', 'Miller', 'Finance', 58000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (7, 'Robert', 'Jones', 'HR', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (8, 'Jessica', 'Davis', 'Marketing', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (9, 'William', 'Wilson', 'IT', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (10, 'Jennifer', 'Taylor', 'Finance', 57000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (11, 'Daniel', 'Anderson', 'Marketing', 54000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (12, 'Linda', 'Martinez', 'HR', 52000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (13, 'Christopher', 'Lopez', 'IT', 62000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (14, 'Karen', 'Hernandez', 'Finance', 56000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (15, 'Mark', 'Garcia', 'Marketing', 53000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (16, 'Patricia', 'Lee', 'HR', 51000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (17, 'Anthony', 'Clark', 'IT', 60000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (18, 'Maria', 'Lewis', 'Finance', 59000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (19, 'Paul', 'Walker', 'Marketing', 55000.00); + +INSERT INTO employees (id, first_name, last_name, department, salary) +VALUES (20, 'Ruth', 'Young', 'HR', 54000.00);