How can I make transaction in java+sqlite3 i check google already.I want to make it to be rollback statement so if somewhere in statement goes wrong all statement go to "space" and the DB got rollback to moment before start transaction.
Something like that here Roolback-stmt I hope my question is understandable. So remember that English is not my native language. Here is part of code that I want to make to be a statement:
ArrayList <String> al = new ArrayList <String> ();
try {
// transaction begin;
ResultSet rs = stat.executeQuery("select _id, godziny_id from tblZmiany where harmonogram_id = " + h_id + " order by pracownik_id, Dzien");
while (rs.next()) {
al.add("insert into tblWykonanie (Zmiana_id, Godziny_id) values ('" + rs.getLong(1) + "', " + rs.getInt(2) + ");");
}
for (String s : al)
if (stat.executeUpdate(s) < 1) {
// Jeśli insert nie wstawił kolejnego rekordu
//rollback;
error_code = "Wystąpił problem podczas zatwierdzania harmonogramu.";
return false;
}
// commit;
} catch (SQLException e) {
e.printStackTrace();
System.out.println(e.getMessage());
return false;
} catch (Exception e) {
error_code = e.getMessage();
return false;
}
return true;
You can do this one of two ways, at the connection level or via batch statements.
At the connection level:
final boolean oldAutoCommit = stat.getConnection().getAutoCommit();
stat.getConnection().setAutoCommit(false);
try {
// Your update and insert code here
} catch(Exception e) {
stat.getConnection().rollback();
} finally {
stat.getConnection().commit();
stat.getConnection().setAutoCommit(oldAutoCommit);
}
Error handling has been omitted from the pseudocode, but you get the general idea. You may wish to avoid messing around with the connection, and to instead use batch statements:
for(String query: queries) {
stat.addBatch(query);
}
try {
stat.executeBatch();
} catch(Exception e) {
// ...
}
Which is alot cleaner. Remember that you can always check wether your DB/Driver supports batched transaction via DatabaseMetaData.supportsBatchUpdates().
Use a JDBC driver like SQLiteJDBC which supports transactions.
Related
I'm trying to return result set some method. I'm sure that my sql query out put some result set. Because in the "while(rs.next())" method I print the values. But problem is when I'm returning that result set values and try to calling "while(rs.next())" in the calling method that doesn't print any value. What is reason for that?
/* Calling method */
public void corpusRetriveDemo(){
ArrayList<String> wordAll= new ArrayList<String>();
/* Get all word list For corpus Retrive */
wordAll=allWordsList(sentence1);
ResultSet rsNew=corpusSentenceRetrive(wordAll);
try {
while (rsNew.next()) {
System.out.println("Heloooo2...");
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/* uni Gram calculate */
double d1=calculateProbUniGram(wordAll,rsNew);
System.out.println(d1);
}
/* Database retrieve method */
public ResultSet corpusSentenceRetrive(List wordList) {
PreparedStatement pstmtFGram = null;
Connection conn = null;
ResultSet rs2 = null;
StringBuilder sb = new StringBuilder();
try {
conn = getConnection();
sb.append("SELECT Cor_Sentence FROM corpus Where ");
for(int k=0;k<wordList.size();k++){
sb.append( " Cor_Sentence like '%" + wordList.get(k) + "%' OR ");
}
sb.append(" 1=0");
pstmtFGram = conn.prepareStatement(sb.toString());
rs2 = pstmtFGram.executeQuery();
while (rs2.next()) {
System.out.println("Heloo1...");
}
} catch (Exception e) {
e.printStackTrace();
}
return rs2;
}
"Heloo1" printing correctly. But calling method "Helooo2" doesn't print. What is reason for that? Is there anything wrong with my return statement?
Remove
while (rs2.next()) {
System.out.println("Heloo1...");
}
from the database retrieve method.
You are using the same result set in both cases, and you already reached the end of it by the time you want to print Hello2.
rsNew.next() doesn't have any where to iterate further anymore in your calling method, since it already reached it's end in the database retrieve method.
As in your question you are appending string to string builder.
One thing thing is that. At last final string become look like.
SELECT Cor_Sentence FROM corpus Where Cor_Sentence like '%" + wordList.get(k) + "%' OR Cor_Sentence like '%" + wordList.get(k) + "%' OR
Due to sql query is It trowing an exception.
Another way you are saying Helloo1 is printing. So please comment below line in your code and test.
while (rs2.next()) {
System.out.println("Heloo1...");
}
when working with RecordSet the proper approach is this:
rs.first();
do
{
// do something here
} while (rs.next());
the reason: after iteration on the set it position is at the end of the set, thus making the next method return false. first positioning it back at the beginning
A RECORDSET CAN BE ITERATED MORE THEN ONCE
also seems like you never close the connection conn... please try this please:
try {
conn = getConnection();
sb.append("SELECT Cor_Sentence FROM corpus Where ");
for(int k=0;k<wordList.size();k++){
sb.append( " Cor_Sentence like '%" + wordList.get(k) + "%' OR ");
}
sb.append(" 1=0");
pstmtFGram = conn.prepareStatement(sb.toString());
rs2 = pstmtFGram.executeQuery();
while (rs2.next()) {
System.out.println("Heloo1...");
}
} catch (Exception e) {
e.printStackTrace();
}
finally
{
if (conn != null) conn.close();
}
I am attempting at writing my own server as a personal project, however I'm running into some issues. I've finally completed the setup for a packet system between the Java server and the C# client which makes me very happy, even though I've had some help. Anyway, here's the code that I've written trying to get this to work properly. I created the SQLManager using static variables, because I read that the database connection should be static, if this is incorrect, please let me know.
Here's the error:
Exception in thread "main" java.lang.NullPointerException
com.fmeg.server.util.SQLManager.runQuery(SQLManager.java:37)
Here's my SQL Class:
public static boolean connectToDatabase() {
try {
connection = DriverManager.getConnection(host, credentials[0], credentials[1]);
connected = true;
} catch (Exception e) { connected = false; }
Misc.log("Database: " + database + " || Connection State: " + connected);
return connected;
}
public static boolean runQuery(String query) {
try {
ResultSet rs = checkQuery(query);
if(rs == null)
Misc.error("Result Set returned null.");
if(rs.next())
Misc.log("Current Row: " + rs.getRow());
return true;
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
public static ResultSet checkQuery(String query) throws SQLException {
try {
Misc.log(query);
return statement.executeQuery(query);
} catch (Exception e) {
destroyConnection();
return null;
}
}
private static void destroyConnection() {
try {
statement.close();
connection.close();
connected = false;
Misc.error("Database connection destroyed!");
} catch (Exception e ) { }
}
Apparently, the ResultSet is returning null, here's the output in the console.
[LOG]: Database: Unity3D || Connection State: true
[LOG]: Server <Test Realm> Successfully Started on port: 9955!
[LOG]: select * from `accounts`
[ERROR]: Result Set returned null.
Here's where I'm calling the query:
SQLManager.runQuery("select * from \'accounts\'");
Any pointers would be greatly appreciated, as I don't exactly see what the problem is. To answer these questions if the do arise, yes I do have a table called accounts, and yes it does have entries.
You have a syntax error on table name. Table names should not be a literal but should be quoted with back ticks. These back ticks are optional unless table name has any special chars in it or if it is a reserved word.
Just because of this error, the statement
return statement.executeQuery(query);
is causing an Exception and the method was returning a null for ResultSet.
You better catch the exception and see what the stacktrace says on it.
Change:
QLManager.runQuery("select * from \'accounts\'");
To:
QLManager.runQuery("select * from `accounts`");
You problem in this code:
if(rs == null) {
Misc.error("Result Set returned null.");
if(rs.next())
Misc.log("Current Row: " + rs.getRow());
In case any exception occurred in checkQuery method, it will return a null for ResultSet, then the code will proceed to rs.next(), which rs null, then a NullPointerException will raise.
What all you have to do is:
if(rs == null) {
Misc.error("Result Set returned null.");
return false;
}
if(rs.next()) {
Misc.log("Current Row: " + rs.getRow());
return true;
}
But you have to at least to log the error or throw the exception in checkQuery to figure out what is the exact problem that you are facing. not just return null object.
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;
}
here is my very simple table (Postgres):
CREATE TABLE IF NOT EXISTS PERFORMANCE.TEST
(
test text NOT NULL UNIQUE
);
if I try to insert a String using the command below FROM the database,everything works as expected, not surprisingly a new row appears in the DB.
insert into performance.test (test) values ('abbbbaw');
However if I want to insert a String through JDBC, nothing gets inserted, although preparedStatement.executeUpdate() always returns 1.
Below is my method that should be working but it does not. Please tell me if I am missing something obvious.
I want to add that I never get any SQLException.
private void storePerformance() {
Connection conn= initializePerformanceConnection();
if (conn!= null) {
PreparedStatement insertPS = null;
try {
insertPS = conn.prepareStatement("insert into performance.test (test) values (?)");
insertPS.setString(1, queryVar);
int i = insertPS.executeUpdate();
LogManager.doLog(LOG, LOGLEVEL.INFO," numberofrows= "+i);
} catch (SQLException e) {
LogManager.doLog(LOG, LOGLEVEL.INFO,"Inserting query failed = "+queryVar,e);
}finally{
if(insertPS != null){
try {
insertPS.close();
} catch (SQLException e) {
LogManager.doLog(LOG, LOGLEVEL.INFO,"Closing PreparedStatement failed = "+queryVar,e);
}
}
try {
conn.close();
} catch (SQLException e) {
LogManager.doLog(LOG, LOGLEVEL.INFO,"Closing performanceConnection failed= "+ queryVar, e);
}
}
}
}
that was missing:
conn.commit();
(after the executeUpdate())
actually a new row was inserted but the DB rolled back immediately.
executeupdate is for a 'update table set column = value so on'. For insert just call execute of PreparedStatement.
I am creating a simple registration frame that adds records onto a database. It gives me an error message every time it runs the SQL query that adds records in the database, however it still adds them, but because of that my programs gets to a standstill, instead of opening another window.
here's that part of the code:
regButton.addActionListener(new ActionListener() {
#Override public void actionPerformed( ActionEvent e ) {
//Execute when button is pressed
if( uNameField.getText().equals("")
|| new String(newPassField.getPassword()).equals("")
|| new String(repeatPassField.getPassword()).equals("") ) {
errorLabel.setForeground(Color.red);
errorLabel.setText("Some fields are left blank");
}
else if( new String(newPassField.getPassword()).equals(
new String(repeatPassField.getPassword()))){
Statement stmt;
ResultSet res;
try
{
//SET USERNAME AND PASSWORD FROM FIELDS TO UPPER CASE
String username = uNameField.getText().toUpperCase();
String password = new String(newPassField.getPassword()).toUpperCase();
//SQL INSERT QUERY
String sql;
sql = "INSERT INTO Employees VALUES ('" +username +"','" +password +"');";
stmt = con.createStatement();
res = stmt.executeQuery(sql);
System.out.println("Added to database!");
con.close();
}
catch(SQLException exe) {
System.out.println("Error creating or running statement: " + e.toString());
try {
con.close();
}
catch(Exception eex){}
}
}
else {
errorLabel.setForeground(Color.red);
errorLabel.setText("Password missmatch");
}
}
Every time it registers a new employee (user) it displays this "Error creating or running statement: ..... " although, I can find the newly added employees in the employee list.
What may be causing this problem?
Before we get to your specific problem, some general advice:
Connection con = ...
try {
// your stuff
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
The way you are doing it now not only swallows the exception, but also avoids printing its stacktrace. And close must be performend once and only once, regardless of the exception.
If you are on Java 7, this would be much easier:
try (Connetion con = ...) {
// stuff to do
}
catch (Exception e) {
e.printStackTrace();
}
The closing in a finally is now done automatically.
Specifically about your exception, you execute an INSERT by calling executeQuery. This method sends the statement to the DB, which properly executes it, but its response back to the JDBC is not a ResultSet. This is where it blows up, after the record is already inserted. Since you are in autocommit mode, there is no transaction to roll back. Lesson: always use transactions.
You need to use executeUpdate for SQL INSERTs
int rowCount = stmt.executeUpdate(sql);
I hate seeing code written this way. You didn't ask about this, and my comment won't solve your problem, but I think it needs to be said.
You're creating a maintenance nightmare for yourself by putting persistence code in a Swing Listener method.
A better idea is to think about objects in a way that gives them a single responsibility.
Take your persistence code and move it into a separate class that you can develop and test on its own. Once it's working, give a reference to the class that needs it.
Your code will be more modular, easier to test, more reusable, and less of a nightmare to understand.
Uncle Bob Martin has a succinct mneumonic for this and other ideas worth remembering: SOLID.
why dont you try PreparedStatement
try{
//SET USERNAME AND PASSWORD FROM FIELDS TO UPPER CASE
String username = uNameField.getText().toUpperCase();
String password = new String(newPassField.getPassword()).toUpperCase();
//SQL INSERT QUERY
PreparedStatement pstmt = con.prepareStatement("insert into Employees values(?,?)");
pstmt.setString(1,username);
pstmt.setString(2,password);
if(!pstmt.execute())
{
//means your code worked correctly
System.out.println("Inserted successfully");
}
else
{
System.out.println("Unsuccessfull");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}