Let say I use JPA
by using @transactions
annotations.
So to have any method run under a transaction I add a @transaction
annotations and BINGO my method run under a transaction.
To achieve the above we need have a interface
for the class and the instance is managed by some container.
Also I should always call the method from interface reference so that the proxy object can start the transaction.
So My code will look like:
class Bar {
@Inject
private FooI foo;
...
void doWork() {
foo.methodThatRunUnderTx();
}
}
class FooImpl implements FooI {
@Override
@Transaction
public void methodThatRunUnderTx() {
// code run with jpa context and transaction open
}
}
interface FooI {
void methodThatRunUnderTx();
}
Well and Good
Now let say methodThatRunUnderTx
does two logic operations
[1] call some service(long request/response cycle let say 5 sec) and fetch the results
[2] perform some jpa entity modifications
Now since this method call is long and we don't want to hold the transaction open for long time, so we change the code so that [2] happens in separate tx and methodThatRunUnderTx
doesnt run in transaction
So we will remove the @Transaction
from the methodThatRunUnderTx
and add another method in class with @transaction
let say new methods is methodThatRunUnderTx2
, now to call this method from methodThatRunUnderTx
we have to inject it into itself and add a method to interface so that the call happen through proxy object.
So now our code will look like:
class Bar {
@Inject
private FooI foo;
...
void doWork() {
foo.methodThatRunUnderTx();
}
}
class FooImpl implements FooI {
@Inject
private FooI self;
@Override
//@Transaction -- remove transaction from here
public void methodThatRunUnderTx() {
...
self.methodThatRunUnderTx2();// call through proxy object
}
@Override
@Transaction //add transaction from here
public void methodThatRunUnderTx2() {
// code run with jpa context and transaction open
}
}
interface FooI {
void methodThatRunUnderTx();
void methodThatRunUnderTx2();
}
NOW The Problem
We have made methodThatRunUnderTx2()
to be public through interface
.
But it is not what we want to expose as our api of FooI
and not meant to be called from outside..
Any suggestion to solve it ?
That's why modern containers don't require any interface to be implemented - proxies are then created by dynamic subclassing or bytecode instrumentation is used.
So, the solution to your design issue is simple: Implement a helper class containing the transactional method and inject it to the class implementing the interface (and to any other class that can benefit from it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With