【第22期】观点:IT 行业加班,到底有没有价值?

使用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脚本

import org.apache.ibatis.jdbc.ScriptRunner; public static void run(String driver, String url, String...
  • vcshcn
  • vcshcn
  • 2016-02-16 10:33
  • 1335

使用MyBatis的ScriptRunner执行sql文件

利用MyBatis的ScriptRunner执行sql文件 利用MyBatis的ScriptRunner执行sql文件 使用原因为什么选择scriptRunner 纯...

java 执行sql脚本的3种方式 (ant,ibatis,ScriptRunner)

ant:  java执行sql文件这个问题麻烦的地方在于解析sql脚本文件。所幸的是ant与 ibatis提供了这种实现。 package com.unmi;    ...

jira 的scriptrunner操作 例三 例四

继之前的案例

MyBatis直接执行SQL的工具SqlMapper

可能有些人也有过类似需求,一般都会选择使用其他的方式如Spring-JDBC等方式解决。能否通过MyBatis实现这样的功能呢?为了让通用Mapper更彻底的支持多表操作以及更灵活的操作,在2.2.0...

mybatis直接执行sql语句

在项目中,使用的是mybatis3.0.5,但没有采用其提供的DAO层接口映射的策略,而且在进行多种属性联合查找时,需要底层提供通用的解决方案,所以需要mybatis直接执行sql语句,各个daoIm...

Mybatis 直接执行SQL

Mybatis 直接执行SQL好久不更新博客了,今天开发遇到一个问题就是如何在mybatis中直接执行sql,直接上代码: ${sql}//#{sql} 上网查了下,网上的解释是: 使用${}...

MyBatis直接执行SQL查询及批量插入数据

一、直接执行SQL查询:  1、mappers文件节选 resultMap id="AcModelResultMap" type="com.izumi.InstanceModel"> ...

Mybatis工具SqlHelper - 获取Mybatis方法的Sql

如果你想在代码中获取执行的sql

MyBatis 执行动态 SQL

应老婆要求写的这篇博客。大家基本上都知道如何使用 MyBatis 执行任意 SQL,使用方法很简单,例如在一个 XXMapper.xml 中: ${_parameter} 你可以如下调用:sq...
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

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