save is not valid without active transaction [duplicate] - java

This question already has answers here:
Hibernate openSession() vs getCurrentSession()
(5 answers)
Closed 4 years ago.
If I use getCurrentSession() to obtain session and I don't begin transaction and save gives exception but when I use openSession() to get session then in the same scenario the program runs without any exception."hibernate.current_session_context_class" is configured with thread in hibernate configuration file.So what is the difference when I use getCurrentSession() and openSession().
Here is the code that gets session using getCurrentSession()-
public static void main(String ar[])
{
SessionFactory sfac=null;
sfac=new Configuration().configure("hibernateconfig/rs.xml")
.buildSessionFactory();
try {
Session session=sfac.getCurrentSession();
Student stu=new Student();
stu.setFirstName("abc23");
stu.setLastName("xyz");
System.out.println("-------------"+stu);
session.save(stu);
}
catch(Exception e)
{
System.out.println(e);
}
}
output-
-------------Student [id=0, firstName=abc23, lastName=xyz]
org.hibernate.HibernateException: save is not valid without active transaction
Here is the code that gets session using openSession()-
public static void main(String ar[])
{
SessionFactory sfac=null;
sfac=new Configuration().configure("hibernateconfig/rs.xml")
.buildSessionFactory();
try {
Session session=sfac.openSession();
Student stu=new Student();
stu.setFirstName("abc23");
stu.setLastName("xyz");
System.out.println("-------------"+stu);
session.save(stu);
}
catch(Exception e)
{
System.out.println(e);
}
}
output-
-------------Student [id=0, firstName=abc23, lastName=xyz]
Hibernate:
insert
into
student
(firstName, lastName)
values
(?, ?)

openSession():
When you call SessionFactory.openSession(), it always create new Session object and give it to you.You need to explicitly flush and close these session objects. As session objects are not thread safe, you need to create one session object per request in multithreaded environment and one session per request in web applications too.
getCurrentSession():
When you call SessionFactory. getCurrentSession(), it will provide you session object which is in hibernate context and managed by hibernate internally. It is bound to transaction scope.When you call SessionFactory.getCurrentSession() , it creates a new Session if not exists , else use same session which is in current hibernate context. It automatically flush and close session when transaction ends, so you do not need to do externally.If you are using hibernate in single threaded environment , you can use getCurrentSession(), as it is faster in performance as compare to creating new session each time.You need to add following property to hibernate.cfg.xml to use getCurrentSession method.
thread

Related

Committing an insert with Transactional decorator

I have the following save method which inserts and commits the object into my database:
public void save() {
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
session.save(this);
session.getTransaction().commit();
}
However, if I use the decorator, it never actually commits to the database:
#Transactional
public void save() {
Session session = HibernateUtil.getSessionFactory().openSession();
session.save(this);
}
Is there something additional I need to do in order for connection to commit it?
The #Transactional annotation will already create a transaction using a proxy.
So you don't need to open a new session from your sessionFactory, you just need to get the current one.
This should work for you:
Session session = HibernateUtil.getSessionFactory().getCurrenstSession();
session.save(this);
Please let me know if it worked :)

Need I close hibernate session after select or not?

if I use SessionFactory
private SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
public Session getSession() {
return sessionFactory.openSession();
}
And use it in my DAO class:
public List<Entity> fetchEntities(Date fromDate, Date toDate) {
Criteria criteria = getSession().createCriteria(Entity.class);
criteria.add(Restrictions.between("cts", fromDate, toDate));
criteria.addOrder(Order.desc("cts"));
return (List<Entity>) criteria.list();
}
Need I close session or not? How curectly do it?
public List<Entity> fetchEntities(Date fromDate, Date toDate) {
Criteria criteria = getSession().createCriteria(Entity.class);
criteria.add(Restrictions.between("cts", fromDate, toDate));
criteria.addOrder(Order.desc("cts"));
return (List<Entity>) criteria.list();
}
Need I close session or not? How correctly do it?
If you create a session instance and close it for each executed query, it may work but it may also have side effects such as a connection pool bottleneck or a overuse of memory.
close() releases the JDBC connection and performs some cleaning.
The Connection close() method of the org.hibernate.Interface Session class states :
End the session by releasing the JDBC connection and cleaning up.
So you should not open and close the session for each executed query.
You should rather close the connection when all queries associated to a client request/processing (user, batch ...) were executed.
Of course if the client request consists of a single query, it makes sense to close it after the query execution.
Actually you use SessionFactory.openSession() that creates a new session that is not bound to the Hibernate persistence context.
It means that you have to explicitly close the session as you finish working with it otherwise it will never be closed.
Supposing that the method is the single one executed in the client request, you could write something like :
public List<Entity> fetchEntities(Date fromDate, Date toDate) {
Session session;
try{
session = getSession();
Criteria criteria = session.createCriteria(Entity.class);
criteria.add(Restrictions.between("cts", fromDate, toDate));
criteria.addOrder(Order.desc("cts"));
return (List<Entity>) criteria.list();
}
finally {
if (session != null) {
session.close();
}
}
Note that if you used SessionFactory.getCurrentSession(), you would not need to close it explicitly as it obtains the current session from the persistence context that creates the session as the transaction is started and close it as the transaction is finished.
The scope of the hibernate session should be the current unit of work (i.e. the transaction) (keep it mind that session is not thread safe).
The factory should be kept for the whole app lifecycle.
See also Struggling to understand EntityManager proper use
No. Actually your web franework ( like spring ) or declarative transaction anagement will do this for you. But there are some cases when you would like to manage sessions yourself. Like batch processing - as hibernate session caches are growing constantly

write good code for hibernate performance [duplicate]

This question already has answers here:
Hibernate Performance Best Practice?
(3 answers)
Closed 7 years ago.
I am facing some performace issue in my application. Especially while saving to and retrieving from the database.
My application is a standalone application. Not a webapplication. I am using hibernate for database communication.
This application has not gone in production. This application will be used 50 people simultaneously.
Here is the below code which I have used for getting session. I suspect below is the code for getting slowness.
public class HibernateUtil {
public Session getSession() {
SessionFactory buildSessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = buildSessionFactory.openSession();
return session;
}
public Transaction getTransaction() {
return getSession().getTransaction();
}
}
I am not sure how to write a good code for opening session.
Can anyone suggest how to refactor this code to a good code?
Also, are the session getting closed, means once the thread has completed a process, are we closing the session.
There is no single statement answer for your question unless the code is observed, there are lot of attributes on which the performance of the system depends.
1.) GC - When and which algorithm being used.
2.) How many session are getting opened, are there any sessions which are left idle. Long running sessions should be avoided.
3.) Introducing Caching mechanism in the code, Hibernate 2nd Level cache, query caching
4.) How big the objects are getting retrieved from the database.
5.) How many queries are getting fired into DB.
Please refer this, this
I faced the similar type of issue in past, the base culprit for this is your are creating the factory instance every time when you are trying to get a transaction.
Please use the singleton pattern to create the SessionFactory object, means just create Session factory once and get all the session instance from that factory object, I am pretty sure you will not face the performance issue after this change
change Something like below-
static SessionFactory buildSessionFactory;
public static getSessionFactory() {
if(buildSessionFactory==null) {
buildSessionFactory = new
AnnotationConfiguration().configure().buildSessionFactory();
}
}
public Session getSession() {
getSessionFactory();
Session session = buildSessionFactory.openSession();
return session;
}
public Transaction getTransaction() {
return getSession().getTransaction();
}
It will solve your problem

Can you have multiple transactions within one Hibernate Session?

Can you have multiple transactions within one Hibernate Session?
I'm unclear if this is an allowable desirable. In my code I have a long running thread and takes items from a Blocking Queue, depending on what is on the queue, it may need to create and save a hibernate object, or it may not need to do anything.
Each item is distinct so if item 1 is saved and item 2 fails to save whatever reason I don't want to that to prevent item 1 being added to the database.
So the simplest way to do this is for each item that needs to be created to create a new session, open transaction, save new object, commit transaction, close session
However, that means a new session is created for each item, which seems to go against Hibernates own recommendations to not do Session Per Request Pattern. So my alternative was to create one session in the thread, then just open and commit a new transaction as required when needed to create a new object. But I've seen no examples of this approach and I'm unsure if it actually works.
The session-per-request pattern uses one JDBC connection per session if you run local transactions. For JTA, the connections are aggressively released after each statement only to be reacquired for the next statement.
The Hibernate transaction API delegates the begin/commit/rollback to the JDBC Connection for local transactions and to the associated UserTransaction for JTA. Therefore, you can run multiple transactions on the same Hibernate Session, but there's a catch. Once an exception is thrown you can no longer reuse that Session.
My advice is to divide-and-conquer. Just split all items, construct a Command object for each of those and send them to an ExecutorService#invokeAll. Use the returned List to iterate and call Future#get() to make sure the original thread waits after all batch jobs to complete.
The ExecutorService will make sure you run all Commands concurrently and each Command should use a Service that uses its own #Transaction. Because transactions are thread-bound you will have all batch jobs run in isolation.
Obviously, you can. A hibernate session is more or less a database connection and a cache for database objects. And you can have multiple successive transactions in a single database connection. More, when you use a connection pool, the connection is not closed but is recycled.
Whether you should or not is a matter of reusing objects from session. If there is a good chance but you can reuse objects that a preceding transaction has put in session, you should keep one single session for multiple transactions. But if once an object has been committed, it will never be re-used, it is certainly better to close the session and re-open a new one, or simply clear it.
How to do it :
If you have a Session object, you create transactions with :
Transaction transaction;
transaction = session.beginTransaction();
... (operations in the context of transaction)
transaction.commit();
... (other commands outside of any transaction)
transaction = session.beginTransaction();
... (and so on and so forth ...)
From hibernates documentation
"A Session is an inexpensive, non-threadsafe object that should be used once and then discarded for: a single request, a conversation or a single unit of work. A Session will not obtain a JDBC Connection, or a Datasource, unless it is needed. It will not consume any resources until used."
so if you are creating sessions again and again it will not burden the system much. If you are continuing a session for too long it may create problems as session is not thread safe .In my opinion you simplest solution is the best "So the simplest way to do this is for each item that needs to be created to create a new session, open transaction, save new object, commit transaction, close session"
By the way if you are creating single record of anything you dont need transaction too much. creating single record is inherently " all or none" thing for which we use transaction
package hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
class Tester {
public static void main(String[] args) {
SessionFactory sf = new org.hibernate.cfg.Configuration().configure().buildSessionFactory(new StandardServiceRegistryBuilder().configure().build());
Session session = sf.openSession();
session.beginTransaction();
Student student = new Student();
student.setName("Mr X");
student.setRollNo(13090);
session.save(student);
session.getTransaction().commit();
session.getTransaction().begin();
session.load(Student.class,23);
student.setName("New Name");
student.setRollNo(123);
session.update(student);
session.getTransaction().commit();
session.close();
}
}
Short answer is yes, you can use same session for transaction. Take a look at org.hibernate.Transaction., it has required method to manage transaction.
docs.jboss.org Chapter 13. Transactions and Concurrency
Use a single database transaction to serve the clients request, starting and committing it when you open and close the Session. The relationship between the two is one-to-one and this model is a perfect fit for many applications.
It seemed we should always obey the "one-to-one relationship" rule.
But, although the sample below will trigger a exception in the line where the second "session.beginTransaction()" is called
Exception in thread "main" java.lang.IllegalStateException: Session/EntityManager is closed
private static void saveEmployees(SessionFactory factory) {
// crate session
//Session session = factory.openSession();
Session session = factory.getCurrentSession();
{
// start a transaction
Transaction trans = session.beginTransaction();
// create an employee
Employee tempEmployee = new Employee("Steve","Rogers", "The Avengers");
// save to database
session.save(tempEmployee);
// commit the transaction
trans.commit();
}
{
// start a transaction
Transaction trans = session.beginTransaction();
// create an employee
Employee tempEmployee = new Employee("Tony","Stark", "The Avengers");
// save to database
session.save(tempEmployee);
// commit the transaction
trans.commit();
}
// close session
session.close();
}
, another sample below will work properly.
The only difference is that the second sample uses "factory.openSession()" to get a session, instead of "factory.getCurrentSession()".
private static void saveEmployees(SessionFactory factory) {
// crate session
Session session = factory.openSession();
//Session session = factory.getCurrentSession();
{
// start a transaction
Transaction trans = session.beginTransaction();
// create an employee
Employee tempEmployee = new Employee("Steve","Rogers", "The Avengers");
// save to database
session.save(tempEmployee);
// commit the transaction
trans.commit();
}
{
// start a transaction
Transaction trans = session.beginTransaction();
// create an employee
Employee tempEmployee = new Employee("Tony","Stark", "The Avengers");
// save to database
session.save(tempEmployee);
// commit the transaction
trans.commit();
}
// close session
session.close();
}
I am a starter, and I don't know why "factory.getCurrentSession()" works differently from "factory.openSession()", yet.

Understanding SessionFactory and Hibernate Sessions

I am learning Hibernate now and I need help to understand how Sessions work. I have some methods in a class which I have given below.
I see there is a getCurrentSession() in SessionFactory class. So, it seems that only one Session can be "active" inside a SessionFactory. Is this SessionFactory like
a queue of transactions where the transactions are completed in in order ? If yes, then
is it possible to promote a transaction to a higher or lower priority ?
private static SessionFactory factory;
//Get a hibernate session.
public static Session getSession(){
if(factory == null){
Configuration config = HibernateUtil.getConfiguration();
factory = config.buildSessionFactory();
}
Session hibernateSession = factory.getCurrentSession();
return hibernateSession;
}
public static void commitTransaction(){
HibernateUtil.getSession().getTransaction().commit();
}
public static void rollbackTransaction(){
HibernateUtil.getSession().getTransaction().rollback();
}
And some more methods that use getTransaction().
SessionFactory's job is to hide the session creation strategy. For example, in a web application, you probably want the SessionFactory to return create a Session the first time getCurrentSession() is called on a thread, and then return the same Session from that point forward for the duration of the request. (Since you probably want to load customer data from that session, then maybe modify their account in that same session.) Other times, you may want SessionFactory to create a brand new session every time you call getCurrentSession(). So by hiding this decision behind the SessionFactory API, you simply write code that gets the Session from the factory and operates on it.
The Session is what handles transactions. As you probably expect, transactions are started in a Session, and then either complete or rollback. There is really no way to prioritize them since once they are started, you are committed to either rolling it back or committing it.

Categories

Resources