This week's book giveaway is in the Go forum.
We're giving away four copies of Head First Go and have Jay McGavren on-line!
See this thread for details.
Win a copy of Head First Go this week in the Go forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
Sheriffs:
  • Devaka Cooray
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Tim Moores
  • Ron McLeod
  • Tim Holloway
  • Claude Moore
  • Stephan van Hulst
Bartenders:
  • Winston Gutkowski
  • Carey Brown
  • Frits Walraven

@Transactional not working in Spring Boot?  RSS feed

 
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey, I am trying to get @Transactional to work with loading a lazy initialized set, however, I am getting an error.

Here is my code:



In @Entity User:

@JsonBackReference
@OneToMany(mappedBy = "from")
private Set<Follower> following;

And the error I am getting:


Thanks in advance!
 
Saloon Keeper
Posts: 20514
115
Android Eclipse IDE Linux
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think that "user" is a detached object. Lazy references cannot be resolved when an object is detached - in fact a dummy object is inserted in place of the lazy object or collection to alert you to that fact.

If that's what happened, you'll need to re-attach "user' by doing a JPA merge() before you can access its lazy collection of Post's. Note that merge does not return the same object back that you pass to it. Once merged, discard the original User object and use the merged User object instead.
 
Marius Richardsen
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:I think that "user" is a detached object. Lazy references cannot be resolved when an object is detached - in fact a dummy object is inserted in place of the lazy object or collection to alert you to that fact.

If that's what happened, you'll need to re-attach "user' by doing a JPA merge() before you can access its lazy collection of Post's. Note that merge does not return the same object back that you pass to it. Once merged, discard the original User object and use the merged User object instead.



Thank you so much for your reply! How do i find out whether it is a dummy object? Calling for example User#getId() returns the id that is also in the database. As you can see, I had commented out “followerService.getFollowing(user)”, which calls “findAllByFrom(User user)” in FollowersRepository extending JpaRepository. And it actually works, but I find it unneccecary to auto-wire the follower service when I can just call User#getFollowing(), but that doesn’t work.

Also, on what and where do I call the #merge()? Could you maybe provide a simple example if it’s not too much to ask for?
 
Tim Holloway
Saloon Keeper
Posts: 20514
115
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm rusty on JPA - people owe me money, so I found other things to do until they start paying me again.

However, I believe that merge() is an EntityManager method.

You'll know when you attempt to reference a detached lazy object. In fact, I think it throws an Exception if you even try.
 
Marius Richardsen
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:I'm rusty on JPA - people owe me money, so I found other things to do until they start paying me again.

However, I believe that merge() is an EntityManager method.

You'll know when you attempt to reference a detached lazy object. In fact, I think it throws an Exception if you even try.



I haven’t touched any EntityManager in my code. I use spring boot, and have managed so far only using JPA sql methods in interfaces that I make extend JpaRepository. Then I create a service class for each repository, and just auto-wire the repo and call the methods in the repo whenever I want to access my database. This seems like the cleanest way to do it, but I have no idea how to access lazy loaded items in my @Entity class.
 
Tim Holloway
Saloon Keeper
Posts: 20514
115
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you use CrudRepository or JPARepository (or a subclass of one of them), then the EntityManager is used internally by their implementations. In my case, I use DAOs as repositories, so I inject an EntityManager via @PersistenceContext.

This might help: https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
 
Marius Richardsen
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you! I will look into that. Any reason you use DAO over JpaRepository?
 
Marius Richardsen
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:If you use CrudRepository or JPARepository (or a subclass of one of them), then the EntityManager is used internally by their implementations. In my case, I use DAOs as repositories, so I inject an EntityManager via @PersistenceContext.

This might help: https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa



I saw multiple people online suggesting User#getFollowing().size(). However, for me, this just throws the same error? I also saw people suggest Hibernate.initialize(User#getFollowing()), however, they also said this would mean that you make your application rely on Hibernate, when you can only take the jpa-specific approach using #size().

I looked into the link you sent, and I think it can quickly get cumbersome. Are there any drawbacks of just using "followerService.getFollowing(user)"? Is it correct practise, or am I then violating some "law"? I guess accessing followers through the followerService is also better for me in the long run, as you might follow A LOT of people, in which case I might want to resort to paging through JpaRepository.
 
Tim Holloway
Saloon Keeper
Posts: 20514
115
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Your setup is very different than mine, and I'm not sure I really understand it.

I think you were asking if it was "wrong" to access an associated object when it was lazy-fetched and detached. It's not wrong, as such, but since the lazy object wasn't fetched before detachment, it will throw an exception. If you need to resolve an associated lazy object before detaching, there's no formal method, but simply referencing that object will fetch it and replace the dummy with the actual object. In other words, to force resolution of a Department record for an Employee, just do something throw-away like "thisEmployee.getDepartment().getId()". For collections (OneToMany, ManyToMany), iterate the collection. For best results, resolve both the forward and backward links, if they exist.


Let me describe how I do things. It's fairly simple and it has worked well for me.

I have basically 3 tiers for persistence in my JPA apps.

1. The bottom tier is the Entity classes themselves.

2. The next-level tier is DAOs. My DAOs are finders and CRUD methods for single-table operations. Or in some cases, where parent/child relationships are tightly bound, parent and child entity DAOs.

3. The top level is persistence services.

Most of my apps don't work on a single table at a time, they work on a network of related table objects. So the persistence services are responsible for making the necessary collection of data available to the non-persistence layer (business logic), and for persisting changes made to that collection of data ("working set"). Both the service tier and the DAO tier are transactional at the class level, although DAOs inherit the transaction context of the service method that calls them. To make things more predictable, DAOs are never called directly by business logic, only by persistence methods.

The service methods work with attached objects, so if I need to expand a working set (which is always detached), I'll pass that set to a service method that re-attaches, resolves whatever lazy dependencies I need resolved, and then returns a new detached instance of the working set with the new relationships in it. The service methods use the DAOs for the low-level work, so all DAOs have an EntityManager injected into them (I haven't been using the Spring CRUD repo). The service methods never use an EntityManager directly.
 
Marius Richardsen
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:Your setup is very different than mine, and I'm not sure I really understand it.

I think you were asking if it was "wrong" to access an associated object when it was lazy-fetched and detached. It's not wrong, as such, but since the lazy object wasn't fetched before detachment, it will throw an exception. If you need to resolve an associated lazy object before detaching, there's no formal method, but simply referencing that object will fetch it and replace the dummy with the actual object. In other words, to force resolution of a Department record for an Employee, just do something throw-away like "thisEmployee.getDepartment().getId()". For collections (OneToMany, ManyToMany), iterate the collection. For best results, resolve both the forward and backward links, if they exist.


Let me describe how I do things. It's fairly simple and it has worked well for me.

I have basically 3 tiers for persistence in my JPA apps.

1. The bottom tier is the Entity classes themselves.

2. The next-level tier is DAOs. My DAOs are finders and CRUD methods for single-table operations. Or in some cases, where parent/child relationships are tightly bound, parent and child entity DAOs.

3. The top level is persistence services.

Most of my apps don't work on a single table at a time, they work on a network of related table objects. So the persistence services are responsible for making the necessary collection of data available to the non-persistence layer (business logic), and for persisting changes made to that collection of data ("working set"). Both the service tier and the DAO tier are transactional at the class level, although DAOs inherit the transaction context of the service method that calls them. To make things more predictable, DAOs are never called directly by business logic, only by persistence methods.

The service methods work with attached objects, so if I need to expand a working set (which is always detached), I'll pass that set to a service method that re-attaches, resolves whatever lazy dependencies I need resolved, and then returns a new detached instance of the working set with the new relationships in it. The service methods use the DAOs for the low-level work, so all DAOs have an EntityManager injected into them (I haven't been using the Spring CRUD repo). The service methods never use an EntityManager directly.



Thank you again for such a response. This is how I have my persistence setup:

1 - first I have my User model/entity, obviously. Which represents the model/entity in the database and defines the columns.



2 - the base layer is just a JpaRepository, same as CrudRepository but supports paging and some other stuff. Using this, I don’t have to write any manual SQL, Spring Data JPA will generate all that for me, which I want.



3 - then I have my service class, which wires in the repository



Now, whenever I want to find a User by their username, I just auto-wire that service class into the class I want to find the user in, and just call UserService.getUser(“their_username”).

This works perfectly. However, with lazily initialized collections in User, I can’t access them, even if I’m using @Transactional in the UserService class, and that’s my problem.

I wrote all of this on my phone, so I apologize for any spelling errors. Thank you again!
 
Tim Holloway
Saloon Keeper
Posts: 20514
115
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Auto-wiring is used at construction time and it generally does not work well when trying to connect dynamic objects, such as data pulled from a database. At least I think that's what you are getting at.
 
Marius Richardsen
Greenhorn
Posts: 19
Java jQuery PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Tim Holloway wrote:Auto-wiring is used at construction time and it generally does not work well when trying to connect dynamic objects, such as data pulled from a database. At least I think that's what you are getting at.



I have followed the official Spring Boot tutorials when writing this. And it's not uncommon to set it up like I have, apparently.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!