I have a bean (SettingService) which is decorated with the #Transactional annotation and injected into another bean where this bean is invoked on the context refreshed event.
public class DefaultConfigManager
implements ApplicationListener<ContextRefreshedEvent>, ConfigManager {
#Autowired
private SettingService service;
#Override
public void onApplicationEvent( ContextRefreshedEvent event ) {
System.out.println( "Proxy: " + AopUtils.isJdkDynamicProxy( service ) );
String key = service.getSystemSetting( "KEY" );
}
Transactions work generally well and the method above works as expected in Spring 4.1.9, where the println indicates that the SettingService bean is a dynamic JDK proxy (for transaction handling).
Now after upgrading to Spring 4.2.5 this suddenly starts to throw the following error:
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.orm.hibernate4.SpringSessionContext. currentSession(SpringSessionContext.java:134)
at org.hibernate.internal.SessionFactoryImpl. getCurrentSession(SessionFactoryImpl.java:993)
and the println indicates that the SettingService is no longer a proxy / has been decorated, meaning that no transactions will be initiated.
According to the Spring documentation, at the time of ContextRefreshedEvent being published, all beans and post-processors should be finished.
A Hibernate transaction manager is configured in the app context, the tx:annotation-driven element is in place, the #Transactional annotation is put on the implementation (not the interface), there are no circular dependencies in the system. Hibernate version: 4.2.20.Final.
Does this ring a bell with anyone? Are there any typical reasons for why beans no longer should be proxied with transactions on ContextRefreshedEvent in Spring 4.2? Any common mistakes or changes between Spring 4.1 and 4.2 to be aware of?
I got same problem as you have. My workaround is, put #Transactional annotation on class level rather than method level.
Related
We are migrating 1.1 StartUp bean which previously used IBM interfaces:
<session id="StartUp">
<ejb-name>StartUp</ejb-name>
<home>com.ibm.websphere.startupservice.AppStartUpHome</home>
<remote>com.ibm.websphere.startupservice.AppStartUp</remote>
<ejb-class>org.bean.StartUpBean</ejb-class>
<session-type>Stateful</session-type>
<transaction-type>Container</transaction-type>
</session>
to EJB 3.1 standard. So far we wrote code for bean without usage of IBM propertialy implementation:
#Startup
#Singleton
public class StartUpBean{
#PostConstruct
public void start() {
...
helper.runHelper(); // in new class
}
}
At first we had problems with deployment order, because StartupBean was starting immediately after module. We solved that using different order in application.xml. However one problem still remains.
In helper method called from start method of this bean we have some code that lookups stateless 1.1 bean using JNDI name. That bean creates new entity bean (1.1) invoking method create in new transaction (using reguires_new in xml descriptor). Then it should commit that transaction in order to persist that entity and calls finder which search that record in database. It looks like:
void runHelper(){
...
oldRemote = Server.lookup(OldBean.JNDI, OldBean.class);
oldBean.prepareApp(); //prepareApp has requires new transaction attribute
findThatNewEntity(key); // FinderException (not in database)
}
And in old stateless bean 1.1
void prepareApp(){
entityHome = Server.lookup(JNDI_NAME, Data.class);
entityHome.create(key, value, value2);
}
I am 100 % sure, that in previous version of StartUp bean that was using IBM interfaces, entity was created and stored. Now it is not. I am affraid that transactions aren't somewhat supported at point whe application is starting. Is it so? Or is there any way how to force using transactions or some kind of workaround? Thank you.
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
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 wanted to introduce #Async methods (for sending mails in parallel) in my SpringBoot application.
But when I put the #EnableAsync annotation on our application's main #Configuration class (annotated with #SpringBootApplication), the Flyway DB migrations are executed before the DataSourceInitializer (which runs schema.sql and data.sql for my tests) executed.
The first operation involving a 'should-be-migrated' database table fails.
Removing the #EnableAsync puts everything back to normal. Why does this happen and how could I fix this (or work around the issue)?
Update Some more findings: #EnableAsync(mode = AdviceMode.ASPECTJ) keeps the original order of DB setup, but the #Async method runs on the same thread as caller thread then. I also saw that the Bean 'objectPostProcessor' is created early (3rd bean) when #EnableAsync is not present, or #EnableAsync(mode = AdviceMode.ASPECTJ) is used. When only #EnableAsync is used, this bean is created much later.
Update 2 While I wasn't able to create a minimal project which reproduces the problem yet, I found out that the proper DB setup order is restored in my affected application when I comment out the #EnableWebSocketMessageBroker in the following:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{
...
}
Bean 'webSocketConfig' is the first bean created (as per INFO-level console output) if #EnableWebSocketMessageBroker is present.
It turned out that having both #EnableAsync and #EnableWebSocketMessageBroker present in my application caused the described effect.
Removing one of it, restored the expected behavior, in which case the DataSourceInitializerPostProcessor created the DataSourceInitializer which triggered execution of schema.sql and data.sql, before flyway migrations took place.
When both annotations were present, the registration of the BeanPostProcessor named internalAsyncAnnotationProcessor happened before the DataSourceInitializerPostProcessor was registered.
The cause of the problem was that the registration of internalAsyncAnnotationProcessor caused the creation of the dataSource bean as a side effect. This side effect was caused by spring looking for a TaskExecutor bean to use, for the #Async method execution. spring unexpectedly picked up the clientInboundChannelExecutor bean which was present because of the #EnableWebSocketMessageBroker. Using this bean caused the instantiation of WebSocketMessagingAutoConfiguration which created the objectMapper bean (for json-serialization) which uses services that use DAO-repositories which depend on dataSource. So all those beans got created.
Because DataSourceInitializerPostProcessor wasn't even registered at that time, DataSourceInitializer was created much later, after the flyway migration took place.
The javadoc for #EnableAsync says the following:
By default, a SimpleAsyncTaskExecutor will be used to process async method invocations. Besides, annotated methods having a void return type cannot transmit any exception back to the caller. By default, such uncaught exceptions are only logged.
I assumed, that a SimpleAsyncTaskExecutor will be created to run the #Async methods, but instead spring picked up an existing bean with a matching type.
So the solution for this issue was to implement AsyncConfigurer, and provide my own Executor. This is also suggested in the javadoc of #EnableAsync:
To customize all this, implement AsyncConfigurer and provide:
* your own Executor through the getAsyncExecutor() method, and
* your own AsyncUncaughtExceptionHandler through the getAsyncUncaughtExceptionHandler() method.
With this tweak the DB setup is again executed as expected.
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
}