Does MySQL Connector/J driver implement JdbcRowSet interface? - java

I'm trying to get acquainted with JDBC basics throuhg Oracle's "The Java™ Tutorials" and now I got stuck right here: https://docs.oracle.com/javase/tutorial/jdbc/basics/jdbcrowset.html.
For my examples, I exploit MySQL Server with the latest version of Connector/J (mysql-connector-java-8.0.16.jar). So far, the driver worked as expected. It gets connection to MySQL Server, creates database, tables, populates them with data and fills ordinary ResultSet objects with the retrieved data. However, as soon as I try to create JdbcRowSet object and perform execute(), I get SQL exception reporting: "No suitable driver found..."
So, now I'm in doubts: whether JdbcRowSet (as well as CachedRowSet / JoinRowSet / FilteredRowSet / WebRowSet) is just not implemented by Connector/J driver, or I'm doing something wrong? Or maybe this functionality is no longer supported in JDK 11?
Here is an example:
import javax.sql.rowset.JdbcRowSet;
import javax.sql.rowset.RowSetProvider;
import java.sql.*;
import java.util.Properties;
public class JdbcRowSetTest {
public static void main(String[] args) {
String connectionURL =
"jdbc:mysql://localhost:3306/testdb?serverTimezone=Europe/Moscow";
String userName = "root";
String password = "root";
try {
Properties connectionProps = new Properties();
connectionProps.put("user", userName);
connectionProps.put("password", password);
System.out.println("Connect to database...");
Connection conn =
DriverManager.getConnection(connectionURL, connectionProps);
System.out.println("Retrieve and process data using ResultSet...");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * from COFFEES");
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
float price = rs.getFloat("PRICE");
System.out.println(coffeeName + ", " + price);
}
System.out.println("Now, update the data using JdbcRowSet...");
JdbcRowSet jdbcRs = RowSetProvider.newFactory().createJdbcRowSet();
jdbcRs.setUrl(connectionURL);
jdbcRs.setUsername(userName);
jdbcRs.setPassword(password);
jdbcRs.setCommand("select * from COFFEES");
// it's where SQLException is thrown
jdbcRs.execute();
jdbcRs.absolute(2);
jdbcRs.updateFloat("PRICE", 10.99f);
jdbcRs.updateRow();
System.out.println("After updating the 2nd row:");
//... view updated table
} catch (SQLException e) {
e.printStackTrace();
}
}
}
And it's the output:
Connect to database...
Retrieve and process data using ResultSet...
Colombian, 7.99
Espresso, 9.99
Now, update the data using ResultSet...
java.sql.SQLException: No suitable driver found for jdbc:mysql://localhost:3306/testdb?serverTimezone=Europe/Moscow
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:702)
at java.sql/java.sql.DriverManager.getConnection(DriverManager.java:228)
at java.sql.rowset/com.sun.rowset.JdbcRowSetImpl.connect(JdbcRowSetImpl.java:643)
at java.sql.rowset/com.sun.rowset.JdbcRowSetImpl.prepare(JdbcRowSetImpl.java:654)
at java.sql.rowset/com.sun.rowset.JdbcRowSetImpl.execute(JdbcRowSetImpl.java:556)
at JdbcRowSetTest.main(JdbcRowSetTest.java:37)
Updated (possible solution):
As the commentators mentioned bellow, the problem described here has nothing to do with MySQL implementing rowset or not. For me, it seems to be just a bug of JDK 11.0.1, because as soon as I updated for the newer version of JDK 12.0.1, the problem dissipated, and now JdbcRowSet object is created without any MySQLException.

Related

How to return a ROWTYPE in PL/SQL and retrieve it in Java?

I have a PL/SQL function , that returns a ROWTYPE. I need to call this function from Java and retrieve the data ( as an array, a map, a struct, a class,whatever, I really don't care , I just need it, preferably without having to screw around the PL/SQL code, like changing the return type of the function). I have looked into multiple "solutions" and forums but I did not find the answer.
I have already tried to register the out parameter as a struct and a class , none worked.
This is my PL/SQL function:
FUNCTION DAR_CLIENTE(cedula VARCHAR2) RETURN CLIENTE%ROWTYPE AS
RET CLIENTE%ROWTYPE;
BEGIN
-- TAREA: Se necesita implantación para FUNCTION P_CLIENTE.DAR_CLIENTE
SELECT * INTO RET FROM CLIENTE WHERE Persona_cedula=cedula;
RETURN RET;
END DAR_CLIENTE;
This is my java code:
public static void main(String args[]) throws SQLException {
Properties info = new Properties();
info.put(OracleConnection.CONNECTION_PROPERTY_USER_NAME, DB_USER);
info.put(OracleConnection.CONNECTION_PROPERTY_PASSWORD, DB_PASSWORD);
info.put(OracleConnection.CONNECTION_PROPERTY_DEFAULT_ROW_PREFETCH, "20");
OracleDataSource ods = new OracleDataSource();
ods.setURL(DB_URL);
ods.setConnectionProperties(info);
// With AutoCloseable, the connection is closed automatically.
try (OracleConnection connection = (OracleConnection) ods.getConnection()) {
// Get the JDBC driver name and version
DatabaseMetaData dbmd = connection.getMetaData();
System.out.println("Driver Name: " + dbmd.getDriverName());
System.out.println("Driver Version: " + dbmd.getDriverVersion());
// Print some connection properties
System.out.println("Default Row Prefetch Value is: " + connection.getDefaultRowPrefetch());
System.out.println("Database Username is: " + connection.getUserName());
System.out.println();
System.out.println(connection.getSchema());
// Perform a database operation
Map<String, Class<?>> myMap = new HashMap<String, Class<?>>();
myMap.put("P09551_1_5.CLIENTE", Cliente.class);
connection.setTypeMap(myMap);
CallableStatement storedProc = connection
.prepareCall("{? = call P09551_1_5.p_cliente.dar_cliente('1144102435')}");
storedProc.registerOutParameter(1, oracle.jdbc.OracleTypes.JAVA_STRUCT);
storedProc.execute();
}
}
I am using ojdbc8.jar.
This information is printed to the console at the start of the program:
Driver Name: Oracle JDBC driver
Driver Version: 18.3.0.0.0
I have resolved the issue by changing the return type to a SYS_REFCURSOR, like this:
FUNCTION DAR_CLIENTE(cedula VARCHAR2) RETURN SYS_REFCURSOR AS
RET SYS_REFCURSOR;
BEGIN
-- TAREA: Se necesita implantación para FUNCTION P_CLIENTE.DAR_CLIENTE
OPEN RET FOR
SELECT * FROM CLIENTE WHERE Persona_cedula=cedula;
RETURN RET;
END DAR_CLIENTE;
Java code as follows:
public static void main(String args[]) throws SQLException {
Properties info = new Properties();
info.put(OracleConnection.CONNECTION_PROPERTY_USER_NAME, DB_USER);
info.put(OracleConnection.CONNECTION_PROPERTY_PASSWORD, DB_PASSWORD);
info.put(OracleConnection.CONNECTION_PROPERTY_DEFAULT_ROW_PREFETCH, "20");
OracleDataSource ods = new OracleDataSource();
ods.setURL(DB_URL);
ods.setConnectionProperties(info);
// With AutoCloseable, the connection is closed automatically.
try (OracleConnection connection = (OracleConnection) ods.getConnection()) {
// Get the JDBC driver name and version
DatabaseMetaData dbmd = connection.getMetaData();
System.out.println("Driver Name: " + dbmd.getDriverName());
System.out.println("Driver Version: " + dbmd.getDriverVersion());
// Print some connection properties
System.out.println("Default Row Prefetch Value is: " + connection.getDefaultRowPrefetch());
System.out.println("Database Username is: " + connection.getUserName());
System.out.println("Schema: "+connection.getSchema());
System.out.println();
// Perform a database operation
Map<String, Class<?>> myMap = new HashMap<String, Class<?>>();
myMap.put("P09551_1_5.CLIENTE", Cliente.class);
connection.setTypeMap(myMap);
CallableStatement storedProc = connection
.prepareCall("{? = call P09551_1_5.p_cliente.dar_cliente('1144102435')}");
storedProc.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
storedProc.execute();
ResultSet resultSet = (ResultSet) storedProc.getObject(1);
ResultSetMetaData meta = resultSet.getMetaData();
int columnCount = meta.getColumnCount();
while (resultSet.next()) {
for (int i = 1; i <= columnCount; i++) {
System.out.println(meta.getColumnLabel(i)+":"+resultSet.getObject(i).toString());
}
//System.out.println(resultSet.getString(1));
}
}
}
Getting this response on the console (I did it so all fields would be printed with their column labels, though this particular table only has one column):
Driver Name: Oracle JDBC driver
Driver Version: 18.3.0.0.0
Default Row Prefetch Value is: 20
Database Username is: P09551_1_5
Schema: P09551_1_5
PERSONA_CEDULA:1144102435
Here is the source of the solution:
https://www.mkyong.com/jdbc/jdbc-callablestatement-stored-procedure-cursor-example/
Using a third party: jOOQ
If using a third party library is acceptable to you, you could use jOOQ's stored procedure support, which includes support for PL/SQL package types. jOOQ's code generator will generate a class PCliente containing a method darCliente() for you, which you can call as follows:
ClienteRecord result = PCliente.darCliente(
configuration, // This wraps your JDBC connection
"1144102435"
);
No need to wrap your head around JDBC bindings. Everything is type safe. The ClienteRecord is the same data type as if you ran that SELECT query directly with jOOQ.
The SQL generated by jOOQ
Because ojdbc still (I think?) can't bind all PL/SQL package types, jOOQ flattens your %ROWTYPE into individual bind values, e.g. like this (actual SQL will vary, because it's trickier than that, considering all the edge cases)
DECLARE
r CLIENTE%ROWTYPE;
BEGIN
r := P_CLIENTE.DAR_CLIENTE(?);
? := r.COL1;
? := r.COL2;
? := r.COL3;
END;
Of course, instead of using jOOQ, you could generate this SQL yourself and continue binding to JDBC directly.
Disclaimer: I work for the company behind jOOQ.

JAVA- JDBC- ORACLE Connection issues

Using standard JDBC code for JAVA-ORACLE connection however not working.
This may be asked earlier but i am not able to debug it myself so asking here.
Request for help.
Code:
import java.sql.*;
class OracleCon {
public static void main(String args[]) {
try {
// step1 load the driver class
Class.forName("oracle.jdbc.driver.OracleDriver");
// step2 create the connection object
Connection con = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:xe", "system",
"nikhil.nik");
/*
* Hostname: Host system for the Oracle database. For your Express
* Edition database, the hostname is localhost. Port: Listener port.
* The default is 1521. SID: Database name. The default for Express
* Edition is xe.
*/
// step3 create the statement object
Statement stmt = con.createStatement();
// step4 execute query
ResultSet rs = stmt.executeQuery("SELECT TEST_NAME FROM TEST1");
// System.out.println(rs);
while (rs.next())
System.out.println(rs.getInt(1) + " " + rs.getString(2) + " "
+ rs.getString(3));
// step5 close the connection object
con.close();
} catch (Exception e) {
System.out.println(e);
}
}
}
Stacktrace:
java.sql.SQLException: Fail to convert to internal representation
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:112)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:146)
at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:208)
at oracle.jdbc.driver.CharCommonAccessor.getInt(CharCommonAccessor.java:132)
at oracle.jdbc.driver.OracleResultSetImpl.getInt(OracleResultSetImpl.java:521)
at dbPrograms.OracleCon.main(OracleCon.java:31)
You selected column TEST_NAME and extracted its values as int. This operation fails because Oracle cannot convert the values accordingly. Use the ResultSet method suitable for the column type.
Also you select one column and access three columns in the ResultSet so you might want to adjust the select command.

can't make updatable resultset with ucanaccess

I've tried most of the examples found here and the web, but I can't open a MS access database(2002 or 2013) and get an updatable result set using UCanAccess. The same code using the JDBC:ODBC driver/connection/works. I've written short test code to check concur_updatable to check this, so I must be missing something. I'm using JDK 1.7 on a Win7 machine. I also have another machine with the same results.
This works:
/*
class jdbc, for testing jdbc:odbc CONCUR_UPDATABLE.
*/
import java.sql.*;
public class jdbc {
private static String dbFQN;
public static void main(String[] args) {
try {
dbFQN = ("C:\\phil\\programming\\kpjl2002.mdb");
String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=" + dbFQN;
System.out.println("Loading database: " + database);
Connection conn = DriverManager.getConnection(database, "", "");
Statement s = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
// Fetch records from table
String selTable = "SELECT * FROM " + "tblLibrary" + " ORDER BY Artist, Cat, Cart";
s.execute(selTable);
ResultSet rs = s.getResultSet();
int concurrency = rs.getConcurrency();
if(concurrency == ResultSet.CONCUR_UPDATABLE)
{
System.out.println("rs is updatable");
} else {
System.out.println("rs Not updatable");
}
s.close();
conn.close();
} //close try
catch (Exception ex) {
ex.printStackTrace();
} //close catch
} //close main method
} //close dbAccess class
The output is that rs is updatable.
This doesn't work:
/*
class ucan, for testing ucanaccess CONCUR_UPDATABLE.
C:\jdk1.7.0_79\jre\lib\ext\ucanaccess-2.0.9.5.jar
C:\jdk1.7.0_79\jre\lib\ext\hsqldb.jar
C:\jdk1.7.0_79\jre\lib\ext\jackcess-2.1.0.jar
C:\jdk1.7.0_79\jre\lib\ext\commons-lang-2.6.jar
C:\jdk1.7.0_79\jre\lib\ext\commons-logging-1.1.1.jar
also present:
C:\jdk1.7.0_79\jre\lib\ext\commons-logging-1.2.jar
C:\jdk1.7.0_79\jre\lib\ext\commons-lang3-3.4.jar
*/
import java.sql.*;
public class ucan {
private static String dbFQN;
public static void main(String[] args) {
try {
dbFQN = ("C:\\phil\\programming\\kpjl2002.mdb");
String database = "jdbc:ucanaccess://" + dbFQN;
System.out.println("Loading database: " + database);
Connection conn = DriverManager.getConnection(database, "", "");
Statement s = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
// Fetch records from table
String selTable = "SELECT * FROM " + "tblLibrary" + " ORDER BY Artist, Cat, Cart";
s.execute(selTable);
ResultSet rs = s.getResultSet();
int concurrency = rs.getConcurrency();
if(concurrency == ResultSet.CONCUR_UPDATABLE)
{
System.out.println("rs is updatable");
} else {
System.out.println("rs Not updatable");
}
s.close();
conn.close();
} //close try
catch (Exception ex) {
ex.printStackTrace();
} //close catch
} //close main method
} //close dbAccess class
the output is that rs is Not updatable. So I cannot update or insert rows in the resultset.
The code posted is the operative part of a larger project, where UCanAccess can read the table and put the contents in a jList and jTextarea, with formatting. When I started writing code to update or add a new record, I ran into the problem.
I apologize if this is a bit long.
Anybody have an idea what I'm missing or doing wrong?
BTW, this is one of my 2 fav sites for good, usable Java answers.
UPDATE:
Got an idea from old co-worker, the original database may have been copied from an original Access97 db. to a 2000 db. I had used 2013 Repair and Compact to make "new" 2002 and 2013 db's. Access must retain '97 type even when doing what I did. So, I created a new 2013 dummy db to test, and UCanAccess will report resultset as updatable. I will try to recreate the record data of the current db in a new database file, and see if that works. I'm hoping this is the problem, since UCanAccess doesn't support updatability with Access97 db's. I'll let ya'll know what I find.
Thanks.
I had used 2013 Repair and Compact to make "new" 2002 and 2013 db's. Access must retain '97 type even when doing what I did. So, I created a new 2013 dummy db to test, and UCanAccess will report resultset as updatable.
The "Compact and Repair Database" feature in Access does not change the database file version. If you have (what you suspect to be) an older-version database file then you should use the "Save Database As" feature under "File > Save & Publish" * to convert the database file to a newer version.
* (... at least that's where it is in Access 2010.)
Well, after a nice weekend of eating brats and drinking good beer at Germanfest, I finally got things working. I decided to scrap the MS Access db and put the 472 records in a SQLite db. With that, I was able to get PreparedStatements to work to display the records in a jList and JTextArea, add a new record and update a couple fields in an existing record within the same run of the test application. Did it both as a command line run GUI and from NetBeans 8.0, so I think my problems are solved. After a couple of summer projects get done, I'll get back to re-writing the original VB app using Java.
Thanks Gord, and everyone here.

JDBC MYSQL Connection without specifying database?

I am using the SphinxQL MySQL client which stores indexes as "tables" but has no real notion of a "database"...One specifies the port (9306 in my case) at which the sphinx mysql instance listens and in theory should be able to communicate as normal.
I have the following test code:
import java.sql.*;
public class Dbtest {
public static void main (String[] args) {
try {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:9306",
"user","password");
con.setReadOnly(true);
Statement stmt = con.createStatement();
ResultSet res = stmt.executeQuery("SELECT * from index_turned_table");
while (res.next()) {
String stuff1 = res.getString(1);
String stuff2 = res.getString(2);
System.out.println("Adding " + stuff1);
System.out.println("Adding " + stuff2);
}
res.close();
stmt.close();
con.close();
}
catch(Exception e)
{
System.out.println (e);
}
}
Upon execution, the code just hangs and does nothing and doesn't print out an exception. What are useful things I can do to figure this out or if any one has direct experience what might be going on?
This work with 1.10-beta http://www.olegsmith.com/2010/12/scalalift-sphinxql.html
and not work with 2.0.1-beta. Use mysql-connector-java 5.1.15.
Your SphinxQL instance is listening on port 9306. Your MySQL is listening on some other port, likely on the default 3306. You can use MySQL JDBC driver to connect to MySQL, but you cannot use it to connect to SphinxQL. It just doesn't understand JDBC driver communication protocol.

Connecting a Microsoft Access Database to Java using JDBC and compiling

for a school database project we are making a database program (user GUI and the database). Using Microsoft Access 2010 I created the database and populated it with some sample data, and saved it in .mdb format and placed it in my project folder.
When running it in eclipse the following code works fine, connects and even retrieves the query. However I find that I am unable to export the code to a jar and run it (which is required for the project, give them a working copy of your program on a CD or flash drive), and I'm also unable to port the code over to Netbeans to have it work, as well as trying to compile on a Linux machine.
I assume this is a problem with including drivers or trying to use Microsoft access. The error I get when running the jar or running on Netbeans is given below the code. So I ask either how do I include drivers to make the program portable, or how else can I approach this problem?
Thanks in advance
import java.sql.*;
public class JDBCTest {
static Connection connection;
static Statement statement;
public static void main(String args[]){
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=TLDATABASEDBM.mdb";
connection = DriverManager.getConnection( database ,"","");
buildStatement();
executeQuery();
}catch(Exception e){
e.printStackTrace();
System.out.println("Error!");
}
}
public static void buildStatement() throws SQLException {
statement = connection.createStatement();
}
public static void executeQuery() throws SQLException {
boolean foundResults = statement.execute("SELECT * FROM tblStaff AS x WHERE City='Calgary'");
if(foundResults){
ResultSet set = statement.getResultSet();
if(set!=null) displayResults(set);
}else {
connection.close();
}
}
public static void displayResults(ResultSet rs) throws SQLException {
ResultSetMetaData metaData = rs.getMetaData();
int columns=metaData.getColumnCount();
String text="";
while(rs.next()){
for(int i=1;i<=columns;++i) {
text+=""+metaData.getColumnName(i)+":\t";
text+=rs.getString(i);
//text+="</"+metaData.getColumnName(i)+">";
text+="\n";
}
text+="\n";
}
System.out.println(text);
}
}
The error mentioned above:
java.sql.SQLException: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified
at sun.jdbc.odbc.JdbcOdbc.createSQLException(JdbcOdbc.java:6957)
at sun.jdbc.odbc.JdbcOdbc.standardError(JdbcOdbc.java:7114)
at sun.jdbc.odbc.JdbcOdbc.SQLDriverConnect(JdbcOdbc.java:3073)
at sun.jdbc.odbc.JdbcOdbcConnection.initialize(JdbcOdbcConnection.java:323)
at sun.jdbc.odbc.JdbcOdbcDriver.connect(JdbcOdbcDriver.java:174)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:207)
at tldatabase.DataConnect.makeConnection(DataConnect.java:35)
at tldatabase.Main.main(Main.java:24)
I know the post was years ago but I felt like answering the question for those who are just experiencing this right now. It took me a while to know the answer to the question so here's the solution:
http://wiki.netbeans.org/FaqSettingHeapSize
Follow the "Running the 32-bit JVM".
All you have to do is find the netbeans.conf in the installation folder of your netbeans and change the directory from something like this:
netbeans_jdkhome="C:\Program Files\Java\jdk1.6.0_24"
to this:
netbeans_jdkhome="C:\Program Files (x86)\Java\jdk1.6.0_21"
The problem is netbeans might be running in 64 bit but MS Access only support 32-bit. So doing this would hopefully solve the problem. Also make sure to install this:
http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=23734
The main problem lies in the line:
String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=TLDATABASEDBM.mdb";
Make sure that the .mdb file is in the correct directory.
Check the file extension as .mdb or .mdbacc.
Also, if you want to use the same DSN every time, it is better to add the DSN(Data Source Name) into the respective system on which the mdb is stored.
I think that your app do not see TLDATABASEDBM.mdb in current directory. You can give full path to this file in connection string or add system DSN in ODBC Manager and then connect to it with connection string like: jdbc:odbc:TLDATABASEDBM
Honestly, I dont like what I am going to say... but, it solved the same issue for me... mysteriously... :(((
on the line where you are defining the database variable, I changed ...(.mdb)... into ...(.mdb, *.accdb)...
All the best for figuring out what difference that made!
package javaapplication1;
import java.sql.*;
public class MSaccess_archive {
public static void main(String[] args) {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
// set this to a MS Access DB you have on your machine
String filename = "mdbTEST.mdb";
String database = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=";
database+= filename.trim() + ";DriverID=22;}"; // add on to the end
// now we can get the connection from the DriverManager
Connection con = DriverManager.getConnection( database ,"","");
Statement stmt = con.createStatement();
stmt.execute("select * from student"); // execute query in table student
ResultSet rs = stmt.getResultSet(); // get any Result that came from our query
if (rs != null)
while ( rs.next() ){
System.out.println("Name: " + rs.getInt("Age") + " ID: "+rs.getString("Course"));
}
stmt.close();
con.close();
}
catch (Exception err) {
System.out.println("ERROR: " + err);
}
}
}

Categories