I am trying to develop a forum system as a part of a university assignment,
which contains a database connectivity part.
I am writing the server in java and decided to use hibernate as an ORM tool to save and load from the data base.
My question is not about the syntax, but about the design of the entire system regarding the database.
Who should be in charge of creating a session and commit transactions? should I make a singleton which recive an object and save it to the database and use this singelton in every setter/constructor of the different classes?
should each change in a memory object be commited directly or should I commit only every few changes? (and if so what is the best way to do this?)
Ideally, a framework should do that for you. Using Spring, for example, you could simply mark methods of Spring beans transactional using an annotation, and the session and transaction handling would be done by Spring:
#Autowired
private SessionFactory sessionFactory;
#Transactional
public void foo() {
Session session = sessionFactory.getCurrentSession();
// do some work with the session
}
instead of
private SessionFactory sessionFactory;
public void foo() {
Session sess = sessionFactory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some with the session
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) {
tx.rollback();
}
throw e;
}
finally {
sess.close();
}
}
You should neither commit after each change, nor commit every few changes. You should commit atomic, coherent changes. That's the whole point of transactions:being able to go from a coherent state of your database to another coherent state of your database.
For example If posting a message to a topic forum consists in
persisting a message instance
incrementing the messageCount field of the forum
creating a notification for the topic poster
then these three changes should be in a single transaction, to make sure you don't end up with the message being persisted, but the messageCount not being incremented.
I suggest you leave creating and committing transactions to the container, unless you are sure you want to do it yourself. In this case you can use JTA, and use Container Managed Transactions (CMT). Also remember to avoid entitymanager-per-operation antipattern. To learn more read about Transactions and Concurrency and decide yourself what suit you the best.
Take a look at the DAO (Data Access Object) pattern. It will help to provide a pattern which will help you to encapsulate your data access.
http://en.wikipedia.org/wiki/Data_access_object
Also, this page does a great job:
Data access object (DAO) in Java
As for the second question, the answer entirely depends on your requirements. Usually you want to commit at least once per user interaction. That might be the result of several in-memory changes. It is definitely easier to commit after each entity is changed.
Related
I have a question regarding #Transactional annotation.
Nothing special defined, so as I understand is PROPAGATION_REQUIRED
Let’s say I have a transactional annotation which on both service and dao layer.
Service
#Transactional
public long createStudentInDB(Student student) {
final long id = addStudentToDB (student);
addStudentToCourses (id, student.getCourseIds());
return id;
}
private long addStudentToDB (Student student) {
StudentEntity entity = new StudentEntity ();
convertToEntity(student, entity);
try {
final id = dao.create(entity);
} catch (Exception e){
//
}
return id;
}
private void addStudentToCourses (long studentId, List<String> coursesIds){
//add user to group
if(coursesIds!= null){
List<StudentCourseEntity> studentCourses = new ArrayList<>();
for(String coursesId: coursesIds){
StudentCourseEntity entity = new StudentCourseEntity ();
entity.setCourseId(coursesId);
entity.setStudentId(userId);
studentCourses.add(studentId);
}
anotherDao.saveAll(studentCourses);
}
}
DAO
#Transactional
public UUID create(StudentEntity entity) {
if ( entity == null ) { throw new Exception(//…); }
getCurrentSession().save(entity);
return entity.getId();
}
ANOTHER DAO:
#Transactional
public void saveAll(Collection< StudentCourseEntity > studentCourses) {
List< StudentCourseEntity > result = new ArrayList<>();
if(studentCourses!= null) {
for (StudentCourseEntity studentCourse : studentCourses) {
if (studentCourse!= null) {
save(studentCourse);
}
}
}
}
Despite the fact that’s not optimal, it seems it causing deadlocks.
Let’s say I have max 2 connections to the database.
And I am using 3 different threads to run the same code.
Thread-1 and thread-2 receive a connection, thread-3 is not getting any connection.
More than that, it seems that thread-1 become stuck when trying to get a connection in dao level, same for thread-2. Causing a deadlock.
I was sure that by using propagation_required this would not happen.
Am I missing something?
What’s the recommendation for something like that? Is there a way I can have #transactional on both layers? If not which is preferred?
Thanks
Fabrizio
As the dao.doSomeStuff is expected to be invoked from within other transactions I would suggest you to configure this method as:
#Transaction(propagation=REQUIRES_NEW)
Thanks to that the transaction which is invoking this method will halted until the one with REQUIRES_NEW will be finished.
Not sure if this is the fix for your particular deadlock case but your example fits this particular set-up.
You are right, Propagation.REQUIRED is the default. But that also means that the second (nested) invocation on dao joins / reuses the transaction created on service level. So there is no need to create another transaction for the nested call.
In general Spring (on high level usage) should manage resource handling by forwarding it to the underlying ORM layer:
The preferred approach is to use Spring's highest level template based
persistence integration APIs or to use native ORM APIs with
transaction- aware factory beans or proxies for managing the native
resource factories. These transaction-aware solutions internally
handle resource creation and reuse, cleanup, optional transaction
synchronization of the resources, and exception mapping. Thus user
data access code does not have to address these tasks, but can be
focused purely on non-boilerplate persistence logic.
Even if you handle it on your own (on low level API usage) the connections should be reused:
When you want the application code to deal directly with the resource
types of the native persistence APIs, you use these classes to ensure
that proper Spring Framework-managed instances are obtained,
transactions are (optionally) synchronized, and exceptions that occur
in the process are properly mapped to a consistent API.
...
If an existing transaction already has a connection synchronized
(linked) to it, that instance is returned. Otherwise, the method call
triggers the creation of a new connection, which is (optionally)
synchronized to any existing transaction, and made available for
subsequent reuse in that same transaction.
Source
Maybe you have to find out what is happening down there.
Each Session / Unit of Work will be bound to a thread and released (together with the assigned connection) after the transaction has ended. Of course when your thread gets stuck it won't release the connection.
Are you sure that this 'deadlock' is caused by this nesting? Maybe that has another reason. Do you have some test code for this example? Or a thread dump or something?
#Transactional works by keeping ThreadLocal state, which can be accessed by the (Spring managed) Proxy EntityManager. If you are using Propagation.REQUIRED (the default), and you have a non-transactional method which calls two different DAOs (or two Transactional methods on the same DAO), you will get two transactions, and two calls to acquire a pooled connection. You may get the same connection twice or two different connections, but you should only use one connection at the time.
If you call two DAOs from a #Transactional method, there will only be one transaction, as the DAO will find and join the existing transaction found in the ThreadLocal state, again you only need one connection from the pool.
If you get a deadlock then something is very wrong, and you may want to debug when your connections and transaction are created. A transaction is started by calling Connection.setAutoCommit(false), in Hibernate this happens in org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor#begin(). Connections are managed by a class extending org.hibernate.resource.jdbc.internal.AbstractLogicalConnectionImplementor so these are some good places to put a break point, and trace the call-stack back to your code to see which lines created connections.
As we all know that in Hibernate if no transaction commit, the changes won't affect in database. But I found something weird. And the code as follows:
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring.xml");
SessionFactory sessionFactory = (SessionFactory) ctx.getBean("sessionFactory");
Session session = sessionFactory.openSession();
Model model = new Model();
...
session.save(model);
session.flush();
session.close();
And the model was saved to database even there's no transaction, anyone can explain this?
Any comments would be appreciated! Thanks!
PS: I am using mysql.
The session.flush command saved the transaction. If it's wrong, you should use transaction.
usually hibernate needs the line session.beginTransaction(); to work. You didn't write that and your application worked, I guess your application runs in an Application server, which provides transaction management. e.g. jboss, weblogic...
However it doesn't mean that there is no transaction. Did you set auto-commit true?
btw, session.flush() and txn.commit() are different.
Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory.
After session.flush(), you still can call txn.rollback() to rollback all changes.
edit
oh I saw you used spring. did you configured txnmanager in spring?
Hibernate doesn't need transactions, the most common problems in database-based applications are just easier to solve with transactions which is why usually everyone uses transactions with Hibernate. But that's mere coincidence/convention/laziness.
All Hibernate needs is a java.sql.Connection and if your container provides one even though there is no current transaction manager configured, Hibernate is fine with that.
In fact, Hibernate has no idea that there might be a transaction manager. So session.flush() will use the ApplicationContext to get a connection, generate the SQL and use JDBC to send the generated SQL code to the database.
From Hibernate's point of view, that's all that happens.
There can be several reasons why the data is committed to the database:
You forgot to turn of auto commit on the connection.
Your web container / spring config automatically wires a transaction manager that synchronizes with HTTP requests.
Your code is called form another method which is annotated with #Transactional; in this case, you inherit the existing transaction.
I am using following code
TestDAO {
Session session = null;
public TestDAO() {
this.session = HibernateUtil.getSessionFactory().getCurrentSession();
}
//...more code create,update ...
//each method starts a transcation using "tx= session.beginTransaction();"
}
1)Now should i commit the transcation using tx.commit for a fetch operation too or only for save/update operation??
2)Should i create a seperate instance of TestDAO every time i need?Or should i create a singleton class that returns a single instance of DAO everytme?Will this have a problem?
You don't need tx.commit() for fetch operation. That is only needed for any save, update or delete. Close the session after data fetching.
If your application connect to only one database then use of single DAO is better. Spring framework encourages this. You will find more details about this on the following link
Don't repeat the DAO!
Transactions should not be the responsibility of the DAO, those really need to be controlled at a higher level. A DAO should be something that does queries and updates without being aware of the bigger picture, calls to DAOs can be grouped within an object like a Spring service or EJB session bean which is responsible for deciding what needs to go together in a transaction. This makes your DAO code more reusable since it doesn't have to know as much about the context in which it's operating.
Look at how Spring does it (in the sample applications like petstore that come with Spring), or better, look at the King/Bauer Hibernate-JPA book, which has a chapter on creating DAOs.
I'm playing around with Spring + Hibernate and some "manual" transaction management with PostgreSQL
I'd like to try this out and understand how this works before moving to aop based transaction management.
#Repository
public class UserDAOImpl extends HibernateDaoSupport implements UserDAO {
#Override
public void saveUser(User u) {
Transaction tx = getSession().beginTransaction();
getHibernateTemplate().saveOrUpdate(u);
tx.rollback();
}
}
Calling saveUser here, I'd assume that saving a new User will be rolled back.
However, moving to a psql command line, the user is saved in the table.
Why isn't this rolled back, What do I have to configure to do transactions this way ?
Edit; a bit more debugging seems to indicate getHibernateTemplate() uses a different session than what getSession() returns (?)
Changing the code to
Transaction tx = getSession().beginTransaction();
getSession().persist(u);
tx.rollback();
and the transaction does get rolled back. But I still don't get why the hibernateTemplate would use/create a new session..
A couple of possibilities spring to mind (no pun intended):
a) Your JDBC driver defaults to autocommit=true and is somehow ignoring the beginTransaction() and rollback() calls;
b) If you're using Spring 3, I believe that SessionFactory.getSession() returns the Hibernate Session object wrapped by a Spring proxy. The Spring proxy is set up on the Session in part to handle transaction management, and maybe it's possible that it is interfering with your manual transaction calls?
While you can certainly use AOP-scoped proxies for transaction management, why not use the #Transactional(readOnly=false|true) annotation on your service layer methods? In your Spring config file for your service layer methods, all you need to do to make this work is to add
<tx:annotation-driven />
See chapters 10 and 13 of the Spring Reference Documentation on Transaction Management and ORM Data Access, respectively:
http://static.springsource.org/spring/docs/3.0.x/reference/index.html
Finally, if you're using Spring 3, you can eliminate references to the Spring Framework in your code by injecting the Spring-proxied SessionFactory bean into your DAO code - no more need to use HibernateDaoSupport. Just inject the SessionFactory, get the current Session, and use Hibernate according to the Hibernate examples. (You can combine both HibernateDaoSupport and plain SessionFactory-based Hibernate code in the same application, if required.)
If you see the JavaDoc for HibernateDaoSupport.getSession() it says it will obtain a new session or give you the one that is used by the existing transaction. In your case there isn't a transaction listed with HibernateDaoSupport already.
So if you use getHibernateTemplate().getSession() instead of just getSession(), you should get the session that is used by HibernateTemplate and then the above should work.
Please let me know how it goes.
EDIT:
I agree its protected...my bad. So the other option then is to keep the session thread bound which is usually the best practice in a web application. If HibernateDaoSupport is going to find a thread bound session then it will not create a new one and use the same one. That should let you do rollbacks.
I run following working code:
Session session = null;
try {
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
session = sessionFactory.openSession();
String id = (String) FacesContext.getCurrentInstance()
.getExternalContext().getRequestParameterMap().get(
"storeId");
Transaction t = session.beginTransaction();
stores = getStores();
for (Store store : stores) {
if (store.getId() == Integer.parseInt(id)) {
session.delete(store);
}
}
t.commit();
} catch (Exception e) {
} finally {
session.close();
}
}
When i try redo this code to use Hibernate template, i go unending request to DB:
HibernateTemplate template = new HibernateTemplate();
template .setSessionFactory(sessionFactory);
stores = template.find("from Stores");
for (Store store : stores) {
if (store.getId() == Integer.parseInt(id)) {
template.delete(store);
}}
Looks like transaction is not closed.
How could I close transaction this case? And is it will better at all to use Hibernate template approach instead of session approach showed at first code?
You didn't say it, but I assume you're referring to the HibernateTemplate class in the Spring Framework. HibernateTemplate participates in Spring transactions, but it doesn't manage them on its own. Spring provides a lot of ways to manage transactions both programmatically and declaratively. If you're just experimenting, you can use the TransactionTemplate class to quickly test it out. For larger projects, you should consider using declarative transaction management because it simplifies your code, although it's a little trickier to set up initially.
As for whether or not the HibernateTemplate approach is better than managing your sessions manually, I'd say anything that reduces boilerplate code is a good thing, so yes. This is especially crucial on big projects. However, depending on your project, HibernateTemplate might not even be necessary. It was originally created to work around some deficiencies in Hibernate 2.x, but many of those deficiencies were eliminated in Hibernate 3. So before adopting it, read the HibernateTemplate JavaDoc for a discussion of the advantages.