I am trying to do SQL with Java, this is my first time. I am trying to select all of a table and put it in a ResultSet, but the ResultSet seems empty. The same query on the MySQL client does show results, which leaves me wondering what is wrong with my code. It could either be the way the query is being done, or the way I am trying to get the data from the result set.
The query in the command line MySQL client...
mysql> SELECT * FROM accounts.sites;
+----------+-----------------------+--------------------------+--------------+----------------+
| username | domain | directory | fpm-template | nginx-template |
+----------+-----------------------+--------------------------+--------------+----------------+
| cyrus | cyrustheg.org | /var/www/sites/cyrustheg | standard | drupal |
| cyrus | tornews.org | /var/www/sites/tornews | standard | standard |
| cyrus | oletf.org | /var/www/sites/oletf | standard | standard |
| taf | theabsolutefinest.org | /var/www/sites/taf | standard | wordpress |
| taf | bitsplit.org | /var/www/sites/bitsplit | bitsplit | bitsplit |
+----------+-----------------------+--------------------------+--------------+----------------+
5 rows in set (0.00 sec)
I am using this code to build a resultSet with that query...
private void read() throws Exception {
try {
Class.forName("com.mysql.jdbc.Driver");
String dburl = "jdbc:mysql://" + dbHost + "/" + dbName +
"?user=" + dbUser + "&password=" + dbPass;
connect = DriverManager.getConnection(dburl);
resultSet = statement.executeQuery("SELECT * from accounts.sites");
} catch (Exception e) {
throw e;
}
}
This code iterates through the resultSet, looking for every domain for every user. I know the problem is either in the former code or this or the former code, because I've added a print statement to the while loop, and it is never called. This is why I conclude the resultSet is empty.
public HashSet<String> listSites(String user)
throws Exception, ExcSiteNosites {
HashSet<String> list = new HashSet<String>();
boolean exists = false;
try {
read();
while (resultSet.next()) {
if (resultSet.getString("username").equals(user)) {
exists = true;
list.add(resultSet.getString("domain"));
}
}
if (!exists) {
throw new ExcSiteNosites(user);
}
} catch (Exception e) {
throw e;
} finally {
resultSet.close();
statement.close();
connect.close();
}
return list;
}
The entire class: http://pastebin.com/0DSbFey7
The unit test for that class: http://pastebin.com/9UYLEeMB
I found the bug running that unit test, which makes the following output...
Listing cyrus's sites...
Listing taf's sites...
java.lang.NullPointerException
at database.Sites.listSites(Sites.java:96)
at test.dbSites.listall(dbSites.java:28)
at test.dbSites.main(dbSites.java:51)
java.lang.NullPointerException
at database.Sites.listSites(Sites.java:96)
at test.dbSites.listall(dbSites.java:28)
at test.dbSites.main(dbSites.java:53)
The NullPointerException I think might be an unrelated problem. I've not done any Java in a while, and I've not worked that out either. Though the problem I want help with (unless related) is just that the ResultSet seems empty.
You never initialize statement in your code, it's a private variable and you have no setter on it, so I think that you are not injecting it either.
So, when you call read(), you will have a NullPointerException on
resultSet = statement.executeQuery("SELECT * from accounts.sites");
this will be catched and thrown again by your catch.
So, in your listSites(), you will catch it, and throw it again, and in the finally, you will have another NullPointerException on
statement.close();
and it's the one in your stack trace.
You need to create a statement from the connection before use it to executeQuery()....
Statement statement = connection.createStatement();
Related
I have a MySQL db and I have an issue with two tables named product and product_older. They have same structure and product table's rows copied into product_older for once in a day. Here is their structure:
+-----------------------+---------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+---------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| price | decimal(18,2) | YES | | NULL | |
| price_older | decimal(18,2) | YES | | NULL | |
+-----------------------+---------------+------+-----+-------------------+----------------+
I have problem with only price_older field. My program updates values of product table for over 3 million data. price_older field takes it value from price column of product_older every time.
Here is the method which I take price_older:
private double getOlderPrice(int id) {
double price_older = 0.0d;
try {
String query = tools.getQuery("select price from product_older where id=?")
.replace("?", String.valueOf(id));
com.mysql.jdbc.Connection connection = (Connection) DriverManager.getConnection(db_url, username, password);
preparedStatement = (PreparedStatement) connection.prepareStatement(query);
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
price_older = resultSet.getDouble(1);
}
} catch (SQLException e) {
..... // error log
} finally {
.... //close the prepared statement
}
return price_older;
}
And I use that price_older value to create PriceList object for every product then I used that list to update product table. Here is my update code:
(Same connection object used in here with the getOlderPrice method.)
private void dbUpdate() throws SQLException {
String query = "update product set price=?, price_older=? where id=?";
try (com.mysql.jdbc.Statement statement = (Statement) connection.createStatement();
com.mysql.jdbc.PreparedStatement updateStatement = (PreparedStatement) connection.prepareStatement(query)) {
connection.setAutoCommit(false);
int batchIndex = 0;
for (UpdatePrice price : priceList) {
if (price.getPrice() == null) {
updateStatement.setNull(1, Types.DECIMAL);
} else {
updateStatement.setDouble(1, price.getPrice());
}
updateStatement.setDouble(2, price.getOlderPrice());
updateStatement.setInt(3, price.getID());
updateStatement.addBatch();
batchIndex++;
if (batchIndex % limitedBatchSize == 0) {
updateStatement.executeBatch();
connection.commit();
}
}
updateStatement.executeBatch();
connection.commit();
connection.setAutoCommit(true);
priceList.clear();
}
}
Here is the problem; It works fine for most of the time but about once every ~30 days it updates older_price with the wrong value and that wrong value is usually belong to another product in the db and when it updates the column with the wrong value there is no error in the log because it appears OK.
And my connection's rewriteBatchedStatements is set to true.
How could that be? If there is a bug, why it works fine most of the time and how there is no problem with the price column? If there is not why it updates a value in the wrong place?
I have been searched for over a week now but there is no result and also I can not reproduce the bug and it makes less possible to be sure where is the problem actually.
This question already has answers here:
ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long on connect to MySQL
(6 answers)
Closed 4 years ago.
I am doing a simple program to connect MySQL database with Java, but the program throws the ClassCastException error.
Java long to MySql
This question says that Unsigned Bigint in MySQL is equivalent to long in Java.
Given below is the java part:
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// TODO code application logic here
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql:///check1","uname","pwd");
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select * from t1");
while(rs.next()){
System.out.println(rs.getObject(1)+ " "+ rs.getObject(2));
}
rs.close();
st.close();
con.close();
}
I am also including the schema for the table I created
mysql> desc t1;
+--------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+----------------+
| rollno | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(40) | NO | | NULL | |
+--------+-------------+------+-----+---------+----------------+
2 rows in set (0.39 sec)
Try to do this way
Class.forName("com.mysql.jdbc.Driver").newInstance();
Through MySQL Workbench Queries i was able to insert an emoji into the table but only if i set names first.
SET NAMES utf8mb4; //only need to do this once everytime i start the server
insert into testtable (testfield) values ('💖'); //works!
However doing the same thing in java results in an exception:
java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x96' for column 'testfield' at row 1
The java:
public static void main(String[] args) {
TestDao t = new TestDao();
t.setNamesUtf8mb4(); //SET NAMES utf8mb4;
t.insertTest("💖"); //doesn't work :(
}
TestDao
public void setNamesUtf8mb4(){
try(Connection conn = DBConnection.getConnection()){
PreparedStatement pst = conn.prepareStatement("SET NAMES utf8mb4;");
pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void insertTest(String test){
try(Connection conn = DBConnection.getConnection()){
PreparedStatement pst = conn.prepareStatement("insert into testtable (testfield) values (?);");
pst.setString(1, test);
pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
DBConnection:
public class DBConnection {
private static String url = null;
private static Connection conn = null;
public static Connection getConnection(){
try{
Class.forName("com.mysql.jdbc.Driver");
url = "jdbc:mysql://localhost:3306/testdb";
conn = DriverManager.getConnection(url,"root","1234");
} catch (Exception e) {
System.out.println(e);
}
return conn;
}
}
My charset and collation for table and database
mysql> SHOW FULL COLUMNS FROM testtable WHERE Field = 'testfield';
+-------+--------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| Field | Type | Collation | Null | Key | Default | Extra | Privileges | Comment |
+-------+--------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
| testfield | varchar(191) | utf8mb4_unicode_ci | YES | | NULL | | select,insert,update,references | |
+-------+--------------+--------------------+------+-----+---------+-------+---------------------------------+---------+
1 row in set (0.00 sec)
mysql> SHOW VARIABLES WHERE Variable_name LIKE 'character\_set\_%' OR Variable_name LIKE 'collation%';
+--------------------------+--------------------+
| Variable_name | Value |
+--------------------------+--------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| collation_connection | utf8mb4_unicode_ci |
| collation_database | utf8mb4_unicode_ci |
| collation_server | utf8mb4_unicode_ci |
+--------------------------+--------------------+
10 rows in set (0.00 sec)
my.ini:
[client]
default-character-set=utf8mb4
[mysql]
no-beep=
default-character-set=utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character_set_server=utf8mb4
collation_server=utf8mb4_unicode_ci
init-connect='SET NAMES utf8mb4'
I've tried changing the connection url:
url = "jdbc:mysql://localhost:3306/testdb?useUnicode=yes&characterEncoding=UTF-8"; //note: "=utf8mb4" isn't valid here
All out of ideas, any ideas why this isn't working? Why is it only working in mysql workbench and not in java? Does it have something to do with the Connector/J ?
EDIT
A comment suggested to set names in the same connection, which i tried and it seems to work. But isn't this terribly inefficient? I don't want to have to execute set names before every single insert or update... Surely there's a better way to do this?
this works:
public void insertTest(String test){
try(Connection conn = DBConnection.getConnection()){
PreparedStatement pst = conn.prepareStatement("SET NAMES utf8mb4;"); //set names in same connection
pst.executeUpdate();
pst = conn.prepareStatement("insert into testtable (testfield) values (?);");
pst.setString(1, test);
pst.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
EDIT2
sql version
mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.11 |
pom.xml
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
EDIT3
JDK version of the project is jdk1.8.0_161
And getting hex of test(💖) using:
public String toHex(String arg) {
return String.format("%040x", new BigInteger(1, arg.getBytes()));
}
produces:
000000000000000000000000000000000000003f
or getting hex of test using:
static String stringToHex(String string) {
StringBuilder buf = new StringBuilder(200);
for (char ch: string.toCharArray()) {
if (buf.length() > 0)
buf.append(' ');
buf.append(String.format("%04x", (int) ch));
}
return buf.toString();
}
produces:
d83d dc96
I am using MySQL 5.1 for my database and I'm sending the commands via a Java program (JBDC).
Is there a MySQL command for creating or altering a table?
Let's say I have a following table:
+----------+----------+
| column_a | column_b |
+----------+----------+
| value_a | value_b |
+----------+----------+
Now I want to use a command, that would add a column "column_c" if it didn't exist.
That would result in:
+----------+----------+----------+
| column_a | column_b | column_c |
+----------+----------+----------+
| value_a | value_b | |
+----------+----------+----------+
If the table didn't exist, it would create a new table with specified columns:
+----------+----------+----------+
| column_a | column_b | column_c |
+----------+----------+----------+
And finally, if the table had columns that weren't specified in the command, it would leave them untouched.
here is code in Java to create a table called Coffees:
/*Making the connection*/
try {//if any statements within the try block cause problems, rather than the program failing
//an exception is thrown which will be caught in the catch block
con = DriverManager.getConnection(url, "your username", "your password");
//create a statement object
stmt = con.createStatement();
//supply the statement object with a string to execute
stmt.executeUpdate("create table COFFEES (COF_NAME varchar(32), " +
"SUP_ID int, PRICE double, SALES int, TOTAL int, " +
"primary key(COF_NAME))");
//close the statement and connection
stmt.close();
con.close();
} catch(SQLException ex) {
System.err.println("SQLException: " + ex.getMessage());
}
Explanation:
-In this example the java program interacts with a database that is located on a server, so we have to firstly we set the url of where the server is located and also sign in username and password, you may not be using the same method that I used.
-These need to be declared at the top of your java program:
String url = "jdbc:mysql://www.yoururlexample.co.uk";
Connection con;
Statement stmt
Hopefully this helps, you will then be able to insert data into the database and execute queries.
Edit:
This can be used in the executeUpdate statement if you want a table to be created if none exists with the name "COFFEES":
create table if not exists COFFEES
/*Making the connection*/
try {
//an exception is thrown which will be caught in the catch block
con = DriverManager.getConnection("jdbc:mysql:exaple.com", "username", "pass");
//create a statement object
stmt = con.createStatement();
//supply the statement object with a string to execute
stmt.executeUpdate("ALTER TABLE table_name ADD column_name datatype");
//close the statement and connection
stmt.close();
con.close();
} catch(SQLException ex) {
System.err.println("SQLException: " + ex.getMessage());
}
I think that this is going to work for you.
Something like that might be a solution (this need at least one record in the table to work):
package com.stackoverflow.so20935793;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class App {
// complete this:
private static final String JDBC_URL = ".....";
private static final String JDBC_USER = ".....";
private static final String JDBC_PASS = ".....";
public static void main(final String[] args) {
Connection con = null;
PreparedStatement stm = null;
ResultSet rs = null;
try {
con = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASS);
stm = con.prepareStatement("SELECT * FROM your_table LIMIT 1");
rs = stm.executeQuery();
if (rs.next() && rs.getMetaData().getColumnCount() == 2) {
// add your new column
}
} catch (final SQLException ex) {
// handle exception
} finally {
closeQuietly(rs);
closeQuietly(stm);
closeQuietly(con);
}
}
private static void closeQuietly(final AutoCloseable what) {
if (what == null) {
return;
}
try {
what.close();
} catch (final Exception ex) {
// ignore
}
}
}
(not tested)
I want to fetch a table from a database using Java code. The sample code which I tried gets only two columns. I want the fetched data to be presented exactly like it is in the table.
How do I do that ?
This code only gives me two rows, side by side -
while (rs.next()) {
System.out.println(rs.getString(4) + " " + rs.getString(6));
}
Full example at -
http://msdn.microsoft.com/en-us/library/aa342339.aspx
This is what I tried -
int size = 0;
if(rs != null){
rs.beforeFirst();
rs.last();
size = rs.getRow();
}
System.out.println("cols = " + size);
And got an error - The requested operation is not supported on forward only result sets.
Use this code
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
int columnsNumber = rsmd.getColumnCount();
Source - How to get the number of columns from a JDBC ResultSet?
After using that code, one can display the results like they are displayed by the DBMS as follows -
ResultSetMetaData rsmd = rs.getMetaData();
int columnsNumber = rsmd.getColumnCount();
// Iterate through the data in the result set and display it.
while (rs.next()) {
//Print one row
for(int i = 1 ; i <= columnsNumber; i++){
System.out.print(rs.getString(i) + " "); //Print one element of a row
}
System.out.println();//Move to the next line to print the next row.
}
Column names are not displayed in this example.
I posted this answer to a similar question here, but I believe this one is also relevant, maybe more so. In short, I wrote a simple utility class to print db table rows to standard out (for part fun, part learning). It may be useful to someone (at least I hope so).
Here is the link to the code repo at GitHub: https://github.com/htorun/dbtableprinter
And here is the basic usage:
// Create a connection to the database
Connection conn = DriverManager.getConnection(url, username, password);
// Just pass the connection and the table name to printTable()
DBTablePrinter.printTable(conn, "employees");
It should print something like this:
Printing 10 rows from table(s) EMPLOYEES
+--------+------------+------------+-----------+--------+-------------+
| EMP_NO | BIRTH_DATE | FIRST_NAME | LAST_NAME | GENDER | HIRE_DATE |
+--------+------------+------------+-----------+--------+-------------+
| 10001 | 1953-09-02 | Georgi | Facello | M | 1986-06-26 |
+--------+------------+------------+-----------+--------+-------------+
| 10002 | 1964-06-02 | Bezalel | Simmel | F | 1985-11-21 |
+--------+------------+------------+-----------+--------+-------------+
.
.
It's because your code only get 2 value of the row. Notice that rs.getString(4) meant, get the value on current row at 4th column (using 0 based index) as String.
If you want to print all the column, you should write the rest rs.getXXXX(), where XXXX is column data type such as getString(), getInteger(), getLong(), etc. See this java documentation for reference.
public static void printSqlTable(String selectQuery) {
try {
Statement statement = connection.createStatement();
resultSet = statement.executeQuery(selectQuery);
DBTablePrinter.printResultSet(resultSet);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}