I am trying to understand the transactions management and try to use its power in my already existing application developed in Struts 2, EJB 3 and hibernate 5.2.
Now I have ejb in my business layer like below
#Stateless
#TransactionManagement(TransactionManagementType.CONTAINER)
public class MyEJb implements ejbxyz {
#Override
public void method(){
Dao dao=new Dao() //Dao class is simple java class
dao.fooMethod(); //this method updates some record
dao.barMethod(); // this method updates some other record
}
}
public class Dao{
fooMethid(){
Session session=sessFactory.openSession();
session.beginTransaction();
session.update(x);
}
barMethod(){
try{
Session session=sessFactory.getCurrentSession();
session.getNamedQuery("xyz").executeUpdate();
}catch(HibernateException ex){
session.getTransaction.rollback();
}
}
}
I understand that Transaction management should be done at service layer(at ejb in my case). But how can I achieve this over there. ?
Now the dependency is if barMethod() fails to update the record then I need to rollback the changes made in fooMethod. So basically I need both the methods to be done in one transaction.
When I execute the application it throws the below exception
Exception while barMethod getNamedQuery is not valid without active transaction
Its because I am not beginning any transaction in barMethod. But then I really dont want to start a new transaction and want to continue with the older transaction started in fooMethod.
Container managed transactions are indeed suported out of the box for EJB beans. However, your Dao class is not a managed bean - it is a regular pojo that you instantiate manualy - therefore it does not participate in any transaction started by your other ejb.
So move your Dao to separate file, annotate it with #Stateless and then inject it into your service using #EJB private Dao dao;
There is more to transactions in Ejb container though. You can control the transaction support on method level via #TransactionAttribute annotation, that specifies how should the container invoke your method with regard to transaction. That way you can control, whether your method requires its own transaction, or if it shall participate in a transaction initiated by the caller(e.g. when invoked from ejb bean). For more info have a look at official Java EE tutorial
Related
i read https://www.baeldung.com/spring-open-session-in-view article
According to this article, it says that the session is created in the request phase.
Spring opens a new Hibernate Session at the beginning of the request. These Sessions are not necessarily connected to the database.
But as far as I know, in Spring, when a transaction starts, it gets an entity manager (session). The reason is that there is no need to create an entity manager for logic that does not use JDBC.
#Transactional
#Service
public class DoService {
// when use this service EntityManager is created;
}
I wonder if I'm getting it wrong.
For example I have #Stateless java bean:
#Stateless(mappedName = "test")
public class Test implements ITest
{
#Override
public void updateActivity
(SomeObj activity)
throws Exception
{
em.persist(activity);
}
}
Because it's a container-managed bean, then tell me, when does the container decide to synchronize the context with a DB? In this case I immediately see the results in the DB, but sometimes they do not seem to immediately appear there, right?
Please explain me How the synchronization works with the context and the DB at Container-Managed mode? When does the container decide to synchronize the context with a DB?
This will be driven by the transaction propagation configuration as your EJB bean might be one of many managed beans participating in a single transaction. This gets more complex if there are multiple transaction sources in flight e.g. XA 2PC. Generally, the changes will be flushed into the database on transaction commit however this further depends on the transaction isolation level or the presence of savepoints when nested transactions are used.
Check the #TransactionAttribute annotation docs or look for a tutorial that explains transaction propagation.
I have a problem accessing stateless EJBs in the preDestroy method of an singleton. I need to log the shutdown of the application server in an database table.
This is what the singleton looks like:
#Startup
#Singleton
public class ServerShutdown {
#EJB
TableFacade tableFacade;
#PreDestroy
private void shutdown() {
TestEntity e = tableFacade.find("test");
//do something
}
}
Here's example code of the stateless bean:
#Stateless
public class TableFacade {
...
public TestEntity find(String test) {
Query query =
getEntityManager().createNamedQuery("TestEntity.namedQuery");
return (TestEntity) query.getSingleResult();
}
}
If the server is shutting down, the preDestroy method is accessed and the EJB method is called. But during the call, the server seems to force the shutdown process and cancels the calling of the EJB method.
I'm using Java EE 6, JDK 1.8, EJB 3.1, eclipselink 2.5.2.
Thanks in advance
The #predestroy should only do ejb resource cleanup, such as connection, variable etc...
Your problem has to do with the transaction context, infact from the spec:
The PreDestroy lifecycle callback interceptor methods for stateless
and stateful session beans execute in an unspecified transaction
context.
And then:
For example, it would be wrong to perform database operations within a
stateful session bean’s PostConstruct or PreDestroy lifecycle callback
interceptor methods and to assume that the operations are part of the
client’s transaction. The PostConstruct and PreDestroy methods for
stateful and stateless session beans are not controlled by a
transaction attribute because handling rollbacks in these methods
would greatly complicate the session instance’s state diagram.
So, it is not explicitly forbidden, but you are warned that things may go wrong.
According to the ejb 3.2 spec, singleton beans are allowed to access ejb's in their pre destroy method. See section 4.8.6 Table 3. If a singleton bean needs to access another singleton bean, then it must declare its dependency using the #DependsOn annotation. The example provided by the original poster should work.
I am currently migrating to EJB3.1 after using Spring for many years. One thing I would like to implement in EJB, for which I couldn't find a matching pattern yet is my MigrationManager.
In Spring I had a bean that dealt with database schema and data migration. For this I implemented a Spring BeanFactoryPostProcessor because this way I had the database connection injected, but the JPA system is not yet initialized. So I could perform all migration steps and then have the application finishing starting.
How can I do something like this in EJB3.1 (Using CDI ... if this is of importance)
Chris
This is the way to run some initialization code from an EJB:
#Singleton
#Startup
public class MigrationManager {
#PostConstruct
public void migrate() {
// do work
}
}
You don't need a separate app for that (as suggested in a comment above).
EntityManagers get instantiated lazily, so as long as you don't inject an EntityManager into some other startup code, this should give you a chance to update your database schema before an EntityManager is actually hitting the database.
By the way, for database schema migration I'd recommend Liquibase, which can be triggered by a ServletContextListener.
I have a Transaction problem on Spring 3.0.5. In my case I get the so-called exception "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"... I have tried everything so far. I can see in my log that the transactional services are detected and registered as Spring beans and I can also see in the logs that they are proxied and associated with underlying Spring transaction interceptors. (Advise) When I run my Spring MVC app my controller will call the service...... :-( but the transaction interceptors are not triggered. (??) I expect my Spring service proxy to open a session and start a transaction before calling my target service method. Since this does not happen, I get the above exception. I have been almost two days on this problem. Tried everything which I found on the internet...but in vain.
I have layered architecture: presentation (springmvc), service (transaction annotated), dataacess (Spring/Hibernate classic sessionfactory). My model objects are annotated with jpa (javax.persistence.*). My spring context config files are separated in appContext.xml, appContext-service.xml and appContext-dao.xml. I have defined my Spring LocalSessionFactoryBean, Datasource and TransactionManager (HibernateTransactionManager) in appContext-dao.xml. I have put in appContext-service.xml where my service implementations resides. In all of my config files I have included and to detect my beans through Controller, Service and Repository annotations.
I appreciate any kind of help.
It sounds like you are doing everything correctly and you know what you are doing. There's not much we can do here unless you show some configuration.
What I'd suggest is some debugging.
First: do you have Unit tests in the service layer that test the queries you are using? Perhaps you can find the error in the service layer.
Then: debug the MVC app, check the types of the injected services. Verify that they are proxies, not the original types.
If they are the original types, you
have an error in your transaction
configuration .
If they are proxies, step through the
query methods and verify that the
transaction logic is applied.
This sounds like accessing a lazily-loaded list or set of you dao after the closing of the transaction. This typically happens if you access that list in the view in stead of the controller, as your controller probably calls methods in transaction scope, and then leaves the transaction and forwards the loaded bean to the view.
Simple solutions:
Configure your data bean to eagerly load
Force loading of the dependencies in the controller (just loop through them)
have a look at this article ans possibly also quite a few right here on SO on lazy loading / lazy fetching of one-to-many associations and the like
Imagine:
// your dao
public class Foo {
// lots of other properties
List<Something> stuff;
// getters and setter for stuff
}
// repository
#Transactional
public class FooRepo {
public Foo loadFoo(int id) {
...
}
}
// Controller
public class Controller {
public void Control() {
sessionContext.set("foo", repo.loadFoo(1)); // transaction managed by spring
}
public void setFooRepo(FooRepo repo) {this.repo = repo};
}
// View
for (Something something : foo.getStuff()) {
// Ooops transaction is closed! stuff is lazily loaded so NOT AVAILABLE
// practical solutions:
// - do not load lazily (Foo.hbm.xml)
// - or force loading by getting all Somethings in the controller
}