I have a problem with following method. The method generate a valid query, but it cannot insert the table monitor.
The method:
public void upLoadData(String table, String[] dbCols,List<LinkedHashMap<String,String>> values){
String wq = "INSERT INTO "+table+" (";
for (int j = 0; j < dbCols.length; j++) {
wq+=dbCols[j]+",";
}
wq = wq.replaceAll(",$", ""); //Remove comma from the end of line.
wq+=") VALUES";
for (LinkedHashMap<String, String> val : values) {
wq+="(";
for (int i = 0; i < dbCols.length; i++) {
wq+="'"+val.get(dbCols[i])+"',";
}
wq = wq.replaceAll(",$","");
wq+="),";
}
wq = wq.replaceAll(",$", ";");
System.out.println(wq);
myDB.DBInsert(wq, MyDBPool.getConnections());
}
And the insert method:
public void DBInsert(String query, Connection conn){
Statement stm;
try{
stm = conn.createStatement(); // conn from db connection pool
stm.executeUpdate(query);
}catch(SQLException ex){ex.getLocalizedMessage();}
}
The output is:
INSERT INTO monitor (id,arr_date,company,disp_size,disp_type,producer,prod_type,color,cond_cat,comments)
VALUES('H13/2:3445','2015-11-15','Valami','jó','21','Dell','T32','fekete','B','sadsadasdasd'),
('H14:/3:5567','2015-11-15','Nincs','TFT','19','HP','B32','piros','A','sadsadasd'),
('H13/8:3321','2015-11-15','CCCP','CRT','19','nincs','T24','fehér','D','sadsadsad');
Manualy(PhPMyAdmin) insert is not problem.
I use JDBC, and Hikari dbpool, XAMPP v3.2.1
Any help will be appreciate. Thanks!
You aren't commiting, and you aren't closeing your Statement (or Connection). You could use a try-with-resources close and add a commit like
public void DBInsert(String query, Connection conn) {
try (Statement stm = conn.createStatement()){
stm.executeUpdate(query);
conn.commit();
} catch (SQLException ex) {
ex.getLocalizedMessage();
} finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Also, I strongly recommend you use a PreparedStatement and ? placeholder (or bind paramters) for performance and security reasons instead of building your inserts as String.
Thanks for the help and advise, finally I found the problem, my old insert method is work fine(but I update and refact as Elliott Frisch advised), the problem is only I swap two columns with different types,so PhPMyAdmin is handle the error(give 0 to mismatch value), but Java JDBC cannot resolve, so drop the insert task.
Once more, Thanks a lot! :)
Related
I am having a problem with a ResultSet being closed. What confuses me is that it works for a portion of the data and then closes. At first I thought it might be because of connection timeout but that doesn't seem the case.
This portion of the program pertains to comparing an .xlsx workbook to an already present SQL database and for lack of a better term merges/updates it.
First, in my CompareDatabase class I am calling a search function that searches an SQLite database for a specific string every 6 iterations.
int columnCount = 6;
dataPoint = dataPoint.replaceAll("Detail", "");
String[] temp = dataPoint.trim().split("\\s+");
System.out.println(Arrays.toString(temp));
for (String tempDataPoint : temp) {
if ( columnCount == 6) {
System.out.println(search(tempDataPoint, connection));
}
columnCount = 0;
} else {
columnCount++;
}
}
This search function (also in the CompareDatabase class is then supposed to search for the value and return a String (was originally a Boolean but I wanted to see the output).
private String search (String searchValue, Connection connection) throws SQLException {
PreparedStatement pStatement = null;
pStatement = connection.prepareStatement("SELECT * FROM lotdatabase where (Vehicle) = (?)");
pStatement.setString(1, searchValue);
try (ResultSet resultSet = pStatement.executeQuery()){
return resultSet.getString(1);
}finally {
close(pStatement);
}
}
At the end you can see that the PreparedStatement is closed. The ResultSet should also be closed automatically (I read somewhere) but JDBC could possibly be being unreliable.
The Connection however is still open as it will be searching some 200+ strings and opening and closing that many times did not seem like a good idea.
These functions are called by my main class here:
One is commented out since it will error out because of primary key violation.
public static void main(String[] args) {
SQLDatabase sqlDatabase = new SQLDatabase();
//sqlDatabase.convertToSQL("Database1.xlsx");
sqlDatabase.compare("Database2.xlsx");
}
I have a suspicion that I am going about a bunch of this wrong (on the aspect of managing connections an such) and I would appreciate a reference to where I can learn to do it properly.
Also, being that PreparedStatement can only handle one ResultSet I don't see that being my issue since I close it every iteration in the for loop.
If more code or explanation is required please let me know and I will do my best to assist.
Thank you for taking the time to read this.
So after a bit more Googling and sleeping on it here is what worked for me.
The search function in compareDatabase changed to this:
private Boolean search (String searchValue, Connection connection) {
PreparedStatement ps = null;
try {
ps = connection.prepareStatement("SELECT * FROM lotdatabase where " +
"(Vehicle) = (?)");
ps.setString(1, searchValue);
ResultSet resultSet = ps.executeQuery();
//The following if statement checks if the ResultSet is empty.
if (!resultSet.next()){
resultSet.close();
ps.close();
return false;
}else{
resultSet.close();
ps.close();
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}
return false;
}
And in the other function within compareDatabase I call the search function like this:
if (search(tempDataPoint, connection)) {
System.out.println("MATCH FOUND: " + tempDataPoint);
}else {
System.out.println("NOT FOUND: " + tempDataPoint);
}
This allows me to check the ResultSet and also be sure that it is closed.
I want to establish single connection with sql server for two different queries having same input.
Is that acheivable?
Here is my code which will establish the connection with database twice for executing queries seperately with same input.
String query1="select ID_Student,Lib_Sec_Book from Library_db1 where ID_Student";
String query2="select ID_Student,Lib_Sec_Book from Library_db2 where ID_Student";
Map<String, String> result1=dba.dbcon(inputListMismatch,query1);
Map<String, String> result2=dba.dbcon(inputListMismatch,query2);
these queries have same student IDs as input,I need to find out which ID having book from two library databases.It may mutually exclusive.
saving resultset of query1 and query2 in result1 and result2 respectively
two results need to be in single Map.
In dba method,
Map<String, String> result=new HashMap<String,String>();
try {
String databaseDriver = "net.sourceforge.jtds.jdbc.Driver";
Class.forName(databaseDriver);
}
catch (Exception e) {
e.printStackTrace();
}
try
{
String url = "jdbc:jtds:sqlserver://server;instance=";
java.sql.Connection con =DriverManager.getConnection(url);
System.out.println("Connection created");
String sqlQuery=query+" "+getIn(list.size());
PreparedStatement preparedStatement = con.prepareStatement(sqlQuery);
for(int i=0; i<list.size(); i++)
preparedStatement.setString(i+1, (String) list.get(i));
ResultSet rs = preparedStatement.executeQuery();
ResultSetMetaData rsMeta=rs.getMetaData();
int colcount=rsMeta.getColumnCount();
result.put(rsMeta.getColumnName(1),rsMeta.getColumnName(2));
while(rs.next())
{
result.put(rs.getString(1),rs.getString(2));
}
rs.close();
preparedStatement.close();
con.close();
}
catch (Exception e1)
{
e1.printStackTrace();
}
return result;
}
getting input list
static String getIn(int numParams) {
StringBuilder builder = new StringBuilder("IN (?");
for(int i=1; i<numParams; i++)
builder.append(",?");
builder.append(")");
return builder.toString();
}
Now I am getting two different resultset, I want to pass two queries in a single instance.
I tried union,It is throwing "Parameter has not been set" error.
and I have also tried 'allowMultiQueries=TRUE" that is not helping.
Can you suggest better way of doing this?
I am not sure what you want,but I try to give you some suggestions.
If you are looking for a solution to improve performance,use two threads to query simultaneously. Use http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html to control threads.
If you want to merge two queries into one query , try the following code to build sql.
String sqlQuery=query+" "+getIn(list1.size()) +" union "+ getIn(list2.size());
PreparedStatement preparedStatement = con.prepareStatement(sqlQuery);
for(int i=0; i<list1.size(); i++)
preparedStatement.setString(i+1, (String) list.get(i));
for(int i=0; i<list2.size(); i++)
preparedStatement.setString(list1.size()+i+1, (String) list.get(i));
I have tested the following code using DB2 database , and I think it will work well with other dbs. Because jdbc will make sure its API's are suitable for different database .
String urlRemote = "jdbc:db2://fake_ip_address:60004/fake_db_instance_name";//远程方式连接DB2的默认端口为6789
String strJDBCRemote = "com.ibm.db2.jcc.DB2Driver";
String userName = "fake_user";
String password = "fake_password";
Class.forName(strJDBCRemote);
//连接远程时必须要有用户名和密码,否则连接时报错
Connection con = DriverManager.getConnection(urlRemote,userName,password);
String sql = "select id,value from fake_table1 where id=? union select member_number as id,dbindx_number as value from fake_table2";
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1,"1");
ResultSet rs = pstmt.executeQuery();
while(rs.next()){
System.out.println(rs.getString(1)+" "+rs.getString(2));
}
con.close();
My DB is Oracle.
I know Statement can mix SQL sentences(insert or delete or update) into one single batch. Here is my code.
DBConnection db = new DBConnection();
Connection c = db.getConn();
Statement s = null ;
try
{
String sql = "insert into t1(id, name) values ('10', 'apple')";
String sql1 = "insert into t1(id, name) values ('14', 'pie')";
String sql2 = "delete from t1 where id = '10'";
s = c.createStatement();
s.addBatch(sql);
s.addBatch(sql1);
s.addBatch(sql2);
int[] re = s.executeBatch();...
My question is can PreparedStatement do this? and how?
You can create a batch by PreparedStatement.addBatch() and you can execute it by PreparedStatement.executeBatch
For more about PreparedStatement you can look into documentation
Now if i am not wrong you want to do something like this:
public void save(List<Entity> elements) throws SQLException {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = database.getConnection();
statement = connection.prepareStatement(SQL_INSERT);
for (int i = 0; i < elements.size(); i++) {
Element element= elements.get(i);
statement.setString(1, element.getProperty1());
statement.setString(2, element.getProperty2());
.....
statement.addBatch();
if ((i + 1) % 200 == 0) {
statement.executeBatch(); // Execute every 200 items.
}
}
statement.executeBatch();
} finally {
if (statement != null) try { statement.close(); } catch (SQLException e) { //}
if (connection != null) try { connection.close(); } catch (SQLException e) {//}
}
}
In this case i am executing every 200 items, if you wish you can set your own. But do test it because it also depends on drivers limitation on batch operations.
Statement:
Use for general-purpose access to your database. Useful when you are using static SQL statements at runtime. The Statement interface cannot accept parameters.
PreparedStatement:
Use when you plan to use the SQL statements many times. The PreparedStatement interface accepts input parameters at runtime.
CallableStatement:
Use when you want to access database stored procedures. The CallableStatement interface can also accept runtime input parameters.
so I am a beginer in JDBC - SQL Programming. I need a little advice which is most probably about SYNTAX.
So, Problem = I'm trying to search a record which has name(string provided in function argument) in the record. Following is my code. Now I've designed this code in such a way that there can be more than 1 records with the same name, so all of that records' data will be printed (by ShowData() Function).
protected static void SearchbyName (String toCompareName)
{
Statement stmt = null;
ResultSet rs = null;
Connection conn = null;
boolean flag = false; //to confirm if record has found atleast once
try
{
Class.forName("com.mysql.jdbc.Driver").newInstance();
conn = DriverManager.getConnection(url, username, password);
stmt = conn.createStatement();
rs = stmt.executeQuery("SELECT idEmployee FROM employee WHERE name = ' "+toCompareName+" ' ");
if( !(rs.next()) ) //if ResultSet is not empty
{
while(rs.next()) //reading all records with the same name, extracted by Query
{
int foundID = rs.getInt("idEmployee"); //extracting ID of found record
ShowRecord(foundID); //prints record of foundID fromDB
flag = true; //set flag
}
}
if(flag==false) //if no record found
{
JOptionPane.showMessageDialog(null, "ERROR:: No Records Found..", "Not Found", JOptionPane.ERROR_MESSAGE);
}
//close connection
if(rs!=null)
{ rs.close(); }
if(stmt!=null)
{ stmt.close(); }
if(conn!=null)
{ conn.close(); }
}
catch(SQLException e)
{ System.err.println(e); }
catch(Exception e)
{ System.err.println(e); }
}
So here it is. As far as my understanding goes, there is some problem with either RESULTSET rs or the Query I'm executing.
Kindly help. & if you can suggest a better approach for search, sure do please. I'm going to write 4 more functions SearchbyAge, SearchbyQualification, SearchbySpecialization on the same pattern.
Just this is enough
while(rs.next()) //reading all records with the same name, extracted by Query
{
int foundID = rs.getInt("idEmployee"); //extracting ID of found record
ShowRecord(foundID); //prints record of foundID fromDB
flag = true; //set flag
}
You don't have to check the data in resultset this way with a if case
if( !(rs.next()) )
This will move to the next record in the resultset
SOVLED
My error was in query. I was putting spaces in string's syntax which I was comparing.
WRONG = `"(.. WHERE name = " ' +toCompareName+ '" ");
RIGHT = `"(.. WHERE name = "'+toCompareName+'" ");
So thats it. Hope it helps to anyone else. :)
I've started creating a toDoList and I like to create a "DataMapper" to fire queries to my Database.
I created this Datamapper to handle things for me but I don't know if my way of thinking is correct in this case. In my Datamapper I have created only 1 method that has to execute the queries and several methods that know what query to fire (to minimalize the open and close methods).
For example I have this:
public Object insertItem(String value) {
this.value = value;
String insertQuery = "INSERT INTO toDoList(item,datum) " + "VALUES ('" + value + "', CURDATE())";
return this.executeQuery(insertQuery);
}
public Object removeItem(int id) {
this.itemId = id;
String deleteQuery = "DELETE FROM test WHERE id ='" + itemId + "'";
return this.executeQuery(deleteQuery);
}
private ResultSet executeQuery(String query) {
this.query = query;
Connection con = null;
Statement st = null;
ResultSet rs = null;
try {
con = db.connectToAndQueryDatabase(database, user, password);
st = con.createStatement();
st.executeUpdate(query);
}
catch (SQLException e1) {
e1.printStackTrace();
}
finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e2) { /* ignored */}
}
if (st != null) {
try {
st.close();
} catch (SQLException e2) { /* ignored */}
}
if (con != null) {
try {
con.close();
} catch (SQLException e2) { /* ignored */}
}
System.out.println("connection closed");
}
return rs;
}
So now I don't know if it's correct to return a ResultSet like this. I tought of doing something like
public ArrayList<ToDoListModel> getModel() {
return null;
}
To insert every record returned in a ArrayList. But I feel like I'm stuck a little bit. Can someone lead me to a right way with an example or something?
It depends on the way the application works. If you have a lot of databases hits in a short time it would be better to bundle them and use the same database connection for all querys to reduce the overhead of the connection establishment and cleaning.
If you only have single querys in lager intervals you could do it this way.
You should also consider if you want to seperate the database layer and the user interface (if existing).
In this case you should not pass the ResultSet up to the user interface but wrap the data in an independent container and pass this through your application.
If I understand your problem correctly!, you need to pass a list of ToDoListModel objects
to insert into the DB using the insertItem method.
How you pass your object to insert items does not actually matter, but what you need to consider is how concurrent this DataMapper works, if it can be accessed by multiple threads at a time, you will end up creating multiple db connections which is little expensive.Your code actually works without any issue in sequential access.
So you can add a synchronized block to connection creation and make DataMapper class singleton.
Ok in that case what you can do is, create a ArrayList of hashmap first. which contains Key, Value as Column name and Column value. After that you can create your model.
public List convertResultSetToArrayList(ResultSet rs) throws SQLException{
ResultSetMetaData mdata = rs.getMetaData();
int columns = mdata.getColumnCount();
ArrayList list = new ArrayList();
while (rs.next()){
HashMap row = new HashMap(columns);
for(int i=1; i<=columns; ++i){
row.put(md.getColumnName(i),rs.getObject(i));
}
list.add(row);
}
return list;
}