Making sure JPA commits my transaction before another service accesses the data - jpa

It feels so simple:
I have a ViewScoped bean (JPA2 + EE6 + Seam3, if that matters) where the user of the web application can invoke a method like this:
public void save() {
doEntityManagerStuff(); // manipulates data in the database
callRemoteWebservice(); // which is to read said data and propagate it to other systems
}
Unfortunately, save() starts a transaction at the opening curly bracket and doesn't commit it before the closing bracket, meaning that the new data is not available to the remote web service to read.
I have tried to explicitly extract and annotate the database work:
#TransactionAttribute(REQUIRES_NEW)
private void doEntityManagerStuff() {
blabla(); // database stuff
}
But that didn't have any impact at all. (Maybe because that's EJB stuff and I'm running on seam...?)
The only thing that worked for me so far was to inject #UserTransaction and force commit the transaction at the end of either save() or doEntityManagerStuff() but that felt incredibly dirty and dangerous.
The other alternative would be to turn off container-managed transactions for the entire project, but that means I'd have to make all my beans manage their transactions manually, just so I can make this one case work.
Is there a better way?

To answer my own question:
I only went half-way, and that's why it didn't work. I didn't know enough about EJBs and their boudaries, and naively though just annotating the doEntityManagerStuff(...) method with a transaction attribute in my view-scoped CDI/Seam bean would be enough.
It isn't.
When I moved said method into a separate, stateless EJB, injected that into my CDI/Seam bean and called it from there, everything worked as expected.
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class MyPersister {
...
public void doEntityManagerStuff() {
blabla(); // database stuff
}
...
}
and
#ViewScoped
public class MyWebsiteBean {
...
#Inject MyPersister persister;
...
public void save() {
persister.doEntityManagerStuff(); //uses its own transaction
callRemoteWebService();
}
...
}

Related

How would you setup an JSF entity, service and backing bean [duplicate]

I'm trying to get used to how JSF works with regards to accessing data (coming from a spring background)
I'm creating a simple example that maintains a list of users, I have something like
<h:dataTable value="#{userListController.userList}" var="u">
<h:column>#{u.userId}</h:column>
<h:column>#{u.userName}</h:column>
</h:dataTable>
Then the "controller" has something like
#Named(value = "userListController")
#SessionScoped
public class UserListController {
#EJB
private UserListService userListService;
private List<User> userList;
public List<User> getUserList() {
userList = userListService.getUsers();
return userList;
}
}
And the "service" (although it seems more like a DAO) has
public class UserListService {
#PersistenceContext
private EntityManager em;
public List<User> getUsers() {
Query query = em.createQuery("SELECT u from User as u");
return query.getResultList();
}
}
Is this the correct way of doing things? Is my terminology right? The "service" feels more like a DAO? And the controller feels like it's doing some of the job of the service.
Is this the correct way of doing things?
Apart from performing business logic the inefficient way in a managed bean getter method, and using a too broad managed bean scope, it looks okay. If you move the service call from the getter method to a #PostConstruct method and use either #RequestScoped or #ViewScoped instead of #SessionScoped, it will look better.
See also:
Why JSF calls getters multiple times
How to choose the right bean scope?
Is my terminology right?
It's okay. As long as you're consistent with it and the code is readable in a sensible way. Only your way of naming classes and variables is somewhat awkward (illogical and/or duplication). For instance, I personally would use users instead of userList, and use var="user" instead of var="u", and use id and name instead of userId and userName. Also, a "UserListService" sounds like it can only deal with lists of users instead of users in general. I'd rather use "UserService" so you can also use it for creating, updating and deleting users.
See also:
JSF managed bean naming conventions
The "service" feels more like a DAO?
It isn't exactly a DAO. Basically, JPA is the real DAO here. Previously, when JPA didn't exist, everyone homegrew DAO interfaces so that the service methods can keep using them even when the underlying implementation ("plain old" JDBC, or "good old" Hibernate, etc) changes. The real task of a service method is transparently managing transactions. This isn't the responsibility of the DAO.
See also:
I found JPA, or alike, don't encourage DAO pattern
DAO and JDBC relation?
When is it necessary or convenient to use Spring or EJB3 or all of them together?
And the controller feels like it's doing some of the job of the service.
I can imagine that it does that in this relatively simple setup. However, the controller is in fact part of the frontend not the backend. The service is part of the backend which should be designed in such way that it's reusable across all different frontends, such as JSF, JAX-RS, "plain" JSP+Servlet, even Swing, etc. Moreover, the frontend-specific controller (also called "backing bean" or "presenter") allows you to deal in a frontend-specific way with success and/or exceptional outcomes, such as in JSF's case displaying a faces message in case of an exception thrown from a service.
See also:
JSF Service Layer
What components are MVC in JSF MVC framework?
All in all, the correct approach would be like below:
<h:dataTable value="#{userBacking.users}" var="user">
<h:column>#{user.id}</h:column>
<h:column>#{user.name}</h:column>
</h:dataTable>
#Named
#RequestScoped // Use #ViewScoped once you bring in ajax (e.g. CRUD)
public class UserBacking {
private List<User> users;
#EJB
private UserService userService;
#PostConstruct
public void init() {
users = userService.listAll();
}
public List<User> getUsers() {
return users;
}
}
#Stateless
public class UserService {
#PersistenceContext
private EntityManager em;
public List<User> listAll() {
return em.createQuery("SELECT u FROM User u", User.class).getResultList();
}
}
You can find here a real world kickoff project here utilizing the canonical Java EE / JSF / CDI / EJB / JPA practices: Java EE kickoff app.
See also:
Creating master-detail pages for entities, how to link them and which bean scope to choose
Passing a JSF2 managed pojo bean into EJB or putting what is required into a transfer object
Filter do not initialize EntityManager
javax.persistence.TransactionRequiredException in small facelet application
It is a DAO, well actually a repository but don't worry about that difference too much, as it is accessing the database using the persistence context.
You should create a Service class, that wraps that method and is where the transactions are invoked.
Sometimes the service classes feel unnecessary, but when you have a service method that calls many DAO methods, their use is more warranted.
I normally end up just creating the service, even if it does feel unnecessary, to ensure the patterns stay the same and the DAO is never injected directly.
This adds an extra layer of abstraction making future refactoring more flexible.

Spring Data MongoDB #Transactional isn't working?

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.

Benefit of applying Unit-of-Work on Service-layer instead of Controller

When implementing MVC project, I usually add Service Layer to perform the actual work. But actually sometimes 1 Web Request should be done with several AppService methods. Then the location of Unit-of-Work (UoW) may affect the coding handling.
No matter in C# EF/Java Spring, there's Transaction annotation in Service Layer methods, so the transaction is Per-Service based (i.e. UoW on Service layer). Let's take Java version as example here:
#Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
Public class UserAppService{
public UserDTO createUser() {
// Do sth to create a new user
userRepository.save(userBean);
// Convert userBean to userDTO
return userDTO;
}
public xxx DoSth() {
// Break the operation here
throw new Exception("Whatever");
// (never execute actually)
sthRepository.save(someBean);
}
}
Then in Controller:
Public class SomeController : Controller {
Public xxx DoSth(){
UserAppService Service = new UserAppService();
Service.CreateUser(); // DB committed
Service.DoSth(); //Exception thrown
}
}
With this structure, If there's any exception thrown on 2nd service method call, the 1st service method still commit the user to the DB. If I want "all-or-nothing" handling, this structure doesn't work unless I wrap those service method calls into another wrapper service call with single transaction. But it's sort of extra work.
Another version is using transaction on Controller action level instead (i.e. UoW on Controller Action). Let's take C# code as example:
Remarks: AppService in code version 2 here use the DbContext (sth like transaction) defined in controller, and doesn't do any commit inside.
Public class SomeController : Controller {
Public ActionResult DoSth(){
using (var DB = new DbContext()){
Var UserAppService = new UserAppService(DB);
var userEntity = userAppService.GetUser(userId);
UserAppService.DoSth(userEntity);
Var AnotherAppService = new AnotherAppService(DB);
AnotherAppService.DoSthElse(userEntity);
// Throw exception here
throw new Exception("Whatever");
DB.Save(); // commit
}
}
}
In this example, there will be no partial commit to the DB.
Is applying UoW on service-layer really better?
Is applying UoW on service-layer really better?
IMO No. And you've just figured out why. If the service methods are discreet and re-usable, they are also not suitable for being atomic transactions.
In .NET the controller should control the transaction lifecycle, and enlist service methods in the transaction.
Note that this also implies that the service methods should be local method calls, not remote or web service calls.
It is better because your following the main principle of Object Oriented Programming seperation of concerns.What if you made another controller and wanted to do more database processing using the same object? You dont want to instantiate the controller in which your doing something completely different.By the way check out the facade service pattern http://soapatterns.org/design_patterns/service_facade it may help you understand why its so sexy. .Hi the image above shows the pattern, basically you wrap your database access objects with transactional at the service layer so a customerService object can wrap 1,2...inf transactions and either all fail or succeed.

java.lang.IllegalArgumentException: Removing a detached instance com.test.User#5

I have a java EE project using JPA (transaction-type="JTA"), hibernate as provider. I write my beans to handle the CRUD things. The program running in JBOSS 7 AS.
I have an EntityManagerDAO :
#Stateful
public class EntityManagerDao implements Serializable {
#PersistenceContext(unitName = "dtdJpa")
private EntityManager entityManager;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public Object updateObject(Object object) {
object = entityManager.merge(object);
return object;
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void createObject(Object object) {
entityManager.persist(object);
}
public void refresh(Object object) {
entityManager.refresh(object);
}
public <T> T find(Class<T> clazz, Long id) {
return entityManager.find(clazz, id);
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteObject(Object object) {
entityManager.remove(object);
}
}
but when I invoke deleteObject, this exception comes out.
java.lang.IllegalArgumentException: Removing a detached instance com.test.User#5
How is this caused and how can I solve it?
EntityManager#remove() works only on entities which are managed in the current transaction/context. In your case, you're retrieving the entity in an earlier transaction, storing it in the HTTP session and then attempting to remove it in a different transaction/context. This just won't work.
You need to check if the entity is managed by EntityManager#contains() and if not, then make it managed it EntityManager#merge().
Basically, the delete() method of your business service class should look like this:
em.remove(em.contains(entity) ? entity : em.merge(entity));
In my case, I got the same error, when I tried to delete an object
using,
session.delete(obj)
without creating any transaction before that.
And the problem is solved by creating the transaction first(session.beginTransaction() and then deleting the object.
I hope my answer will help someone :)
Sometimes its simply because you are missing the #Transaction annotation for add, remove, update operations.
I faced the same problem. The detached entity should be re-attached. As #BalusC mentioned, using EntityManager.merge() should be used to attach the detached entity. EntityManager.merge() generates SQL Query which fetches the current state of the entity, on which EntityManager.remove() has to be performed. But in my case it didn't worked.
Try EntityManager.remove(EntityManager.find(Class<T>,arg)) instead. It worked for me.
In my experience, if I query an object from the DB then closed the entity manager then do a DB delete, the problem happens. Or if I copy that loaded object to another instance then do a delete, this problem also happens.
In my opinion there are 2 things to keep note:
The object must be in the same session that was created by the Entity Manager
And the object mustn't be transferred to another object while the Entity Manager's session is still opened.
Cheers

No need to dispose DataContext/ObjectContext in EF?

Albahari writes in "c# 4.0 in a nutshell":
>
Although DataContext/ObjectContext implement IDisposable, you can (in general)
get away without disposing instances. Disposing forces the context’s connection
to dispose—but this is usually unnecessary because L2S and EF close connections
automatically whenever you finish retrieving results from a query
<<
This feels wrong and FxCop also complains if you are not diposing something that is IDisposable.
I have the following repository code:
public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{ ...
public void Add(TEntity entity)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
dbContext.Set<TEntity>().Add(entity);
dbContext.SaveChanges();
}
}
...
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
{
using (var dbContext = this.UnityContainer.Resolve<DbContext>())
{
return dbContext.Set<TEntity>().Where(expression).ToList().AsEnumerable();
}
}
...
Note: I do not return IQueryable - lazy loading should not play a role.
Resolve DbContext is configured as PerResolveLifetimeManager.
Is this approach OK or do I need to reconsider this based on Albaharis description?
You should always call dispose if class exposes it. The statement claims that EF and L2S close connection whenever they finish operation - as I know the statement is correct but in the same time ADO.NET team also closes connection in Dispose method so perhaps there are situations when connection is not closed.
I'm working on EF 4.0 ObjectContext (yeah, I know...). I ended up looking at the code in DotPeek, and the dispose just nulls the reference to the connection and a few other things in the ObjectContext class.
When a connection is created (also found through DotPeek) it returns the existing instance. If the connection string is changed, it'll update the connection string for all instances.
That was my take on it at least. Need to look deeper but at first glance, it seems that you can get away with it.