I'm using Hibernate 4.2.3 and I have a class similar to the following:
#Entity
#DynamicInsert
#DynamicUpdate
#SelectBeforeUpdate
public class Test {
#Id
private BigInteger theId;
#Lob
#Basic(fetch = FetchType.LAZY)
#JsonIgnore
private Blob data;
#Lob
#Basic(fetch = FetchType.LAZY)
#JsonIgnore
private Blob otherData;
// Getters and setters....
}
The sql that this is generating for an update includes the data column, even though it hasn't changed. (To be precise, what I do is get the object, detach it, read the data and use that to generate otherData, set that and then call saveOrUpdate on the session.)
Can anyone explain why this would happen? Does this functionality work with Blobs? I've searched for documentation but found none.
PS I'm not using #DynamicUpdate for performance reasons. I know that it would be questionable to use it from that standpoint.
The safest and most portable (between different databases and JPA providers) way to achieve real lazy loading of Lobs is to create an artificial lazy one-to-one association between the original entity and a new one to which you move the Lob.
This approach is suitable for other kinds of optimizations as well, for example when I want to enable second-level caching of a complex entity, but a few columns of the entity are updated frequently. Then I extract those columns to a separate non-second-level-cacheable entity.
However, keep in mind general pitfalls specific to one-to-one associations. Basically, either map it with a mandatory (optional = false) one-to-one association with #PrimaryKeyJoinColumn or make sure the foreign key is in the entity (table) which declares the lazy association (in this case the original entity from which the Lob is moved out). Otherwise, the association could be effectively eager, thus defeating the purpose of introducing it.
Related
I have a Hibernate entity that is comprised of many other entities that are used within the application. The other entities that make up this MainEntity are joined by using #ManyToOne and #JoinColumn. This MainEntity class has 5 columns (#Column) and 7 #ManyToOne/#JoinColumn entities that are used.
I seem to be running into performance issues when retrieving all of these MainEntity classes. We want to serialize the MainEntity to JSON as well as the other entities that are associated with it. Note that there aren't that many that we are retrieving - less than 30 total.
Below is an example of what the class looks like along with my findAll() method to retrieve these classes. I know that #ManyToOne is EAGER by default, so I'm wondering if there's a better way to get all of these entities that is easier on the system. Thank you in advance.
#Entity(name = "MainEntity")
#Table(name = "main_entity")
public class MainEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
// Other #Columns defined here
#ManyToOne()
#JoinColumn(name = "entity_1_id")
private Entity1 entity1;
#ManyToOne()
#JoinColumn(name = "entity_2_id")
private Entity2 entity2;
#ManyToOne()
#JoinColumn(name = "entity_3_id")
private Entity3 entity3;
// ... and so on, for a total of 7 #ManyToOne() columns
}
Here is the findAll() method that I have:
final List<E> findAllOrdered(Class<E> clazz, Order order) {
final Session session = sessionManager.openNewSession();
try {
return session.createCriteria(clazz)
.addOrder(order)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
} finally {
sessionManager.closeSession(session);
}
}
I found myself having to add the Criteria.DISTINCT_ROOT_ENTITY because we were getting duplicate MainEntity results if a child had multiple associated with it. I suspect this is big part of my performance problem.
If you are retrieving unwanted response and if you want to filter then you may use #JsonIgnore
eg:
#ManyToOne()
#JoinColumn(name = "entity_1_id")
#JsonIgnore
private Entity1 entity1;
Few pointers to consider:
Consider making associations Lazy by default unless you really want to load all the association data and its associations along the parent.
Use JOIN in HQL/criteria based on which association we really want to fetch and the depth of associations.
Or use EntityGraph to decide which associations to be fetch.
Enable show_sql as this show the number of SQLs and the exact SQLs that are getting fired to the DB. This would be a good starting point and subsequently you can tune you associations to LAZY/EAGER, SELECT/JOIN/SUBSELECT based on your use case.
You can run these queries against the DB and see if tuning the query/DB (indexes, partitioning etc) will help reduce the query times.
See if second level cache would help for your use case. Note that second level cache will come with its own complexity and extra overhead and especially if the data is of transactional type and not read-only mostly. With application deployed on nodes maintaining the cache coherence will be another aspect to think about. Need to validate if the extra overhead and complexity is really worth the efficiency outcome of the second level cache.
From an application design perspective, you can also consider and see if you really want to retrieve the MainEntity and the associations in a single request or UI. Instead we could first show the MainEntity with some paging and based on the selection we could fetch the associations for that MainEntity with paging.
Note that, this is not a complete list. But a good starting point and based on your use case you can see which one would fit for you and any other additional techniques.
I have a class Entry which has two fields serving auditing purposes: startAuditAction and endAuditAction. One audit action can affect several entries, therefore the class Entry describes ManyToOne relationships as follows:
public class Entry{
#Id
#Column(nullable = false)
protected String path;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "start_action_id")
protected AuditAction startAction;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(updatable = true, nullable = true, name = "end_action_id")
protected AuditAction endAction;
}
I want to retrieve instances of Entry based on conditions on the path field and the audit fields. For example to retrieve entries which have not yet been deleted, the HQL would look something like that:
SELECT DISTINCT entry FROM ENTRY_TABLE entry JOIN FETCH entry.startAction startAct LEFT JOIN FETCH entry.endAction endAct WHERE entry.path LIKE myPath and endAct IS NULL
I am using lazy loading together with JOIN FETCH to avoid the N+1 problem while still being able to access the audit fields. However, I have two problems with this:
Firstly, this really does not seem clean to me: if I know I want to access the audit fields (namely the audit actions timestamp), then they should not be lazy loaded. But if I use eager loading I am facing the n+1 problem even if I use JOIN FETCH (and in that case I do not understand why fetch = FetchType.EAGER would ever be useful)...
Secondly, even though I am avoiding the n+1 problem and therefore firing less SQL queries, I get some performance issues for the overall use of my database, probably because of the joins.
What is the proper way to avoid firing additional queries while preserving a good throughput ?
Thanks!
1- Using join fetch is useful when you have FetchType.LAZY in a field that you know you'll need in that specific case whereas using FetchType.EAGER will force that entity to always load the collection independently from the query
(e.g. with your same configuration example you can do multiple query and only when you need the collection use the JOIN FETCH)
2- You probably have problems somewhere else, i doubt the join is what is slowing you down
I have a set of entities that that build some sort of graph. This is modelled by a class Entity with two fields modelling the relationships between entities.
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "fromId")
private Set<EntityRelation> outEdges;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "toId")
private Set<EntityRelation> inEdges;
All outEdges are supposed to belong to the entity when it is saved, the inEdges are "inferred" from these. Problem is then after removing an out-edge I always get an error ERROR: null value in column "fromid" violates not-null constraint where fromid is a field of EntityRelation.
For performance reasons, I don't want to have direct relations form Entity to Entity.
To fix this, I used a new Spring-Data JPA method (in the corresponding Repository class) to explicitly remove everything an entity points to (like
#Modifying
#Query(value = "delete from entityrelation where fromid = ?1", nativeQuery = true)
int deleteEntityRelations(String entityId);
But this somehow misses the whole point, since I want JPA to take responsibility of that.
what is wrong here? I really got stuck, since all posts I could find suggest that it should simply work with orphan-delete.
In the SQL-Trace you can see that an org.hibernate.SQL - update EntityRelation set fromId=null where fromId=? and id=? is issued automatically (which then triggers the error).
thanks and regards
fricke
This is a known issue of hibernate. In certain scenarios (and you found one of them) it violates constraints on foreign key relations. There are various options (but I'm afraid you might not like any of them)
remove the constraint. I know, I know ..
make the constraint deferred. Not sure if this feature is available in other databases but Oracle.
limit the expectations to JPA. Seriously, it looks like you expecting more from it then it will give you. I highly recommend reading this article before proceeding with any project using any kind of ORM.
Please note that even though setting hbm2ddl.auto to UPDATE, it doesn't remove the not-null type constrains when the nullable in entity is set to FALSE. I would suggest that check the history of the class for any changes to entity relationship or column mapping for nullable constraint.
If anybody is looking for the solution, updatable=false in the JoinCoulum annotation fixed this problem for me
#JoinColumn(name = "fromId", updatable = false)
Preliminary Info
I'm currently trying to integrate Hibernate with my team at work. We primarily do Java web development, creating webapps that provide data to clients. Our old approach involves calling stored procedures with JDBC (on top of Oracle boxes) and storing their results in beans. However, I've heard a lot about the benefits of integrating Hibernate into a development environment like ours so I'm attempting to move away from our old habits. Note: I'm using the Hibernate JPA annotation approach due to simplicity for team adoption's sake.
Specific Problem
The specific issue I'm having currently is using Hibernate with normalized tables. We have a lot of schemas structured like so:
StateCodes (integer state_code, varchar state_name)
Businesses (integer business_id, varchar business_name, integer state_code)
I want to be able to have a single #Entity that has all of the "Businesses" fields, except instead of "state_code" it has "state_name". To my understanding, Hibernate treats #Entity classes as tables. The #OneToMany, #OneToOne, #ManyToOne annotations create relationships between entities, but this is a very simplistic, dictionary-like lookup and I feel like it doesn't apply here (or might be overkill).
One approach I've seen is
#Formula("(select state_name from StateCodes where Businesses.state_code = state_code)")
private String stateCode;
But, given Hibernate's perk of "avoiding writing raw SQL", this seems like bad practice. Not to mention, I'm extremely confused about how Hibernate will then treat this field. Does it get saved on a save operation? It's just defined as a query, not a column, after all.
So what is the best way to accomplish this?
I do not see any reason not use the standard JPA mappings in this case. Short of creating a database view and mapping an entity to that (or using the non-JPA compliant #Formula) then you will have to map as below.
Unless you are providing a means for the State to be changed then you do not need to expose the State entity to the outside world: JPA providers do not need getters/setters to be present.. Neither do you need to Map a State to Businesses:
#Entity
#Table(name = "Businesses")
public class Business{
//define id and other fields
#ManyToOne
#JoinColumn(name = "state_code")
private State state;
public String getStateName(){
return state.getName();
}
}
#Entity
#Table(name="StateCodes")
public class State{
//define id and other fields.
#Column(name = "state_name")
private String stateName;
public String getStateName(){
return stateName;
}
}
I have a #ManyToMany relationship between two entities. When I perform an update on the owning side, it appears that JPA deletes all the linked records from my database and re-inserts them. For me this is a problem because I have a MySQL trigger that fires before a record is deleted. Any ideas on how to get around this problem?
#Entity
public class User {
#Id
#Column(name="username")
private String username;
...
#ManyToMany
#JoinTable(name="groups", joinColumns=
#JoinColumn(name="username", referencedColumnName="username"),
inverseJoinColumns=#JoinColumn(name="groupname",
referencedColumnName="type_id"))
private List<UserType> types;
...
}
#Entity
public class UserType {
#Id
#Column(name="type_id")
private String id;
#ManyToMany(mappedBy="types")
private List<User> users;
...
}
Use Set instead of List solved the problem. But I have no idea why it works.
Another solution provided by Hibernate is to split the #ManyToMany association into two bidirectional #OneTo#Many relationships. See Hibernate 5.2 documentation for example.
If a bidirectional #OneToMany association performs better when
removing or changing the order of child elements, the #ManyToMany
relationship cannot benefit from such an optimization because the
foreign key side is not in control. To overcome this limitation, the
link table must be directly exposed and the #ManyToMany association
split into two bidirectional #OneToMany relationships.
Try this one:
1) change declaration to:
private List<UserType> types = new Vector<UserType>();
2) never call
user.setTypes(newTypesList)
3) only call
user.getTypes().add(...);
user.getTypes().remove(...);
Its probably related to this question. You have to ensure you have an appropriately defined hashCode an equals method in your mapped object so that Eclipselink can determine equality and thus determine that the existing objects map to existing objects in the DB. Otherwise it has no choice but to recreate the child objects every time.
Alternatively, I've read that this kind of join can only support efficient adding and removing of list items if you use an index column, but that's going to be EclipseLink specific, since the JPA annotations don't seem to support such a thing. I know there is an equivalent Hibernate annotation, but I don't know what it would be in Eclipselink, if such a thing exists.
It appears my problem was that I was not merging the entity.