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
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();
a table has a column named 'score' with different values.
| name | contact | area | score |
| james | +222451 | eastp|70 |
| jimmy | +222451 | eestp | 80 |
| k.josh | +222451 | ecstp | 50 |
| L.john | +222451 | efstp | 60 |
I want to update all score values with a specific value. eg. update all score values with 10.
therefore value 70 will be 80
value 80 will be 90
value 50 will be 60
value 60 will be 70
please how do I write a code to achieve this. wrote down this but all columns get changed to the same value. please help.
int reg = 10;
try {
String sql1 = "select Score from db_table where ID=db_table.ID";
pst = con.prepareStatement(sql1);
rs = pst.executeQuery();
while(rs.next())
{
int ad = rs.getInteger("Score");
int fad = ad+reg;
String sql2 = "update db_table set Score='" + fad + "' where _ID=db_table.ID";
pst = con.prepareStatement(sql2);
pst.execute();
}
} catch(SQLException | HeadlessException e)
{
JOptionPane.showMessageDialog(null,e);
} finally
{
try
{
rs.close();
pst.close();
} catch(Exception e)
{}
}
but anytime is executed, the whole column values are replaced with the same value '10'. instead of each column value should rather be increased by 10. please help
Use the following query:
UPDATE db_table
SET score = score + 10
So, basically you don't need to SELECT all the scores first, and then manipulate them inside Java code, and use UPDATE one by one. Instead, change your try block in the Java code as follows:
try
{
String sql1 = "UPDATE db_table Set score = score + " + String.valueOf(reg);
pst = con.prepareStatement(sql1);
rs = pst.executeQuery();
}
Try this:
int reg = 10;
try{
String sql1="select Score from db_table where ID=db_table.ID";
pst=con.prepareStatement(sql1);
rs=pst.executeQuery();
while(rs.next()){
int ad = rs.getInteger("Score");
int fad = ad+reg;
String sql2 = "update db_table set Score=Score + "+fad+" where _ID=db_table.ID";
pst=con.prepareStatement(sql2);
pst.execute();
}
}catch(SQLException | HeadlessException e){
JOptionPane.showMessageDialog(null,e);
}finally{
try{
rs.close();
pst.close();
}
catch(Exception e){}
}
I have a table in my SQL in the following structure called student:
+-----------+-----------+-----------+------------+
| studentno | lastname | firstname | middlename |
+-----------+-----------+-----------+------------+
| 2001-0001 | Matrix | John | G |
| 2001-0002 | Mata | Evan | A |
| 2001-0003 | Melly | Carmelo | P |
| 2001-0004 | Hamburger | Hardy | P |
+-----------+-----------+-----------+------------+
I have a JTable and a JTextField in my Java Program. What I would like to do is, if I type letter M (case insensitive) in the JTextField, all the student who's last name starts with letter M will display on my JTable. If I type a second letter, say for example, A, all the students who's last name starts with MA will display, until I got a specific last name on my JTable..
My problem is that, even though I type letter M, all of the data in my MAappears on my JTable instead of just all the students who's last name starts with letter M..
And my JTable doesn't clears up even if I empty my JTextField..
I am using Netbeans and so far I have this code in my JTextFieldKeyPressed:
private void lastNameKeyPressed(java.awt.event.KeyEvent evt) {
Connection conn = null;
String url = "jdbc:mysql://localhost:3306/";
String dbName = "students_dbs";
Statement stmt = null;
ResultSet result = null;
String driver = "com.mysql.jdbc.Driver";
String databaseUserName = "user1";
String databasePassword = "test";
PreparedStatement pst = null;
try{
conn = DriverManager.getConnection(url + dbName, databaseUserName, databasePassword);
stmt = conn.createStatement();
System.out.println("Connected to the database.");
}catch(Exception e){
System.out.println("Failed to connect ot the database.");
}
try{
String sql = "SELECT studentno, lastname, firstname, middlename FROM student WHERE lastname LIKE '%" + lastname.getText() + "%'";
pst = conn.prepareStatement(sql);
result = pst.executeQuery();
studentsTable.setModel(DbUtils.resultSetToTableModel(result));
}
catch(Exception e){
JOptionPane.showMessageDialog(null, e);
}
}
First you need to add a listener to Listen for changes in the text, then send that text to your query to retrieve new data based on the passed text.
// Listen for changes in the text
textField.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
warn();
}
public void removeUpdate(DocumentEvent e) {
warn();
}
public void insertUpdate(DocumentEvent e) {
warm();
}
public void warn() {
// fire the execute statement.
}
});
then you need to change your query to something like this:
String sql = "SELECT studentno, lastname, firstname, middlename FROM student WHERE firstname= '" + jtextfield.getText() + "%'";
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();