I have a Filename.sql(Mysql Script) file which has multiple SQL Statements. I'm using MyBatis as persistence framework and MySQL as the database. I want to execute the Filename.sql file in a Java program.
NOTE: I don't want to execute the queries as separate SQL Statements.
This operation is equivalent to source Filename.sql in MySQL command prompt.
you can use org.apache.ibatis.jdbc.ScriptRunner to do this:
ScriptRunner runner = new ScriptRunner(dataSource.getConnection());
runner.setAutoCommit(true);
runner.setStopOnError(true);
runner.runScript(getResourceAsReader("Filename.sql"));
runner.closeConnection();
private void runMysqlScript(String sqlScriptFilePath) {
try {
// Create MySQL Connection
Class.forName(driverClassName);
Connection connection =
DriverManager.getConnection(jdbcURL, jdbcUsername, jdbcPassword);
// Initialize object for ScriptRunner
ScriptRunner runner = new ScriptRunner(connection);
// Give the input file to Reader
Reader br = new BufferedReader(new FileReader(sqlScriptFilePath));
// Execute script
runner.runScript(br);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
As an alternative you can try to use something like liquibase or something similar, which brings you a healthy way of versioning your scripts. In this case you need to convert your .sql-script into the liquibase one. Then you can execute it with Maven plugin or just from Java. It allows you to control the state of your data.
Otherwise, for DML and DQL types of queries you can use the ScriptRunner approach.
Related
Hello there and thanks in advance for any reply,
I'm creating a restful web service and I would like to know:
How to execute a "table exporting query" from eclipse
the query works, it backs up the file, the only problem is it's not being executed for some reason from eclipse
Important to add, I'm using oracle's database express.
in sqlplus: $exp USERID=hr/password TABLES=(hr.students) FILE=exp_tab.dmp
from cmd: sqlplus /as sysdba
$exp USERID=hr/password TABLES=(hr.students) FILE=exp_tab.dmp
The method, where I attempted to execute such query is combined with anotherinsert query
My objective is to backup the table (to a file on a local drive) after every insert
note: Yes, I know I can create a trigger for that.
public static boolean insertUser(int id, String name, String gender, int grade) throws SQLException, Exception {
boolean insertStatus = false;
Connection dbConn = null;
try {
try {
dbConn = DBConnection.createConnection();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Statement stmt_backup = dbConn.createStatement();
Statement stmt = dbConn.createStatement();
String query = "INSERT into students(id, name, gender, grade) " +
"values('"+id+"',"+"'"+name+"','"+gender+"','"+grade+"')";
String query_backup = "$exp USERID=hr/password TABLES=(hr.students) FILE=exp_tab.dmp";
stmt_backup.executeQuery(query_backup);
stmt_backup.close();
//System.out.println(query);
int records = stmt.executeUpdate(query);
//System.out.println(records);
//When record is successfully inserted
if (records > 0) {
insertStatus = true;
}
} catch (SQLException sqle) {
//sqle.printStackTrace();
throw sqle;
} catch (Exception e) {
//e.printStackTrace();
// TODO Auto-generated catch block
if (dbConn != null) {
dbConn.close();
}
throw e;
} finally {
if (dbConn != null) {
dbConn.close();
}
}
return insertStatus;
}
PS: I've tried doing that with one statement , and got the same result.
Also I tried replacing executeQuery(query_backup);
with executeUpdate(Query_backup);
You did well to ask for help. That will save you a lot of time.
First point: You need to understand better what a Java DB connection is done for. In fact, I think, but maybe I am wrong, that your mistake shows a lack of architectural understanding about client / server architecture (DBMS in the present context).
Quick answer: You can only execute SQL statement through a client connection (whatever the technology you use for establishing that connection). So everything is good for your INSERT request but you cannot execute your sqlplus command through your JDBC connection.
Second point: I find a little bit strange for a web service to make a backup of a table. What do you really want to do?
Third point : if you want to execute a command line statement from Java, here is the solution (but in your case I think it is a bad idea):
public class NewClass {
final String userName = "myuser";
final String myPassword = "password";
public NewClass () {
String[] myCommandWithParams=new String[4];
myCommandWithParams[0]="sqlplus";
myCommandWithParams[1]="USERID="+userName+"/"+myPassword;
myCommandWithParams[2]="TABLES=(hr.students)";
myCommandWithParams[3]="FILE=exp_tab.dmp";
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec(myCommandWithParams);
} catch (SecurityException | IOException ex) {
System.err.println("There is a problem for executing the command");
} catch (IndexOutOfBoundsException ex) {
System.err.println("myCommandWithParams can't be empty");
}
}
}
A remark : The Runtime.exec(String[]) doesn't take into account environment variables. If you want to set environment variables, you must use Runtime.exec(String[],String[]).
The second parameter corresponds to the list of environment variables you want to set. The syntax for these strings is "<VARIABLE_NAME>=<VALUE>". But it is easier to put the path of your sqlplus command in myCommandWithParams[0]. It is up to you to see what is best for you. I don't have the context.
I have connection provider class as bleow to return connection.
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws ClassNotFoundException, SQLException {
try (Connection connection = DriverManager
.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
) {
return connection;
}
}
}
Here is main method to call connection provider.
public void Test() {
try {
Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("");
} catch (SQLException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
But "com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: No operations allowed after connection closed." error are always show at below line of code.
PreparedStatement ps = con.prepareStatement("");
Because, according to Oracle documentation, If use try with resources java 7 features, resources are auto close after try block even it's errors occurred or not. So even I returned the connection it's already closed.
Let me know, my usage logic is wrong?
How can I return this connection inside try with resource?
I tried many time googling for solution but does not get convenience answers for me.
Let me know your suggestion and feedback please.
What you can't do...
With a try-with-resources as you have it after you return the connection you return(d) is close(d). You can't return the connection from inside the try with resources.
What you can do...
Pass the connection (inside your try-with-resources) to a method that takes a connection. You can also use a ConnectionPool, and get the Connection when you need it (to create and execute a query).
Let me know, my usage logic is wrong?
The usage of 'try-with-resources' logic is wrong in this context, because the intention of ConnectDB() is to return a connection instance which could be actually used by the caller to send a SQL statement, but instead, the connection instance is getting auto-closed, before it could be used by the caller, because of using 'try-with-resources' construct of Java.
Quick how-to on try-with-resource and JDBC
Your ConnectionProvider's ConnectDB already declares it is throwing SQLException - so no need to catch it in here: (You should consider replacing this code with connection pool maybe)
public class ConnectionProvider {
static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection ConnectDB() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/jspservlet_test","root", "root");
}
}
Instead use try-with-resource in your test-class to clean up your code and focus on errors your SQL code
might have:
public void Test() {
try (Connection con = ConnectionProvider.ConnectDB();
PreparedStatement ps = con.prepareStatement("SELECT 1")) {
//Prepare your Statement
ps.setInt(1, 1);
//And another try-with-resource for the result - note the closing brace
try(ResultSet rs = ps.executeQuery()) {
while(rs.next()) {
//Handle your Result
System.out.println(rs.getString(1));
}
} // This closes try-with-resource. Exception will be rethron to be caught in outer catch!
} catch (SQLException e) {
//SQL is Broken - but only ONE catch to catch them all
e.printStackTrace();
}
}
That way you gain
Better readability for your code (no calls to close surrounded by finally and if != null)
Centralized error handling if anything in your SQL code breaks (so you can focus on functional error of "statement didn't run")
Better code quality: No need to worry about Cursors, Statements, Connections not being propery closed.
I'm trying to connect to my sql database on localhost.
With the following code :
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch(ClassNotFoundException e) {
System.out.println("JdbcOdbcDriver wasn't found");
e.printStackTrace();
}
Connection connection = null;
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost/testBase", "root", "");
Statement statement = connection.createStatement();
ResultSet res = statement.executeQuery("");
}
catch(SQLException e){ System.out.println(e); }
finally {
if(connection != null) {
try { connection.close(); } catch (SQLException e) { e.printStackTrace(); }
}
}
I have 2 questions related to this code :
I am using the sun.jdbc.odbc.JdbcOdbcDriver driver because it seem that it was the only available on my system, however I've read that it's a windows component... Is there a way to make it platform independent (or is it already) ?
The second catch outputs a
java.sql.SQLException: No suitable driver found for
jdbc:mysql://localhost/
Which is quite annoying and I don't seem to be able to find a way to work...
Thanks for your help !
When you generate jar, you can include all its dependencies.
So, you can use any driver you need and include it when you generate jar for the application.
Now you're cross platform.
About the question #2, that's because you don't have the mysqLconnector at lib folder.
You can download it here: http://dev.mysql.com/downloads/connector/j/
Just include it, if you're using IDE, you can look for a option "include jar/folder" and add it, then, try again; if you aren't in a IDE ... you have to set it on classpath.
I have been given a task to create profiles for the applications. The Database that we use is Postgresql. I've defined some function that will give me those profile and I've added them to the Postgresql source code. Now I don't know how to call those functions with a GUI. I mean how connect my Graphical user interface to those functions that I've created. For example I have a button in my GUI that is "Start creating profiles" and it's supposed to call those functions in postgresql source code code and so on...
Any ideas of how to call those function from my GUI?
I deeply appreciate your kind help in advance!
Based on the replies, in order to use the JDBC to connect my GUI to postgreSQL, I wrote this code but I have a problem with "URL"
I know these commands in Java to connect to database(PostgreSQL):
Connection con = null;
Statement s = null;
String url = "jdbc:postgresql://localhost/mydb";
String user = "user";
String password = null;
try {
con = DriverManager.getConnection(url, user, password);
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(Home.class.getName());
lgr.log(Level.SEVERE, ex.getMessage(), ex);
out.println(ex.getMessage());
}
String query = " select * from my_function()";
try {
s =con.createStatement();
r = s.executeQuery(query);
}catch (Exception e){
}finally {
try {
if (con != null)
con.close();
} catch (SQLException ex) {
Logger lgr = Logger.getLogger(HomeServlet.class.getName());
lgr.log(Level.WARNING, ex.getMessage(), ex);
}
But I'm not sure about what I have to insert in "URL"
Would you please help me with that!
I'm using this template:
try {
connection.setAutoCommit(false);
try {
// ... do something with that connection ...
connection.commit();
catch (SQLException exception) {
connection.rollback();
throw exception;
} finally {
connection.setAutoCommit(true);
}
} catch (SQLException exception) {
// log error
}
Is this the right way? How can this template be improved?
Your code should work fine. Do you get any errors or anything else?
Here's an example on using JDBC Transaction anyway
http://www.java2s.com/Code/Java/Database-SQL-JDBC/JDBCTransaction.htm
P.S. Specify your problem and I'll try to help.