@IndexColumn seems to add an extra column to the schema - any way I can do without that?
RE: @Cache on the collection - I do want to cache the collection (create a Collection cache node); I just don't want to insert all collection members in Entity cache:
Imagine that a given User has 3000 Friends. User.friends Collection cache entry will essentially be a single node containing an array with 3000 Friends.IDs. I do want to cache that information. What I don't want is to eagerly insert 3000 Friend nodes into Entity cache.
Perhaps I should back up and be more specific:
- we have User entity and Friends entity. Friends is essentially a join table between two Users.
- we'd like to optimize returning Collection<User> that includes only those of user's friends who are currently online (which is often < 10% of all friends) and avoid storing in cache Friends entities pointing to offline users (i.e. the 90% case)
- we always have an in-memory Collection of userIDs of users currently online.
So, let's say Bob is our user with 3000 friends, of whom only 10 are online. Bob logs in and now has to get some info on online friends only and a count of all friends (those online and offline). Here's what I'm trying to get to:
Code:
User userBob = session.get(bobId); //caches one User entity
Collection<Friends> allFriends = userBob.getFriends();
//returns a proxy collection; creates a single Collection cache entry with 3000 IDs (need this cached to avoid repeat query)
//count all of bob's friends: issue sql like "select * from friends where firstUserId=bobId" - problem is this results in initialization (and caching) or 3000 Friends entities. need to avoid that
int totalFriends = allFriends.size();
//find out who's online in general
Collection<Long> onlineUserIDs = systemService.getOnlineUserIDs(); //another service that keeps tracks IDs of all users currently online
//now I want to filter allFriends using onlineUserIDs and only load and cache Friends and User entities for Bob's onlineFriends
Set<Friends> onlineFriends = session.createFilter(allFriends, " where this.secondUser.id in: " onlineUserIDs); //last arg is pseudo code
//now retrieve and cache needed info for the 10 online friends only
List<User> onlineFriendUsers = new ArrayList<User>(onlineFriends.size());
for(Friends f : onlineFriends)
{
User onlineUser = f.getSecondUser(); //fetch, cache, and initialize a single Friends entity; return User proxy
String userName = onlineUser.getUserName(); //fetch, cache, and initialize a single User entity
onlineFriendUsers.add(onlineUser);
}
//at the end of all this we should only have:
//11 Users in entity cache (bob + 10 online friends)
//1 user.friends entry in collection cache (with 3000 IDs)
//10 Friend entities in entity cache (one for each online friend of Bob)
return onlineFriendUsers;
The problem right now is that we end up with 3000 Friends entries in entity cache and that the perf suffers because of high memory consumption (under load) and because every time the above method is executed Hibernate hydrates 3000 Friends entities.
Schema:
Code:
Create Table: CREATE TABLE `friends` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`hibernateVersion` int(11) NOT NULL,
`creationDate` datetime DEFAULT NULL,
`firstUserId` bigint(20) NOT NULL,
`secondUserId` bigint(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `firstUserId` (`firstUserId`,`secondUserId`),
KEY `FKDC3B499515152FBC` (`firstUserId`),
KEY `FKDC3B499528AE3E80` (`secondUserId`),
CONSTRAINT `FKDC3B499515152FBC` FOREIGN KEY (`firstUserId`) REFERENCES `users` (`id`),
CONSTRAINT `FKDC3B499528AE3E80` FOREIGN KEY (`secondUserId`) REFERENCES `users` (`id`)
)
Create Table: CREATE TABLE `users` (
`id` bigint(20) NOT NULL,
`hibernateVersion` int(11) NOT NULL,
`userName` varchar(255) NOT NULL
)
//User.friends collection:
@OneToMany(targetEntity = Friends.class, mappedBy = "firstUser")
@Cascade({org.hibernate.annotations.CascadeType.ALL, org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
@LazyCollection(LazyCollectionOption.EXTRA)
@Cache(usage = CacheConcurrencyStrategy.TRANSACTIONAL)
@OptimisticLock(excluded = true)
public List<Friends> getFriends() {
return friends;
}