I am using Spring with Hibernate. I am running jUnit test like this:
String number = invoiceNumberService.nextInvoiceNumber();
and invoiceNumberService method is:
InvoiceNumber invoiceNumber = invoiceNumberRepository.findOne(1L);
it is using simple spring data repository method, and it's working well. But when I override this method to use locking:
#Lock(LockModeType.PESSIMISTIC_READ)
#Override
InvoiceNumber findOne(Long id);
I am getting "javax.persistence.OptimisticLockException: Row was updated or deleted by another transaction"
I can't understand why its optimistic lock exception, while I am using pessimistic locking? And where is this part when another transaction is changing this entity?
I have already dig a lot similar questions and I am quite desperate about this. Thanks for any help
Solution:
The problem was in my init function in test class:
#Before
public void init() {
InvoiceNumber invoiceNumber = new InvoiceNumber(1);
em.persist(invoiceNumber);
em.flush();
}
There was lack of
em.flush();
Which saves the data into database, so findOne() can now retreive it
Question: Have you given the #transcational annotation in dao or service layer?
it happens due to the reason that two transaction is simultaneously trying to change the data of same table..So if you remove all the annotation from the dao layer and put in the service layer it should solve the problem i this..because i faced similar kind of problem.
Hope it helps.
Just for the sake of it I'll post the following, if any one disagrees please correct me. In general in java you are advised to use Spring/hibernate and JPA. Hibernate implements JPA so you will need dependencies for Spring and Hibernate.
Next let Spring/hibernate manage your transactions and the committing part. It is bad practice to flush/commit your data yourself.
For instance let assume the following method:
public void changeName(long id, String newName) {
CustomEntity entity = dao.find(id);
entity.setName(newName);
}
Nothing will happen after this method (you could call merge and commit). But if you annotate it with #Transactional, your entity will be managed and at the end of the #Transactional method Spring/hibernate will commit your changes. So this is enough:
#Transactional
public void changeName(long id, String newName) {
CustomEntity entity = dao.find(id);
entity.setName(newName);
}
No need to call flush, Spring/Hibernate will handle all the mess for you. Just don't forget that your tests have to call #Transactional methods, or should be #Transactional themselves.
Related
Following tutorial on Java Spring, I'm trying to understand how does #Transactional work with setters, and from other question/sources, I can't find a beginner-friendly explanation for it.
Let's say I have a user entity with getters and setters:
#Entity
public class User {
// Id set up
private Long id;
private String name;
private String email;
private String password;
// Other constructors, setters and getters
public void setName(String name) {
this.name = name;
}
}
And in the UserService I have a getUserName method:
#Service
public class UserService {
private final UserRepository userRepository;
#Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
#Transactional
public void getUserName(Long id) {
User user = userRepository.findById(id).orElseThrow();
user.setName("new user name"); // Why will this update db?
}
}
With #Transactional annotated, the setter function does update db, is this the spring way of updating data? Can someone help explain in layman term, how the Transactional work with setters under the hood?
Edit:
Without #Transactional, setter function won't update db, but in
order to mutate db, will have to call userRepository.save(user). And from the video, the instructor simply says the Transactional will handle jpql for us, and use setters along with it to update db.
Resource update:
Spring Transaction Management: #Transactional In-Depth, hope this is helpful.
Firstly, it is the underlying JPA provider (assume it is Hibernate) to be responsible for updating the entity but not Spring. Spring just provides the integration support with Hibernate.
To update an entity loaded from the DB , generally you need to make sure the following happens in order.
Begin a DB transaction
Use EntityManager to load the entity that you want to update.The loaded entity is said to be managed by this EntityManager such that it will keep track all the changes made on its state and will generate the necessary update SQL to update this entity in (4) automatically.
Make some changes to the entity 's state. You can do it through any means such as calling any methods on it , not just restricting to calling it by setter
Flush the EntityManager. It will then generate update SQL and send to DB.
Commit the DB transaction
Also note the followings:
Spring provides #Transactional which is a declarative way to execute (1) and (5) by annotating it to a method.
By default , Hibernate will call (4) automatically before executing (5) such that you do not need to call (4) explicitly.
Spring Data JPA repository internally use EntityManager to load the user. So the user return from the repository will be managed by this EntityManager.
So in short , #Transactional is necessary to update the entity. And updating the entity is nothing to do with setter as it just care if there are state changes on the entity in the end , and you can do it without using setter.
Spring uses Hibernate as ORM under the hood.
When you call userRepository.findById, Hibernate entity manager is called under the hood, it retrieves entity from database and at the same time makes this entity manageable (you can read separately about Hibernate managed entities).
What it means, in a simple words, the Hibernate 'remembers' the reference to this entity in its internal structures, in the so-called session. It, actually, 'remembers' all entities which it retrieves from database (even the list of entities obtained by queries) during single transaction (in the very basic case).
When you make some method #Transactional, by default Hibernate session is flushed when such method is finished. session.flush() is called under the hood.
Once session gets flushed, Hibernate pushes all changes made to these managed entities back into the database.
That is why your changes got to the database, once method was finished, without any additional calls.
To dig deeper into the topic, you can read more about Hibernate managed entities , session flush mode, repository.save(), repository.saveAndFlush() in Spring Data.
I am using Spring data JPA's repository for my application. Currently I am using basic CRUD operations provided by default by spring data jpa repositories and for complex join queries, I am writing custom JPQL queries as follows:
public interface ContinentRepository extends JpaRepository<Continent, Long>
{
#Query(value = "SELECT u FROM Continent u JOIN FETCH ... WHERE u.id = ?1")
public List<Continent> findContinent(Long id);
}
In my Service class, I am autowiring this repository and performing DB operations.
#Service
public class MyService
{
#Autowired
public ContinentRepository cr;
public void read()
{
var result1 = cr.findContinent(1);
var result2 = cr.findContinent(2);
}
#Transactional
public void write()
{
var c = new Continent();
// setters
c = cr.save(c);
}
}
Currently I am just marking the write() as org.springframework.transaction.annotation.Transactional.
Should I also mark read() method with Transactional(readOnly = true)? As it only performs read operations.
Should I also mark the findContinent(Long id) as Transactional(readOnly = true)? I read that all the default methods as marked as Transactional https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
In the repository interface, should I mark the Transactional annotation at the method level or at the interface level. (Also, I suspect most of the custom methods will be read only)
Is it good to have #Transactional at both Service and Repository layer?
Should I also mark read() method with Transactional(readOnly = true)? As it only performs read operations.
Not really necessary, however it might create some optimisations regarding cache memory consumption accordingly to this blog https://vladmihalcea.com/spring-read-only-transaction-hibernate-optimization/
Should I also mark the findContinent(Long id) as Transactional(readOnly = true)? I read that all the default methods as
marked as Transactional
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
The same answer like in the first case
In the repository interface, should I mark the Transactional annotation at the method level or at the interface level. (Also, I
suspect most of the custom methods will be read only)
In general I added to the method level, because I have more control over the parameters like rollback
Is it good to have #Transactional at both Service and Repository layer?
I recommend you to have at the Service level because, there, you can update many tables (so you can use many repositories), and you want your entire update to be transactional.
Should I also mark read() method with Transactional(readOnly = true)? As it only performs read operations.
Yes. It is good practice, you will know immediately that this method doesn't change anything in database, and what is more important, you will disable some unintentional changes in database using this service method. If this method tries to do any update on DB exception will be thrown and rollback will be called.
Should I also mark the findContinent(Long id) as Transactional(readOnly = true)? I read that all the default methods as
marked as Transactional
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#transactions
Depends how you are using it. If you are always calling this from #Sevice then no. I think that is common use case as fare as I know.
In the repository interface, should I mark the Transactional
annotation at the method level or at the interface level. (Also, I
suspect most of the custom methods will be read only)
Same as 2.
Is it good to have #Transactional at both Service and Repository
layer?
Same as 2.
So I have this method:
#Transactional
public void savePostTitle(Long postId, String title) {
Post post = postRepository.findOne(postId);
post.setTitle(title);
}
As per this post:
The save method serves no purpose. Even if we remove it, Hibernate
will still issue the UPDATE statement since the entity is managed and
any state change is propagated as long as the currently running
EntityManager is open.
and indeed the update statement is issued, but if I run the method without the #Transactional annotation:
public void savePostTitle(Long postId, String title) {
Post post = postRepository.findOne(postId);
post.setTitle(title);
}
Hibernate will not issue the update statement so one has to call postRepository.save(post);explicitly.
What is the difference between using #Transactional or not in this specific scenario?
In a standard configuration, the scope of a persistence context is bound to the transaction.
If you don't have an explicit transaction defined by means of the annotation your (non-existing) transaction span just the reading call to the database.
After that the entity just loaded is not managed.
This means changes to it won't get tracked nor saved.
Flushing won't help because there are no changes tracked.
I am having quite complex methods which create different entities during its execution and use them. For instance, I create some images and then I add them to an article:
#Transactional
public void createArticle() {
List<Image> images = ...
for (int i = 0; i < 10; i++) {
// creating some new images, method annotated #Transactional
images.add(repository.createImage(...));
}
Article article = getArticle();
article.addImages(images);
em.merge(article);
}
This correctly works – images have their IDs and then they are added to the article. The problem is that during this execution the database is locked and nothing can be modified. This is very unconvinient because images might be processed by some graphic processor and it might take some time.
So we might try to remove the #Transactional from the main method. This could be good.
What happens is that images are correctly created and have their ID. But once I try to add them to article and call merge, I get javax.persistence.EntityNotFoundException for Image with ID XXXX. The entity manager can't see that the image was created and have its ID. So the database is not locked, but we can't do anything either.
So what can I do? I don't want to have the database locked during the whole execution and I want to be able to access the created entities!
I am using current version of Spring and Hibernate, everything defined by Annotations. I don't use session factory, I am accessing everything via javax.persistence.EntityManager.
Consider leveraging the Hibernate cascading functionality for persisting object trees in one go with minimal database locking:
#Entity
public class Article {
#OneToMany(cascade=CascadeType.MERGE)
private List<Images> images;
}
#Transactional
public void createArticle() {
//images created as Java objects in memory, no DAOs called yet
List<Image> images = ...
Article article = getArticle();
article.addImages(images);
// cascading will save the article AND the images
em.merge(article);
}
Like this the article AND it's images will get persisted at the end of the transaction in a single transaction with a minimal lifetime. Up until then no locking occurred on the database.
Alternativelly split the createArticle in two #Transactional business methods, one createImages and the other addImagesToArticle and call them one after the other in a third method in another bean:
#Service
public class OtherBean {
#Autowired
private YourService yourService;
// note that no transactional annotation is used, this is intentional
public otherMethod() {
yourService.createImages(); // first transaction - images are committed
yourService.addImagesToArticle(); // second transaction - images are added to article
}
}
You could try setting the transaction isolation on your datasource to READ_UNCOMMITTED, though that can lead to inconsistencies so it is generally not a recommended thing to do.
My best guess is that your transaction isolation level is SERIALIZABLE. That's why the DB locks affected tables for the whole duration of a transaction.
If that's the case change the level to READ_COMMITTED. Hibernate (or any JPA provider) works nicely with this one.
It won't lock anything unless you explicitly call entityManager.lock(someEntity, LockModeType.SomeLockType))
Also when you choose transaction boundaries firstly think in terms of atomicity. If createArticle() is an atomic unit of work it just has to be made transactional, breaking it into smaller transactions for the sake of 'optimization' is wrong.
I just started working on a Spring-data, Hibernate, MySQL, JPA project. I switched to spring-data so that I wouldn't have to worry about creating queries by hand.
I noticed that the use of #Transactional isn't required when you're using spring-data since I also tried my queries without the annotation.
Is there a specific reason why I should/shouldn't be using the #Transactional annotation?
Works:
#Transactional
public List listStudentsBySchool(long id) {
return repository.findByClasses_School_Id(id);
}
Also works:
public List listStudentsBySchool(long id) {
return repository.findByClasses_School_Id(id);
}
What is your question actually about? The usage of the #Repository annotation or #Transactional.
#Repository is not needed at all as the interface you declare will be backed by a proxy the Spring Data infrastructure creates and activates exception translation for anyway. So using this annotation on a Spring Data repository interface does not have any effect at all.
#Transactional - for the JPA module we have this annotation on the implementation class backing the proxy (SimpleJpaRepository). This is for two reasons: first, persisting and deleting objects requires a transaction in JPA. Thus we need to make sure a transaction is running, which we do by having the method annotated with #Transactional.
Reading methods like findAll() and findOne(…) are using #Transactional(readOnly = true) which is not strictly necessary but triggers a few optimizations in the transaction infrastructure (setting the FlushMode to MANUAL to let persistence providers potentially skip dirty checks when closing the EntityManager). Beyond that the flag is set on the JDBC Connection as well which causes further optimizations on that level.
Depending on what database you use it can omit table locks or even reject write operations you might trigger accidentally. Thus we recommend using #Transactional(readOnly = true) for query methods as well which you can easily achieve adding that annotation to you repository interface. Make sure you add a plain #Transactional to the manipulating methods you might have declared or re-decorated in that interface.
In your examples it depends on if your repository has #Transactional or not.
If yes, then service, (as it is) in your case - should no use #Transactional (since there is no point using it). You may add #Transactional later if you plan to add more logic to your service that deals with another tables / repositories - then there will be a point having it.
If no - then your service should use #Transactional if you want to make sure you do not have issues with isolation, that you are not reading something that is not yet commuted for example.
--
If talking about repositories in general (as crud collection interface):
I would say: NO, you should not use #Transactional
Why not: if we believe that repository is outside of business context, and it should does not know about propagation or isolation (level of lock). It can not guess in which transaction context it could be involved into.
repositories are "business-less" (if you believe so)
say, you have a repository:
class MyRepository
void add(entity) {...}
void findByName(name) {...}
and there is a business logic, say MyService
class MyService() {
#Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.SERIALIZABLE)
void doIt() {
var entity = myRepository.findByName("some-name");
if(record.field.equal("expected")) {
...
myRepository.add(newEntity)
}
}
}
I.e. in this case: MyService decides what it wants to involve repository into.
In this cases with propagation="Required" will make sure that BOTH repository methods -findByName() and add() will be involved in single transaction, and isolation="Serializable" would make sure that nobody can interfere with that. It will keep a lock for that table(s) where get() & add() is involved into.
But some other Service may want to use MyRepository differently, not involving into any transaction at all, say it uses findByName() method, not interested in any restriction to read whatever it can find a this moment.
I would say YES, if you treat your repository as one that returns always valid entity (no dirty reads) etc, (saving users from using it incorrectly). I.e. your repository should take care of isolation problem (concurrency & data consistency), like in example:
we want (repository) to make sure then when we add(newEntity) it would check first that there is entity with such the same name already, if so - insert, all in one locking unit of work. (same what we did on service level above, but not we move this responsibility to the repository)
Say, there could not be 2 tasks with the same name "in-progress" state (business rule)
class TaskRepository
#Transactional(propagation=Propagation.REQUIRED,
isolation=Isolation.SERIALIZABLE)
void add(entity) {
var name = entity.getName()
var found = this.findFirstByName(name);
if(found == null || found.getStatus().equal("in-progress"))
{
.. do insert
}
}
#Transactional
void findFirstByName(name) {...}
2nd is more like DDD style repository.
I guess there is more to cover if:
class Service {
#Transactional(isolation=.., propagation=...) // where .. are different from what is defined in taskRepository()
void doStuff() {
taskRepository.add(task);
}
}
You should use #Repository annotation
This is because #Repository is used for translating your unchecked SQL exception to Spring Excpetion and the only exception you should deal is DataAccessException
We also use #Transactional annotation to lock the record so that another thread/request would not change the read.
We use #Transactional annotation when we create/update one more entity at the same time. If the method which has #Transactional throws an exception, the annotation helps to roll back the previous inserts.