I have a Java-application that loads data from a legacy file format into an SQLite-Database using JDBC. If the database file specified does not exist, it is supposed to create a new one. Currently the schema for the database is hardcoded in the application. I would much rather have it in a separate file as an SQL-Script, but apparently there is no easy way to execute an SQL-Script though JDBC. Is there any other way or a pattern to achieve something like this?
Your sentence "there is now easy way to execute an SQL-Script though JDBC" confused me for a minute, but I reckon you are saying "there is no easy way". :)
Based on what others have said, yes... the perfect world scenario is to use an ORM tool, like Hibernate, but I also understand the fact when you are dealing with legacy stuff at work, your team may not want to spend too much time refactoring that project.
I agree that you should refactor out the database schema into a separate file. You can actually execute the SQL script using JDBC. I do that all the time when I run my certain testcases.
Here's how I do it. I use SQL Server database in my case. So, you need to tweak the code to fit your needs.
String ddl = ... // load your SQL script file into this string
String delimiter = "GO"; // in my case, SQL Server uses GO as delimiter, you use whatever you want here.
private void executeDDL(String ddl, String delimiter) {
Connection con = null;
try {
con = ... // get the connection
// enable transaction
con.setAutoCommit(false);
Statement statement = con.createStatement();
// for every DDL statement, execute it
for (String sql : ddl.split(delimiter)) {
if (StringUtils.isNotBlank(sql)) {
statement.executeUpdate(sql);
}
}
statement.close();
con.commit();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
con.close();
}
catch (Exception ignored) {
}
}
}
The "right" way is to use Hibernate. Among all other benefits it is capable of creating/updating a DB schema automatically (SO1, SO2).
In case you are working in a development environment, I would advice you to use an ORM tool like Hibernate that forward engineers based on your Java Domain Models to create the DB tables. Hibernate has the feature to auto create/update the tables in case there are changes to DB schema.
As you are using SQLite you could have a look at Hibernate for SQLite
I have read somewhere that it not advisable to use this feature in a production environment because the incremental table creation might negatively affect the existing data.
Related
I want to integrate jOOQ in a project which uses native SQL and org.springframework.jdbc.core.JdbcTemplate. The database schema changes often and developers have to search the code for a column that has been removed and update the queries. Hibernate or another ORM solution isn't an option as queries are sometimes very large and developers get them and just have to insert into the application code. This is very error-prune. So I thought to integrate jOOQ but gradually.
Can jOOQ throw compile time errors if a native SQL cannot be executed?
I've tried the following:
// Existing code
JdbcTemplate jdbcTemplate = ...
String sql = "select ...";
// Check code
try {
DSLContext dslContext = DSL.using(jdbcTemplate.getDataSource().getConnection());
Query query = dslContext.parser().parseQuery(sql + " order by NON_EXISTING_COLUMN");
} catch (SQLException e) {
...
}
// Existing code
return jdbcTemplate.query(sql, ...)
But it compiles well although NON_EXISTING_COLUMN doesn't really exist. Maybe I know the jOOQ API not very well yet. But I thought that it should be capable of doing it. The table classes are generated, so it can check whether the query which is build from a native SQL string is executable without executing it. Isn't it?
why don't use generated class files rather than typing native SQL?
dslContext.selectFrom(GENERATED_TABLE)...
PS: If you use JOOQ DSL(with generated classes) for generating SQL it would be work but not completely in some cases if you do mistakes even on generated classes (relations or some aggregate functions) it will not complain about it and will compile successfully.
Older versions of jOOQ did not implement meta data lookups in the parser, or only to some limited extent, and just accepted all valid identifiers. Starting with jOOQ 3.14, there will be an improved implementation as of:
https://github.com/jOOQ/jOOQ/issues/9061
You will need to provide jOOQ with a Configuration.metaProvider() (it defaults to the JDBC DatabaseMetaData backed implementation. You might prefer using generated code), and then jOOQ will try to resolve all identifiers.
Prior to jOOQ 3.14, you could implement a VisitListener which traverses the parsed SQL query, and validate all the identifiers yourself.
I need to create a web application that allows users to create a database using ER diagrams and then perform basic CRUD operations on it. I have already done most of the job, how it's work:
As you can see after create tables i have ready to use SQL code (right bottom corner).
And now i need to execute this code from java.
I am using Java (1.8), Oracle(11gR2), Hibernate (5.4.9.Final)
Here is my code which is used to execute native queries (i am loading sql from file):
Session session = hibernateFactory.openSession();
String query = null;
try {
query = new String(Files.readAllBytes(Paths.get(ClassLoader.getSystemResource("test.sql").toURI())));
} catch (IOException | URISyntaxException e) {
e.printStackTrace();
}
String finalQuery = query;
session.doWork(connection -> connection.prepareStatement(finalQuery).execute());
And here is the question:
Is this possible to execute this whole code at once?
I can execute this:
but when i will put another table, then i will got this error:
Its seems like hibernate don't like character: ";"
Is it possible to fix this and force this prepareStatement to execute whole code sql? Or i will need to do it in parts?
How can I get SQL query that was received by MySQL server when it raises exception?
I have a code similar to the following:
Connection con = null;
PreparedStatement ps = null;
try {
con = DbConnectionManager.getConnection();
ps = con.prepareStatement(query);
setStatementParameters(ps, params);
ps.executeUpdate();
} catch (SQLExeption e) {
// How to get wrong query here?
} finally {
DbConnectionManager.closeConnection(ps, con);
}
Where query variable is like "INSERT into someTable (qwe, asd) VALUES (?, ?)"
The question is how can I get query string in the catch block?
The SQLException may or may not have the query string contained in its exception message. You can't depend on it. If you just want to see it for debugging purposes, though, then that's probably your best bet. However, in this particular example that's not a problem because you have direct access to the query variable that you used to set up the query in the first place.
I've run across another solution to this problem.
The MySQL JDBC driver overrides the toString of PreparedStatement to display the query as it is sent to the database. This is implementation dependent so it may not the best thing to rely on, but it's very simple to get at. I'm now using this to dump query text to a log file for debugging purposes. While there are probably other solutions that are more portable and future-proof, this has the advantage of getting exactly the string that the MySQL driver says it's sending to the database.
The string comes back with an object ID, then a colon, then the SQL string. You can split it on the colon to get just the SQL.
The type com.mysql.jdbc.PreparedStatement also exposes a protected method call asSql(). You could override the class with your own implementation that gives public access to this method. From looking at the disassembly of the class's toString() method, it seems to be using asSql() to get the actual SQL string. This approach adds the problem of how to instantiate your subclass, though; the simplest approach is just to use the toString that you already have access to, without even having to downcast your PreparedStatement to a MySQL-specific subtype.
Again, just be aware that the maintainers of the MySQL API probably don't consider this part of the public interface to their software (JDBC defines the standard interface), so they may make changes later that would break this mechanism. For the time being, though, it will get the job done.
This is true for the version of the MySQL driver I'm currently using, which is 5.1.7.
I am new to using Derby and databses in eclipse, and I have become a tad lost and in need to a bit of help. I have established a database connection, created a new database, and a new schema, within which I have some tables containing some test data. I don't have any problem with the sql queries to select the relevant data. The problem I have is getting to a point where I can use queries. I am trying to create a class which connects to the database, and for testing purposes, uses a simple query to select some data. This is what I have so far:
public void getExerciseInfo() {
try {
Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
connect = DriverManager.getConnection("jdbc:derby://localhost/c:/TestDatabase");
PreparedStatement statement = connect.prepareStatement("SELECT * from TESTSCHEMA.TESTTABLE");
resultSet = statement.executeQuery();
while (resultSet.next()) {
String name= resultSet.getString("NAME");
String type = resultSet.getString("TYPE");
System.out.println(name);
System.out.println(type);
}
} catch (Exception e) {
} finally {
close();
}
}
All I am trying to do is output the data in the table to the console, but I cant even do this simple task :( Im guessing my connection url is invalid, is it supposed to be the file path to the database folder in my eclipse workspace?
Anyhow, I am very lost, and any help would be greatly appreciated.
Did you take a look over: http://db.apache.org/derby/integrate/plugin_help/derby_app.html ? You seem to be using the network server but your db URL is wrong.
If you are not running the Derby server, you can establish an embedded database connection or use an EmbeddedDataSource, shown here.
I'm trying to determine the best way to ping a database via JDBC. By 'best' I mean fast and low overhead. For example, I've considered executing this:
"SELECT 1 FROM DUAL"
but I believe the DUAL table is Oracle-specific, and I need something more generic.
Note that Connection has an isClosed() method, but the javadoc states that this cannot be used to test the validity of the connection.
With JDBC 4 you can use isValid(int) (JavaDoc) from the Connection Interface. This basically does the trial statement for you.
Some driver implement this by sending the correct dummy SQL to the database and some directly uses low level operations which reduces the parsing overhead.
However beware of the timeout, some drivers (DB/400 and Oracle Thin) do spawn a new time thread for each invocation, which is not really acceptable for most Pool validation scenarios). And Oracle also does not seem to use a prepared statement, so it’s kind of relying on the implicit cache.
Yes, that would be Oracle-only, but there is no generic way to do this in JDBC.
Most connection pool implementations have a configuration parameter where you can specify the SQL that will be used for ping, thus pushing the responsiblity to figure out how to do it to the user.
That seems like the best approach unless someone comes up with a little helper tool for this (of course, it precludes using potentially even faster non-SQL-based methods like Oracle's internal ping function)
MySQL has a nice mechanism, documented in this SO answer. From the answer:
"/* ping */ SELECT 1"
This will actually cause the driver send a ping to the server and return a fake, light-weight, result set.
Having said that, #eckes answer is the best (using JDBC 4's Connection.isValid(int)).
I'm not aware of a generic solution, either. For IBM's UDB on iSeries (and perhaps other DB2 systems) it would be
select 1 from SYSIBM.SYSDUMMY1;
You could try to get the db name from the connection meta data and execute a matching sql staement. E.g.
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = dataSource.getConnection();
String dbProductName = con.getMetaData().getDatabaseProductName();
Statement st = con.createStatement();
if ( "PostgreSQL".equalsIgnoreCase(dbProductName) ) {
rs = st.executeQuery("select version();");
} else if ( "Oracle".equalsIgnoreCase(dbProductName) ) {
rs = st.executeQuery("select 1 from dual");
} else {
...
}
} catch ( Exception ex ) {
System.out.prinln("DB not reachable");
} finally {
// close statement, connection etc.
...
}
I may be out to lunch on this one, but could you simply execute some non-sense query, such as:
SELECT * FROM donkey_giraffe_87
I don't know very much about JDBC's error handling, but perhaps you could check to see if the database is at least telling you that the table does not exist. If JDBC's error codes are vendor-specific, the Spring Framework has some utilities for mapping these codes to more meaningful exceptions.