Transactions via spring annotations - readonly or not? - spring

I've got in my project code similar to this
#Transactional(readOnly = true)
public void tt() {
dd();
}
#Transactional()
public void dd() {
gg();
}
#Transactional(readOnly = true)
public void gg() {
}
Function dd is used both by other readonly transaction functions and not readonly functions. Assuming that transaction should extendend from execution of tt to gg - operations in dd will in be read-only transaction or not?

In this particular example, your question is moot.
The call to dd() from tt() will not pass the proxy boundary so no transactional advise will be applied to dd() (since it's a call inside the same instance). Same with the call to gg() from dd(). Consequently, only the call from outside to tt() would actually be transaction-advised (in your case, with readOnly=true) and that would be the transaction that would be used in the entire call-chain.
In the general case though, read the documentation hinted by #melihcelik - it explains the behavior.

Spring's AbstractPlatformTransactionManager has a property named validateExistingTransaction that controls this behavior. Javadoc states that:
When participating in an existing transaction (e.g. with PROPAGATION_REQUIRES or PROPAGATION_SUPPORTS encountering an existing transaction), this outer transaction's characteristics will apply even to the inner transaction scope. Validation will detect incompatible isolation level and read-only settings on the inner transaction definition and reject participation accordingly through throwing a corresponding exception.
Since default propagation for Spring #Transactional annotation is REQUIRED and default validation strategy is false, I expect Spring to use existing transaction created from tt method call in readonly mode.
If you want to have a read only transaction, then you have to annotate your method with:
#Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=true)

use #Transactional(readoOnly = true) if you are performing a get/select and not making any changes, this means that no locks will be applied (which is more efficent).
For updates/inserts/deletions/saves/merges I use (when a lock is required) :
#Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)

Related

How to propagate JTA state when using reactive-messaging?

I would like to propagate JTA state (= the transaction) between a transactional REST endpoint that emits a message to a reactive-messaging connector.
#Inject
#Channel("test")
Emitter<String> emitter;
#POST
#Transactional
public Response test() {
emitter.send("test");
}
and
#ApplicationScoped
#Connector("test")
public class TestConnector implements OutgoingConnectorFactory {
#Inject
TransactionManager tm;
#Override
public SubscriberBuilder<? extends Message<?>, Void> getSubscriberBuilder(Config config) {
return ReactiveStreams.<Message<?>>builder()
.flatMapCompletionStage(message -> {
tm.getTransaction(); // = null
return message.ack();
})
.ignore();
}
}
As I understand, context-propagation is responsible for making the transaction available (see io.smallrye.context.jta.context.propagation.JtaContextProvider#currentContext). The problem seems to be, that currentContext gets created on subscription, which happens when the injection point (Emitter<String> emitter) get its instance. Which is too early to properly capture the transaction.
What am I missing?
By the way, I am having the same problem when using #Incoming / #Outgoing instead of the emitter. I have decided to give you this example because it is easy to understand and reproduce.
At the moment, you need to pass the current Transaction in the message metadata. Thus, it will be propagated to your different downstream components (as well as the connector).
Note that, Transaction tends to be attached to the request scope, which means that in your connector, it may already be too late to use it. So, make sure your endpoint is asynchronous and only returns when the emitted message is acknowledged.
Context Propagation is not going to help in this case as the underlying streams are built at startup time (at build time in Quarkus) so, there are no capture contexts.

How to rollback transaction invoked with jpa entity listeners

I'm using jpa , spring data and entity listeners to audit my entities precisely on postUpdate , postPersist , PostRemove
This is a pseudo code of my entity listener class
public class EntityListener extends AuditingEntityListener {
#PostUpdate
public void postPersist(Object auditedEntity) {
writer.saveEntity(auditedEntity,"UPDATE");
}
This the pseudo code of the Writer class
public class Writer {
#Async
public void saveEntity(Object auditedEntity, String action) {
try {
//some code to prepare the history entity
historyDAO.save(entity);
} catch (Exception e) {
}
}
when an exception is thrown in Writer class , the auditedEntity is updated or inserted however the historyEntity where i store the audit action doesnt
The problem is i need to invoke the saveEntity method in another thread for performance issue (#Async) but in that case a new transaction is open instead of the previously one which opened
how can i solve the rollack issue for both transactions
so when an exception is throwen both historyEntity and auditedEntity not persisted
I understand that you want to rollback both the child and the parent transaction when an exception is thrown from within Writer.saveEntity.
The problem is that the thread with the original transaction would still need to wait for all these complicated operations to finish before it could mark the transaction as committed. You can't easily span a transaction across multiple threads, either.
The only thing you could probably do to speed things up is you could run the logic of generating the history entities in parallel, and then save them all just before the transaction commits.
One way of doing that that I can think of is using a Hibernate interceptor:
public class AuditInterceptor extends EmptyInterceptor {
private List<Callable<BaseEntity>> historyEntries;
private ExecutorService executor;
...
public void beforeTransactionCompletion(Transaction tx) {
List<Future<BaseEntity>> futures = executor.invokeAll(historyEntries);
if (executor.awaitTermination(/* some timeout here */)) {
futures.stream().map(Future::get).forEach(entity -> session.save(object));
} else {
/* rollback */
}
}
}
Your listener code then becomes:
#PostUpdate
public void postPersist(Object auditedEntity) {
interceptor.getHistoryEntries().add(new Callable<BaseEntity> {
/* history entry generation logic goes here */
});
}
(note that the above code is greatly simplified, you could use any other asynchronous execution API, the basic idea is that you need to block in AuditInterceptor.beforeTransactionCompletion, waiting for all the history entries to be generated)
However, I would strongly advise against using the above technique, as it is rather complicated and error prone.
If you look here: https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/events/Events.html, you'll find that Hibernate interceptors have more interesting methods that could help you gather auditing info, and that perhaps your implementation could make use of them, possibly avoiding the need for complicated logic altogether (Hibernate already does track changes to fields of individual entities, so you get that information for free).
Why reinvent the wheel, though? If you dig even deeper, you'll find the Hibernate Envers module (http://hibernate.org/orm/envers/, works for both JPA and pure Hibernate) which gives you business auditing out of the box. Envers already digs into the above mechanism, so hopefully the performance issue would go away.
Final note: have you measured how long history entry generation takes? I would guess that executing for loops and if statements might be cheaper than database access operations. If I were you, I wouldn't do any of the above unless I was absolutely sure that's where the performance bottleneck was.

How to link JPA persistence context with single database transaction

Latest Spring Boot with JPA and Hibernate: I'm struggling to understand the relationship between transactions, the persistence context and the hibernate session and I can't easily avoid the dreaded no session lazy initialization problem.
I update a set of objects in one transaction and then I want to loop through those objects processing them each in a separate transaction - seems straightforward.
public void control() {
List<> entities = getEntitiesToProcess();
for (Entity entity : entities) {
processEntity(entity.getId());
}
}
#Transactional(value=TxType.REQUIRES_NEW)
public List<Entity> getEntitiesToProcess() {
List<Entity> entities = entityRepository.findAll();
for (Entity entity : entities) {
// Update a few properties
}
return entities;
}
#Transactional(value=TxType.REQUIRES_NEW)
public void processEntity(String id) {
Entity entity = entityRepository.getOne(id);
entity.getLazyInitialisedListOfObjects(); // throws LazyInitializationException: could not initialize proxy - no Session
}
However, I get a problem because (I think) the same hibernate session is being used for both transactions. When I call entityRepository.getOne(id) in the 2nd transaction, I can see in the debugger that I am returned exactly the same object that was returned by findAll() in the 1st transaction without a DB access. If I understand this correctly, it's the hibernate cache doing this? If I then call a method on my object that requires a lazy evaluation, I get a "no session" error. I thought the cache and the session were linked so that's my first confusion.
If I drop all the #Transactional annotations or if I put a #Transactional on the control method it all runs fine, but the database commit isn't done until the control method completes which is obviously not what I want.
So, I have a few questions:
How can I make the hibernate session align with my transaction scope?
What is a good pattern for doing the separation transactions in a loop with JPA and declarative transaction management?
I want to retain the declarative style (i.e. no xml), and don't want to do anything Hibernate specific.
Any help appreciated!
Thanks
Marcus
Spring creates a proxy around your service class, which means #Transactional annotations are only applied when annotated methods are called through the proxy (where you have injected this service).
You are calling getEntitiesToProcess() and processEntity() from within control(), which means those calls are not going through proxy but instead have the transactional scope of the control() method (if you aren't also calling control() from another method in the same class).
In order for #Transactional to apply, you need to do something like this
#Autowired
private ApplicationContext applicationContext;
public void control() {
MyService myService = applicationContext.getBean(MyService.class);
List<> entities = myService.getEntitiesToProcess();
for (Entity entity : entities) {
myService.processEntity(entity.getId());
}
}

When does Grails assign an ID to an object?

A Grails 2.3.4 application is connecting to an Oracle database using the following domain class:
class Person {
String name
static mapping = {
id column: "PERSON_ID", generator: "sequence", params: [sequence: 'person_seq']
}
}
The PersonController makes a call to a method in PersonService and it makes a call to UtilService. The method in UtilService being called has some logic based on wether this Person object is new:
if (personInstance.id == null) { ... }
What I have found is that the id property of personInstance (which is passed through the method calls described above) is assigned when the UtilService is called.
The controller action calling PersonService is #Transactional, and the services do not have any transaction configuration.
So, a couple of questions:
When is id value assigned by GORM (I assumed at insert but that seems wrong)?
Is there a better way of checking if the object is new (isAttached() returns true so that's not good for me)?
EDIT: save() has not been called on the personInstance when UtilService does the id check.
The id is assigned when you call save(). For most persistence calls, Hibernate delays flushing the change until it feels it has to flush) to ensure correctness. But save() calls are treated differently. I believe the motivation is that even if we know that flush() will eventually be called, even if it's at the very end of the request, we want to retrieve the id early so it doesn't suddenly change.
Note that a service that does "not have any transaction configuration" is transactional - the only way to get a non-transactional service is to remove all #Transactional annotations (the newer Grails annotation and the older Spring annotation) and add
static transactional = false
All other services are transactional, although you can configure individual methods to be ignored ## Headin.
Turns out, I had a findBy which was flushing the session:
utilService.someMethod(Person.findByUsername(username))
It was at this point that the id was populated.
Got around it by using withNewTransaction:
def personInstance = Person.withNewSession { Person.findByUsername(username) }
utilService.someMethod(personInstance)
Which now leads me onto the next question...

Spring Transactions With Supports Propagation

I would like to understand the use of having a spring transaction with Propagation Supports. The java docs mention that if the method which has #Transactional(propagation = Propagation.SUPPORTS) is called from within a transaction it supports the transaction but if no transaction exists, the method is executed non-transactionally.
Isn't this already the behavior of spring transactions irrespective of Propagation.SUPPORTS?
public class ServiceBean {
#Transactional(propagation = Propagation.SUPPORTS)
public void methodWithSupportsTx() {
//perform some database operations
}
}
public class OtherServiceBean {
#Transactional(propagation = Propagation.REQUIRED)
public void methodWithRequiredTx() {
//perform some database operations
serviceBean.methodWithSupportsTx();
}
}
In the above code example, irrespective of whether methodWithSupportsTx() has #Transactional(propagation = Propagation.SUPPORTS) annotation it would be executed in a transaction depending on whether methodWithRequiredTx() has #Transactional annotation, right?
So what's the need/use of having a propagation level SUPPORTS?
From javadoc:
Note: For transaction managers with transaction synchronization, PROPAGATION_SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope. Note that this depends on the actual synchronization configuration of the transaction manager.
So, it means that, for example, multiple invocations of Hibernate's SessionFactory.getCurrentSession() inside methodWithSupportsTx() would return the same session.
A required transaction will create a new transaction if none exists. Therefore a new transaction would be made when you call serviceBean.methodWithSupportsTx(). If your method is truly transactional you will see an error from spring if no transaction exists.

Resources