Any problems in using hibernate's session.connection() to run native sql - java

In my project, they use Hibernate's session the below mentioned way and then save entity objects with in a transaction.
Session session = HibernateUtil.getCurrentSession();
session.beginTransaction();
Employee employee = new Employee() ;
employee.setName("someName") ;
employee.setEmailId ("someId")
employee.setID (100000) ;
session.saveOrUpdate(employee) ;
session.getTransaction().commit();
Now for few functionality I decided to run native SQL. Below is the way i used to run native sql. I wanted to run the queries with-in a transaction and so i decided to write the code the below way
String query = "select name from master_employee where id=?"
Session session = HibernateUtil.getCurrentSession();
session.beginTransaction();
Connection connection = session.connection();
PreparedStatement psStmt = connection.prepareStatement(query);
psStmt.setInt(1,id) ;
ResultSet resultSet = psStmt.executeQuery();
// here i will take data from this result set
psStmt.close();
resultSet.close() ;
// I am not closing the connection object since am taking it from hibernate session
// rather i commit hibernate's transaction
session.getTransaction().commit();
Is this the right way ?? will the transaction's still be managed ?? taking the connection object from session cannot be managed in to the transaction ????
Please tell if there any problems in using this way ??? thanks

Yes, there are no problems here.
However, it would be much easier to run a native query using Session.createSQLQuery():
Session session = HibernateUtil.getCurrentSession();
session.beginTransaction();
String name = (String) session
.createSQLQuery("select name from master_employee where id = ?")
.setInteger(1, id)
.uniqueResult();
session.getTransaction().commit();
See also:
Chapter 18. Native SQL

Related

How to batch execute SQL query using Hibernate session

I am using the below set of code for an update:
private void updateAvatarPath(Integer param1, String param2, String param3, boolean param4){
Transaction avatarUpdatePathTransaction = session.beginTransaction();
String updateQuery = "query goes here with param";
Query query = session.createSQLQuery(updateQuery);
query.executeUpdate();
avatarUpdatePathTransaction.commit();
session.flush();
}
This function is being called from a loop. So this takes time to update since for each loop it's hitting the DB. Instead of hitting DB every time, to increase the performance I am planning to execute it as batches. But have no idea how to do it.
session.doWork() is one of the solutions which I got. I want to know any other option available to do it.
You should move Transaction avatarUpdatePathTransaction = session.beginTransaction(); before the start of your loop and avatarUpdatePathTransaction.commit(); after the end of your loop.
The recommended pattern is to have one session per "unit of work", in your case this seems to be modifying multiple entities in a single session/transaction.
The session.flush(); is not necessary I think, committing the transaction should flush the session

Doesn't session.get() in hibernate always hit the database?

Theoretically, session.get() method is supposed to hit the database always, no matter whether the entity is stored in the cache or not. But whenever I use session.get() or session.load(), both doesn't hit the database second time.
Session session = factory.openSession();
tx = session.beginTransaction();
Customer cust = (Customer)session.get(Customer.class,2);
System.out.println(cust.getCid()+","+cust.getFirstName()+","+cust.getLastName()+","+cust.getPhone());
Customer cust2 = (Customer)session.get(Customer.class,2);
System.out.println(cust2.getCid()+","+cust2.getFirstName()+","+cust2.getLastName()+","+cust2.getPhone());
tx.commit();
session.close();
and this is the output,
Hibernate: select customer0_.cid as cid1_1_0_, customer0_.firstName as firstNam2_1_0_, customer0_.lastName as lastName3_1_0_, customer0_.email as email4_1_0_, customer0_.phone as phone5_1_0_, customer0_.aid as aid6_1_0_ from mycustomers customer0_ where customer0_.cid=?
2,Sam,pp,9799999999
2,Sam,pp,9799999999
Select query is executed only once and next time, it's retrieved from the cache. Same output if I use session.load() method also.
Am I missing something here? Please clarify.
Here's what's happening here:
The first query on console
It will always return a “proxy”. For example if you do session.load(Customer.class, 2), it will return a proxy object. Proxy object just have an identifier value and nothing else. You can imagine it to be somewhat like this.
customer.id = 2;
customer.fname = null;
customer.lname = null;
customer.address = null;
//rest all properties are null
It will Hit the database whenever you'll access the properties. In your case you're immediately calling ust.getCid() so it will immediately hit the database to fetch those queries. So the first query that you see in your console will appear for both the cases (i.e., session.get() and session.load())
Try doing this and see what your console looks like:
Session session = factory.openSession();
tx = session.beginTransaction();
Customer cust = (Customer)session.get(Customer.class,2);
//do not call any getter.
You'll see the difference on your console.
 
Why is second query not appearing
Hibernate Second Level Cache
You're trying to access the same object that you've accessed previously. Hibernate will then (instead of fetching it from database again) fetch it from second level cache.
You'll find detailed example of this scenario on this page : Hibernate Second Level Cache.
(just see the last example, it's similar to what you're getting)

Hibernate's SQLQuery executeUpdate function starts, but does not fully execute

Working on a Spring application that uses Hibernate, and in my DAO layer we are running an UPDATE statement to update some values in an Oracle database.
To make sure I'm not crazy, I ran the statement in SQL Developer to make sure it works properly. Here is part of my DAO code:
public void updateObjectInMyTable(SomeClassA objectOfSomeClassA) {
Session session = getCurrentSession();
String sql = "UPDATE SCHEMA_NAME.TABLE_XYZ SET FIRST_NAME=:firstName, LAST_NAME=:lastName, ADDRESS=:address, CITY=:city, ZIPCODE=:zipcode WHERE ID_NUMBER = :idNumber";
SQLQuery query = session.createSQLQuery(sql);
query.setParameter("firstName", objectOfSomeClassA.getFirstName());
query.setParameter("lastName", objectOfSomeClassA.getLastName());
query.setParameter("address", objectOfSomeClassA.getAddress());
query.setParameter("city", objectOfSomeClassA.getCity());
query.setParameter("zipcode", objectOfSomeClassA.getZipcode());
query.setParameter("idNumber", objectOfSomeClassA.getIdNumber());
query.executeUpdate();
}
(Excuse the poor variables names used for substitutions of the real ones.) I did debug on the server and I do not see any errors with query.executeUpdate() It gets to that line, and doesn't pass on to the next statement I have in my service layer.
Anything I'm doing wrong?
Where's your transaction ?!
Use :
session.beginTransaction().commit();
add this in the end line of your code.
I hope this helps you.

Insert Sql query not working with HQL

I am trying to make a simple insert into a DB with HQlL by using native SQL code.
It doesn't give any error, it just doesn't work. Any help is appreciated.
Thanks.
public void AddMedicament(Medicament medicament) {
System.out.println(medicament.getName());
// open a database connection
Session session = FarmacieHibernateUtil.getSessionFactory().openSession();
Transaction transaction = session.beginTransaction();
// prepare SQL insert command
session.createSQLQuery("insert into Medicament(name) values('test')");
// close the database connection
session.close();
}
You need to call
session.executeUpdate()
transaction.commit();
before closing session.
I am not familar with Hibernate, but i dont see you sre running your command. You just create query and close session
I think you need some statement to execute it.
If you use createSQLQuery this throw a native sql instruction
Your object table name is Medicament too?
session.saveOrUpdate(medicament);
tx.commit();
then it will insert if u r not setting the Primarykey, if u r setting the PK in the domain object then it will be updated.
no need to executeQuery in hibernate if you are using the Spring ORM.

JPA and MySQL transaction isolation level

I have a native query that does a batch insert into a MySQL database:
String sql = "insert into t1 (a, b) select x, y from t2 where x = 'foo'";
EntityTransaction tx = entityManager.getTransaction();
try {
tx.begin();
int rowCount = entityManager.createNativeQuery(sql).executeUpdate();
tx.commit();
return rowCount;
}
catch(Exception ex) {
tx.rollback();
log.error(...);
}
This query causes a deadlock: while it reads from t2 with insert .. select, another process tries to insert a row into t2.
I don't care about the consistency of reads from t2 when doing an insert .. select and want to set the transaction isolation level to READ_UNCOMMITTED.
How do I go about setting it in JPA?
Update
So I ended up creating a regular SQL connection for this case as it seemed to me the simplest option. Thanks everyone!
You need to set it at the connection level, get the session from the entitymanager and do this:
org.hibernate.Session session = (Session)entityManager.getDelegate();
Connection connection = session.connection();
connection.setTransactionIsolation(Connection.READ_UNCOMMITTED);
In JPA you don't. JDO is the only standard that supports setting txn isolation. Obviously going for particular implementations methods can allow it, but then you become non-portable
Since you are using BMT, you can do the following using a datasource to get the connection.
and set the iso. level.
DataSource source = (javax.sql.DataSource) jndiCntxt.lookup("java:comp/env/jdbc/myds");
Connection con = source.getConnection( );
con.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);

Categories