0

Let's say there are two DB tables, say

  1. Table A with primary key as aId, and
  2. Table B with primary key as bId.
@Entity
@Table(name = "A")
public class A implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "A_KEY")
    private String aId;


    @OneToMany(mappedBy=aId)
    List<B> b;
}

@Entity
@Table(name = "B")
public class B implements Serializable{
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "B_KEY")
    private String bId;

    @Column(name = "A_KEY")
    private String aId;

}

When I retrieve A the first time database is called and I have A and associated B. Now I save this instance of A to some file and read it back. When I say (instance of A)#getB I do not want a DB call as I have the data in in memory with me. How to avoid this DB call.

Rax
  • 323
  • 1
  • 5
  • 17
  • By default, the JPA @OneToMany related entities are fetched Lazily, so the (instance of A)#getB will result in a DB call. If you mark the B in A with fetchType Eager, it will load the entire entity in a single DB call. – S B Dec 06 '19 at 05:05
  • @ S B : Thanks for replying. Do you mean when it is marked fetchType Eager and then (instance of A)#getB call (in the scenario explained above) will not trigger a DB call? See my main doubt how to avoid a DB trigger if I already have the data. – Rax Dec 06 '19 at 05:11
  • that is correct. A good discussion is available on [link] https://stackoverflow.com/questions/2990799/difference-between-fetchtype-lazy-and-eager-in-java-persistence-api Basically - eager fetch will load all child entities when parent is fetched while lazy fetch will load the child entities on demand i.e. B will be loaded when (instance of A)#getB is called and not when A is loaded. – S B Dec 06 '19 at 05:16

1 Answers1

0

When you do it in the same transaction , calling a#getB() multiple times will only trigger a DB call to get B for the first time (Since you are using lazy loading on A 's B which is recommended rather than change it to Eager which is a code smell).

The subsequent calls on a#getB() will not trigger any DB calls. You can think that there is an in-memory hash map inside an EntityManager (i.e which is called persistence cache or 1st-level cache etc.). It will first try to check if an entity that you want to load exist in this map before making a DB call. If it exist , return the entity from the map. Otherwise , make a DB call to get it and put the loaded entity in the map. The scope of the 1st-level cache is per transaction which means every transaction will have their own 1st-level cache.

Also , if you save A to a file and read it back. A and its B will not managed by JPA (i.e. in the detached state) , which means it will not trigger any DB calls on a#getB() (Assuming you do not use EntityManager to process A after you read it back from file).

Ken Chan
  • 84,777
  • 26
  • 143
  • 172
  • Thanks @Ken Chan, very well explained. Yes, I do not use `EntityManager` to process A. Once I have A read from file, I do `a#getB()` to get associated B. – Rax Dec 06 '19 at 09:09