使用MyBatis的ScriptRunner执行sql文件

原创 2015年11月17日 17:37:40

利用MyBatis的ScriptRunner执行sql文件

使用原因

我的需求是ORACLE数据库.
在执行sql文件的时候可以把文件内容复制到工具里面执行,比如plsql里面,
在语句比较少或者数据比较少的情况下在PLSQL里面执行还是比较快的.
但是当数据比较多的时候执行就会让PLSQ卡死 出现无响应的情况.

所以需要使用到java代码来执行sql文件,这样速度比较快也不会出现上述所说的问题.

为什么选择scriptRunner?

在网上搜索方法,分别有三种方法:

  • 纯java代码引用文件流的方式
  • ibatis方式执行脚本(scriptRunner)
  • ant执行SQL脚本

下面分别列出三种方法的写法:

纯java代码引用文件流的方式

package com.unmi.db;

import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 读取 SQL 脚本并执行
 * @author Unmi
 */
public class SqlFileExecutor {

    /**
     * 读取 SQL 文件,获取 SQL 语句
     * @param sqlFile SQL 脚本文件
     * @return List<sql> 返回所有 SQL 语句的 List
     * @throws Exception
     */
    private List<String> loadSql(String sqlFile) throws Exception {
        List<String> sqlList = new ArrayList<String>();

        try {
            InputStream sqlFileIn = new FileInputStream(sqlFile);

            StringBuffer sqlSb = new StringBuffer();
            byte[] buff = new byte[1024];
            int byteRead = 0;
            while ((byteRead = sqlFileIn.read(buff)) != -1) {
                sqlSb.append(new String(buff, 0, byteRead));
            }

            // Windows 下换行是 /r/n, Linux 下是 /n
            String[] sqlArr = sqlSb.toString().split("(;//s*//r//n)|(;//s*//n)");
            for (int i = 0; i < sqlArr.length; i++) {
                String sql = sqlArr[i].replaceAll("--.*", "").trim();
                if (!sql.equals("")) {
                    sqlList.add(sql);
                }
            }
            return sqlList;
        } catch (Exception ex) {
            throw new Exception(ex.getMessage());
        }
    } 

    /**
     * 传入连接来执行 SQL 脚本文件,这样可与其外的数据库操作同处一个事物中
     * @param conn 传入数据库连接
     * @param sqlFile SQL 脚本文件
     * @throws Exception
     */
    public void execute(Connection conn, String sqlFile) throws Exception {
        Statement stmt = null;
        List<String> sqlList = loadSql(sqlFile);
        stmt = conn.createStatement();
        for (String sql : sqlList) {
            stmt.addBatch(sql);
        }
        int[] rows = stmt.executeBatch();
        System.out.println("Row count:" + Arrays.toString(rows));
    }

    /**
     * 自建连接,独立事物中执行 SQL 文件
     * @param sqlFile SQL 脚本文件
     * @throws Exception
     */
    public void execute(String sqlFile) throws Exception {
        Connection conn = DBCenter.getConnection();
        Statement stmt = null;
        List<String> sqlList = loadSql(sqlFile);
        try {
            conn.setAutoCommit(false);
            stmt = conn.createStatement();
            for (String sql : sqlList) {
                stmt.addBatch(sql);
            }
            int[] rows = stmt.executeBatch();
            System.out.println("Row count:" + Arrays.toString(rows));
            DBCenter.commit(conn);
        } catch (Exception ex) {
            DBCenter.rollback(conn);
            throw ex;
        } finally {
            DBCenter.close(null, stmt, conn);
        }
    }

    public static void main(String[] args) throws Exception {
        List<String> sqlList = new SqlFileExecutor().loadSql(args[0]);
        System.out.println("size:" + sqlList.size());
        for (String sql : sqlList) {
            System.out.println(sql);
        }
    }
}

此方法的缺点是分割的考虑比较麻烦


ant执行SQL脚本

package com.unmi;   
import java.io.*;   
import org.apache.tools.ant.*;   
import org.apache.tools.ant.taskdefs.*;   
import org.apache.tools.ant.types.*;  
/**  
* 调用 ant.jar 的 SQLExec 执行 SQL 脚本文件  
* @author Unmi  
*/  
public class AntExecSql {  
/**  
* @param args  
*/  
public static void main(String[] args) {   
SQLExec sqlExec = new SQLExec();   
//设置数据库参数   
sqlExec.setDriver("oracle.jdbc.driver.OracleDriver");   
sqlExec.setUrl("jdbc:oracle:thin:@10.128.x.x:1521:xxsid");  
sqlExec.setUserid("xxuser");   
sqlExec.setPassword("xxpass");   
//要执行的脚本   
sqlExec.setSrc(new File("src/data.sql"));  
//有出错的语句该如何处理   
sqlExec.setOnerror((SQLExec.OnError)(EnumeratedAttribute.getInstance(   
SQLExec.OnError.class, "abort")));  
sqlExec.setPrint(true); //设置是否输出  
//输出到文件 sql.out 中;不设置该属性,默认输出到控制台   
sqlExec.setOutput(new File("src/sql.out"));   
sqlExec.setProject(new Project()); // 要指定这个属性,不然会出错   
sqlExec.execute();   
}   
}  
package com.unmi;
import java.io.*;
import org.apache.tools.ant.*;
import org.apache.tools.ant.taskdefs.*;
import org.apache.tools.ant.types.*;
/**
* 调用 ant.jar 的 SQLExec 执行 SQL 脚本文件
* @author Unmi
*/
public class AntExecSql {
/**
* @param args
*/
public static void main(String[] args) {
SQLExec sqlExec = new SQLExec();
//设置数据库参数
sqlExec.setDriver("oracle.jdbc.driver.OracleDriver");
sqlExec.setUrl("jdbc:oracle:thin:@10.128.x.x:1521:xxsid");
sqlExec.setUserid("xxuser");
sqlExec.setPassword("xxpass");
//要执行的脚本
sqlExec.setSrc(new File("src/data.sql"));
//有出错的语句该如何处理
sqlExec.setOnerror((SQLExec.OnError)(EnumeratedAttribute.getInstance(
SQLExec.OnError.class, "abort")));
sqlExec.setPrint(true); //设置是否输出
//输出到文件 sql.out 中;不设置该属性,默认输出到控制台
sqlExec.setOutput(new File("src/sql.out"));
sqlExec.setProject(new Project()); // 要指定这个属性,不然会出错
sqlExec.execute();
}
}

此方法我测试过,只要有一句语句报错,就整个文件不执行,rollback,这种方式在执行多个文件的是不方便.希望有错误的能忽略把正确的导入.


ibatis方式执行脚本(scriptRunner)

package cn.zb.java8.utils;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;

import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DriverManager;

public class ScriptRunnerExecSql {

    public static void main(String[] args) {
        try {
            Configuration configuration = new PropertiesConfiguration(ScriptRunnerExecSql.class.getClassLoader().getResource("")
                    + "META-INF/spring/db.properties");
            String url = configuration.getString("jdbc.url");
            String driver = configuration.getString("jdbc.driver");
            String username = configuration.getString("jdbc.user");
            String password = configuration.getString("jdbc.password");

            Class.forName(driver).newInstance();
            Connection conn =DriverManager.getConnection(url, username, password);
            ScriptRunner runner = new ScriptRunner(conn);
            Resources.setCharset(Charset.forName("GBK")); //设置字符集,不然中文乱码插入错误
            runner.setLogWriter(null);//设置是否输出日志
            runner.runScript(Resources.getResourceAsReader("sql/CC20-01.sql"));
            runner.runScript(Resources.getResourceAsReader("sql/CC21-01.sql"));
            runner.closeConnection();
            conn.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    }

这种方式就是我现在使用的方式,可以同时执行多个文件.遇到错误会忽略而且还能继续执行.

使用 ibatis方式执行脚本(scriptRunner)需要的步骤

  • 首先需要下载mybatis包
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>

读取配置文件的话可以使用commons包

        <dependency>
            <groupId>commons-configuration</groupId>
            <artifactId>commons-configuration</artifactId>
            <version>1.8</version>
        </dependency>
  • 添加数据库驱动

    • oracle

          <dependency>
              <groupId>com.oracle</groupId>
              <artifactId>ojdbc14</artifactId>
              <version>10.2.0.4.0</version>
          </dependency>
    • mysql

          <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.35</version>
          </dependency>
  • 配置文件

jdbc.driver     =   oracle.jdbc.driver.OracleDriver
jdbc.url        =   jdbc:oracle:thin:@ \
                      (DESCRIPTION =\
                        (ADDRESS_LIST =\
                          (ADDRESS = (PROTOCOL = TCP)(HOST = xxx.xxx.xxx.xxx)(PORT = 1521))\
                        )\
                        (CONNECT_DATA =\
                          (SID = xxx)\
                          (SERVER = DEDICATED)\
                        )\
                      )
jdbc.user       =   xxxx
jdbc.password   =   xxxx
  • 复制下面的代码:
package cn.zb.java8.utils;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.jdbc.ScriptRunner;

import java.nio.charset.Charset;
import java.sql.Connection;
import java.sql.DriverManager;

public class ScriptRunnerExecSql {

    public static void main(String[] args) {
        try {
            Configuration configuration = new PropertiesConfiguration(ScriptRunnerExecSql.class.getClassLoader().getResource("")
                    + "META-INF/spring/db.properties");
            String url = configuration.getString("jdbc.url");
            String driver = configuration.getString("jdbc.driver");
            String username = configuration.getString("jdbc.user");
            String password = configuration.getString("jdbc.password");

            Class.forName(driver).newInstance();
            Connection conn =DriverManager.getConnection(url, username, password);
            ScriptRunner runner = new ScriptRunner(conn);
            Resources.setCharset(Charset.forName("GBK")); //设置字符集,不然中文乱码插入错误
            runner.setLogWriter(null);//设置是否输出日志
            runner.runScript(Resources.getResourceAsReader("sql/CC20-01.sql"));
            runner.runScript(Resources.getResourceAsReader("sql/CC21-01.sql"));
            runner.closeConnection();
            conn.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    }

最后编译运行就OK了.

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

mybatis 一次执行多条SQL

原文出处 感谢作者: http://rhodian.iteye.com/blog/1930891 mybatis+mysql如何批量执行多条语句 博客分类:  myb...

用ibatis的ScriptRunner执行sql程序 ,失效

用ibatis的ScriptRunner执行sql程序后, runner.setAutoCommit(true); runner.setSendFullScript(true); runner.run...

使用mybatis的ScriptRunner执行sql文件

最近有需要通过java执行sql文件(进行数据库、表的创建),使用的mybatis的ScriptRunner工具类,现在记录下。     pom.xml主要jar org.mybatis...

MyBATIS中的插件原理和应用

如果你不懂反射和动态代理请参考我的博文:http://blog.csdn.net/ykzhen2015/article/details/50312651 这是本文的基础,请先掌握它,否则下面内容的将...

Mybatis最入门---Mapper文件配置详解(上)

[一步是咫尺,一步即天涯] 前文中,我们演示了最基本的HelloWorld程序,下面我们将介绍我们上面各项配置文件的详细解释,以及我们正式开发过程中,各种配置的注意事项等。 惯例,先来看看我们的准...

Mybatis最入门---分页查询(内部原理篇)

[一步是咫尺,一步即天涯] 本文的内容将作为前面我们叙述的内容的内部原理篇的解释,希望各位读者能够仔细理解本篇的内容,下一篇,我们将详细的介绍如何实现一个生产环境下的分页查询,好了,马上开始我们的正文...

深入浅出Mybatis-分页

Mybatis的分页功能很弱,它是基于内存的分页(查出所有记录再按偏移量和limit取结果),在大数据量的情况下这样的分页基本上是没有用的。本文基于插件,通过拦截StatementHandler重写s...

Mybatis插件原理分析(三)分页插件

在Mybatis中插件最经常使用的是作为分页插件,接下来我们通过实现Interceptor来完成一个分页插件。 虽然Mybatis也提供了分页操作,通过在sqlSession的接口函数中设置RowBo...

Mybatis逻辑分页原理解析RowBounds

Mybatis提供了一个简单的逻辑分页使用类RowBounds,在DefaultSqlSession提供的某些查询接口中我们可以看到RowBounds是作为参数用来进行分页的,如下接口: publi...

IDEA中MyBatis Migrations Maven plugin 使用总结

MyBatis/migrations-maven-plugin( 下载地址 下文简称migrations)是一个开源的用于DB版本控制的命令行插件
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)