I am using mongodb with spring mvc for a REST API. I have a controller which adds comments for events. This controller use a method of my event service. And implementation of them are below. However It seems to me as if my mongodb connection works without transaction. I have 1 insert and 1 update in that my controller adding comment. If update of event throws an error, the request commits inserting.Why is it not doing rollback? How can I fix this problem?
public Comments addComment(Comments comment) throws Exception{
comment.setCommentDate(SowUtil.getDateTimeDB());
comment.setCommenter(personService.findPersonById("531cc90e3c37b20bef47dfc7"));
mongoTemplate.insert(comment);
Events adv = findEventById(comment.getEventId());
adv.addComment(comment);
eventService.save(adv);
return comment;
}
MongoDB does not have the same notion of transactions as RDBMS. Based on your example, it looks like you are using two documents.
MongoDB has an article on 2-phase commit patterns involving multiple documents (
http://docs.mongodb.org/manual/tutorial/perform-two-phase-commits/). Perhaps, that can help you implementing a rollback?
I believe that Spring also has a notion of transaction support for MongoDB (http://docs.spring.io/spring-integration/reference/html/mongodb.html).
Related
Having a circuit breaker with Spring Boot for external calls (e.g. HTTP) is a common pattern that is rather easy to put into place, for example with resilience4j.
I cannot find any information about doing the same with database calls, via resilience4j or some other common pattern, and this is unexpected to me.
Suppose we have a service with a simple JDBC connection to a traditional SQL database. If the database goes down for any reason, I would like to be able to stop all incoming requests to the service at the controller level until the connection is restored. Is there a way to achieve what is essentially circuit breaker functionality for all the transactions happening over the connection to the database?
Yes, this is possible. Chapter 7 of the book Spring Microservices in Action gives an example of this. Effectively, you treat a SQL call in the same way as an HTTP call:
#CircuitBreaker(name = "entityService") ❶
public List<Entity> getEntity(String entityId) {
return entityRepository.findByEntityId(entityId);
}
You will need the following dependencies:
io.github.resilience4j:resilience4j-spring-boot2
io.github.resilience4j:resilience4j-circuitbreaker
io.github.resilience4j:resilience4j-timelimiter
org.springframework.boot:spring-boot-starter-aop
This is using an AOP pattern of adding new behavior to existing code without modifying the code itself.
I'm having a problem where I need to perform several slow HTTP requests on a separate thread after having written to the database using a JpaRepository. The problem is that doActualJob() blocks while waiting for a series of futures to resolve. This seems to prevent the underlying Hibernate session from closing, causing the application to run out of connections shortly after.
How do I write this function so the database connection isn't kept open while doing the blocking I/O? Is it even possible using JpaRepositories, or do I need to use a lower level API like EntityManager/SessionFactory?
#Service
class SomeJobRunner {
private final SomeJobRepository mSomeJobRepository; //extends JpaRepository
#AutoWired
public SomeJobRunner(final SomeJobRepository someJobRepository) {
mSomeJobRepository = someJobRepository;
}
#Async
public void doSlowJob(final long someJobId) {
SomeJob someJob = mSomeJobRepository.findOne(someJobId);
someJob.setJobStarted(Instant.now());
mSomeJobRepository.saveAndFlush(someJob);
doActualjob(); // Synchronous job doing several requests using Unirest in series
someJob = mSomeJobRepository.findOne(someJobId);
someJob.setJobEnded(Instant.now());
mSomeJobRepository.saveAndFlush(someJob);
}
Well - non-blocking database IO is not possible in Java/JDBC world in a standard way .To put it simply - your Spring data repository would be eventually using JPA ORM Implementation ( likes of Hibernate) which in turn will use JDBC to interact with the database which is essentially blocking in nature. There is work being done on this currently by Oracle (Asynchronous Database Access API ) to provide a similar API as JDBC but non-blocking. They intend to propose this as a standard. Also there is an exciting and parallel effort by Spring guys on this namely R2DBC – Reactive Relational Database Connectivity. They have actually integrated this with Spring data as well (link) so that may help you integrate in your solution. A good tutorial by Spring on this can be found here.
EDIT: As of 2022 Hibernate has reactive option as well
I would suggest to write in the database using a separate JTA transaction. Do do so, define a methode like
#Transactional(Transactional.TxType.REQUIRES_NEW)
public void saveJobStart(final long someJobId) {
SomeJob someJob = mSomeJobRepository.findOne(someJobId);
someJob.setJobStarted(Instant.now());
mSomeJobRepository.saveAndFlush(someJob);
}
Of course it is not quite the same. If doActualjob() fails, in your case, the database won't persist the start date. In my proposal, it will persist it. To compensate, you need to remove the start date in a catch bloc in doSlowJob, within a new transaction, and then rethrow the exception.
I want to update the DB and a server with some new data in one transaction.
I'm using java 8 and i was looking for Java transaction API.
I have found JTA but saw no code example. Can someone please link to one?
I saw this post and post
but there were about DB transaction and had no code example.
I want to make the transaction at a higher lever than the DAL level
as it wraps the peer-server update as well.
private void updateDbAndServer() throws Exception {
if (rulesUiRepository.updateRulesUiSnapshot(nonSplittedRulesSnapshot) == -1)
throw new RuntimeException("cannot save ui snapshot in DB");
Map<RuleConditionBl, RtRule> splittedMap = nonSplittedRulesSnapshot.toSplittedMap();
anotherService.updateConfig(splittedMap);
}
I think the Spring Transaction API is very easy to use and allows you to concentrate about your businesses logic. The API is used in a declarative form. Check this for more info.
I´m reading about Hibernate and using Spring data. In one chapter I´ve read about the different of use get() and load(), supposedly in Hibernate load return a proxy placeHolder and only access to database in case that you access to the entity attribute.
In my application many times I just need to return and entity to add as dependency to another entity and for that specific case add a proxy would be more than enough, but using Spring data repository I cannot find the get() or load() method, so I guess they dont implement the same feature as in Hibernate. Any idea if Spring data has that Hibernate´s features to have a proxy placeHolder?.
Regards.
JpaRepository interface has two methods: First is getOne(id) which is an alternative of hibernate load, second is findById(id) which is an aternative of hibernate get method.
Here consistent request in Mongo I found how to handle consistent request in java code.
DB db...;
db.requestStart();
try {
db.requestEnsureConnection();
code....
} finally {
db.requestDone();
}
Does spring-data cares about it. Or I should do it manually as using plain java driver?
In spring data to execute with in same connection, you should use mongoTemplate.executeInSession(DbCallback action). Please take a look at the Spring documentation Section 5.1.1 about Execution Callback.