Given:
controller PersonController with a #Transactional action save
service PersonService with a method populateProperties(PersonInstance) being called from the controller action
I'd like to populate personInstance properties based on some data already persisted in the database, like this:
def personLookupData = PersonLookupData.findByUsername(personInstance.username)
personInstance.firstName = personLookupData.firstName
The findByUsername method flushes the hibernate session and in order to avoid it (because it has been giving me problems described here), I do this:
def personLookupData = PersonLookupData.withNewSession { PersonLookupData.findByUsername(personInstance.username) }
personInstance.firstName = personLookupData.firstName
This does what I want (lets me use findBy without flushing the session), and this is fine when there is only a couple of findBys to use, but given a deeper call stack (in terms of services) and more database lookups in different places, using withNewSession everywhere becomes a bit ugly.
Apart from making a PersonLookupService which will collect all the required data in one withNewTransaction block and return it, is there any other nice (groovy) way of doing this?
I think you should move #Transactional from PersonControlller to PersonService.
If you have more service calls to include in the same transaction, you need to use a Transaction boundary gateway, that's marked as #Transactional and calls all services you need for the current business case.
It's not the responsibility of the MVC components to control transactions. The transactions boundary are handled by the service layer.
Related
I have a question regarding the transactional boundaries in REST-Controllers using Java/Jakarta EE and JAX-RS.
Given the following controller, when a user is created in the #POST method, first the user is created using a dedicated service. Afterwards, the user´s permissions are stored using a different service.
Both services wrap incoming calls in a container managed transaction.
#Path("/users")
public class UserController {
#Inject
private UserService userService;
#Inject
private PermissionService permissionService;
#POST
public UserDto createUser(UserDto userDto) {
User user = mapToUser(userDto);
User createdUser = userService.create(user);
Permissions perms = mapToPermissions(userDto);
permissionService.createPermissions(createdUser.getId());
return mapToUserDto(createdUser);
}
}
From my point of view, there exists a transactional boundary around userService.create() and a second one around permissionService.createPermissions(). Can you confirm that this is true?
Secondly, if the previous statement is true, and the applications shuts down mid processing, the users permissions might not be persisted. Is this appraoch considered bad practise and should both operations be performed in a single transaction (or in the REST-paradigm under different ressources / endpoints)?
You are correct, there are two transactions, so the first could succeed while the second fails.
A common practice is using a Service Façade pattern. A coarse grained service that sets the transactions boundaries, and call the services to achieve the result.
Summary (details below):
I'd like to make a stored proc call before any entities are saved/updated/deleted using a Spring/JPA stack.
Boring details:
We have an Oracle/JPA(Hibernate)/Spring MVC (with Spring Data repos) application that is set up to use triggers to record history of some tables into a set of history tables (one history table per table we want audited). Each of these entities has a modifiedByUser being set via a class that extends EmptyInterceptor on update or insert. When the trigger archives any insert or update, it can easily see who made the change using this column (we're interested in which application user, not database user). The problem is that for deletes, we won't get the last modified information from the SQL that is executed because it's just a plain delete from x where y.
To solve this, we'd like to execute a stored procedure to tell the database which app user is logged in before executing any operation. The audit trigger would then look at this value when a delete happens and use it to record who executed the delete.
Is there any way to intercept the begin transaction or some other way to execute SQL or a stored procedure to tell the db what user is executing the inserts/updates/deletes that are about to happen in the transaction before the rest of the operations happen?
I'm light on details about how the database side will work but can get more if necessary. The gist is that the stored proc will create a context that will hold session variables and the trigger will query that context on delete to get the user ID.
From the database end, there is some discussion on this here:
https://docs.oracle.com/cd/B19306_01/network.102/b14266/apdvprxy.htm#i1010372
Many applications use session pooling to set up a number of sessions
to be reused by multiple application users. Users authenticate
themselves to a middle-tier application, which uses a single identity
to log in to the database and maintains all the user connections. In
this model, application users are users who are authenticated to the
middle tier of an application, but who are not known to the
database.....in these situations, the application typically connects
as a single database user and all actions are taken as that user.
Because all user sessions are created as the same user, this security
model makes it very difficult to achieve data separation for each
user. These applications can use the CLIENT_IDENTIFIER attribute to
preserve the real application user identity through to the database.
From the Spring/JPA side of things see section 8.2 at the below:
http://docs.spring.io/spring-data/jdbc/docs/current/reference/html/orcl.connection.html
There are times when you want to prepare the database connection in
certain ways that aren't easily supported using standard connection
properties. One example would be to set certain session properties in
the SYS_CONTEXT like MODULE or CLIENT_IDENTIFIER. This chapter
explains how to use a ConnectionPreparer to accomplish this. The
example will set the CLIENT_IDENTIFIER.
The example given in the Spring docs uses XML config. If you are using Java config then it looks like:
#Component
#Aspect
public class ClientIdentifierConnectionPreparer implements ConnectionPreparer
{
#AfterReturning(pointcut = "execution(* *.getConnection(..))", returning = "connection")
public Connection prepare(Connection connection) throws SQLException
{
String webAppUser = //from Spring Security Context or wherever;
CallableStatement cs = connection.prepareCall(
"{ call DBMS_SESSION.SET_IDENTIFIER(?) }");
cs.setString(1, webAppUser);
cs.execute();
cs.close();
return connection;
}
}
Enable AspectJ via a Configuration class:
#Configuration
#EnableAspectJAutoProxy
public class SomeConfigurationClass
{
}
Note that while this is hidden away in a section specific to Spring's Oracle extensions it seems to me that there is nothing in section 8.2 (unlike 8.1) that is Oracle specific (other than the Statement executed) and the general approach should be feasible with any Database simply by specifying the relevant procedure call or SQL:
Postgres for example as the following so I don't see why anyone using Postgres couldn't use this approach with the below:
https://www.postgresql.org/docs/8.4/static/sql-set-role.html
Unless your stored procedure does more than what you described, the cleaner solution is to use Envers (Entity Versioning). Hibernate can automatically store the versions of an entity in a separate table and keep track of all the CRUD operations for you, and you don't have to worry about failed transactions since this will all happen within the same session.
As for keeping track who made the change, add a new colulmn (updatedBy) and just get the login ID of the user from Security Principal (e.g. Spring Security User)
Also check out #CreationTimestamp and #UpdateTimestamp.
I think what you are looking for is a TransactionalEvent:
#Service
public class TransactionalListenerService{
#Autowired
SessionFactory sessionFactory;
#TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleEntityCreationEvent(CreationEvent<Entity> creationEvent) {
// use sessionFactory to run a stored procedure
}
}
Registering a regular event listener is done via the #EventListener
annotation. If you need to bind it to the transaction use
#TransactionalEventListener. When you do so, the listener will be
bound to the commit phase of the transaction by default.
Then in your transactional services you register the event where necessary:
#Service
public class MyTransactionalService{
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
#Transactional
public void insertEntityMethod(Entity entity){
// insert
// Publish event after insert operation
applicationEventPublisher.publishEvent(new CreationEvent(this, entity));
// more processing
}
}
This can work also outside the boundaries of a trasaction if you have the requirement:
If no transaction is running, the listener is not invoked at all since
we can’t honor the required semantics. It is however possible to
override that behaviour by setting the fallbackExecution attribute of
the annotation to true.
I'm trying to refactor the existing code base of one of my project following Repository pattern, so that i can make the project more re-usable and testable.
I've written services, repositories, when I try to set Authentication, Authorization and Transactional annotation on service layer, I am facing issues.
These annotations works only on controller level, but not on service layer, so I want a way for annotate service methods.
Is it possible to do so?
It would be helpful, if someone points me samples using repository pattern on Play framework or better way to proceed further.
Authentication and authorization only make sense on a request, so sticking them on anything but a controller method is not going to work either way.
Transactional is just a helper annotation to wrap the entire request in a JPA transaction. It is usually advisable to do the wrapping yourself anyway, so you don't really need that. Example taken from the documentation:
#Inject
private JPAApi jpaApi;
public void updateSomething() {
// do something with the entity manager, per instance
// save, update or query model objects.
jpaApi.withTransaction(() -> {
EntityManager em = jpaApi.em();
Query query = em.createNativeQuery("update people set active = 1 where age > 18");
query.executeUpdate();
});
}
I was trying to understand the caching that happens at the client side.
Unfortunately I am unable to find any resources that can help me out.
I have employee model objects which are fairly small in size.
Once a use a GET request to obtain an employee object, I want it to be cached at the client side
Now when the request comes again to obtain the same employee, I want to see if the actual object has been modified, if not, then serve from the client cache else return the modified object also adding it to the cache.
I am using Spring boot to create a REST endpoint.
What I have been able to figure out is that cache-control would be used some how, but I am not sure how the objects would be added here in spring.
Any help here is much appreciated!!!!
Thanks,
Amar
HTTP caching is not an easy topic. There are different ways to do it, and you should probably start by familiarizing yourself with the mechanisms, this seems to be a good starting resource: HTTP caching
Then, you will probably identify some common usage patterns you will want to reuse. One way to do that is to create custom annotations and write an interceptor that reacts on them.
For example, you could write such an annotation:
#Inherited
#Retention(RUNTIME)
#Target({METHOD, TYPE})
public #interface CacheFor {
long amount();
TimeUnit unit() default TimeUnit.SECONDS;
}
and use it on controller methods like this:
#CacheFor(amount=10, unit = MINUTES)
#RequestMapping(bla bla)
public FooBar serveMyData(){
// code here
}
and in your interceptor, you will need to look at the handler method, check whether it has this annotation, and if it does, set the appropriate headers.
I have some bussines classes that get injected some dependencies that are provided using servlet request scope.
The problem is that I want to use that bussines classes in some threads that outlive the servlet request.
Whats the most transparent way to do that?
If you are using Spring (which, by the terms you use to describe your problem, you seem to be using), you can use an AOP scoped-proxy for your request-scoped object, and inject this proxy into the objects that outlive the servlet request. The scoped-proxy will take care of using the right instance everytime you access it.
Well,
I'm not sure if I get your problem. I think there is problem with architecture itself, but however this could help you:
Guice module
bind(Bussines.class).annotatedWith(Names.named("request")).to(Bussines.class).in(RequestScoped.class);
bind(Bussines.class).annotatedWith(Names.named("session")).to(Bussines.class).in(SessionScoped.class);
bind(Bussines.class).annotatedWith(Names.named("application")).to(Bussines.class).asEagerSingleton();
Usage
#Inject #Named("request")
private Bussines bussines; //inject a new bussines class every request
#Inject #Named("session")
private Bussines bussines; //inject a new bussines class each session
//This is little bit tricky, cuz Bussines is stored in session. In Stage.PRODUCTION are all injection created eagerly and there is no session at injection time. Session binding should be done in lazy way - inject provider and call bussinesProvider.get() when em is needed;
#Inject #Named("application")
private Bussines bussines; //inject singleton
Also you can use Private modules to bind different scoped objects to a class. Don't forget to expose it.
I see 3 options:
You could add the information you need to an object that has a larger scope like application or session scope
You could persist the information in a file or the database and look it up later
You could save the information on the thread or use a thread scope: http://code.google.com/p/google-guice/issues/detail?id=114
I may not suggest you directly use or inject HttpServletRequest at business bean which is not in request scope . because this will break up app layers. if you want the value from the request or request header, then you can pass value to object to pass to the business layer, because otherwise, it is not secure, and generally, app will apply some security interceptor at that request scope , but if you directly inject to other layer , then it jump over and the interceptor may be skipped... this way also break the encapsulation and obvious is anti-pattern.