@OneToOne relationship querying DB instead of pulling from L2 Cache

We are in the midst of a migration from spring 5 → 6 and hibernate upgrade as part of it. All is going well except an issue with our Hibernate L2 Cache. We are using Redisson and spring boot 3.4 with corresponding hibernate 6.

We have two objects lets call them
A
AConfig

In A we have class annotated with

@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "A_1725466322")

with object inside

  @OneToOne(fetch = FetchType.EAGER, mappedBy = "a")
  @Fetch(FetchMode.SELECT)
  @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE })
  public AConfig getAConfig() {
    return a;
  }

And AConfig is class annotated

@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region = "AConfig_1741191503")

with inner object

  @OneToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "a_id")
  @Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
  public A getA() {
    return a;
  }

In Hibernate 5, this all worked and we wouldn’t see subsequent requests to the database for AConfig.
In Hibernate 6.6, everytime we pull the A from Hibernate we see a query to the DB for AConfig.

Can someone explain to me why?

If i change the object to a Set and create a single transient getAConfig on A and change from OneToOne to OneToMany/ManyToOne it caches properly…but thats not ideal.

Is a_id within AConfig also the primary key of AConfig? If it isn’t, then loading the aConfig association for A will do a lookup by unique key, which can’t go to the cache.
I don’t know what Hibernate ORM 5 did in this case, but AFAICT, what ORM 6.6 does is correct, given that the a association in AConfig is not marked as @Id.

First i’d like to say thanks for your response. What you are stating is what I’m seeing while debugging.

You are correct. a_id is not the primary key. And i debugged the code and found what you state that it runs loadByUniqueKey.

I found two work arounds…hoping maybe you could let me know your thoughts:

  1. Turn AConfig into a collection with a OneToMany/ManyToOne and build wrappers for the fact that its really a single instance and cache
  2. If i add remove the mappedBy=“a”
    @OneToOne(fetch = FetchType.EAGER, mappedBy = "a")
    and add a
    @JoinColumn("a_config_id")

onto A both ways this also works but this one leaves me a little more scared.

Do you have any other ways that i could get this @OneToOne to cache by using a @NaturalId or some other manner?

Having look at the code and found this

		//TODO: implement 2nd level caching?! natural id caching ?! proxies?!

I dont think NaturalId will work

Since there is no point in having a different primary key for the one-to-one association, I’d suggest you mark the a association in AConfig as @Id.