Hibernate caches the query while data is being changed - java

I'm developing an application which connects to an outside service to fetch new SMS. Theses messages are stored in a local database by Hibernate. My client can search these messages based on numerous parameters such as time, number, and etc.
After calling the search method with a list of parameters called 'List1', I get the desired result without any problems. Though while I'm waiting for this result a new message has arrived.
Soon after, I call the search method with same parameter list again and I'm expecting to get the new message as well, but I get the previous result.
I have checked my database and the new message is present so all I can think of is Hibernate caching. Since both queries are exactly the same, I guess hibernate return the same result set as before.
In case my assumption is correct, how can I overcome this problem? If not, so what exactly is going on?
Edit
here is relevant part of my source code. Following two methods will be invoked when client initiates a search request:
smsService.refresh();
JSONArray result = smsService.retrieveMessages(...);
#Transactional
public JSONArray retrieveMessages(Long periodBegining, Long periodEnd, String order, Integer limit, String profile, Boolean unread, String correspondent) {
List<ShortMessage> messageList = shortMessageDAO.find(beginDate, endDate, order, limit, profile, unread, correspondent);
JSONArray result = new JSONArray();
for (ShortMessage message : messageList)
result.put(message.toJSON());
shortMessageDAO.markRead(messageList);
return result;
}
#Transactional
public void refresh() {
webService.authentication(serviceUsername, servicePassword);
while(webService.hasUnread() > 0) {
SMS sms = webService.retrieveMessage();
ShortMessage message = new ShortMessage(sms.getHash(), sms.getFrom(), sms.getTo(), "DEFAULT", sms.getMessage(), new Date(sms.getTime()), true);
shortMessageDAO.insert(message);
}
}
}
public List<ShortMessage> find(Date beginDate, Date endDate, String order, Integer limit, String profile, Boolean unread, String correspondent) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ShortMessage.class);
criteria.add(Restrictions.ge("time", beginDate));
criteria.add(Restrictions.le("time", endDate));
criteria.add(Restrictions.eq("profile", profile));
if (unread)
criteria.add(Restrictions.eq("unread", true));
if (correspondent != null)
criteria.add(Restrictions.eq("origin", correspondent));
criteria.addOrder(order.equals("ASC") ? Order.asc("time") : Order.desc("time"));
criteria.setMaxResults(limit);
criteria.setCacheMode(CacheMode.IGNORE);
return (ArrayList<ShortMessage>) criteria.list();
}

Yes it looks like hibernate is caching your query and returning cached results.
Please give us a overview of your code to suggest better.
Below listed are two ways of controlling the caching behaviour of queries:-
1) At the main named query level:-
#NamedQuery(
name = "myNamedQuery"
query = "SELECT u FROM USER WHERE u.items is EMPTY"
hints = {#QueryHint(name = "org.hibernate.cacheMode", value = "IGNORE")}
)
2) At individual query level :-
Query q = session.createQuery("from User")
.setCacheMode(CacheMode.IGNORE);

After running numerous test, I found out that this problem is not cache related at all. Upon receiving each message I would have stored the time of arrival based on data provided by SMS panel and not my own machine time.
There was a slight time difference (20 seconds to be exact) between those 2 which was the reason behind the query not returning the new received message.

Related

Why would my DAO return null when the Database Inspector shows a record?

As you see from the image below, I am sending workoutExercise=20 to my Repository's updateWorkoutExercise function.
//Repository:
public Completable updateWorkoutExercise(Long workoutExercise, String exerciseName) {
WorkoutExercise we = workoutExerciseDAO.getWorkoutExercise(workoutExercise);
Exercise e = exerciseDAO.getExerciseByName(exerciseName);
we.exercise = e.id;
return workoutExerciseDAO.update(we);
}
I would expect to see the same result that my Database Inspector gives if I'm using the same SQL string.
//workoutExerciseDAO:
#Query("SELECT * FROM workoutExercises WHERE id = :workoutExercise LIMIT 1")
WorkoutExercise getWorkoutExercise(Long workoutExercise);
But my DAO returns a null. Why would that be?
Thank you in advance.
In case you got the above error, it turns out I had two databases. Database names, it appears, are case specific, and some of my code was accessing the old database.

CollectionGroup query in firestore android studio

I am not able enter into for loop. it is not showing any error. when I try to debug it is not entering for loop. after entering into for loop only it can retrieve result. can any one help?
Query query =fstore.collectionGroup("ride").whereEqualTo("from",from1).whereEqualTo("to",to1).whereEqualTo("date",date);
query.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot snapshots) {
for (QueryDocumentSnapshot queryDocumentSnapshot:snapshots)
{
String source = queryDocumentSnapshot.getString("from");
String destination = ueryDocumentSnapshot.getString("to");
String date1 = queryDocumentSnapshot.getString("date");
String time = queryDocumentSnapshot.getString("time");
String vehicle = queryDocumentSnapshot.getString("vehicle number");
String cost = queryDocumentSnapshot.getString("Cost per person");
String seats = queryDocumentSnapshot.getString("number of seats");
String model = queryDocumentSnapshot.getString("car model");
data += source+" "+destination+" "+date1+" "+time+" "+vehicle+" "+cost+" "+seats+" "+model+"\n";
}
});
enter image description here
In the reference you may find following sentence:
Before using a collection group query, you must create an index that supports your collection group query. You can create an index through an error message, the console, or the Firebase CLI.
From the same reference example it seems that code is done properly. Of course we do not know what do you have in from1, to1 and date variables. From the screenshot it seems that date has strange format in your database. As well I am not sure how it will work with multiple whereEqualTo methods.
So many think could go wrong here, but if I were in your shoes I would start with checking the indexes, and than start from building query with single whereEqualTo trying to get anything from database, exactly like in the reference example.
If you succeed than you can extend it to more sophisticated solutions.
I hope it will help!

How to handle when call requests at same time

I am using Spring boot create a restful for save data to Database.
Now I have problem when you call this service in the same time my data its duplicated in database because previous request not finish yet.
I generate number like 00001 I need to running its from database
I get last from DB
then 00001+1 = 00002
save to Database
but when request same time in database save 00002 for 2 records.
#Transactional
public List<Object> saveData(String data) {
//validate data
//Get Last Data
//set prepare data
//save data
int idLatest = Integer.parseInt(getLatest("7", "8"));
List<Object> objects = autoGenarateEntity(idLatest);
Repository.save(Object);
}
public String getLatest(String idFirst, String idSecond){
Optional<Object> running = Repository.findByBIdStartingWithOrderByBIdDesc(idFirst, idSecond).stream().findFirst();
if(running.isPresent()){
String bId =running.get();
return bId.getBId();
}else {
return "70000000";
}
}
public List<Object> autoGenarateEntity(int idLatest){
List<Object> objects = new ArrayList<>();
IntStream.range(1, 5 + 1).forEach(i -> {
Object obj = new Object();
obj.setBId(Integer.toString(idLatest + i));
obj.add(Object);
});
return objects;
}
Following are the options that can be done in this case:
1.) have unique key constraint for the column having the value of 00001. So that, the second transaction which was trying to commit same value would roll-back.
And you could use Spring-Retry mechanism to execute the second transaction with updated value
2.) Use a custom sequence Generator to increment the value, instead of handling it yourself.
I have a solution for this
#Transactional(isolation = Isolation.SERIALIZABLE)
and use spring retry

Order a ParseQuery by the date at which only one field has been updated

I have a feed containing posts that are currently ordered by "updatedAt". My original intention was to push up posts to the top of the feed which were last replied to (I do this by incrementing a "replyCount" field in each post when a user leaves a comment), not totally cognizant of the fact that another field, "likeCount" is also being updated when user's "like" a post. I would still like to push those posts that were recently "replied to" to the top of the feed, but do not at the expense of the weird UX behavior that associated with liking posts pushing them up as well. I'm not sure how to separate the two.
What should I do here? Can I maybe add another column called "lastReplyCountTime" and then sort queries based on that? Maybe set lastReplyCountTime for all posts to the current time when saved to the database, and then only update that value when a post receives a reply?
String groupId = ParseUser.getCurrentUser().getString("groupId");
ParseQuery<ParseObject> query = new ParseQuery<>(ParseConstants.CLASS_POST);
query.whereContains(ParseConstants.KEY_GROUP_ID, groupId);
/*query.addDescendingOrder(ParseConstants.KEY_CREATED_AT);*/
query.orderByDescending("updatedAt");
query.findInBackground((posts, e) -> {
if (mSwipeRefreshLayout.isRefreshing()) {
mSwipeRefreshLayout.setRefreshing(false);
}
if (e == null) {
// We found messages!
mPosts = posts;
String[] usernames;
usernames = new String[mPosts.size()];
int i = 0;
for(ParseObject post : mPosts) {
usernames[i] = yeet.getString(ParseConstants.KEY_SENDER_NAME);
i++;
}
FeedAdapter adapter = new FeedAdapter(
getListView().getContext(),
mYeets);
setListAdapter(adapter);
}
});
}
You have 2 options:
Like you suggested you can create another date property let's call it sortedUpdatedAt and update it with the current date each time you are updating the relevant values
If you still want to use updatedAt you can wrap your like object in a separate parse object (class). This class will be saved as a relation in the parent class and then each time the user "like" you can just update only this class and not the whole object. This way the updatedAt of your parent object will not be changed.
I think that option 1 is great since it's not so complicated and you can do it very quick.

fetching salesforce object's record count using java

I have a Java code using partner API for connecting to Salesforce.
I am trying to get the number of records/rows for my salesforce object. All my tries were unsuccessful.
I went through a sample code that uses AggregateResult class for this purpose.When I try to implement it, the program throws error(Cannot cast from SObject to AggregateResult).
How can I do it.
The following may work for you. In my system I have an object Device that is a child of Account. There is also an object Alert that is a child of Device. I used an aggregate query to get the account ids for Alert records that meet a certain condtion.
StringBuilder openAlertQuery = new StringBuilder();
openAlertQuery.append("SELECT Device__r.Account__c");
openAlertQuery.append(" FROM Alert__c WHERE Cleared__c = FALSE GROUP BY Device__r.Account__c");
List<SObject> alertRecords = sfdcServer.doQuery(openAlertQuery.toString());
List<String> accountIds = new ArrayList<String>();
for (SObject alert : alertRecords)
{
String accountId = (String) alert.getChild("Account__c").getValue();
accountIds.add(accountId);
}
Notice the SObject method is getChild(name) rather than the usual getField(name). getChild(name) returns an com.sforce.ws.bind.XmlObject which has the getValue() method.

Categories