I am having a bean within which I create a new Thread with Runnable:
#Component
public class MyBean {
private final Task task = new Task();
#PersistenceContext
EntityManager em;
#PostConstruct
public void init() {
task.setEntityManager(em);
new Thread(task).start();
}
public static class Task implements Runnable {
#Setter
private EntityManager em;
#Override
public void run() {
while (true) {
// working with EntityManager
Thing t = em.findById(...); // Fetching a Thing from repo
t.getSomethingList(); // LazyInit exception
wait();
}
}
}
}
Withing the init method, new Thread is created with instance of EntityManager. When I try to load something from the repository the session is instantly closed and getting any lazy field results in failed to lazily initialize a collection of role: Something, no session or session was closed exception from Hibernate.
I tried all the #Transactional annotations with no effect. I need to achieve something like OpenEntityManagerInView, but with the difference that this is not within view.
Thanks
EDIT1:
According to comments - I tried using em.getTransaction().begin(); but this is getting me Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT.
skirsch suggested that I should invoke Transactional method on some other bean. That is what I actually do - exactly as you suggested. I wanted to make things simpler and I did not realize the difference, so I demostrated the problem directly in the class Task. So to summarize, I have it exactly like skirsch suggested, but the problem persists.
As Spring is not managing your Runnable, annotating it won't have the desired effect. So you either need to use an annotated (and Spring-managed) bean from within your Runnable or you need to take care of the txn management manually.
Use Spring transaction management
You define some kind of service
#Service
public class MyService {
#PersistenceContext
EntityManager em;
#Transactional
public void doSomething() {
Thing t = em.findById(...);
t.getSomethingList();
}
}
And then your bean would look like this:
#Component
public class MyBean {
private final Task task = new Task();
#Autowired
MyService service;
#PostConstruct
public void init() {
task.setService(service);
new Thread(task).start();
}
public static class Task implements Runnable {
#Setter
private MyService service;
#Override
public void run() {
while (true) {
service.doSomething();
wait();
}
}
}
}
Manual transaction management
In case you set up JPA Resource Local Transactions, here you go:
// working with EntityManager
em.getTransaction().begin()
try {
Thing t = em.findById(...);
t.getSomethingList();
} finally {
em.getTransaction().rollback()
}
wait();
Related
I have the following classes and interfaces(simplified to make things clear).
#Serivce
class Service1 {
#Cacheable("cacheName")
public Metadata preLoadMetadata() {
// load data from database
}
}
#Service
class Service2 implements Loader {
#Autowired #Lazy
private Service1 service1;
#Overrride
public CacheWrapper getCacheWrapper() {
return new CacheWrapper(() -> service1.preLoadMetadata());
}
}
interface Loader {
CacheWrapper getCacheWrapper();
}
class CacheWrapper {
private Callable callable;
public CacheWrapper(Callable callable) {
this.callable = callable;
}
public getCallable() {
return callable;
}
}
The Spring bean responsible for loading the cache at the time of deployment.
#Component
class LoadCache {
#Autowired
private List<Loader> allLoaders;
#PostConstruct
public void load() {
allLoaders.getCacheWrapper().getCallable().call();
}
}
preLoadMetadata() doesn't save the data in the cache but it does execute. After deployment is complete and I call the same method preLoadMetadata() again, then it saves the data in the cache.
Why does #Cacheable doesn't work at the time of deployment?
If I manually use put method of Cache to populate cache inside method annotated with #PostConstruct, I am able to do it successfully while deployment.
I am using Tomcat as server.
I am using Couchbase cache behind Spring cache abstraction.
If you want to preload your cache I suggest you use an ApplicationListener that will execute once your application has started:
#Component
public class CacheInitializer implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
private List<Loader> allLoaders;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
allLoaders.getCacheWrapper().getCallable().call();
}
}
The root cause for not working of Cacheable annotation:
afterSingletonsInstantiated() method sets the initialized flag to true only when BeanFactory has instantiated all the beans. If the initialized flag is false, no caching operations are performed. Here, inside the post construct, when we start pre-loading caches, then it is highly probable that LoadCache is not the last bean to be instantiated. Hence, no caching operations are performed(while using caching annotations).
Hence, EventListener annotation responding to ContextRefreshEvent is the best thing to use in this case which ensures that the context has started and then only loading of caches take place.
I'm working in a project with Java EE 7 and I need to inject a javax.ejb.#Stateless bean into another. Both beans have a similar structure:
#Stateless
public class OperationRepository extends GenericRepository<Operation> {
#PersistenceContext
private EntityManager entityManager;
public OperationRepository() {
}
/*Implementation of abstract methods, getters/setters, etc*/
}
#Stateless
public class MenuRepository extends GenericRepository<Menu> {
#PersistenceContext
private EntityManager entityManager;
#Inject
private OperationRepository operationRepository;
public MenuRepository() {
}
/*idem OperationRepository*/
public List<Menu> getMenuFromOperation(...) {
// Do something where I need operationRepository
}
}
The GenericRepository<E> is just an abstract class with some common methods and other abstract methods, doesn't matter here.
The problem is that in the getMenuFromOperation() method I get a NullPointerException. Debugging the code I realized that the injected operationRepository is null when requested in the method.
Why does fail the injection point? what am I missing here?
Just to make a little test, I injected manually by instantiating a default OperationRepository in the MenuRepository constructor, but in that case the OperationRepository.entityManager isn't injected (is null)
Thanks in advance for your answers.
Edit #1
As requested by John Ament, here it goes:
All my code is in a single jar file. It's a Maven module that will be deployed together with a web module (a war package) in a Glassfish Server 4.1.
The beans.xml still doesn't exists yet, because the project isn't ready to be deployed (I didn't perform any integration test yet)
The MenuRepository is leveraged from a #Test class because I'm still developing MenuRepository.
The code for the test class is as follows:
public class MenuOperationRepositoryUTest extends BaseTestRepository {
private MenuRepository menuRepository;
private OperationRepository operationRepository;
#Before
public void initTestCase() {
initTestDB();
menuRepository = new MenuRepository();
menuRepository.setEntityManager(em);
operationRepository = new OperationRepository();
operationRepository.setEntityManager(em);
}
#After
public void finalizeTestCase() {
closeEntityManager();
}
/*Some successful tests*/
#Test
public void showMenuFromOperation() {
// Insert some dummy data into the test DB (HSQL)
// This method needs the injected OperationRepository in MenuRepository
List<Menu> menu = menuRepository.getMenuFromOperation(...);
// Assertions
}
}
And the BaseTestRepository is as follows:
#Ignore
public class BaseTestRepository {
private EntityManagerFactory emf;
protected EntityManager em;
// This is a helper class that contains all the boilerplate to begin transaction
// and commit, it's used to insert data in the test DB
protected DBCommandExecutor dbCommandExecutor;
protected void initTestDB() {
// sigeaPU is the name declared in persistence.xml
emf = Persistence.createEntityManagerFactory("sigeaPU");
em = emf.createEntityManager();
dbCommandExecutor = new DBCommandExecutor(em);
}
protected void closeEntityManager() {
em.close();
emf.close();
}
}
I think that's all I got so far. Let me know any clue you can get (or guess)
Because you're testing out of the CDI container you should also set your dependencies manually in the #Before method of the test class.
menuRepository.setOperationRepository(operationRepository)
I am learning to use JPA. And I'm a little confused.
According JPA EntityManager manages transactions. But a design pattern is to inject the EntityManager in DAOs. So how is possible that are different EntityManager to the same transaction?
This is the case I want to solve
I have the DAOs defined
#Repository
JPARepository1 {
#PersistenceContext
protected EntityManager em;
....
.
#Repository
JPARepository2 {
#PersistenceContext
protected EntityManager em;
....
I have a Service
#Service
public class ServiceImpl1 {
#Autowired
private JPARepository1 repo1;
#Autowired
private JPARepository2 repo2;
public void mainMethod(){
Object o= transactionalMethod1();
try{
transactionalMethod2(o);
}catch (Exception e){
transactionalMethod3(o);
}
}
private Object transactionalMethod1(){
....
}
private void transactionalMethod2(Object o){
....
}
private void transactionalMethod3(Object o){
....
}
Then from #Controller I will invoke mainMethod().
What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.
I would like it if there is an exeption in transactionalMethod2, this abort the transaction, but keep the transactions of transactionalMethod1 and transactionalMethod3
Thanks, sorry for my English
Usually you configure one EntityManager, so the wired manager is always the same, the one you configured. The instance of this manager though, is different in every wiring.
So, every transaction in your service uses a different instance of the EntityManager and thus every transaction invoked is seperated from each other.
As so, an exception in transactionalMethod2 doesn't necessarily affects the transactionalMethod1 and transactionalMethod3
What would be the right way to do transactional to transactionalMethod1, transactionalMethod2 and transactionalMethod3,within the same Service and using the same Repository's.
Now, you have two options to do service methods transactions
1) You could annotate your whole #Service like that:
#Service
#Transactional
public class ServiceImpl1 {
....
so every method declared here is also a transaction.
2) You could annotate each method as #Transactional:
#Transactional
private Object transactionalMethod1(){
....
}
#Transactional
private void transactionalMethod2(Object o){
....
}
#Transactional
private void transactionalMethod3(Object o){
....
}
If you want to use a single repository just #Autowired a single one and use it in your #Transactional method. E.g:
#Service
#Transactional
public class ServiceImpl1 {
#Autowired
private JPARepository1 repo1;
public void mainMethod(){
Object o= transactionalMethod1();
try{
transactionalMethod2(o);
}catch (Exception e){
transactionalMethod3(o);
}
}
private Object transactionalMethod1(){
return repo1.findOne();
}
private void transactionalMethod2(Object o){
repo1.create(o);
}
private void transactionalMethod3(Object o){
repo1.delete(o)
}
I am trying to find a way to add/get a resource/state to an existing transaction. Is this possible in Spring?
What I'm trying to achieve is similar to the pseudo code below:
#Service
#Transactional("txManager")
public class ServiceImpl implements Service {
#Override
#AddResourceHere
public TestObj doSomething(){
...
}
#Override
#AddResourceHere
public TestObj doSomethingAgain(){
...
}
}
#Aspect
#Component
public class Interceptor {
private static final Logger logger = LogManager.get(Interceptor.class);
#Before("#annotation(my.package.AddResourceHere)")
public void switchDatabase(JoinPoint joinPoint){
MyResource resource = TransactionResouceAdder.getResource("transactionSpecificResource");
if(resource == null){
TransactionResouceAdder.addResource(new MyResource("A new resource"));
...
}
else
log.info("resource has already been added for this transaction");
}
}
public class Test {
...
#Test
#Transactional("txManager")
public void doSomethingTest(){
serviceImpl.doSomething();
serviceImpl.doSomethingAgain();
}
}
I found something similar
org.springframework.transaction.support.TransactionSynchronizationManager#getResouce(Object)
org.springframework.transaction.support.TransactionSynchronizationManager#bindResource(Object, Object)
However, this adds a resource to the current thread of the transaction. Is there a way to make the resource transaction bounded only?
In my actual code, I am using spring jdbc's DataSourceTransactionManager as the transaction manager.
Thanks in advance for any help :)
TransactionSynchronizationManager was designed for this purpose and resources are cleared at the end of a transaction (see AbstractPlatformTransactionManager). You'd have to hook it up to your custom annotation with an aspect, but it looks like you already know how to do that.
I'm using a UnitOfWork in a background task method (operated by Quartz) with Guice-persist on top of hibernate. The background task call a service, which need to commit the current transaction in the middle of it's task - and continue on another transaction. How can I commit the current UnitOfWork and create a new one?
class BackgroundJob {
#Inject UnitOfWork unitOfWork;
#Inject MyService myService;
public void run() {
try {
unitOfWork.begin();
myService.foo();
} finally {
unitOfWork.end();
} } }
class MyServiceImpl implements MyService {
#Override public void foo() {
foo1();
// I would like to commit here and start a new transaction
foo2();
} }
The service is also managed by Guice, but is a singleton, and do not have access to the caller UnitOfWork as is.
Ideally I do not want to change service signature. A workaround is for the caller to give two UnitOfWork as parameters to foo(), but this seems a bit hacked.
EDIT: For ease of use of future fellow reader, here is my implementation of the solution given by ColinD, which fits the bill nicely:
class BackgroundJob {
#Inject UnitOfWork unitOfWork;
#Inject MyService myService;
public void run() {
try {
unitOfWork.begin();
myService.foo();
} finally {
unitOfWork.end();
} } }
class MyServiceImpl implements MyService {
#Override public void foo() {
foo1();
foo2();
}
#Transactional private void foo1() { ... }
#Transactional private void foo2() { ... }
}
If I recall correctly, a unit of work in Guice Persist is not a single transaction. Rather, it represents a single unit of work such as a single web request or, in your case, a single background job. I believe that a single database connection is used for a whole unit of work, but that unit of work may have multiple distinct transactions. In fact, I think that just starting and ending a unit of work will not cause any transactions to be started or ended.
I think what you want to do is to annotate both foo1() and foo2() (but not foo()) with #Transactional. As long as there's no outer transaction wrapping both calls, they'll each run in a separate transaction.
This may fit the bill.
class BackgroundJob {
#Inject UnitOfWork unitOfWork;
#Inject MyService myService;
public void run() {
try {
unitOfWork.begin();
myService.foo1();
unitOfWork.end();
unitOfWork.begin();
myService.foo2();
unitOfWork.end();
} finally {
unitOfWork.end();
}
}
}