.sql文件导入显示进度条

导入.sql文件显示进度条

业务以及问题描述:要将.sql文件进行上传并导入到数据库中。使用ScriptRunner的runScript方法。封装好的方法没办法获取执行的次数就没办法算百分比。

开始的思路是计算大文件上传的进度条,但是后来想到实际上占用时间比较久的是sql导入执行的过程。怎么把这两个进度一起进行合并计算执行进度就是个比较大的问题了。

将重点放在runScript方法,runScript有两种执行方法,一种是sendFullScript为true的将会执行executeFullScript方法,另为executeLineByLine。

  public void runScript(Reader reader) {
    setAutoCommit();

    try {
      if (sendFullScript) {
        executeFullScript(reader);
      } else {
        executeLineByLine(reader);
      }
    } finally {
      rollbackConnection();
    }
  }

顾名思义,一种是全部一起执行,一种为一行一行的执行。可以查看源代码得知,executeFullScript将每一行进行拼接,传入executeStatement方法。executeLineByLine将读取到的每一行传入到handleLine方法中,底层实现也是通过executeStatement执行。(这里我就不贴源码啦,可以自己去看一下)

说一下实现思路:

骚操作一波,文件上传部分我自己设置了百分之十,剩下百分之九十为sql的导入。创建文件夹设置百分之三到百分之四的随机数,上传文件设置百分之五到百分之六。计算文件行数(为计算sql进度做准备)设置百分之十。

接下来是sql部分:

先说思路,再贴代码。思路很简单,将ScriptRunner的代码copy出来自己改。改executeLineByLine的方法就行。需要传入三个参数:Read read和文件的总行数total,用户主键userAccount(存储进度时候的key值)在读取每一行数据的时候进行累加,将累加的值除以文件总行数total就行。

(用Redis的时候这里遇到个问题,不能注入于是乎自己写了个方法存储)

上传文件代码:

public boolean uploadFile(MultipartFile file, HttpServletRequest request,User user) throws Exception {
        Random random = new Random();
        String f = file.getOriginalFilename();

        //拼接文件名
        String filename = f.substring(f.lastIndexOf("/")+1);
        String id = UUID.randomUUID().toString().replaceAll("_","").substring(0,8);
        String type = filename.substring(filename.lastIndexOf("."));
        String name = filename.substring(0,filename.lastIndexOf("."));
        filename = name+id+type;

        //如果上传的不是sql文件抛出文件错误
        if(!".sql".equals(type)){
            throw new BusinessException(CodeEnum.FILE_ERROR.getCode(),CodeEnum.FILE_ERROR.getMsg());
        }

        //创建文件夹
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
        String nowDate = format.format(new Date());
        String filePath = new File(fileUploadUrl+"/"+nowDate).getAbsolutePath();
        File fileUpload = new File(filePath);

        //在创建文件夹的时候设置百分之三到百分之四的进度
        ProcessUtil.setKey(user.getAccount(),(double) Math.round(3+(random.nextDouble())) / 100);

        //不存在就创建
        if (!fileUpload.exists()) {
            fileUpload.mkdirs();
        }
        fileUpload = new File(filePath, filename);

        //上传文件
        file.transferTo(fileUpload);

        //在文件上传的时候设置百分之5到百分之6的进度
        ProcessUtil.setKey(user.getAccount(),(double) Math.round(5+(random.nextDouble())) / 100);

        //文件路径
        String path = fileUpload.getAbsolutePath();

        //计算文件行数,为sql进度条做准备
        long lineNumber = this.getLineNumber(fileUpload);

        //计算完文件行数之后设置
        ProcessUtil.setKey(user.getAccount(),0.1);

        //sql上传
        boolean flag = this.uploadSql(path,lineNumber,user);

        return flag;
    }

getLineNumber计算文件行数:

private long getLineNumber(File file) {
        if (file.exists()) {
            try {
                FileReader fileReader = new FileReader(file);
                LineNumberReader lineNumberReader = new LineNumberReader(fileReader);
                lineNumberReader.skip(Long.MAX_VALUE);
                long lines = lineNumberReader.getLineNumber() + 1;
                fileReader.close();
                lineNumberReader.close();
                return lines;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return 0;
    }

uploadSql: 执行.sql文件导入数据库

public boolean uploadSql(String path,long lineNumber,User user) throws Exception {
        Class.forName(driverClassName);
        Connection conn = DriverManager.getConnection(url, username, password);

        // 创建ScriptRunner,用于执行SQL脚本
        ScriptRunner runner = new ScriptRunner(conn);
        runner.setErrorLogWriter(null);
        runner.setLogWriter(null);// 执行SQL脚本
        Reader read = new FileReader(new File(path));
        runner.runScript(read,lineNumber,user.getAccount());

        //删除存储的进度条数值
        ProcessUtil.removeKey(user.getAccount());

        // 关闭连接
        conn.close();
        return true;
    }

自己改写的ScriptRunner类(只贴了改的部分,剩下的不变):

public void runScript(Reader reader, long total, String userAccount) {
        setAutoCommit();

        try {
            if (sendFullScript) {
                executeFullScript(reader);
            } else {
                executeLineByLine(reader,total,userAccount);
            }
        } finally {
            rollbackConnection();
        }
    }

    private void executeLineByLine(Reader reader,long total,String userAccount) {
        StringBuilder command = new StringBuilder();
        try {
            double i = 0.0;
            BufferedReader lineReader = new BufferedReader(reader);
            String line;
            while ((line = lineReader.readLine()) != null) {
                handleLine(command, line);
                i++;
                double percent = (i / total) * 0.9;
                BigDecimal bigDecimal = new BigDecimal(percent);
                percent = bigDecimal.setScale(3,BigDecimal.ROUND_HALF_UP).doubleValue();
                double v = new BigDecimal(percent).add(new BigDecimal(0.09)).setScale(3,BigDecimal.ROUND_HALF_UP).doubleValue();
                System.out.println(v);
                ProcessUtil.setKey(userAccount,v);
            }
            commitConnection();
            checkForMissingLineTerminator(command);
            ProcessUtil.setKey(userAccount,1.00);
        } catch (Exception e) {
            String message = "Error executing: " + command + ".  Cause: " + e;
            printlnError(message);
            throw new RuntimeSqlException(message, e);
        }
    }

ProcessUtil类:存储进度条数据

public class ProcessUtil {

    private static Map<String, Double> map = new HashMap<String, Double>();

    public static synchronized Double getKey(String key){
        return map.get(key);
    }

    public static void setKey(String key,Double value){
        map.put(key, value);
    }

    public static synchronized void removeKey(String key){
        if(map.containsKey(key)){
            map.remove(key);
        }
    }
}

基本上业务实现了,本来进度条也只是个大概的时间提示嘛,如果有大佬有将文件上传进度和sql导入进入可以一起计算的方法可以分享~因为实现这种计算方式要额外计算文本行数,多少会有一丢丢影响上传时间。但是没有想到两全其美的办法。

https://blog.csdn.net/qq_42065027/article/details/118387864

  • 14
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 将2G大小的文件导入SQL Server 时,可以按照下面的步骤操作。 1. 首先,确保你有足够的磁盘空间来存储导入文件。检查你的服务器上的磁盘空间,并确保至少有2G的可用空间。 2. 在SQL Server Management Studio中创建一个新的数据库,用于存储导入的数据。 3. 在SQL Server Management Studio中,打开“工具”菜单,并选择“选项”。在“SQL Server Integration Services”下,将“运行时分配内存限制”设置为一个足够大的值,以适应导入过程中的内存需求。 4. 使用SQL Server Management Studio中的“导入和导出数据”向导来导入文件。在向导的源选项中,选择合适的数据源(如File或Flat File)并指定文件路径。在目标选项中,选择创建的数据库以及要导入的表。 5. 在向导的映射选项中,将源文件中的每一列映射到目标表中的对应列。确保映射正确,并根据需要转换数据类型和格式。 6. 在向导的导入操作选项中,可以选择执行某些特定的操作,如创建新表或在导入时删除已存在的数据。根据需要选择适当的操作。 7. 开始导入过程后,等待导入完成。这可能需要一些时间,取决于你的系统性能和文件大小。你可以在导入过程中观察进度条以及可能的错误或警告消息。 8. 导入完成后,可以验证导入的数据是否准确。查询导入的表并检查结果是否与源文件匹配。 导入文件时,可能会遇到性能问题或服务器资源限制。如果导入过程较慢或失败,你可以尝试使用其他方法,如分批导入或使用数据导入工具等。同时,确保服务器的硬件和网络连接状况良好,以获得更好的性能和成功导入文件的机会。 ### 回答2: 要导入2GB的大文件SQL Server,可以按照以下步骤进行操作: 1. 确保数据库有足够的磁盘空间来存储导入文件。检查数据库的磁盘配额,如果需要,可以扩展磁盘空间。 2. 将要导入文件复制到SQL Server所在的服务器上。确保该服务器与数据库服务器之间有良好的网络连接,以便文件可以快速传输。 3. 打开SQL Server Management Studio(SSMS),连接到目标数据库。 4. 在SSMS中,右键点击目标数据库,选择“Tasks”(任务),然后选择“Import Data”(导入数据)。 5. 在“Import and Export Wizard”(导入和导出向导)中,选择“Flat File Source”(扁平文件源),选择要导入文件,并配置文件的格式选项(如分隔符、文本编码等)。 6. 在“Destination”(目标)中,选择SQL Server作为目标数据库,并选择要导入的表或视图。 7. 进一步配置导入选项,例如表之间的映射、数据类型匹配等。 8. 在“Summary”(摘要)页面上,检查所有配置选项,并确保一切设置正确。 9. 单击“Finish”(完成)按钮,开始导入数据。这可能需要一段时间,具体取决于文件的大小和网络速度。 10. 导入完成后,在SSMS中验证数据的正确性。可以执行一些查询或浏览数据来确认导入的准确性和完整性。 在导入文件时,可能会遇到一些挑战,如导入速度较慢、内存不足等。为了处理这些问题,可以考虑使用BULK INSERT命令、调整服务器配置参数以提高导入速度,或者分批导入文件。 总之,导入文件SQL Server需要进行一些准备工作和配置选项,以确保数据的正确导入和存储。 ### 回答3: 要在SQL Server中导入2GB大文件,有几种方法可以选择。 首先,您可以使用SQL Server Management Studio(SSMS)来导入文件。首先,打开SSMS并连接到您的SQL Server实例。然后右键单击您要导入文件数据库,选择“任务”>“导入数据”选项。接下来,按照导入向导的指导,选择文件来源和目标数据库,选择正确的数据源和表,以及选择正确的导入行为。最后,启动导入过程,并等待导入完成。 第二种方法是使用SQL Server Integration Services(SSIS)。通过创建一个SSIS包来导入文件。在Visual Studio中,创建一个新的Integration Services项目,然后添加一个数据流任务。在数据流任务中,设置正确的数据源和目标,配置映射以确保数据正确导入,并设置适当的容错和错误处理机制。最后,构建和部署SSIS包,并执行它来启动导入过程。 另外,您还可以使用BULK INSERT命令来导入文件。打开SQL Server Management Studio,并连接到您的SQL Server实例。然后打开一个新的查询窗口,使用BULK INSERT命令指定正确的数据源和目标表,并设置适当的选项,如字段分隔符、行结束符等。最后,执行该命令并等待导入完成。 无论您选择哪种方法,导入文件可能需要一些时间和资源。因此,在进行导入操作之前,确保您的SQL Server实例有足够的存储空间和性能来处理这个大文件。您也可以考虑将文件拆分成较小的部分,以便更好地管理和导入数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值