How can I turn off auto commit and give explicit commit using #transactional?
I have multiple operations and I want them to get committed after all select and update are done. Reason being the select is done based on some field as null and this data is used somewhere and then update is done to some records. So before new records come, I have to change the field as to some value and avoid selection of new data i.e select only those record that got updated
You just need to put the #Transaction annotation around all the work you want to be committed:
#Autowired
private Manager1 manager1;
#Autowired
private Manager2 manager2;
#Transactional
public void doStuff() {
manager1.do();
manager2.do();
}
Everything in method doStuff() will all be committed together, unless there is an exception thrown, in which case it will all be rolled back.
I would recommend you to use Programmatic approach for this case.
Programmatic transaction management: This means that you have manage the transaction with the help of programming. That gives you extreme flexibility, but it is difficult to maintain.
Vs
Declarative transaction management: This means you separate transaction management from the business code. You only use annotations or XML based configuration to manage the transactions.
Perhaps, alternative way for your questions by Programmatic transaction management.
Eg.
/** DataSourceTransactionManager */
#Autowired
private PlatformTransactionManager txManager;
public void yourMethod() {
try {
// Start a manual transaction.
TransactionStatus status = getTransactionStatus();
your code...
.....
.....
//your condition
txManager.commit(status);
//your condition
txManager.rollback(status);
} catch (YourException e) {
//your condition
txManager.rollback(status);
}
}
/**
* getTransactionStatus
*
* #return TransactionStatus
*/
private TransactionStatus getTransactionStatus() {
DefaultTransactionDefinition dtd = new DefaultTransactionDefinition();
dtd.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
dtd.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
dtd.setReadOnly(false);
return txManager.getTransaction(dtd);
}
Note: It does not mean you need to always use one approach like Programmatic transaction management. I prefer mixed approach. Please use easy way like Declarative transaction for simple database services, otherwise, just control with Programmatic transaction in your services will save your logic easily.
Related
I am having trouble finding information about this issue I am running into. I am interested in implementing row level security on my Postgres db and I am looking for a way to be able to set postgres session variables automatically through some form of an interceptor. Now, I know that with hibernate you are able to do row-level-security using #Filter and #FilterDef, however I would like to additionally set policies on my DB.
A very simple way of doing this would be to execute the SQL statement SET variable=value prior to every query, though I have not been able to find any information on this.
This is being used on a spring-boot application and every request is expected to will have access to a request-specific value of the variable.
Since your application uses spring, you could try accomplishing this in one of a few ways:
Spring AOP
In this approach, you write an advice that you ask spring to apply to specific methods. If your methods use the #Transactional annotation, you could have the advice be applied to those immediately after the transaction has started.
Extended TransactionManager Implementation
Lets assume your transaction is using JpaTransactionManager.
public class SecurityPolicyInjectingJpaTransactionManager extends JpaTransactionManager {
#Autowired
private EntityManager entityManager;
// constructors
#Override
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
super.prepareSynchronization(status, definition);
if (status.isNewTransaction()) {
// Use entityManager to execute your database policy param/values
// I would suggest you also register an after-completion callback synchronization
// This after-completion would clear all the policy param/values
// regardless of whether the transaction succeeded or failed
// since this happens just before it gets returned to the connection pool
}
}
}
Now simply configure your JPA environment to use your custom JpaTransactionManager class.
There are likely others, but these are the two that come to mind that I've explored.
My application loads a list of entities that should be processed. This happens in a class that uses a scheduler
#Component
class TaskScheduler {
#Autowired
private TaskRepository taskRepository;
#Autowired
private HandlingService handlingService;
#Scheduled(fixedRate = 15000)
#Transactional
public void triggerTransactionStatusChangeHandling() {
taskRepository.findByStatus(Status.OPEN).stream()
.forEach(handlingService::handle);
}
}
In my HandlingService processes each task in issolation using REQUIRES_NEW for propagation level.
#Component
class HandlingService {
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Task task) {
try {
processTask(task); // here the actual processing would take place
task.setStatus(Status.PROCCESED);
} catch (RuntimeException e) {
task.setStatus(Status.ERROR);
}
}
}
The code works only because i started the parent transaction on TaskScheduler class. If i remove the #Transactional annotation the entities are not managed anymore and the update to the task entity is not propagated to the db.I don't find it natural to make the scheduled method transactional.
From what i see i have two options:
1. Keep code as it is today.
Maybe it`s just me and this is a correct aproach.
This varianthas the least trips to the database.
2. Remove the #Transactional annotation from the Scheduler, pass the id of the task and reload the task entity in the HandlingService.
#Component
class HandlingService {
#Autowired
private TaskRepository taskRepository;
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void handle(Long taskId) {
Task task = taskRepository.findOne(taskId);
try {
processTask(task); // here the actual processing would take place
task.setStatus(Status.PROCCESED);
} catch (RuntimeException e) {
task.setStatus(Status.ERROR);
}
}
}
Has more trips to the database (one extra query/element)
Can be executed using #Async
Can you please offer your opinion on which is the correct way of tackling this kind of problems, maybe with another method that i didn't know about?
If your intention is to process each task in a separate transaction, then your first approach actually does not work because everything is committed at the end of the scheduler transaction.
The reason for that is that in the nested transactions Task instances are basically detached entities (Sessions started in the nested transactions are not aware of those instances). At the end of the scheduler transaction Hibernate performs dirty check on the managed instances and synchronizes changes with the database.
This approach is also very risky, because there may be troubles if you try to access an uninitialized proxy on a Task instance in the nested transaction. And there may be troubles if you change the Task object graph in the nested transaction by adding to it some other entity instance loaded in the nested transaction (because that instance will now be detached when the control returns to the scheduler transaction).
On the other hand, your second approach is correct and straightforward and helps avoid all of the above pitfalls. Only, I would read the ids and commit the transaction (there is no need to keep it suspended while the tasks are being processed). The easiest way to achieve it is to remove the Transactional annotation from the scheduler and make the repository method transactional (if it isn't transactional already).
If (and only if) the performance of the second approach is an issue, as you already mentioned you could go with asynchronous processing or even parallelize the processing to some degree. Also, you may want to take a look at extended sessions (conversations), maybe you could find it suitable for your use case.
The current code processes the task in the nested transaction, but updates the status of the task in the outer transaction (because the Task object is managed by the outer transaction). Because these are different transactions, it is possible that one succeeds while the other fails, leaving the database in an inconsistent state. In particular, with this code, completed tasks remain in status open if processing another task throws an exception, or the server is restarted before all tasks have been processed.
As your example shows, passing managed entities to another transaction makes it ambiguous which transaction should update these entities, and is therefore best avoided. Instead, you should be passing ids (or detached entities), and avoid unnecessary nesting of transactions.
Assuming that processTask(task); is a method in the HandlingService class (same as handle(task) method), then removing #Transactional in HandlingService won't work because of the natural behavior of Spring's dynamic proxy.
Quoting from spring.io forum:
When Spring loads your TestService it wrap it with a proxy. If you call a method of the TestService outside of the TestService, the proxy will be invoke instead and your transaction will be managed correctly. However if you call your transactional method in a method in the same object, you will not invoke the proxy but directly the target of the proxy and you won't execute the code wrapped around your service to manage transaction.
This is one of SO thread about this topic, and Here are some articles about this:
http://tutorials.jenkov.com/java-reflection/dynamic-proxies.html
http://tutorials.jenkov.com/java-persistence/advanced-connection-and-transaction-demarcation-and-propagation.html
http://blog.jhades.org/how-does-spring-transactional-really-work/
If you really don't like adding #Transaction annotation in your #Scheduled method, you could get transaction from EntityManager and manage transaction programmatically, for example:
UserTransaction tx = entityManager.getTransaction();
try {
processTask(task);
task.setStatus(Status.PROCCESED);
tx.commit();
} catch (Exception e) {
tx.rollback();
}
But I doubt that you will take this way (well, I wont). In the end,
Can you please offer your opinion on which is the correct way of tackling this kind of problems
There's no correct way in this case. My personal opinion is, annotation (for example, #Transactional) is just a marker, and you need a annotation processor (spring, in this case) to make #Transactional work. Annotation will have no impact at all without its processor.
I Will more worry about, for example, why I have processTask(task) and task.setStatus(Status.PROCESSED); live outside of processTask(task) if it looks like does the same thing, etc.
HTH.
i'm working with spring jdbcTemplate in some desktop aplications.
i'm trying to rollback some database operations, but i don't know how can i manage the transaction with this object(JdbcTemplate). I'm doing multiple inserts and updates through a methods sequence. When any operation fails i need rollback all previous operations.
any idea?
Updated... i tried to use #Transactional, but the rolling back doesn't happend.
Do i need some previous configuration on my JdbcTemplate?
My Example:
#Transactional(rollingbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
public void Testing(){
jdbcTemplate.exec("Insert into table Acess_Level(IdLevel,Description) values(1,'Admin')");
jdbcTemplate.exec("Insert into table Acess_Level(IdLevel,Description) values(STRING,'Admin')");
}
The IdLevel is a NUMERIC parameter, so... in our second command will occur an exception. When i see the table in database, i can see the first insert... but, i think this operation should be roll back.
what is wrong?
JdbcTemplate doesn't handle transaction by itself. You should use a TransactionTemplate, or #Transactional annotations : with this, you can then group operations within a transaction, and rollback all operations in case of errors.
#Transactional
public void someMethod() {
jdbcTemplate.update(..)
}
In Spring private methods don't get proxied, so the annotation will not work. See this question: Does Spring #Transactional attribute work on a private method?.
Create a service and put #Transactional on the public methods that you want to be transactional. It would be more normal-looking Spring code to have simple DAO objects that each do one job and have several of them injected than it would to have a complicated DAO object that performed multiple SQL calls within its own transaction.
I have a comprehension question. I cannot understand how the database actions from the Neo4jTemplate like "getOrCreateNode()" belong to the surrounding transction. How is it implemented? The Neo4jTemplate would be shared in a multi-threaded environment? I cannot see a distinct membership of the transaction. I would understand if the actions are directly in the transaction object (e.g. tx.getOrCreateNode()).
#Service
public class TestService {
#Autowired
private Neo4jTemplate template;
public void save(IndexedTriple triple) {
GraphDatabase gdb = template.getGraphDatabase();
Transaction tx = gdb.beginTx();
Node subject = gdb.getOrCreateNode()
...
tx.success();
tx.finish();
}
}
Thanks in advance.
The below extract from the reference documentation pretty much sums it up. Use the spring transaction manager instead of using the Neo4j transactions and let spring take care of demarcation. Also, the transaction management is completely thread-safe. For you, I suggest using #Transactional annotation. If there is an existing transaction already, then spring joins that existing transaction as well.
Transactions
The Neo4jTemplate provides implicit transactions for some of its
methods. For instance save uses them. For other modifying operations
please provide Spring Transaction management using #Transactional or
the TransactionTemplate.
Environment: Spring 3, Custom Transaction Management, JDBC Transactions
I just read the Spring docs on using the transaction template to handle transaction management. It seemed overly complex so I want to ask:
Most of my transactions are JDBC related, meaning I just declare an #Transactional on my service. But now I am making a REST service call to another site which needs to rollback if any of the following JDBC operations fail, I'll provide the rollback code in this case.
As I progress in my method, in my transaction - I want to save a reference to the REST service call (needed to roll back that action), and upon exception I just want a method myCustomRollback() called which can access the previously stored object.
Why not just provide a map in the transactionTemplate for storing stuff and define a custom rollback method on the #Transactional annotation?
This is the way I think about it, I'm not following the way Spring thinks about this. Can someone help me bridge the gap between what I want and how I accomplish it most efficiently in Spring? I only need to do this for a few special case operations.
To anyone still reading this:
I solved a similar problem with spring events - as suggested by Den Roman in option 3.
Here's the basic idea (scenario is fictional):
Whenever I perform external operations that need to be rolled back together with the transaction, I publish an event inside my #Transactional method using support from spring (org.springframework.context.ApplicationEventPublisher):
#Transactional
public String placeOrder(Order order) {
String orderId = orderServiceGateway.createOrder(order);
applicationEventPublisher.publishEvent(new OrderCreatedEvent(orderId));
workflowService.startWorkflow(orderId);
return orderId;
}
The event itself can be any object - I created a POJO with details about the remote entity to be deleted.
Then I registered a special event listener that is bound to a transaction phase - in my case to the rollback:
#TransactionalEventListener(phase = TransactionPhase.AFTER_ROLLBACK)
public void rollBackOrder(OrderCreatedEvent orderCreatedEvent) {
String orderId = orderCreatedEvent.getOrderId();
orderServiceGateway.deleteOrder(orderId);
}
Of course, it's recommended to catch & log the exception from rollback operation, not to lose the original exception from the placeOrder() method.
By default these events are synchronous, but they can be made async by additional configuration.
Here's a very good article on this mechanism, including detailed configuration and pitfalls: Transaction Synchronization and Spring Application Events (DZone)
While I don't like the solution 100% because it clutters the business logic with event publishing stuff and binds to spring, it definitely does what I expect it to do and makes it possible to pass context from the transactional method to the rollback method - which is not available through a traditional try/catch block outside of the transactional method (unless you put your context in the exception itself, which is not very nice).
I've re-read your question a few times and am not sure I understand your question completely. I assume your executing someCode and if that fails you would like to execute myCustomRollback which has some information about someCode. So I'll try to provide a Generic answer.
If you want spring to rollback some code. It will only rollback that which is rollBackAble, like jdbc transactions. Assume you have a method which performs 2 calls.
#Transactional
public void doStuff(SomeEntity entity, File file) {
persist(entity);
customFileService.createOnFileSystem(file);
throw new RunTimeException();
}
So the code above will always rollback. It will undo the persisting of your entity, but not the creation of your file, since that is not managed by Spring transactions, unless you provide custom implementation for it to be.
Second, Spring provides 2 ways of working with transactions:
Spring AOP: a proxy is created at runtime which will decorate your code with transactional stuff. If your class would be named MyClass, then Spring will create a class names MyClassProxy, which will wrap your code in transactional code.
AspectJ: at compile time your .class file will be adjusted and transactional code will be embedded inside your method.
The aspectJ approach seems harder to configure, but isn't so much and is way easier to use. Since anything which is annotated with #Transactional will be embedded (weaved) with code. For Spring AOP this is not the case. Transactional inner method calls for instance in Spring will be ignored! So aspectJ provides a more intuitive approach.
Back to what I think your question is (the code is all in 1 class):
public void doSomeCode() {
Object restCall = initialize();
try {
execute(restCall);
} catch (CustomException e) {
myCustomRollback(restCall; e);
}
}
#Transactional(rollbackFor = CustomException.class)
private void execute(Object restCall) throws CustomException {
// jdbc calls..
restCall = callRest(restCall);
throw new CustomException();
}
void myCustomRollback(Object restCall, CustomException e) {
...
}
The code above will only work with AspectJ! Since your making inner method calls which also seems to be private! AOP at runtime cannot handle this.
So what happens is everything (which is rollbackAble) in execute will be rollbacked. And in doStuff you have information about the objects which were used in execute, you now can use in myCustomRollback to rollback your REST stuff manually.
Not sure if I answered this question properly, but I hope it helps someone with a similar problem.
1 solution is to implement your own transactional manager by extending a one
2 solution is to use TransactionSynchronizationManager class
3 solution is to use #TransactionalEventListener in case you have Spring 4
Spring transaction management the default behavior for automatic rollback is for unchecked exceptions
so for a custom exception,
#Transactional(rollbackFor = CustomException.class, noRollbackFor = RuntimeException.class)
public void doSomething(...
)
the transaction be rolled back if it there is an exception that matches the specified. If an exception not matches, it is propagated to caller of the service or TransactionRolledBackException wrapper
if you use use the org.springframework.transaction.PlatformTransactionManager it is more manageable handling exceptions than template
check the documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html
you can use the AfterThrowing advice (when an exception is thrown) & call your method (myCustmRollback()) there, you can use TransactionSynchronizationManager class to get thecurrent transaction & roll it back...
alternatively.. you can use the AroundAdvice to begin & commit/rollback your transaction (this way you can use the spring provided transaction manager by using the TransactionSynchronizationManager class)