Hibernate transaction does not commit changes to database (SQL Server) - java

We have a function in our application that cleans up the database and resets the data, we call a method cleanup() which at first deletes all the data from the database and then calls a sql script file to insert all the necessary default data of our application. Our application supports Oracle - MySQL and MSSQL, the function works fine on both Oracle and MySQL but doesn't work as it supposed to on MSSQL.
The problem is that it is clearing all the data from the database but not inserting the default data, the first section of the method works fine but the second section doesn't get committed to the database. Here is the function:
public boolean cleanup(...){
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
// delete and drop sql queries here...
tx.commit();
session.close();
// end of first section
session = sessionFactory.openSession();
tx = session.beginTransaction();
// insert default data sql queries here...
tx.commit();
session.close();
// end of second section
}
The database gets cleared successfully, but the default data is not being inserted to the database. Please let me know what am I doing wrong here. I tried doing both delete and insert sections in one transaction with no luck.

Related

How to start an IMMEDIATE TRANSACTION in SQLITE JDBC

I'm having a little problem with transactions using JDBC.
I want to start an IMMEDIATE transaction which in pure SQL is:
BEGIN IMMEDIATE;
In Java JDBC SQLite, you cannot do this. You can't call BEGIN IMMEDIATE on a statement if you have autocommit enabled. Committing queries will result in an "autocommit is enabled" error.
db = DriverManager.getConnection("jdbc:sqlite:sqlite.db");
// start a transaction using an sql query...
db.createStatement().execute("BEGIN IMMEDIATE");
// create another statement because this is running from another method...
stmt = db.createStatement();
stmt.executeUpdate("UPDATE table SET column='value' WHERE id=1");
// this will cause an error(exception): AUTOCOMMIT IS ENABLED.
db.commit();
The code above will throw an AUTOCOMMIT IS ENABLED exception.
However, there is also a problem when disabling autocommit because it starts the transaction after using that code. consider the code below:
db = DriverManager.getConnection("jdbc:sqlite:ez-inventory.db");
// doing the createstatement and setautocommit reciprocally still produce the same exception.
db.setAutoCommit(false);
db.createStatement().execute("BEGIN IMMEDIATE");
This code will throw another exception:
[SQLITE_ERROR] SQL error or missing database (cannot start a
transaction within a transaction)
There is a setTransactionIsolation method in the connection but it's not for transaction locking. It's for isolation. I need to start a transaction using any of the SQLite transaction modes: DEFFERED, IMMEDIATE, or EXCLUSIVE
Is this possible with SQLite JDBC?
OK I got it! You should create a Properties object with transaction_mode key and a desired transaction mode value. and put the Properties object as a parameter when your creating your new SQL Connection instance.
import java.sql.*; // <-- bad practice.. just too lazy to put the needed modules one by one for this example
public void immediate_transaction_example() throws SQLException {
// create a properties with a transaction_mode value
Properties sqlprop = new Properties();
properties.put("transaction_mode", "IMMEDIATE"); // <-- can be DEFERRED, IMMEDIATE, or EXCLUSIVE
db = new DriverManager.getConection("jdbc:sqlite:sqlite.db", sqlprop); // <-- pass the properties to the new sql connection instance.
db.setAutoCommit(false); // <-- this will automatically begin the transaction with the specified transaction mode...
// other new transactions attempts with immediate transaction mode will be blocked until the connection is closed.
try {
// proceed the transactions here...
db.createStatement().execute("INSERT INTO table (id, value) VALUES (1, 'myvalue')");
db.createStatement().execute("INSERT INTO table (id, value) VALUES (2, 'myvalue')");
// no errors proceed
db.commit();
} catch (SQLException ex) {
// there is an error!
db.rollback();
}
db.close() // <-- you need to close the connection for sqlite to create a new immediate transaction.
}
Note: This uses xerial's sqlite-jdbc module.
Module Link: https://github.com/xerial/sqlite-jdbc

Hibernate not executing an UPDATE query

I'm trying to setup hibernate in a project, and as part of it, I'm trying to do a simple update query just to make sure that its able to work. Here's my code:
Session sess = factory.openSession();
sess.beginTransaction();
sess.createSQLQuery("UPDATE fooTable SET bar='baz' ");
sess.getTransaction().commit();
sess.close();
When I run the code, everything executes without any error messages, and I see debug messages about getting a JDBC driver (using the config info I've provided), but the update query doesn't seem to be executed, as the table still shows the old info.
What am I doing wrong?
You created the query, but didn't execute it.
...
Query qry = sess.createSQLQuery("UPDATE fooTable SET bar='baz' ");
int updatedRows = qry.executeUpdate();
...

Java with Hibernate Database

I have code which updates a column in a database which looks like this:
logger.info("Entering Update Method");
Query query =session.createQuery("update CardMaster cm set cm.otpAmount = :otpAmount" + " where cm.cardNumber = :cardnumber");
double otpAmount= cardMaster.getOtpAmount();
String cardNumber=cardMaster.getCardNumber();
query.setParameter("otpAmount",otpAmount);
query.setParameter("cardnumber",cardNumber);
query.executeUpdate();
logger.info("cardMasterUpdated successfully");
In this I am getting otpamount ,cardnumber and it is giving result of executeupdate as 1 but it is not reflecting in Database .. I am opening the session and committing correctly outside.
Instead of using this, if I use update() of hibernate it is happening correctly.
Can you help me out of this?
You have to commit the transaction.
Since you do not commit, nothing is visible for other processes, like the tool you are using to view your DB.
You can acquire your transaction with session.getTransaction(). However, normally you start your transaction manually like this:
Transaction tx = session.beginTransaction();
// Do your stuff
session.flush();
tx.commit()

using Hibernate to loading 20K products, modifying the entity and updating to db

I am using hibernate to update 20K products in my database.
As of now I am pulling in the 20K products, looping through them and modifying some properties and then updating the database.
so:
load products
foreach products
session begintransaction
productDao.MakePersistant(p);
session commit();
As of now things are pretty slow compared to your standard jdbc, what can I do to speed things up?
I am sure I am doing something wrong here.
The right place to look at in the documentation for this kind of treatment is the whole Chapter 13. Batch processing.
Here, there are several obvious mistakes in your current approach:
you should not start/commit the transaction for each update.
you should enable JDBC batching and set it to a reasonable number (10-50):
hibernate.jdbc.batch_size 20
you should flush() and then clear() the session at regular intervals (every n records where n is equal to the hibernate.jdbc.batch_size parameter) or it will keep growing and may explode (with an OutOfMemoryException) at some point.
Below, the example given in the section 13.2. Batch updates illustrating this:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
if ( ++count % 20 == 0 ) {
//flush a batch of updates and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
You may also consider using the StatelessSession.
Another option would be to use DML-style operations (in HQL!): UPDATE FROM? EntityName (WHERE where_conditions)?. This the HQL UPDATE example:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
Again, refer to the documentation for the details (especially how to deal with the version or timestamp property values using the VERSIONED keyword).
If this is pseudo-code, I'd recommend moving the transaction outside the loop, or at least have a double loop if having all 20K products in a single transaction is too much:
load products
foreach (batch)
{
try
{
session beginTransaction()
foreach (product in batch)
{
product.saveOrUpdate()
}
session commit()
}
catch (Exception e)
{
e.printStackTrace()
session.rollback()
}
}
Also, I'd recommend that you batch your UPDATEs instead of sending each one individually to the database. There's too much network traffic that way. Bundle each chunk into a single batch and send them all at once.
I agree with the answer above about looking at the chapter on batch processing.
I also wanted to add that you should make sure that you only load what is neccessary for the changes that you need to make for the product.
What I mean is, if the product eagerly loads a large number of other objects that are not important for this transaction, you should consider not loading the joined objects - it will speed up the loading of products and depending on their persistance strategy, may also save you time when making the product persistent again.
The fastest possible way to do a batch update would be to convert it to a single SQL statement and execute it as raw sql on the session. Something like
update TABLE set (x=y) where w=z;
Failing that you can try to make less transactions and do updates in batches:
start session
start transaction
products = session.getNamedQuery("GetProducs")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
count=0;
foreach product
update product
if ( ++count % 20 == 0 ) {
session.flush();
session.clear();
}
}
commit transaction
close session
For more information look at the Hibernate Community Docs

Hibernate transaction duplicate problem

I want update some of my table in database and want all of these work do in 1 transaction,
first of all I delete some entry in branchbuildin(Table) and Insert new one after this action
The problem occurred when I insert and entry with same buildingname and branch_fk (be cause I have this constraint on this table ( uniqueConstraints={#UniqueConstraint(columnNames={"buildingname","branch_fk"})})) but when I don't use hibernate session and use normal JDBC transaction I don't have these problem.
List<Integer> allBranchBuilding = branchBuildingDao.getAllBranchBuildingID(pkId, sess);
for (Integer integer : allBranchBuilding) {
branchBuildingDao.delete(integer, sess); // delete kardane tamame BranchBuilding ha va tel haie aanha
}
Address myAdr = new Address();
setAddress(myAdr, centralFlag, city, latit, longit, mainstreet, remainAdr, state);
BranchBuildingEntity bbe = new BranchBuildingEntity();
setBranchBuildingEntity(bbe, be, myAdr, city, centralFlag, latit, longit, mainstreet, buildingName, remainAdr, state, des);
branchBuildingDao.save(bbe, sess);//Exception Occurred
I get my session at the first of Method:
Session sess = null;
sess = HibernateUtil.getSession();
Transaction tx = sess.beginTransaction();
You're right, everything occurs in the same transaction, and the same Hibernate Session.
The Session keeps track of every entity it manages. Even though you asked to delete it in the database, the corresponding object is still memorised in the Session until the Session is terminated.
In general, it is possible that
Hibernate reorders your operations
when sending them to the database, for
efficiency reasons.
What you could do is flush (ie. send to the database) your transaction because the save (if needed, you could also clear - ie empty the entities memorized by the Session - it after flushing):
sess.flush();
// sess.clear(); // if needed or convenient for you
branchBuildingDao.save(bbe, sess);
Note also that while your entities are memorized by the session, modifying them will trigger an automatic update when closing the session.
In our project, we have a method that deletes efficiently a collection (and another for an array, declared using the convenient ... parameter syntax) of entities (it works for all entities, it doesn't have to be done for each entity), removing them out of the session at the same time, and taking care of the flushing before :
Loop on all entities, delete it (using sess.delete(e)) and add it to a 'deleteds' list.
Every 50 entities (corresponding to the batch size we configured for efficiency reasons) (and at the end) :
flush the Session to force Hibernate to send immediately the changes to the database,
loop on 'deleteds' list, clear each entity from the Session (using sess.evict(e)).
empty the 'deleteds'list.
Don't worry, flush only sends the SQL to the database. It is still subject to commit or rollback.

Categories

Resources