This is just a theoretical question, but I am building a program that gets data from Facebook using the CDATA JDBC Plugin, I wanted to know if all JDBC Plugins have the same syntax. For example, if I just change the JAR file for the driver to a Twitter one, and change the names of the tables and columns I am accessing, would it still work?
By a plugin I mean a driver, also, to put it more clearly, if I was developing a MySQL app and switched from the stock Connector/J Driver to the CData driver, would I need to change the code?
Until the underlying schema where you store remains same, the use of JDBC driver will yield the same result.
Note: Twitter/FB... both has to support the JDBC Model...
However, if you have changes in Drivers, you can consider using ApacheMetamodel Link for reference
JDBC is a standard that has been established and vetted over the years. As long as the drivers you're working with are written to that standard (which as a CData employee, I can say that ours are) you can expect your code referencing a JDBC driver to be essentially identical, regardless of the manufacturer of the driver or the data source you're connecting to.
//optional, register the driver with the DriverManager
Class.forName(myDriverName).newInstance();
//obtain a Connection instance from the DriverManager
Connection conn = null;
try {
conn = DriverManager.getConnection(myJDBCurl);
//execute a select query
Statement stmt = conn.createStatement();
Result rs = stmt.executeQuery("SELECT foo FROM bar");
} catch (SQLException ex) {
//handle any errors
}
As you can see, the code to utilize the JDBC driver can be generalized with variables to use any driver or to use different connections under a single driver (if, for instance, you wanted to connect to different Facebook accounts).
JDBC is an interesting standard. It was intentionally designed to load the driver at run-time, so no vendor classes are used during compilation.
It also has some JDBC own mechanisms for schema data (DatabaseMetaData), and for such things as doing an INSERT with an autoincrement key, and retrieving that key (getGeneratedKeys).
However the SQL is far from standardized by vendor, despite standardisation efforts. For example just getting the first 10 rows.
Unfortunately the visionaries of JDBC seem no longer to exist.
But it a sound basis for professional usage.
Related
I'm using MySQL 5.7 with Java in Eclipse, and the connection statement below code below is causing an error when I try to connect:
try
{
//1. Get a connection to database
jdbc:mysql://localhost:3306/databaseName?autoReconnect=true;useSSL=false;
// 2. Create a statement
Statement myStmt=myConn.createStatement();
// 3. Execute SQL query
ResultSet myRs=myStmt.executeQuery("select * from employee");
//4. Process the result set
while(myRs.next())
{
System.out.println(myRs.getString("last_name")+","+myRs.getString("first_name"));
}
}
catch(Exception exc){
exc.printStackTrace();
}
First things first.
Code will only be used to validate the error. So you must paste the error fired by your program.
Since we don't have enough information to the problem, I will just cover basic troubleshooting.
Basic trouble shooting:
Do you have the driver? if not, you can download it here.
Next, Do you have the driver on your project class path? If not yet, you must add it. see how here
Did you load the driver to the program? if not, Class.forName("com.mysql.jdbc.Driver"); // Load Driver like that before doing anything.
Did you establish the connection? if not, Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/DATABASE","USERNAME","PASSWORD");//3306 or port number depends on you config, same with DATABASE, USERNAME, PASSWORD
After the connection were established, so you should create a statement object like Statement s = con.createStatement(); // Create Statement. This will be used to execute sql commands.
finally, you can execute the commands like s.execute("select * from employee"); // Execute Query NOTE that s here is the variable created on number 5.
If all of the above were properly done but still gets an error, check if your have the database server running. In you case, mysql. Make sure there were not other installation of mysql prior to your current mysql. Sometimes, it will mess up your database. Troubleshooting your mysql, see mysql official doc here
While possible error is the datatype of mysql to your java code or getting a column that does not exist on your query or worse the column does not exist on your table.
Hope that help you and other who needs it.
I have a usecase of supporting multiple RDBMS. User should define the data source as a prerequisite and at the code level i have to determine which RDBMS the user going to connect with and provide specific RDBMS attributes.
Eg:,
com.mysql.jdbc.Driver jdbc:mysql://hostname/ databaseName
oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:#hostname:port Number:databaseName
As shown above we can retrieve connection url or may be driver name and identify the RDBMS. But i want to clarify what is the best way to identify which RDBMS user is using. Any help would be greatly appreciated.
This is really simple. See DatabaseMetaData
DatabaseMetaData databaseMetaData = connection.getMetaData();
String databaseName = databaseMetaData.getDatabaseProductName();
String userName = databaseMetaData.getUserName();
UPDATE To answer #dnWick comment.
Yes, This DatabaseMetaData support for the wide range of RDBMS. Through the DatabaseMetaData interface we can obtain metadata about the database that we have connected. For instance, we can see what tables are defined in the database, and what columns each table has, Even we can check supported features for the database we have connected.
Example We can see if a database has support for multiple transactions, supports for UNION or not, etc.,
So I have been playing around with querying databases using the standard
Statement s = connection.createStatement();
ResultSet rs = s.executQuery(queryString);
ResultSetMetadata rsmd = rs.getMetaData();
while(rs.next)){
String code = "";
String value = "";
for(int i = 1; i <= rsmd.getColumnCount(); i++){
Object obj = rs.getObject(i);
if(i == 1){
code = obj.toString():
}
else{
label = obj.toString();
}
}
//Store code and labels in map
}
...go on to close statement and move on.
I am trying to select two columns from a table in each instance.
For the most part this works well. When working with MySql & Microsoft Sql databases I get a result set full of data in the table. However when I try to do this with an Oracle database I get an empty result set.
I have tested my query string in the SQL Developer application and it works fine, returns my data. But the result set doesnt contain anything. The resultSet metadata says that it has two columns though. Is there anything I need to do when interacting with an Oracle Database that is different from the other two? Thanks.
If your query works when you run it against the Oracle database, and you know the code works since you've run it against MySQL, then some other things to try are:
1.) Make sure your JDBC connection URL is correct. Are you sure you are connecting to the database that you intend to? (i.e. - the one that would return the rows you expect?)
2.) Take into account credentials. Make sure you are using the same credentials through JDBC that you are when connecting to Oracle directly.
3.) Make sure both connections are being made from the same machine and with the same environment. Oracle drivers rely on environment variables to find a file (I believe it is called tnsnames.ora, or something like that) that contains the alias & connection info. Getting different versions of that file could point you to different Oracle instances.
4.) Try manually specifying your schema name in the query. So instead of select * from my_table use select * from my_schema.my_table. Sometimes Oracle clients will configure their sessions to have default schemas set up in their preferences.
5.) If your are attempting to select data that you've inserted with your Oracle client, make sure you've committed the transaction in your Oracle client so that the data is visible to other sessions.
One last debugging tool to use is to try connecting via the Squirrel DB client. Squirrel is a 100% pure java SQL client that connects to any DB using JDBC. It would be a good test to make sure your JDBC Driver, Connection URL, etc. are all valid.
The database table has records but the JDBC client can't retrieve the records. Means the JDBC client doesn't have the select privileges. Please run the below query on command line:
grant all on emp to hr;
I'm using official JDBC driver for PostgreSQL, but I'm stuck with the following issues:
No support for PostgreSQL-ish data structures such as UUIDs.
Common JDBC weirdness, such as:
No function to escape values for consuming by PostgreSQL.
Limited support for executing heterogeneous statements in batch.
No rewriting of multiple insert statements into single insert statement when inserting many rows in one table.
So, the question — is there any PostgreSQL database driver which can leverage full power of PostgreSQL without much boilerplate? I'm also use Scala language for development, so if driver is designed specifically for Scala it would be so much awesome awesome.
Some of this seems to be (unless I'm not understanding) user error in using JDBC. JDBC is a pretty ugly API, so never ask if you can do it elegantly, just ask if you can do it at all.
Escaping and inserting multiple rows should be handled, as #ColinD and #a_horse pointed out, with Prepared statements and batch operations. Under the hood, I would expect a good JDBC implementation to do the things you want (I am not familiar with PostgreSQL's implementation).
Regarding UUIDs, here is a solution:
All that PostgreSQL can do is convert string literals to uuid.
You can make use of this by using the data type
org.postgresql.util.PGobject, which is a general class used to
represent data types unknown to JDBC.
You can define a helper class:
public class UUID extends org.postgresql.util.PGobject {
public static final long serialVersionUID = 668353936136517917L;
public UUID(String s) throws java.sql.SQLException {
super();
this.setType("uuid");
this.setValue(s);
}
}
Then the following piece of code will succeed:
java.sql.PreparedStatement stmt =
conn.prepareStatement("UPDATE t SET uid = ? WHERE id = 1");
stmt.setObject(1, new UUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"));
stmt.executeUpdate();
The driver supports batched statements to speed up bulk inserts.
And using batched statements is a lot more portable than using proprietary INSERT syntax (and as far as I can tell, there is no big different between a multi-row insert and batched inserts)
Check out PreparedStatement.addBatch()
The reason why UUID is not supported is probably that UUID is not part of the Postgres core, just a contrib module.
Edit
Regarding the execute heterogeneous statements
The Postgres driver does support different types of statements in the a batch.
The following works fine:
Connection con = DriverManager.getConnection("jdbc:postgresql://localhost/postgres", "foo", "bar");
con.setAutoCommit(false);
Statement stmt = con.createStatement();
stmt.addBatch("create table foo (id integer, data varchar(100))");
stmt.addBatch("insert into foo values (1, 'one')");
stmt.addBatch("insert into foo values (2, 'two')");
stmt.addBatch("update foo set data = 'one_other' where id = 1");
stmt.executeBatch();
con.commit();
Although you do lose the automatic escaping that PreparedStatement gives you.
I realise this doesn't answer your entire question, but hopefully it will be useful all the same.
I'm using Java 6 and Postgres 8.4. The driver I'm using is in my Maven POM file as:
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-702.jdbc4</version>
</dependency>
I'm using PreparedStatement.getObject() and PreparedStatement.setObject() with Java's java.util.UUID class to retrieve and store UUIDs.
For example:
pstm.setObject(1, guid); //where pstm is a PreparedStatement and guid is a UUID
and:
//where rs is a ResultSet
UUID myGuid = (UUID) rs.getObject("my_uuid_column_name");
Works fine.
With newer drivers, the following is alsow supported
UUID myGuid = rs.getObject("my_uuid_column_name", UUID.class);
No support for PostgreSQL-ish data structures such as UUIDs.
On the contrary, the current JDBC driver (9.2-1002 JDBC 4) for Postgres 9.x does indeed support UUID via the setObject and getObject commands. You cannot get any more direct or simpler than that (in any database, Postgres or any other) because JDBC does not recognize UUID as a data type.
As far as I can tell, there is no need to create a helper class as suggest in another answer by Yishai.
No need to do any casting or go through strings.
See my blog post for more discussion and code example.
Code example excerpt:
java.util.UUID uuid = java.util.UUID.randomUUID();
…
preparedStatement.setObject( nthPlaceholder++, uuid ); // Pass UUID to database.
Take a look at O/R Broker, which is a Scala JDBC-based library for relational database access.
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.