Treating JSON array as a String to insert into MYSQL - java

say I've got a JSON like this:
{"name": "tom", "id":1, "clothes":[{"shirt":"yellow"},{"shoes":black},.......]}
I'm trying to insert it, as is, into a column in a mysql DB using Java.
void insertVal(JsonObject json){
Connection conn = null;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/Orders?user=root", "root", "1234");
Statement st = conn.createStatement();
StringBuilder values = new StringBuilder("(");
for (String key : json.keySet()){
if (key.equals("clothes")){
//do something to deal with this array
break;
}
values.append(json.get(key)).append(",");
}
values.append(")");
String insert = "INSERT INTO ORDERS VALUES " + values;
st.executeUpdate(insert);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This code works fine up to clothes key. So far, I've tried using JSON OBJECT and JSON MERGE but the format doesn't quite match, and I'd rather not parse right now.
So, is it possible to add clothes or do I have to parse it somehow? if so, what format would work best?
Thanks a lot

To all those concerned: The problem was the " string. mysql, and probably SQL in general, don't handle these well. There are two options. The first, and less recommended:
String parsed = json.get(key).toString().replace("\"", "");
Then, insert normally.
The second, much more recommended - use PreparedStatement. This way, you can write an insert/update query without minding the escape characters. Example, after i've inserted 'null' values for the clothes column:
PreparedStatement ps = conn.prepareStatement("UPDATE ORDERS set CLOTHES = ? WHERE ID = ?");
ps.setString(1, clothes); // clothes - get(key).toString()
ps.setInt(2, count); // count - counts which iteration we are
ps.executeUpdate();
I hope anyone in the future finds this useful.

Related

Inserting values in MySQL using an array

I have a very large input form with over 90 fields and i need to store all the values in a database.
The following is just a test sample code to show how i am inserting my values right now.
public void insertToDB() {
Connection con = SoftwareConnectionFactory.getInstance().getConnection();
PreparedStatement ps = null;
String sql = "INSERT INTO person.test (name, class, subject) "
+ "VALUES(?,?,?)";
try {
ps = con.prepareStatement(sql);
ps.setString(1, name);
ps.setString(2, class);
ps.setString(3, subject);
ps.executeUpdate();
} catch (Exception e) {
log.error("error storing into db: " + e.getMessage());
} finally {
SoftwareConnectionFactory.getInstance().closeConnection(con);
}
}
The above code works just fine but i am trying to find a neat way of coding this by setting it with help of an array. I looked into the following:
String[] check = { name, class, subject };
Array arrayCcheck = con.createArrayOf("VARCHAR", check);
The createArrayOf is not supported by my current dbpc and i am trying to find alternate ways of doing this. I have tried updating my jar files but the above method still doesn't work. I am trying to keep my code as short as possible. Any help is appreciated. Thank you.
I would suggest following:
Reduce number of fields in your table to only those fields that you are currently using for search queries (you can also think of something that might be used in the future). As a result you will not have 90 fields table.
To store everything else, you can parse your object to JSON and store entire object in one additional table field. When you will read from database you will parse it back.
So as a result you will have something like that:
WRITE
ObjectWith90Fields obj;
String sql = "INSERT INTO person.test (name, class, json) "
+ "VALUES(?,?,?)";
try {
ps = con.prepareStatement(sql);
ps.setString(1, obj.getName());
ps.setString(2, obj.getClass());
ps.setString(3, createJson(obj));
ps.executeUpdate();
}
READ
ObjectWith90Fields obj;
String sql = "SELECT * FROM person.test";
try {
st = con.createStatement(sql);
ResultSet rs = st.execute(sql);
ObjectWith90Fields obj = parseJson(rs.getString("json"));
}

Return integer for the last row in MYSQL using JDBC

I'm new to working with JDBC commands. I have a database in MYSQL and each entry gets an ID. As initially created the ID was just a static variable that I iterated when the constructor runs. This was okay until I started deleting entries or running the program a second time. Then I start getting collisions. I need a way to return the highest row in the table and assign it to an integer that I can iterate.
The QuerySELECT MAX(ID) FROM table seems to get the value that I'm looking for. But I'm not sure of the syntax to get that value into an integer so I can return it.
public int getHighestRow() {
PreparedStatement ps;
int highestID = 0;
try {
ps = getSQLDB().prepareStatement("SELECT MAX(studentID) FROM student");
ps.execute();
} catch (SQLException e){
Logger.getLogger(Undergraduate.class.getName()).log(Level.SEVERE, null, e);
}
if (highestID > 0) return highestID;
else return 0;
I have a feeling this is very simple, but I wasn't able to find an existing answer. Or is there a more elegant way to do this in general?
SQL of different providers solve the retrieval of automatic generated keys differently. JDBC provides a standard solution.
Better use this JDBC solution, as it prevents mixing up those keys when insertions are done at the same time.
try (PreparedStatement ps = getSQLDB().prepareStatement(
"INSERT INTO student(....) VALUES(?, ..., ?)",
Statement.RETURN_GENERATED_KEYS)) { // Without StudentId
ps.setString(1, name);
...
ps.executeUpdate();
try (ResultSet rsKeys = ps.getGeneratedKeys()) {
if (rsKeys.next()) { // Only one record inserted
int studentId = rsKeys.getInt(1); // One key generated
}
}
} catch (SQLException e){
Logger.getLogger(Undergraduate.class.getName()).log(Level.SEVERE, null, e);
}
The mechanism with try(...). try-with-resources, ensures that close is called automatically.

Read a string with apostrophe from a JTextField and save it on a database

I have many JTextField objects and I want to read, in one of them, a string that contains apostrophes and then, this It will be saved on a database. The problem is when I try to save this string, because I obtain this error:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error
in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near 'k')' at line 1
I put the apostrophe in a JTextField and the "k" letter is in the next JTextField. I can't understand if who can't read this kind of character is the database (I have a database written in SQL and I use MySQL), or the JTextField object. What can I do?
This is the code that save the strings caught from the JTextField objects (I get the strings into another method, simply using the method jTextField.getText();):
public void setNuovaAzienda(){
try {
int contCliente = 0;
Class.forName(NOMEDRIVER); //avvio il driver
conn = DriverManager.getConnection(SERVERURL, USER, PASSWORD);
Statement st = conn.createStatement();
Statement st1 = conn.createStatement();
Statement st2 = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT MAX(IdCliente) FROM cliente");
while (rs.next())
contCliente = rs.getInt(1);
contCliente++;
int showConfirmDialog = JOptionPane.showConfirmDialog(null,"Vuoi confermare l'inserimento del nuovo cliente?", "Conferma Inserimento", JOptionPane.YES_NO_OPTION);
if (showConfirmDialog == 0) {
try {
st1.executeUpdate("INSERT INTO cliente () VALUES ('"+contCliente+"', '"+citta+"', '"+indirizzo+"', '"+nCivico+"', '"+telefono+"')");
st2.executeUpdate("INSERT INTO personagiuridica () VALUES ('"+contCliente+"', '"+partitaIva+"', '"+nomeAzienda+"', '"+ragSociale+"', '"+fax+"')");
ImageIcon icon = new ImageIcon("C:\\Users\\salva\\Documents\\NetBeansProjects\\JavaApplication10\\src\\javaapplication7\\Icons\\icona v.png");
JOptionPane.showMessageDialog(null, "Cliente Inserito", "Conferma Inserimento", JOptionPane.INFORMATION_MESSAGE, icon);
InserisciOrdine linkInserisciOrdine;
linkInserisciOrdine = new InserisciOrdine();
linkInserisciOrdine.setLocationRelativeTo(null);
linkInserisciOrdine.setVisible(true);
dispose();
} catch (SQLException ex) {
Logger.getLogger(NuovaAzienda.class.getName()).log(Level.SEVERE, null, ex);
}
}
conn.close();
} catch (ClassNotFoundException | SQLException ex) {
Logger.getLogger(NuovaAzienda.class.getName()).log(Level.SEVERE, null, ex);
}
}
contCliente, citta, indirizzo, etc. are global variable.
Sounds like you construct your SQL statements as a String, embedding the data directly, like
String dataString = ...; //get value from field
String sql = "INSERT INTO `mytable` (`col`) VALUES ('"+dataString+"')";
This is wrong, since if you have single quote in your string, this will result in invalid statement. Try outputting that string to System.out and executing it in the SQL worksheet, you should see what goes wrong. You should use Prepared Statements instead:
//Assuming you have jdbc Connection named conn
String dataString = ...; //get value from field
PreparedStatement ps = conn.prepareStatement("INSERT INTO `mytable` (`col`) VALUES (?)");
ps.setString(1, dataString);
ps.execute();
ps.close();
It will give you a decent protection against SQL injections as a bonus.
If you are unable to rewrite your code with prepared statements (e.g. legacy third-party API), then you should escape single quotes in your string, by replacing them with two single quotes (' -> '').
UPDATE
Indeed you do construct the statements using concatenation. AVOID THIS, unless you want to get hacked by a random script kiddie one day. Read about SQL injections, there's plenty of info, and they are one of the main vectors of hacker attacks.

Reading a File Into a Derby Database

This is my latest attempt to read a text file into a Netbeans Derby database. The file contains 5 rows with each row containing 7 items delineated by commas. The program runs without any errors but the database is not updated at all. I would appreciate any help in fixing this code.
<% Connection connection = null;
PreparedStatement ps = null;
String urlanddatabasename = "jdbc:derby://localhost:1527/ProgramName
String userName = "root";
String password = "root";
Class.forName("org.apache.derby.jdbc.ClientDriver");
connection = DriverManager.getConnection(urlanddatabasename,userName,password);
try{
String fileName = saveFile;
File file = new File(fileName);
Scanner inputStream = new Scanner(file);
String[] array = new String[7];
Statement statement = connection.createStatement();
while(inputStream.hasNext()){//reads from the file until there are no items left
String data = inputStream.next();
array = data.split(",");
String reportidString = array[0];
String coursenameString = array[1];
String tardiesString = array[2];
String absencesString = array[3];
String totalgradeString = array[4];
String teachernameString = array[5];
String schoolnameString = array[6];
statement.executeUpdate("INSERT INTO report(reportid, coursename, tardies, absences, totalgrade, teachername, schoolname) values(reportidString, coursenameString,tardiesString, absencesString, totalgradeString, teachernameString, teachernameString, schoolnameString)");
}
inputStream.close();
}catch(FileNotFoundException e){e.printStackTrace();}
%>
It seems that you are using this code inside a JSP scriptlet. This is very bad style. Especially for code without any relation to the view representation.
So the first thing you should do, is to create an ordinary Java class and put that code inside. Then you will remark that Class.forName() throws a checked exception (ClassNotFoundException) and some other parts like DriverManager.getConnection(), connection.createStatement() and statement.executeUpdate() throw SQLException. You shouldn't let the servlet container catch these exceptions.
Then write a simple main() method to check if your code is working or even better a JUnit test.
You declared a PreparedStatement variable but never used it. Instead later you used a simple Statement. The first one fits better here. So use something like that:
ps = connection.prepareStatement("INSERT INTO "
+ "report(reportid, coursename, tardies, absences, totalgrade, teachername, schoolname) "
+ "values(?, ?, ?, ?, ?, ?, ?)");
Use the ? as a placeholder for the actual values.
Then later you set the values. Beware that the prepared statement index begins at 1. After the execution of all SQL inserts, you should commit the transaction. In case of an exception use abort().
while(inputStream.hasNext()){//reads from the file until there are no items left
// ...
ps.setString(1, reportidString);
ps.setString(2, coursenameString);
// ...
ps.executeUpdate();
}
connection.commit();
Afterwards you should clean up and free the ressources. The best place is in a finally of a try block:
} finally {
try {
ps.close();
} catch(SQLException e) {
e.printStackTrace();
}
try {
connection.close();
} catch(SQLException e) {
e.printStackTrace();
}
}
Some further considerations:
If you really want to use plain JSP, then make use of the Front Controller pattern. So every request goes to the front controller servlet. There you decide what kind of action to execute and collect the data for the view. In the end forward to a JSP to create the view. Inside the JSP you should not use any scriptlets.
Consider to use a MVC framework like Struts or Spring MVC. But the current standard is Java Server Faces which is more component based.
Use a connection pool for the database connection.
Use logging instead of System.out.println() or e.printStackTrace()
To efficiently insert larger files into the database use batch inserts.
There is a system procedure in Derby that may help:
http://db.apache.org/derby/docs/10.11/ref/rrefimportproc.html
http://db.apache.org/derby/docs/10.11/adminguide/cadminimport16245.html

Generating Sequential Transaction ID's in Java

I want to generate Sequential Trnsaction ID's for employees to store in the Database ... I wrote the below jsp code(This ain't the code to insert Tx ID in the database) ..The code works fine .. When i use order by clause to see the latest transaction ..i'm not getting the expected transation ID...How can i make the transaction ID's unique , Sequential so that i can retrieve them in a particular sequence by using Order By clause?
<%
String url = "jdbc:mysql://localhost:3306/";
String dbName = "ystem";
String driver = "com.mysql.jdbc.Driver";
String userName = "root";
String password = "";
try {
Class.forName(driver).newInstance();
Connection conn = DriverManager.getConnection(url+dbName,userName,password);
Statement stat=conn.createStatement();
ResultSet rs=stat.executeQuery("select count(*) from `employee`");
int x=0;
UUID idOne = UUID.randomUUID();
while(rs.next()) {
x=Integer.parseInt(rs.getString(1))+1;
}
out.println(idOne.toString().toUpperCase()+"-"+String.valueOf(x));
stat.close(); conn.close();
}
catch(Exception x) {
out.println(x.getMessage());
}
%>
Leaving aside the wisdom of this approach, appending the count to the UUID isn't going to give you something that will be meaningfully orderable by an order by clause because you are creating something in the form RANDOMSTUFF-2. That can't be ordered in any sequence because order by will sort a string column lexically starting with the first character.
So instead, put the counter at the beginning of your string. Then you'll have something order by can meaningfully sort:
String s = String.valueOf(x) + "-" + idOne.toString().toUpperCase();
(Though you'll probably want/need to zero-pad the output of String.valueOf(x) because otherwise "1000" will be sorted to be before "2". So you need "2" to output as "0002", for example.)
(and of course you should use StringBuilder.append() (or StringBuffer if your version of Java is old enough) rather than string concatenation).

Categories

Resources