Execute SQL file from Spring JDBC Template
Asked Answered
C

5

30

I'm trying to write a bit of code that reads a SQL file (multiple CREATE TABLE statements separated by ;) and executes all the statements.

In pure JDBC, I could write:

String sqlQuery = "CREATE TABLE A (...); CREATE TABLE B (...);"
java.sql.Connection connection = ...;
Statement statement = connection.createStatement();
statement.executeUpdate(sqlQuery);
statement.close();

and both (all) the statements got executed. When I tried to do the same in spring JdbcTemplate, only the first statement is executed though!

String sqlQuery = "CREATE TABLE A (...); CREATE TABLE B (...);"
org.springframework.jdbc.core.JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute(sqlQuery);

Is there a way to execute multiple statements? While googling I found only solutions like "split the sqlQuery by ; manually" which of course is useless (it'd require much more parsing).

Crider answered 9/6, 2015 at 12:40 Comment(0)
T
27

Maybe Spring's ScriptUtils will be useful in your case. Especially executeSqlScript methods.

Note that DEFAULT_STATEMENT_SEPARATOR has a default value of ';' (see Constant Field Values)

Tabbie answered 9/6, 2015 at 12:48 Comment(6)
it seems to work. Does remove comments though (which SQLite can keep as description for columns), but that does not worry me now that much.Crider
Are there any ways to get number of rows changed using this executeSqlScript() method?Cerebroside
executeSqlScript are now deprecated. Any alternative?Movable
@Movable usually deprecated methods have a hint on what to use instead in their JavaDoc. However, I don't see any deprecation info even on the latest ScriptUtils. Are you looking at a different class?Mcmillian
@DarioSeidl yes true. The deprecation started with spring Spring 4.0.3 in favor of using springframework.jdbc.datasource.init.ResourceDatabasePopulatorMovable
@Movable may be referring to the indeed deprecated executeSQLScript methods provided by JdbcTestUtils, not the ScriptUtils.executeSQLScript() that (along with ResourceDatabasePopulator) is suggested as its replacement.Booklover
C
28

I've solved the issue this way:

public void createDefaultDB(DataSource dataSource) {
    Resource resource = new ClassPathResource("CreateDefaultDB.sql");
    ResourceDatabasePopulator databasePopulator = new ResourceDatabasePopulator(resource);
    databasePopulator.execute(dataSource);
}

You can inject DataSource as usual:

import javax.sql.DataSource;
//...
@Autowired
private DataSource dataSource;
Cooperative answered 9/8, 2015 at 11:28 Comment(0)
T
27

Maybe Spring's ScriptUtils will be useful in your case. Especially executeSqlScript methods.

Note that DEFAULT_STATEMENT_SEPARATOR has a default value of ';' (see Constant Field Values)

Tabbie answered 9/6, 2015 at 12:48 Comment(6)
it seems to work. Does remove comments though (which SQLite can keep as description for columns), but that does not worry me now that much.Crider
Are there any ways to get number of rows changed using this executeSqlScript() method?Cerebroside
executeSqlScript are now deprecated. Any alternative?Movable
@Movable usually deprecated methods have a hint on what to use instead in their JavaDoc. However, I don't see any deprecation info even on the latest ScriptUtils. Are you looking at a different class?Mcmillian
@DarioSeidl yes true. The deprecation started with spring Spring 4.0.3 in favor of using springframework.jdbc.datasource.init.ResourceDatabasePopulatorMovable
@Movable may be referring to the indeed deprecated executeSQLScript methods provided by JdbcTestUtils, not the ScriptUtils.executeSQLScript() that (along with ResourceDatabasePopulator) is suggested as its replacement.Booklover
G
11

try it

public void executeSqlScript(Connection connection,StringBuffer sql)throws SQLException{
         try {
             connection.setAutoCommit(false);//disable auto commit
             ScriptUtils.executeSqlScript(connection, new ByteArrayResource(sql.toString().getBytes()));
             connection.commit();//commit manually 
        } catch (SQLException e) {
            connection.rollback();
        }finally{
            connection.close();
        }
     }
Gao answered 21/12, 2016 at 3:35 Comment(0)
P
0

We can also achive through SQLExec. Below code is working for me.

import java.io.File;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.SQLExec;

public class Test {

    public static void main(String[] args) {
        Test t = new Test();
        t.executeSql("");
    }

    private void executeSql(String sqlFilePath) {
        final class SqlExecuter extends SQLExec {
            public SqlExecuter() {
                Project project = new Project();
                project.init();
                setProject(project);
                setTaskType("sql");
                setTaskName("sql");
            }
        }

        SqlExecuter executer = new SqlExecuter();
        executer.setSrc(new File("test1.sql"));
        executer.setDriver("org.postgresql.Driver");
        executer.setPassword("postgres");
        executer.setUserid("postgres");
        executer.setUrl("jdbc:postgresql://localhost/test");
        executer.execute();
    }
}
Procession answered 13/4, 2016 at 10:55 Comment(0)
O
0

I was looking for a similar option for my project's case then I did stumble upon the following https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/init/ResourceDatabasePopulator.html

The provided Stackoverflow example is really neat and simple, if you want the Spring to handle the boilerplate sql handling on your behalf https://mcmap.net/q/101464/-how-to-execute-sql-insert-queries-to-populate-database-during-application-start-load

Odell answered 22/2, 2021 at 12:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.