JpaRepository#getReferenceById calls Database inside @Transactional

I’ve encountered a weird issue when I tried to use JpaRepository#getReferenceById inside an opened Transaction. The starting situation is as follows:

The postId is known, but the related entity is not in the PersistenceContext

I now want to get hold to a proxy Post object without extra calling the database, so that I can set the foreign key for a PostComment using JPA and not having to rely on native SQL. For this, I call postRepository.getReferenceById(1L);.

And here’s the weird thing: As long as I request a reference object outside a running transaction everthing works as expected. But when I request it inside a running transaction, Hibernate creates a SELECT statement, although there is no need for this.

So this’ first endpoint /proxy1 works just fine, while the second one /proxy2 sends a SELECT statement to the database due to its Transactional annotation:

@Controller
@RequestMapping("/posts")
public class PostController {

    @GetMapping("/proxy1")
    public String proxyTest1() {

        Post post = postRepository.getReferenceById(1L); /* no database call */

        return "redirect:/";
    }

    @Transactional /* the culprit ;) */
    @GetMapping("/proxy2")
    public String proxyTest2() {

        Post post = postRepository.getReferenceById(1L); /* database call initiated */

        return "redirect:/";
    }
}

My question is:
Is this intentional and if, can I tell Hibernate to not initialize the proxy by default within a running transaction?

Depends what you are doing with this proxy. If you are initializing it, then Hibernate ORM will have to issue a query to load it. You can set a break point in org.hibernate.resource.jdbc.internal.EmptyStatementInspector#inspect and see where the call originates from.

1 Like

Hi beikov,

as the examples above show, I’m doing nothing with them in these examples. I’m just requesting a proxy and that’s all. In other examples I use it to set the foreign key, and when I later on save the entity there is also no additional call to the database made. According to my understanding, that’s the whole point of requesting a proxy, so that you don’t have to make extra database calls to only set a foreign key which id you already know.

Or am I wrong here at some point?

Edit:

Well , setting the breakpoint in IntelliJ (you might already guess^^) gave this message:

Skipped breakpoint at org.hibernate.resource.jdbc.internal.EmptyStatementInspector:22 because it happened inside debugger evaluation

So further investigation resulted in the insight, that IntelliJ, while running in debugging mode with breakpoint set inside the same stackframe, will try to access the proxy, although the debugging panel is not shown and at least there is no intent from my side to gain information from the proxy at all. So IntelliJ seems to try to read the proxy (what it does not with non-proxy entities when the debugging panel is not visible). Finally, this results in a database call inside an open transaction (and thus a skipped lazy initializing exception when there is no transaction).

Sorry to have bothered you, but thank you for your help - it at least led me to the point now knowing why this call is done. Wish you a nice evening and greets from Carinthia.