Process的使用

前言

目前需要做一个功能,就是通过java进行mysqldump备份,但是mysql时运行在容器中的时候,
已知Java目前只有一个Runtime.getRuntime()一种方式能获得当前linux运行时环境的方式
所以接下来就是通过这个方式实现这个功能

遇到的问题一:process.waitFor()一直阻塞不返回

代码:
下面是实现代码:

public void backup(HttpServletResponse reponse){
   BufferedReader reader;
   try{
       String  cmdStr = "docker exec mysql sh -c 'mysqldump -h 127.0.0.1 -uroot -p123456 database --ser-charset=UTF-8'";
       // 回去结果
       int exitCode=process.waitFor();
       Process exec = Runtime.getRuntime.exec(cmdStr);
       reader=new BufferedReader(new InputStreamReader(process.getInputStream())); 
       String line=null;  
       while((line=reader.readLine())!=null){  
              System.out.println(line);  
       }     
       if (exitCode != 0){
          log.error("错误")
       }
   }
  
}

原因:

process.waitFor()方法和exitValue()方法很像,
但是exitValue()是直接获得一个返回结果,但是有可能命令还在执行中,因此结果不一定正确;
而waitFor()方法是等待进程结束后才会有返回值。

因此waitfor方法是会被阻塞的,同时因为因为输入和输出流提供有限的缓冲区大小,如果读写子进程的输出流或输入流出现失败,当缓冲区满之后将无法继续写入数据,则可能导致子进程阻塞

因此我们需要不断的将缓冲区的内容读取出来就了以防止阻塞,所以process.waitFor()应该换个位置

改进代码如下:

public void backup(HttpServletResponse reponse){
   BufferedReader reader;
   try{
       String  cmdStr = "docker exec mysql sh -c 'mysqldump -h 127.0.0.1 -uroot -p123456 database --ser-charset=UTF-8'";
       Process exec = Runtime.getRuntime.exec(cmdStr);
       reader=new BufferedReader(new InputStreamReader(process.getInputStream())); 
       String line=null;  
       while((line=reader.readLine())!=null){  
              System.out.println(line);  
       }    
       // 回去结果
       int exitCode=process.waitFor(); 
       if (exitCode != 0){
          log.error("错误")
       }
   }
  
}

遇到的问题二:process.waitFor()返回值为127

查明原因127对应的应该是没有环境导致的,
因此在使用Process 的过程中推荐使用绝对路径,就算docker也一样

代码改进如下:

public void backup(HttpServletResponse reponse){
   BufferedReader reader;
   try{
       String  cmdStr = "/usr/bin/docker exec mysql sh -c 'mysqldump -h 127.0.0.1 -uroot -p123456 database --ser-charset=UTF-8'";
       Process exec = Runtime.getRuntime.exec(cmdStr);
       reader=new BufferedReader(new InputStreamReader(process.getInputStream())); 
       String line=null;  
       while((line=reader.readLine())!=null){  
              System.out.println(line);  
       }    
       // 回去结果
       int exitCode=process.waitFor(); 
       if (exitCode != 0){
          log.error("错误")
       }
   }
  
}

遇到的问题三:process.waitFor()返回值为1

返回值为1的原因大概是因为执行的语句有问题,但是我将该语句放到linux环境中执行却能过得到正常结果

后面简单的百度一下并且看了一下源码:
发现Runtime.exec()是存在两种字符参数的
分别是:

  • 1、Runtime.exec(String command)
  • 2、Runtime.exec(String[] cmdarray)

但是第1种方法的本质是Runtime.exec(command.split(" "))
看下代码,可以见到我们通过linux执行docker命令,在通过docker 执行容器命令,简单的空格已经不能支持这么复杂的逻辑了,其实一些包含特殊字符的也不能进行执行,所以我们需要使用第二种方式,手动将命令分层

改进代码如下:

public void backup(HttpServletResponse reponse){
   BufferedReader reader;
   try{
       //String  cmdStr = " mysqldump -h 127.0.0.1 -uroot -p123456 database --ser-charset=UTF-8";
       //String  cmdStr = "docker exec mysql sh -c 'mysqldump -h 127.0.0.1 -uroot -p123456 database --ser-charset=UTF-8'";
       String[] cmdStr = {"/usr/bin/docker","exec","mysql","sh","-c","/usr/bin/mysqldump -h 127.0.0.1 -uroot -p123456 database --ser-charset=UTF-8"}
       Process exec = Runtime.getRuntime.exec(cmdStr);
       reader=new BufferedReader(new InputStreamReader(process.getInputStream())); 
       String line=null;  
       while((line=reader.readLine())!=null){  
              System.out.println(line);  
       }     
       int exitCode=process.waitFor();
       if (exitCode != 0){
          log.error("错误")
       }
   }
  
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值