Inserting values in MySQL using an array - java

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"));
}

Related

Treating JSON array as a String to insert into MYSQL

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.

rs.next() is returning false in while statement

So, I'm trying to extract msgID and msgStatus values from database for each reference Id(variable msgRefList) stored in the list object and I'm trying to store these extracted values in String objects for further processing. But rs.next() method is returning false and hence it is not going into the while loop where the assignment statements are. I checked in database with the query that i'm using in the code and it shows one record in the result, but still rs.next() is returning false. Screenshot attached with the database results.
Below is the actual code that i'm using
List<String> msgRefList = listofRefrnceValues:
try {
Connection connect = connectToDB(ENV);
for(String reference: msgRefList){
String query="select ID, MSG_STS from TABLE where INSTR_ID = ?";
PreparedStatement stmt = connect.prepareStatement(query);
stmt.setString(1,reference);
ResultSet rs = stmt.executeQuery();
if(rs!=null){
while(rs.next()) {
P_MID = rs.getString("P_MID");
P_MSG_STS = rs.getString("P_MSG_STS");
}
}
}
}catch (Exception e) {
e.printStackTrace();
}
You have some typos in your SQL-Query-String in java. Instead of TABLE you probably meant MINF (your real table) also all of your properties don't have the prefix P_ and ID is probably MID. So change:
String query="select ID, MSG_STS from TABLE where INSTR_ID = ?";
To:
String query="select P_MID, P_MSG_STS from MINF where P_INSTR_ID = ?";
And you'll be fine.

SQLServerException: A result set was generated for update

I'm trying to insert a new record into an MS SQL database, and I'm getting an exception I've never seen before. When I call executeUpdate the following exception is thrown:
com.microsoft.sqlserver.jdbc.SQLServerException: A result set was generated for update.
This is the Java code that produces the error:
// addComment method adds a new comment for a given requestId
public CommentBean addComment(CommentBean comment) {
PreparedStatement stmt = null;
INative nat = null;
Connection conn = null;
try {
nat = dbConn.retrieveNative();
conn = (Connection)nat.getNative("java.sql.Connection");
stmt = conn.prepareStatement(ADD_COMMENT);
stmt.setInt(1, comment.getRequestId());
stmt.setString(2, comment.getComment());
stmt.setString(3, new SimpleDateFormat("MM/dd/yyyy").format(comment.getDateCreated()));
stmt.setString(4, comment.getCreatedBy());
comment.setCommentId(stmt.executeUpdate()); // exception
} catch(Exception ex) {
System.err.println("ProjectRegistration::SQLDAO - addComment");
ex.printStackTrace();
} finally {
try {
if (stmt != null) stmt.close();
} catch (Exception e) {}
}
return comment;
}// end addComment
Where ADD_COMMENT is defined as a String:
private static final String ADD_COMMENT = "INSERT INTO RequestComments OUTPUT INSERTED.commentId VALUES(?,?,?,?)";
For the sake of being thorough, the table is defined as:
CREATE TABLE RequestComments (
commentId int NOT NULL PRIMARY KEY IDENTITY(1,1),
requestId int FOREIGN KEY REFERENCES Requests(requestId),
comment varchar(400),
dateCreated date,
createdBy varchar(12)
);
I don't think I'm doing anything terribly complicated here, but I can't think of why I'm getting this exception. I have a method in the same class which does the exact same type of insertion (literally the same query with a different table name and number of values), and it has no issues. Does anyone have any ideas on how to resolve this issue?
This particular error can also be caused by an INSERT-trigger, which has a SELECT-statement as a part of the trigger code.
To test whether this is the case, you can try:
using executeQuery(), instead of executeUpdate() - and display the result.
executing the insert in tool like MySQL Workbench, SQL Server Management Studio, or whatever flavour of database design tools are available for your DBMS, to see whether a result is returned.
Related: sql server error "A result set was generated for update"
I'm hoping this may help others looking at the same error message, as it did for me. My solution was to live with a call to executeQuery(), although it only handles an underlying issue, instead of fixing it.
This instruction stmt.executeUpdate() is not returning the commentId, it returns a ResultSet which you could then get the commentId from. Something like this,
ResultSet rs = stmt.executeQuery(); // Not update, you're returning a ResultSet.
if (rs.next()) {
comment.setCommentId(rs.getInt(1));
}
you are using OUTPUT in your insert query i.e you will get a resultset after your query executes and to hold that you need an object of class ResultSet to hold that data
SqlServer : When SET NOCOUNT is ON, the count is not returned. When SET NOCOUNT is OFF, the count is returned.
Connection conn = DriverManager.getConnection(connectDB,user,pwd);
String sql = " set nocount off;INSERT INTO test (name) values (1)";
PreparedStatement prepareStatement = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
System.out.println(prepareStatement.executeUpdate());
ResultSet generatedKeys = prepareStatement.getGeneratedKeys();
if(generatedKeys.next()){
System.out.println(generatedKeys.getString(1));
}
Related:
set-nocount-on-usage
I've had a similar problem where after a while an insert on a autonumber table would give a "A result set was generated for update." at random. I use connection pooling and somehow the driver can get into a state where executeUpdate in combination with Statement.RETURN_GENERATED_KEYS doesn't work anymore. I found out that in this state an executeQuery does the trick, but in the initial state executeQuery does not work. This lead me to the following workaround:
PreparedStatement psInsert = connection.prepareStatement("INSERT INTO XYZ (A,B,C) VALUES(?,?,?)", Statement.RETURN_GENERATED_KEYS);
ResultSet rs = null;
try {
psInsert.setString(1, "A");
psInsert.setString(2, "B");
psInsert.setString(3, "C");
Savepoint savePoint = connection.setSavepoint();
try {
psInsert.executeUpdate();
rs = psInsert.getGeneratedKeys();
} catch (SQLServerException sqe)
{
if (!sqe.getMessage().equals("A result set was generated for update."))
throw sqe;
connection.rollback(savePoint);
rs = psInsert.executeQuery();
}
rs.next();
idField = rs.getInt(1);
} finally {
if(rs != null)
rs.close();
psInsert.close();
}

Newbie pointer rs.next

I would like to see only that products user is looking for them, but when second if is executed it will push(pointer or whatever is there) to next ID(id I have as unique so it will push to nowhere) and result is null. I hope you understand my problem :).
if (stmt.execute(
"SELECT * FROM products where ID=" + removeName)) {
rs = stmt.getResultSet();
if (!rs.next()) {
m = "ID not found.";
return m;
}
In your case, you can go for PreparedStatement for avoiding SQL-Injection problem.
PreparedStatement prodsQuery= con.prepareStatement("SELECT * FROM products where ID=?");
prodsQuery.setInt(1,removeName);
ResultSet rs = prodsQuery.executeQuery();
if(!rs.next())
{
m = "ID not found.";
return m;
}
The problem is that you're reading the first result in order to know if there's at least one result, then trying to consume the next results and missing the first one (adapted from your question description). I gave an explanation of how this works here.
A possible solution for this problem would be assuming the query executed with no problems and you have your results, then retrieve the data (or List of data) and as a last step verify if the data is not null or the List of data is not empty.
Code adapted from Naveen's answer to show the proposed solution
PreparedStatement prodsQuery =
con.prepareStatement("SELECT * FROM products where ID=?");
prodsQuery.setInt(1,removeName);
ResultSet rs = prodsQuery.executeQuery();
Assuming there's only one result to get:
//also assuming you will set the results in a Data class (yes, this can be replaced)
Data data = null;
if (rs.next()) {
//logic to retrieve data...
data = new Data();
data.setSomething(rs.get(1));
//more and more code to fill the data...
//because it looks that you need it as String (wonder why you return a String as well)
return data.toString();
}
//note: I use an else statement to check if indeed there were no results at all
//else statement added using a line separator for code explanation purposes
else {
m = "ID not found.";
return m;
}
Assuming there is a list of results to get:
//also assuming you will set the results in a Data class (yes, this can be replaced)
List<Data> dataList = new ArrayList<Data>();
while (rs.next()) {
//logic to retrieve data...
Data data = new Data();
data.setSomething(rs.get(1));
//more and more code to fill the data...
//because it looks that you need it as String (wonder why you return a String as well)
dataList.add(data);
}
//in this case, there's no validation in order to know if there's any result
//the validation must be in the client of this class and method checking if
//the result list is empty using if(!List#isEmpty) { some logic... }
return dataList;
First thing, your approach is vulnerable to SQL Injection. Please go for PreparedStatement.
Look at this simple example for using PreparedStatement
And you should do like this :
ResultSet rs = stmt.executeQuery("SELECT * FROM products where ID=" + removeName);
if (!rs.next()) {
m = "ID not found.";
return m;
}

Getting an Integer From MySQL Select Statement

I would like to get an integer saved in my MySql DB into an Integer in Java. I have a Table, that includes PlayerName and Level. I would like to get The Level (Integer) From a Specific Player. And then Add Integer "Value" to it. Then put it back in the DB. My Code up to now is:
public void addinputPData(String loc, int value, Player player, String playername){
//add input Player Data
try{
logm("Putting Kill Death Int Data into " +player.getName() + "'s Profile!");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/WebCom", "root", "MyPW");
int ovalue = -1;
Statement stmt = (Statement) con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT "+loc+" FROM PlayerData WHERE PlayerName='"+playername+"'");
if(rs.next()){
ovalue= rs.getInt(loc);
}
if(ovalue == -1){
logm("Error Occured");
}
int nvalue = value + ovalue;
String insert = "UPDATE PlayerData SET "+ loc + "='" + nvalue + "' WHERE PlayerName='" + playername + "'";
stmt.executeUpdate(insert);
con.close();
}catch(Exception e){
logm("Could Not Send Data To MYSQL DATABASE SERVER s: "+ e.getMessage());
}
}
I don't know why this won't work, Is there anything obvious that i am missing? Thank you in advance.
So first what you must understand is that when you won't use parametrized statements, there is big danger of SQL Injection. So your code is very dirty written.
So anyway, use PreparedStatement with parametrized SQL statements for much more better performace. Now rewrite your code like this:
final String SELECT_QUERY = "SELECT level FROM PlayerData WHERE PlayerName = ?";
final String UPDATE_QUERY = "UPDATE PlayerData SET level = ? WHERE PlayerName = ?";
public boolean dataMethod(String playerName) {
Connection con = null;
PreparedStatement ps = null;
PreparedStatement ps1 = null;
ResultSet rs = null;
int dataLevel = 0;
try {
// getConnection etc...
ps = con.prepareStatement(SELECT_QUERY);
ps.setString(1, playerName) // first param is order of ? param, starts with 1(not 0)
rs = ps.executeQuery();
while (rs.next()) {
dataLevel = rs.getInt();
}
if (dataLevel > 0) {
ps1 = con.prepareStatement(UPDATE_QUERY);
ps1.setInt(1, dataLevel);
ps1.setString(2, playerName);
ps1.executeUpdate();
}
return true;
}
catch (SQLExcetion ex) {
Logger.getLogger(YourClass.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
finally {
if (con != null) {
con.close();
}
}
}
Step by step, first init your statement, sets parameters if you have then when you use select, you will retrieve data in ResultSet that is table of data generated with query. imlicitly cursor in ResultSet is position before first row so you have to use next() method to go on current row and with the help of getter method you add data from ResultSet to your variable. Then you check if it's correct, if do, init second statement and execute it. And that's all.
But you should consider when you use more that 1 operation, sets autoCommit on false and all operations will do in one Transaction, because implicitly in JDBC is one operation = one transaction. And second, you should consider to use SQL stored procedures for add any data, update data or delete. It's more safer yet and less code. So let database working when it able to do it and also it's faster of course.
At the last, really you should think about this approach and makes your code more safer, faster and cleaner. Not have look on simplicity but on efficiency, compability and security.
More about SQL Injection
And when you decided right to use stored procedure, you can use it like this:
CREATE OR REPLACE PROCEDURE SOME_NAME(VARCHAR v_name PlayerData.name%type)
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
// body
COMMIT;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;
So now you have to create String for call procedure.
final String CALL_SOMENAME = "{call SOME_NAME(?)}";
Then intead of PreparedStatement you have to use CallableStatement that is interface used to execute SQL stored procedures.
cs.prepareCall(CALL_SOMENAME); // Creates a cs object for calling db stored procedures
cs.setString(1, playerName);
cs.execute();
I don't know why many people searching the easiest way to do something and don't look at performance and readability of code.
Regards
In the UPDATE statement, you're inserting the value for the "loc" column as a string (there are single quotes around the value). If the database column is an integer, then this could be causing a problem.
Tip: JDBC provides a class called PreparedStatement. This class allow you to build SQL queries safely. It makes sure that all user input is properly escaped in order to avoid security vulnerabilities.
PreparedStatement ps = con.prepareStatement("UPDATE PlayerData SET " + loc + " = ? WHERE PlayerName = ?");
ps.setInt(1, nvalue);
ps.setString(2, playername);
ps.execute();

Categories

Resources