how to Resolve "could not initialize proxy - no session" error when using Spring repository - spring-boot

I'm working on a mutitenant project it maintains different schema for each tenant, followed Project
As we are dynamically switching the tenants so it looks like some configuration is missed which is closing the session or not keeping the session open to fetch the LAZY loaded objects. Which results in "could not initialize proxy - no session" error.
Please check below link to access the complete project and db schema scripts, please follow the steps given in Readme file.
Project
It will be helpful if someone can point out the issue in the code.
i tried to put service methods in #Transactional annotation but that didn't work.
I'm expecting it to make another call to the LAZY loaded object, This project is simplefied verson of the complex project, actually i have lot more lazy loaded objects.
Issue:-
I'm getting no Session error "could not initialize proxy [com.amran.dynamic.multitenant.tenant.entity.Tenant#1] - no Session"
at line 26 (/dynamicmultitenant/src/main/java/com/amran/dynamic/multitenant/tenant/service/ProductServiceImpl.java)

The issue is that your transaction boundaries are not correct. In TenantDatabaseConfig and MasterDatabaseConfig you've correctly added #EnableTransactionManagement, which will setup transactions when requested.
However - the outermost component that has an (implicit) #Transactional annotation is the ProductRepository (by virtue of it being implemented by the SimpleJpaRepository class - which has the annotation applied to it - https://github.com/spring-projects/spring-data-jpa/blob/864c7c454dac61eb602674c4123d84e63f23d766/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java#L95 )
and so your productRepository.findAll(); call will start a transaction, create a JPA session, run the query, close the session, close the transaction, which means that there is no longer any transaction / session open in which to perform the lazy-loading.
Therefore, your original attempt of
i tried to put service methods in #Transactional annotation but that didn't work.
IS the correct thing to do.
You don't say exactly what you tried to do, and where, but there are a few things that could have gone wrong. Firstly, make sure you're adding a org.springframework.transaction.annotation.Transactional and not a javax.transaction.Transactional annotation.
Secondly (and the more likely problem in this scenario), you'll need to configure the annotation with which transaction manager the transaction should be bound to, otherwise it may use an existing / new transaction created against the master DB connection, not the tenant one.
In this case, I think that:
#Service
#Transactional(transactionManager = "tenantTransactionManager")
public class ProductServiceImpl implements ProductService {
should work for you, and make all the methods of the service be bound to a transaction on the tenant DB connection.
EDIT: Answering a follow-up question:
can you please also suggest a better way to inject my tenantTransactionManager in all my service classes, as I don't want to mention tenantTxnManger in all service classes if there is any better way to do it ?
Yes, sure. You can create a meta-annotation that applies multiple other annotations, so you could create:
/**
* Marks class as being a service operating on a single Tenant
*/
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Service
#Transactional("tenantTransactionManager")
public #interface TenantService {
}
and then you can simply annotate your service classes with #TenantService instead of #Service:
#TenantService
public class ProductServiceImpl implements ProductService {

Related

Spring boot with multiple database connections

I made a simple SpringBoot REST application for testing purposes where the tables are in 2 databases, one is Mysql and one is Postgresql. To configure the 2 connections I used the instructions from here, at point 6 - "Multiple Databases in Spring Boot" and all seemed to be fine, the 2 connections were initiated but only the primary connection works.
So if the Mysql connection is annotated as #Primay only Mysql REST services work, on Postgresql the error for all tables is "org.hibernate.hql.internal.ast.QuerySyntaxException: <Entity_Name> is not mapped". But if I make a single change and set #Primary on the Postgresql connection then all Postgres tables are working and all Mysql tables give the same error(table not mapped).
So somehow I think the right connection is not autoselected based on the package.
UPDATE: I found another tutorial here using different database types, I followed the instructions but the result is the same, all tables in the secondary database give the error "org.hibernate.hql.internal.ast.QuerySyntaxException: <Entity_Name> is not mapped". I think the secondary connection is not used, somehow the primary one defaults on the wrong tables but I don't know why.
I uploaded this small Github project with my work.
https://github.com/victorqedu/MultipleSpringBootDS
UPDATE: In the DAO class a have autowired the constructor and #Autowire is setting the wrong EntityManager(I think this is the source of the problem), could I manually specify the right EntityManager?
#Autowired
public AntibiogramaAntibioticeDAOHibernateImpl(EntityManager theEntityManager) {
entityManager = theEntityManager;
}
I also tried the annotation #PersistenceContext on the EntityManager but the result is the same.
#PersistenceContext
private EntityManager entityManager;
I'm not sure the problem is EntityManagaer or the Session that I obtain from EntityManager.unwrap, seems to be little documentation about this...
This can be solved with Qualifier in a short description if you have multiple same type of beans(like EntityManager) you should use qualifier to wire them.
Therefore in your code you should
public AntibiogramaAntibioticeDAOHibernateImpl(
#Qualifier("primaryEntityManagerFactory") EntityManager theEntityManager)

JPA transactional proxy within a thread issue

In my Controller I have injected (#Autowired) this Service, which implements Runnable (I need multi-threading) and I call it like so:
Thread t = new Thread(service);
t.start();
t.join();
Then, in my Service's run() I call this Repository (simple JPARepository), which is injected in Service also with #Autowired:
repository.save(someEntity);
The problem is that it doesn't persist the entity with id=1. The transactional proxy (and Hibernate connection pool) is initialized after the unsuccessful saving of the first entity. After that, it works fine.
Can anyone point me to the right direction with my issue: how to force the Thread to initialize the Hibernate transactional proxy before persisting the first entity?
You should consider to start the thread after Spring context is refreshed. This is safer because all your beans may be in an inconsistent state.
#EventListener(ContextRefreshedEvent.class)
public void handleContextStart() {
// ...
}

Mule connector config needs dynamic attributes

I have develop a new Connector. This connector requires to be configured with two parameters, lets say:
default_trip_timeout_milis
default_trip_threshold
Challenge is, I want read ${myValue_a} and ${myValue_a} from an API, using an HTTP call, not from a file or inline values.
Since this is a connector, I need to make this API call somewhere before connectors are initialized.
FlowVars aren't an option, since they are initialized with the Flows, and this is happening before in the Mule app life Cycle.
My idea is to create an Spring Bean implementing Initialisable, so it will be called before Connectors are init, and here, using any java based libs (Spring RestTemplate?) , call API, get values, and store them somewhere (context? objectStore?) , so the connector can access them.
Make sense? Any other ideas?
Thanks!
mmm you could make a class that will create the properties in the startup and in this class obtain the API properties via http request. Example below:
public class PropertyInit implements InitializingBean,FactoryBean {
private Properties props = new Properties();
#Override
public Object getObject() throws Exception {
return props;
}
#Override
public Class getObjectType() {
return Properties.class;
}
}
Now you should be able to load this property class with:
<context:property-placeholder properties-ref="propertyInit"/>
Hope you like this idea. I used this approach in a previous project.
I want to give you first a strong warning on doing this. If you go down this path then you risk breaking your application in very strange ways because if any other components depend on this component you are having dynamic components on startup, you will break them, and you should think if there are other ways to achieve this behaviour instead of using properties.
That said the way to do this would be to use a proxy pattern, which is a proxy for the component you recreate whenever its properties are changed. So you will need to create a class which extends Circuit Breaker, which encapsulates and instance of Circuit Breaker which is recreated whenever its properties change. These properties must not be used outside of the proxy class as other components may read these properties at startup and then not refresh, you must keep this in mind that anything which might directly or indirectly access these properties cannot do so in their initialisation phase or your application will break.
It's worth taking a look at SpringCloudConfig which allows for you to have a properties server and then all your applications can hot-reload those properties at runtime when they change. Not sure if you can take that path in Mule if SpringCloud is supported yet but it's a nice thing to know exists.

Add property to entity in spring data REST

I am trying out the ResourceProcessor interface in Spring Data REST. I don't think my Processor ever gets called. No error message either.
Here is my processor (in Groovy):
#Autowired
PersonService personService
#Override
public Resource<Person> process(Resource<Person> resource) {
resource.content.isAdult = personService.isAdult(resource.content)
// sanity check: does this link get added?? (NOPE!!)
resource.add(new Link("http://localhost:8080/people", "added-link"))
log.info "## resource.content.isAdult ==> ${resource.content}"
return resource
}
Any help would be most appreciated!! You can see the entire project here in GitHub: https://github.com/txiasummer/spring-data-rest-examples
Finally got it to work! It turns out to be something completely trivial and I can't believe I missed it. I have a PersonProcessor classes which implements Spring's native ResourceProcessor interface. But PersonProcessor is still just a basic class that must be injected by Spring!! I think I was getting it confused with #Projection, which will be recognized automatically and does not need to be injected explicitly.
I addd #ComponentScan to my Application.groovy and now everything is working swimmingly. Alternatively, you an also manually define the PersonProcessor class and its service PersonService class as #Bean in Application.groovy. Again, you can see the whole project here: https://github.com/txiasummer/spring-data-rest-examples

bitronix transaction manager

I'm trying to migrate from JPA to JTA and use bitronix transaction manager. I'm getting below error message when try to run unit tests. According to bitronix documentation this is normal b/c my spring context configuration is trying to load the resources twice (once in base class and then in the test class, see code below), I have tried the same with atomikos and I got similar result.
Caused by:
java.lang.IllegalArgumentException:
resource with uniqueName 'xyzDb'
has already been registered
My base class
#ContextConfiguration(locations = {"classpath:com/xyz/baseContext.xml"})
#Transactional
public abstract class AbstractTestSupport extends Assert implements ApplicationContextAware
{
In some unit tests I have to extend the test support and add a context config file like below. so it loads context once for base class and another time for child class and fails
Child class
#ContextConfiguration(locations = {"classpath:com/xyz/testContext.xml"})
public class UnitTest extends AbstractTestSupport
{
After the test I'm shutting down context, so next test works fine as long as it doesn't extend the base class with another context config file.
#AfterClass
public static void onTearDownAfterClass() throws Exception
{
applicationContext.shutdownApplicationContext();
assertFalse("Spring application context is still active after shutdown. ", applicationContext.isActive());
}
I want to keep context config files in the child classes and make this work like that, any ideas greatly appreciated....
The error message basically means you created the connection pool with unique name 'xyzDb' (remember there is a uniqueName property you need to set on BTM's pools?) for the second time at the time the exception is thrown. You cannot do that: each connection pool must have a unique name and must be closed before another one with an identical name can be created.
I suppose there is some overlap between your two context files causing this or maybe the connections pools aren't always closed like they should. Unfortunately you published too little information to get a definitive answer.

Resources