I try to describe my environment shortly. Technologies: EJB 3.1, JSF, JBoss 7.1.1
There are Servise-classes (#SessionScoped #Stateful). Servise-classes call Dao classes (#Stateless)
I want :
use EntityManager only into #StateLess beans (Dao)
have short transaction in most cases (like persist, merge)
have one long transaction for some multistep-methods (methods are in Dao also)
have actual (up to date, without first-level cache) data
I have:
Pesistense.xml
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/MydataSource</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.dialect"value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.transaction.manager_lookup_class"
value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.connection.autocommit" value="true"/>
<property name="hibernate.connection.characterEncoding" value="utf8"/>
<property name="hibernate.c3p0.min_size" value="5"/>
<property name="hibernate.c3p0.max_size" value="20"/>
<property name="hibernate.c3p0.timeout" value="1800"/>
<property name="hibernate.c3p0.max_statements" value="50"/>
</properties>
</persistence-unit>
Dao
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class UserDaoBean implements UserDAO, Serializable {
#PersistenceContext(name = "MyEntityManager")
private EntityManager em;
#Override
#Transactional
public void update(User user) throws Exception {
User tmpUser = getUser(user.getUser());
//some code, should be rollback, if it is an exception
em.persist(tmpUser);
}
Transaction interceptor
#Transactional
#Interceptor
public class TransactionInterceptor implements Serializable {
#Resource
private UserTransaction userTransaction;
#AroundInvoke
public Object verifyAccess(InvocationContext context) throws
Exception {
Object result = null;
try {
userTransaction.begin();
result = context.proceed();
userTransaction.commit();
} catch (Exception e) {
userTransaction.rollback();
throw new CustomRuntimeException(e.getMessage());
}
return result;
}
}
Problem:
If it is throw an Exception into Dao method, part data will save in DB instead of total rollback.
I think, is need Join Transaction to EM. Or disconnect persists each item to the DB right away (using cache).
I've try different ways, but didn't have success.
Thanks for in advance!
This like looks particularly problematic:
<property name="hibernate.connection.autocommit" value="true"/>
You shouldn't be doing any connection management at all in your persistence.xml file. The <jta-data-source> element and the notion of putting connection information in <properties> are mutually exclusive.
Either the JPA provider creates and manages connections (using properties) or it gets the connections from the container (using jta-data-source). Putting both in there will give you unpredictable results. If the JPA provider chooses to honor the connection properties you can quite easily shut off transaction management, connection pooling and more.
What you want is to configure all those things in the container and do not do any of that in the persistence unit declaration.
UPDATE
The combination of TransactionManagementType.BEAN (BMT) and UserTransaction should be fine. Note that you'll want to catch Throwable rather than Exception. As well the rollback() call can also throw exceptions which should be handled. Overall, though, this should produce the results you want.
Note carefully that while this looks to be nearly identical to what you get from TransactionManagementType.CONTAINER (CMT) and no interceptor, they do differ in one critical way:
Two CMT beans can share the same transaction
Two BMT beans can not share the same transaction.
This is because the container is required to suspend any transaction that might be in progress before invoking any bean using BMT. In that regard the term Bean-Managed Transaction is actually a bit of a misnomer as the container will always take action on any transactions in progress before invoking the BMT bean.
As such BMT and CMT are not on equal footing and it is actually impossible to implement some of the basic CMT features such as SUPPORTS or REQUIRED using BMT.
Related
I have below maven dependency & configuration set up
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
#Configuration
#EnableMongoAuditing
public class MongoConfig {
#Bean
MongoTransactionManager transactionManager(MongoDbFactory mongoDbFactory) {
return new MongoTransactionManager(mongoDbFactory);
}
}
Updated: I've taken the suggested solution to create a bean with #Transactional, and have it injected into my test class. Below is the service bean I created:
#Service
#Transactional
#RequiredArgsConstructor
public class MongoTransactionService {
private final UserRepo userRepo;
public void boundToFail() throws RuntimeException {
userRepo.save(User.builder().id("1").build());
throw new RuntimeException();
}
}
and test class where I inject a bean of MongoTransactionService:
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class,
includeFilters = #ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = MongoTransactionService.class))
#ExtendWith(SpringExtension.class)
class MongoTransactionServiceTest {
#Autowired
UserRepo userRepo;
#Autowired
MongoTransactionService mongoTransactionService;
#Test
void testTransactional() {
try {
mongoTransactionService.boundToFail();
} catch (Exception e) {
// do something
}
val user = userRepo.findById("1").orElse(null);
assertThat(user).isNull();
}
}
I am expecting a call to boundToFail(), which throws a RuntimeException, would roll back the saved user, but the user still gets persisted in the database after the call.
It turns out that #DataMongoTest doesn't activate the auto-configuration for MongoDB transactions. I've filed a ticket with Spring Boot to fix that. In the mean time, you can get this to work by adding
#ImportAutoConfiguration(TransactionAutoConfiguration.class)
to your test class.
Note that using MongoDB transactions requires a replica set database setup. If that's not given the creation of a transaction will fail and your test case will capture that exception and the test will still succeed. The data will not be inserted but that's not due to the RuntimeException being thrown but the transaction not being started in the first place.
The question previously presented a slightly different code arrangement that suffered from other problems. For reference, here's the previous answer:
#Transactional needs to live on public methods of a separate Spring bean as the transactional logic is implemented by wrapping the target object with a proxy that contains an interceptor interacting with the transaction infrastructure.
You example suffers from two problems:
The test itself is not a Spring bean. I.e. there's no transactional behavior added to boundToFail(…). #Transactional can be used on JUnit test methods but that's controlling the transactional behavior of the test. Most prominently, to roll back the transaction to make sure changes to the data store made in the test do not affect other tests. See this section of the reference documentation.
Even if there was transactional logic applied to boundToFail(…), a local method call to the method would never trigger it as it doesn't pass the proxy that's applying it. See more on that in the reference documentation.
The solution to your problem is to create a separate Spring bean that carries the #Transactional annotation, get that injected into your test case and call the method from the test.
I'm writing a custom implementation for a Spring Data JPA repository. So I have:
MyEntityRepositoryCustom => interface with the custom methods
MyEntityRepositoryUmpl => implementation of the above interface
MyEntityRepository => standard interface which extends JpaRepository and MyEntityRepositoryCustom
My problem is this: within the implementation of MyEntityRepositoryUmpl I need to access the entity manager that was injected into Spring Data. How to get it?
I can use #PersistenceContext to get it autowired, but the problem is that this repository must work in an application that sets up more than one persistence units. So, to tell Spring which one I need, I would have to use #PersistenceContext(unitName="myUnit"). However, since my repositories are defined in a reusable service layer, I can't know at that point what will be the name of the persistence unit that the higher-level application layer will configure to be injected into my repositories.
In other words, what I would need to do is to access the entity manager that Spring Data itself is using, but after a (not so quick) look at Spring Data JPA documentation I couldn't find anything for this.
Honestly, the fact that the Impl classes are totally unaware of Spring Data, although described as a strength in Spring Data manual, is actually a complication whenever you need to access something that is usually provided by Spring Data itself in your custom implementation (almost always, I would say...).
Since version Spring Data JPA 1.9.2 you have access to EntityManager through JpaContext, see: http://docs.spring.io/spring-data/jpa/docs/1.9.2.RELEASE/reference/html/#jpa.misc.jpa-context.
Example:
#Component
public class RepositoryUtil
{
#Autowired
private JpaContext jpaContext;
public void deatach(T entity)
{
jpaContext.getEntityManagerByManagedType(entity.getClass()).detach(entity);
}
}
P.S.
This approach will not work if you have more than one EntityManager candidate for some Class, see implementation of JpaContext#getEntityManagerByManagedType -> DefaultJpaContext#getEntityManagerByManagedType.
The best I could find is to set up a "convention": my repositories declare that they expect a persistence unit named myConventionalPU to be made available. The application layer then assigns that alias to the entity manager factory that it sets up and injects into Spring Data, so my custom implementations can receive the correct EMF with autowiring by using that alias. Here's an excerpt of my application context:
<bean id="myEntityManagerFactory" name="myConventionalPU"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
[...]
</bean>
<jpa:repositories base-package="com.example"
entity-manager-factory-ref="myEntityManagerFactory"
transaction-manager-ref="transactionManager" />
And within my custom implementation:
#PersistenceContext(unitName = "myConventionalPU")
private EntityManager em;
I opened DATAJPA-669 with this requirement.
Spring Data JPA uses Auto configuration classes to auto generate entityManagerFactory, dataSource and transactionManager.
If you want get access to entityManager and control the instantiation and settings, you need to define your own PersistenceConfiguration. Below is the sample code using Java Config
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = { "com.test.repositories.*" })
public class PersistenceJpaConfig {
#Autowired
JpaVendorAdapter jpaVendorAdapter;
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setName("testdb")
.setType(EmbeddedDatabaseType.HSQL)
.build();
}
#Bean
public EntityManager entityManager() {
return entityManagerFactory().createEntityManager();
}
#Bean
public EntityManagerFactory entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("com.test.domain.*");
lef.afterPropertiesSet();
return lef.getObject();
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager(entityManagerFactory());
}
}
If you have multiple data sources, follow this article.
I have two Entitymanager bean configurations. Each pointing to a separate database with a different schema (one is Oracle, the other one is an in-memory H2)
What could I do to solve the ambiguity of what Entitymanager should be used for each Repository? Right now I'm getting this error:
No unique bean of type [javax.persistence.EntityManagerFactory] is defined:
expected single bean but found 2
I guess I could provide a quick-fix simply by using something like
<jpa:repositories base-package="com.foo.repos.ora"
entity-manager-factory-ref="entityManagerFactoryA">
<jpa:repositories base-package="com.foo.repos.m2"
entity-manager-factory-ref="entityManagerFactoryB">
But hopefully there is a better solution.
EDIT:
I give you an idea of the current scenario:
Spring-Config: there're two EM
<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/>
<jpa:repositories base-package="com.foo.repos.m2" entity-manager-factory-ref="entityManagerFactory2"/>
<context:component-scan base-package="com.foo" /> ....
Everything from here on is in "package com.foo.repos.ora"
Following the pattern of how to make a custom repository I get two interfaces 'ARepository', 'ARepositoryCustom' and its implementation 'ARepositoryImpl' like so
#Repository
public interface ARepository extends ARepositoryCustom, JpaRepository<myEntity, BigDecimal>, QueryDslPredicateExecutor {
}
public interface ARepositoryCustom {
FooBar lookupFooBar()
}
public class ARepositoryImpl extends QueryDslRepositorySupport implements ARepositoryCustom {
ARepositoryImpl(Class<?> domainClass) {
super(domainClass.class)
}
ARepositoryImpl() {
this(myEntity.class)
}
#Override
FooBar lookupFooBar() {
JPQLQuery query = ....
....
return found
}
}
resulting in the following error message:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'aRepositoryImpl': Injection of
persistence dependencies failed; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [javax.persistence.EntityManagerFactory] is
defined: expected single bean but found 2
Which is of course correct, there are 2 EM beans, but since I restricted EM #1 aka 'entityManagerFactory' to package 'com.foo.repos.ora' only, I'm still not sure how to reference the exact EM bean.
There is no magic under the hood.
<jpa:repositories base-package="com.foo.repos.ora" entity-manager-factory-ref="entityManagerFactory"/>
doesn't help you at all with your custom interface implementations. Best way I found is to treat your custom implementations as regular beans. So I defined a 'sharedEntitManager' bean in my spring configuration like so
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
...
</bean>
<bean id="sharedEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name = "entityManagerFactory" ref="entityManagerFactory"/>
</bean>
After that, I simply injected the EntityManager into my implementation beans
<bean id="aRepositoryImpl" class="comm.foo.repos.ora.ARepositoryImpl">
<property name="entityManager" ref="sharedEntityManager"/>
</bean>
The 'entity-manager-factory-ref' attribute discriminates between different entitymanager factories but only for straight Spring Data Repositories (i.e. only for interfaces). It doesn't however concern itself with any of your implementations.
To sum it up
1) if you simply rely on standard Spring Data repositories with no custom implementation, use the "entity-manager-factory-ref" attribute to differentiate databases.
2a) Additionally, if you use any custom implementation, inject the appropriate EntityManager directly into the implementing class. Wirering is done under control of your spring xml configuration. For some reason I wasn't able to use the #Autowire annotation with a #Qualifier to reference the correct EntityManager. EDIT I just learned about the #Resource annotation
#Resource(name = "sharedEntityManagerA")
EntityManager entityManager
<bean id="sharedEntityManagerA" name="sharedEntityManagerA" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name = "entityManagerFactory" ref="entityManagerFactory"/>
</bean>
With this at hand selecting what EntityMAnger should be used becomes straightforward. No need of plumbing everything togehther in your context xml.
2b) As an alternative to Spring's xml configuration for hooking up your stuff you may also go with
#PersistenceContext( unitName = "nameOfPersistenceUnit" )
to inject the correct EntitymanagerFactory
While 'nameOfPersistenceUnit' referes to your persistence sitting in your standard JPA persistence.xml
However 2b) doesn't go well with 'QueryDslRepositorySupport', since it expects an EntityManager instance. But I found that 'QueryDslRepositorySupport' doesn't offer much support anyway, so I removed it.
I have created my own job class by extending the default class added couple of member variables and member methods. I saw the job gets triggered and is running for a very long time.
I just wanted to get the Job Instance not the JobDetail and wanted to invoke any member methods which has been defined by me or wanted to access the member variables.
Could you please let me know how we can achieve this?
Thanks,
Kathir
There is not such way, probably because quartz is meant to be compatible with a remote scheduling mode (i.e. cluster).
But if you are using it in a single server / application context, you could probably implement your own JobFactory (http://quartz-scheduler.org/api/2.1.5/org/quartz/simpl/SimpleJobFactory.html) that will just delegate to the super class the creation of the instance, and then register the instance somehow in a map or something else. Then you'll have to loop over the map keys to find the instance you are looking at.
Be careful of memory leaks with such a solution
Quick example:
In your spring configuration file:
<!-- quartz scheduler -->
<bean id="orchestration-api-quartz-factory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:spring/quartz.properties"/>
<property name="jobFactory">
<bean class="service.scheduler.SpringServiceJobFactory"/>
</property>
</bean>
And the basic implementation of your Factory:
/**
* This job factory tries to locate the spring bean corresponding to the JobClass.
*
* #author Mathieu POUSSE
*/
public class SpringServiceJobFactory extends SpringBeanJobFactory implements JobFactory {
#Autowired
private ApplicationContext context;
/**
* {#inheritDoc}
*/
#Override
protected Object createJobInstance(final TriggerFiredBundle bundle)
throws Exception {
// create or get the bean instance
Object bean = this.context.getBean(bundle.getJobDetail().getJobClass());
// do what you want with the bean
// but remeber what you did, otherwise if you forget to forget
// you will have memory leaks !!!
// myConcurrentMap.put("job.key", bean);
return bean ;
}
}
HIH
I'm building a JAX-RS app that consists of a stockroom and a workplace. The stockroom holds a set of Java classes that can be instantiated (via AJAX) to create named instances of those classes in the workplace.
So far I'm able to reference the stockroom and workplace fine by declaring them as "singletons" in the RestEasy application
singletons.add(StockPlace.getInstance());
singletons.add(WorkPlace.getInstance());
I'm unable to understand how to understand how the stockroom content classes should be handled. The effect I'm trying to achieve is that when I dynamically create an instance of one of the stockroom classes, that instance can be dynamically accessed via REST commands. I've tried various permutations of:
classes.add(SomeComponent.class);
I think I'm missing knowledge of how the Java notion of how classes work as factories for making instances, and how both of these relate to what RestEasy calls classes, singletons (singletons ARE classes, yet RestEasy registers them as instances) and resources (instances?).
I suspect I'll wind up needing to dynamically register new instances but can't find a way to do that either. I did find a way to do it given the ServletContext, but am not able to get access to that either. Can someone get me on the right track?
Our eventual answer to this question was to bail out of RestEasy and convert to DropWizard. That problem and many others vanished and everything became easy again.
I believe I know what you are after, but I should at least give you a push in the right direction.
You will need to add the annotated RESTEasy class(es) to the registry. Below is the class I used for a recent project. It adds to the singletons (per what you did) but it also adds to the registry.
public class RESTEasyServerApplication extends javax.ws.rs.core.Application
{
// The RESTEasy registry
#Autowired
protected org.jboss.resteasy.spi.Registry registry;
// The annotated RESTEasy handler classes
private Set<Object> singletons = new HashSet<Object>();
private List<Object> handlers = new ArrayList<Object>();
public RESTEasyServerApplication()
{}
#Override
public Set<Object> getSingletons()
{
return singletons;
}
// Spring injection support
public void setHandlers( List<Object> handlers )
{
for( Object handler : handlers )
{
if( registry != null )
{
// Save a reference to the handler
this.handlers.add( handler );
// Register the handler with RESTEasy
registry.addSingletonResource( handler );
}
singletons.add( handler );
}
}
// Spring injection support
public List<Object> getHandlers()
{
return handlers;
}
}
I used Spring, and here is the relevant configuration:
<!-- RESTeasy/Spring integration -->
<import resource="classpath:springmvc-resteasy.xml" />
<!-- RESTeasy server application -->
<bean id="application" class="blah.blah.resteasy.RESTEasyServerApplication">
<property name="handlers">
<list>
<!-- Application specific handler classes -->
<ref bean="sample"/>
</list>
</property>
</bean>
Should be easy to modify/add a method to accept a single annotated RESTEasy class and make it work dynamically as required. The registry is defined in the springmvc-resteasy.xml file.
Since I've found no answers that don't involve strapping another whole layer of complexity (Spring) onto RestEasy, the solution I found livable is outlined in the final comment above. That is, don't rely on sending remote messages to instances unless the app is truly stateless (e.g. instances don't persist across messages). Only send remote messages to singletons which do persist across requests. Each such message can identify the desired instance (by String id in my case), and the singleton can forward to the identified instance as an ordinary POJO.
I still don't see why RestEasy unconditionally treats non-Singletons (instances) as ephemeral. Statelessness is not a restriction on REST, only a restriction on when GET methods can be used (idempotent calls). PUT and POST calls are neither stateless nor idempotent.
As I understand this, of course, and feel free to correct me. My focus is getting this app on the air, not exploring every corner of RestEasy, REST, and certainly not Spring.