Reputation: 10071
I have a class called NodeType
backed using JPA by a SQL Server database.
Nothing special there, no relations, just some fields. There are even more of them, but for simplification I've omit them:
@Entity
@Table(name="node_type")
@NamedQuery(name="NodeType.findAll", query="SELECT n FROM NodeType n")
public class NodeType implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String name;
public NodeType() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
When starting up my application, I read them and put them all into a HashMap
, taking the property name
as key to find it easier later.
In the database, there are currently five items.
id name maxNoExits mandatoryExits defaultExits
== ========= ========== ============== ============
1 NTYPE_HUP 0 NodeHangup
2 NTYPE_ANN 1 NodeAnnounce
3 NTYPE_SLP 1 NodeWait
4 NTYPE_XFR 0 NodeTransfer
5 NTYPE_TBR 32 NodeTimebased
Somewhen later, and I don't know where exactly this happens, multiple instances for each item suddenly exist (3 instances per item currently)
Example: In the application, I have an instance of NodeType with the values
1 NTYPE_HUP 0 NodeHangup
The eclipse debugger tells me that:
map.get
returns null
for this instanceNodeType
id
for the strings seem to be the same ones. Shouldn't getHash()
return the same and equals()
should return true
then?The last point shocks me as I'm not instanciating them anywhere in my application! Does anybody know when this happens?
If JPA uses a cache (does it?), it should look previously created items up using the @Id
column. Even though I'm doing more than one createQuery
, they should all refer to the same items. Or am I wrong?
It's all quite strange for me and I don't know how to debug it.
I hope someone can bring some light in the dark.
Edit: All I can tell is that these 15 instances exist as soon as I use the corresponding JPA request for the first time. Placing a debugger trap in the constructor, I can confirm that all instances are created right one after the other.
Edit2: For the fun and the sake of testing, I just tried to work it around reimplementing hashCode()
(simply return this.id;
) and overriding equals()
(return this.id == other.id;
)
The 15 instances are still there. As I'm only reading, I currently don't care about it as I can now consider all the three instances as an equal item. But it's not the solution to the base problem. I suspect this might happen elsewhere, too - without having tested.
Upvotes: 4
Views: 96
Reputation: 1666
If I understand well, you have 5 tuples in the database, 5 different instances in the map (given that the names are uniques ?) and 15 different instances loaded by JPA, which are equals by groups of 3...
I guess this is a problem of Cache Level.
It is possible that EclipseLink creates different equal instances for a same tuple while reading if the loaded instances are stored in the Persistence Context Cache - Level 2 (i.e. the EntityManager) - and not the Persistence Unit Cache - Level 1 (i.e. the EntityManagerFactory) . You probably use a different EntityManager for each read operation. In such a case, EclipseLink can not find the previously cached entity.
This depends on your application configuration. The problem could also be caused by a memory lack and a weak reference cache. Further explanation is available in the EclipseLink cache documentations page.
Upvotes: 1