2008-10-14 38 views
9

tengo un conjunto de scripts sql que deberían actualizar la base de datos cuando se inicia la aplicación web java.ejecute el script sql de Oracle desde java

intenté usar el scriptrunner ibatis, pero falla gloriosamente al definir desencadenadores, donde el ";" el personaje no marca un final de declaración.

ahora he escrito mi propia versión de un script runner, que básicamente hace el trabajo, pero destruye posibles formatos y comentarios, especialmente en "crear o reemplazar vista".

public class ScriptRunner { 
private final DataSource ds; 


public ScriptRunner(DataSource ds) { 
    this.ds = ds; 
} 

public void run(InputStream sqlStream) throws SQLException, IOException { 
    sqlStream.reset(); 
    final Statement statement = ds.getConnection().createStatement(); 
    List<String> sqlFragments = createSqlfragments(sqlStream); 
    for (String toRun : sqlFragments) { 
     if (toRun.length() > 0) { 
      statement.execute(toRun); 
     } 
    } 
} 

private static List<String> createSqlfragments(InputStream sqlStream) throws IOException { 
    BufferedReader br = new BufferedReader(new InputStreamReader(sqlStream)); 

    List<String> ret = new ArrayList<String>(); 
    String line; 
    StringBuilder script = new StringBuilder(); 
    while ((line = br.readLine()) != null) { 
     if (line.equals("/")) { 
      ret.add(removeMultilineComments(script)); 
      script = new StringBuilder(); 
     } else { 
      //strip comments 
      final int indexComment = line.indexOf("--"); 
      String lineWithoutComments = (indexComment != -1) ? line.substring(0, indexComment) : line; 
      script.append(lineWithoutComments).append(" "); 
     } 
    } 
    if (script.length() > 0) { 
     ret.add(removeMultilineComments(script)); 
    } 
    return ret; 
} 

private static String removeMultilineComments(StringBuilder script) { 
    return script.toString().replaceAll("/\\*(.*?)\\*/", "").trim(); 
} 

¿hay alguna manera limpia de conseguir esto? ¿Hay algo en Hibernate que no haya visto? o puedo pasar un inputstream a sqlplus de alguna manera? además de mis preocupaciones sobre el formateo, dudo que este código esté libre de errores, ya que tengo conocimiento limitado sobre la sintaxis pl/sql.

Respuesta

2

sqlplus: si se puede. Ejecuto sqlplus desde Xemacs (editor) todo el tiempo. Entonces, puede ejecutar sqlplus en un modo interpretado y luego proporcionarle comandos y leer la salida también.

Otra forma es descargar la herramienta de desarrollador de SQL basada en java desde Oracle (http://www.oracle.com/technology/software/products/sql/index.html). viene con una utilidad sqlcli.bat que es un contenedor sobre un programa Java. Es posible que desee utilizar esta utilidad de línea de comandos para hacer su trabajo.

resumen, intentaría ejecutar sqlplus en segundo plano y proporcionar su entrada y leer su salida (como lo hace emacs).

4

iBATIS ScriptRunner tiene un método setDelimiter(String, boolean). Esto le permite tener una cadena que no sea ";" ser el separador entre las declaraciones SQL.

En su secuencia de comandos Oracle SQL, separe las declaraciones con un "/" (barra inclinada).

En su código Java, antes de llamar al runScript, realice un setDelimter("/", false) que le indicará al ScriptRunner que reconozca "/" como separador de instrucciones.

+0

Estoy usando ibatis-common-2.jar y no he encontrado setDelimiter (String , boolean) method, ¿Qué versión de iBatis estás usando? –

7

Utilice la siguiente solución como referencia, la probé y ejecuté con éxito.

private static String script_location = ""; 
private static String file_extension = ".sql"; 
private static ProcessBuilder processBuilder =null; 

public static void main(String[] args) { 
    try { 
     File file = new File("C:/Script_folder"); 
     File [] list_files= file.listFiles(new FileFilter() { 

      public boolean accept(File f) { 
       if (f.getName().toLowerCase().endsWith(file_extension)) 
        return true; 
       return false; 
      } 
     }); 
     for (int i = 0; i<list_files.length;i++){ 
      script_location = "@" + list_files[i].getAbsolutePath();//ORACLE 
      processBuilder = new ProcessBuilder("sqlplus",  "UserName/[email protected]_name", script_location); //ORACLE 
      //script_location = "-i" + list_files[i].getAbsolutePath(); 
      // processBuilder = new ProcessBuilder("sqlplus", "-Udeep-Pdumbhead-Spc-de-deep\\sqlexpress-de_com",script_location); 
      processBuilder.redirectErrorStream(true); 
      Process process = processBuilder.start(); 
      BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream())); 
      String currentLine = null; 
      while ((currentLine = in.readLine()) != null) { 
       System.out.println(" " + currentLine); 
      } 
     } 
    } catch (IOException e) { 
     e.printStackTrace(); 
    }catch(Exception ex){ 
     ex.printStackTrace(); 
    } 
} 

Utilice este código de fragmento e intente y ejecute.

Gracias al usuario menciona la solución en el siguiente enlace:

http://forums.sun.com/thread.jspa?threadID=5413026

Saludos | Nitin

+1

esto parece una buena alternativa :) gracias por compartir –

3

tenía el mismo problema no hace mucho tiempo, tropezó con su pregunta varias veces mientras buscando en Google para una solución, por lo que creo que te-aquí debo son mis resultados hasta ahora:

En resumen, no hay soluciones listas para ello: si abre o AntMaven fuentes, verá que están utilizando un simple divisor de script basado en expresiones regulares que está bien para scripts simples, pero por lo general se produce un error en el ejemplo procedimientos almacenados. La misma historia con iBATIS, c5 migraciones de db, etc.

El problema es que hay más de un lenguaje involucrado: para ejecutar "SQL Scripts" uno debe ser capaz de manejar (1) SQL, (2) PL/SQL y (3) comandos sqlplus.

corriendo sqlplus en sí es la forma de hecho, sino que crea desorden configuración, así que tratamos de evitar esta opción.

Hay analizadores ANTLR para PL/SQL, como Alexandre Porcelli's one, que están muy cerca, pero nadie preparó una solución integral completa basada en esos hasta ahora.

Terminamos escribiendo yet another ad hoc splitter que es consciente de algunos comandos sqlplus como / y EXIT - sigue siendo feo, pero funciona para la mayoría de nuestros scripts. (Tenga en cuenta que algunos scripts, por ejemplo, con los comentarios finales --, no funcionarán, sigue siendo un kludge, no una solución.)

Cuestiones relacionadas