Je souhaite exécuter un fichier de script SQL en Java sans lire le contenu complet du fichier dans une requête volumineuse ni l'exécuter.
Existe-t-il un autre moyen standard?
Il n'y a pas de moyen portable de le faire. Vous pouvez exécuter un client natif en tant que programme externe, mais:
import Java.io.*;
public class CmdExec {
public static void main(String argv[]) {
try {
String line;
Process p = Runtime.getRuntime().exec
("psql -U username -d dbname -h serverhost -f scripfile.sql");
BufferedReader input =
new BufferedReader
(new InputStreamReader(p.getInputStream()));
while ((line = input.readLine()) != null) {
System.out.println(line);
}
input.close();
}
catch (Exception err) {
err.printStackTrace();
}
}
}
Il existe un excellent moyen d’exécuter des scripts SQL à partir de Java sans les lire vous-même, tant que vous n’aurez pas une dépendance à ant A mon avis, une telle dépendance est très bien justifiée dans votre cas. Voici un exemple de code dans lequel la classe SQLExec réside dans ant.jar:
private void executeSql(String sqlFilePath) {
final class SqlExecuter extends SQLExec {
public SqlExecuter() {
Project project = new Project();
project.init();
setProject(project);
setTaskType("sql");
setTaskName("sql");
}
}
SqlExecuter executer = new SqlExecuter();
executer.setSrc(new File(sqlFilePath));
executer.setDriver(args.getDriver());
executer.setPassword(args.getPwd());
executer.setUserid(args.getUser());
executer.setUrl(args.getUrl());
executer.execute();
}
Non, vous devez lire le fichier, le diviser en plusieurs requêtes, puis les exécuter individuellement (ou à l'aide de l'API de traitement par lots de JDBC).
Une des raisons est que chaque base de données définit sa propre manière de séparer les instructions SQL (certaines utilisent ;
, d'autres /
, certaines autorisent les deux ou même de définir votre propre séparateur).
La bibliothèque Flyway est vraiment bonne pour cela:
Flyway flyway = new Flyway();
flyway.setDataSource(dbConfig.getUrl(), dbConfig.getUsername(), dbConfig.getPassword());
flyway.setLocations("classpath:db/scripts");
flyway.clean();
flyway.migrate();
Cette analyse les emplacements pour les scripts et les exécute dans l'ordre. Les scripts peuvent être versionnés avec V01__name.sql. Ainsi, si seul le migrate est appelé, seuls ceux qui ne sont pas encore exécutés seront exécutés. Utilise une table appelée 'schema_version' pour garder la trace des choses. Mais vous pouvez aussi faire d’autres choses, voir la documentation: flyway .
L'appel de nettoyage n'est pas obligatoire, mais il est utile de démarrer à partir d'une base de données vierge . on m'a attrapé.
Vous ne pouvez pas utiliser JDBC car il ne supporte pas. La solution consiste à inclure iBatis iBATIS est un cadre de persistance et appelle le constructeur Scriptrunner
comme indiqué dans iBatis documentation.
Il n’est pas bon d’inclure un cadre de persistance très lourd comme ibatis afin d’exécuter un simple script SQL de toutes les manières possibles en utilisant la ligne de commande.
$ mysql -u root -p db_name < test.sql
JDBC ne prenant pas en charge cette option, le meilleur moyen de résoudre ce problème consiste à exécuter des lignes de commande via le programme Java. Ci-dessous, un exemple pour postgresql:
private void executeSqlFile() {
try {
Runtime rt = Runtime.getRuntime();
String executeSqlCommand = "psql -U (user) -h (domain) -f (script_name) (dbName)";
Process pr = rt.exec();
int exitVal = pr.waitFor();
System.out.println("Exited with error code " + exitVal);
} catch (Exception e) {
System.out.println(e.toString());
}
}
L’outil externe le plus simple que j’ai trouvé qui soit également portable est jisql - https://www.xigole.com/software/jisql/jisql.jsp . Vous l’exécuteriez de la manière suivante:
Java -classpath lib/jisql.jar:\
lib/jopt-simple-3.2.jar:\
lib/javacsv.jar:\
/home/scott/postgresql/postgresql-8.4-701.jdbc4.jar
com.xigole.util.sql.Jisql -user scott -password blah \
-driver postgresql \
-cstring jdbc:postgresql://localhost:5432/scott -c \; \
-query "select * from test;"
JDBC ne prend pas en charge cette option (bien qu'un pilote de base de données puisse l'offrir) . Quoi qu'il en soit, le chargement de tout le contenu du fichier en mémoire ne devrait pas poser de problème.
Essayez ce code:
String strProc =
"DECLARE \n" +
" sys_date DATE;"+
"" +
"BEGIN\n" +
"" +
" SELECT SYSDATE INTO sys_date FROM dual;\n" +
"" +
"END;\n";
try{
DriverManager.registerDriver ( new Oracle.jdbc.driver.OracleDriver () );
Connection connection = DriverManager.getConnection ("jdbc:Oracle:thin:@your_db_IP:1521:your_db_SID","user","password");
PreparedStatement psProcToexecute = connection.prepareStatement(strProc);
psProcToexecute.execute();
}catch (Exception e) {
System.out.println(e.toString());
}