R
R
rPman2011-08-22 10:56:49
Java
rPman, 2011-08-22 10:56:49

Is it possible to guarantee at least something in the GAE datastore (Java, JDO)?

I am learning/working with Google App Engine for Java.
I chose Java and JDO as a development environment because of the convenient description of the data structure right in the code (more than convenient for projects of medium complexity), but it seems that this creates more problems than conveniences.
In addition to the peculiarities and 'inconveniences' of working with the datastore (it's still a key-value database), I came across the fact that it seems that there are no guarantees that what was recorded a few seconds earlier will be available now, moreover, without any errors, the recording may not work at all. happen.
* The simplest example: the object Test {id, amount}, you need to create 1 instance if it has not been created yet, and increase the amount by 1 each time the servlet is called.
Version sdk 1.5.2, windows 7. The project is created by default in eclipse with google appengine plugin installed + create file Test.java and change TestServlet.java, code here paste.ly/B44n
Here is the output:

# curl localhost :8888/test
Test is empty
OK
# curl localhost :8888/test
Test length:1
Test[1]: 1
OK
# curl localhost :8888/test
Test length:1
Test[1]: 1
OK
# curl localhost :8888/test
Test length:1
Test[1]: 2
OK
# curl localhost :8888/test
Test length:1
Test[1]: 3
OK
# curl localhost :8888/test
Test length:1
Test[1]: 4
OK
# curl localhost :8888/test
Test length:1
Test[1]: 4
OK
And in the server logs:
08/22/2011 02:29:13 PM com.google.appengine.tools.development.DevAppServerImpl start
INFO: The server is running at localhost :8888/
08/22/2011 02:29:17 PM test.TestServlet doGet
WARNING: new amount: 1
08/22 .2011 14:29:18 test.TestServlet doGet
WARNING: add amount: 2
22.08.2011 14:29:20 test.TestServlet doGet
WARNING: add amount: 2
22.08.2011 14:29:22 test.TestServlet doGet
WARNING: add amount: 3
8/22/2011 2:29:23 PM test.TestServlet doGet
WARNING: add amount: 4
8/22/2011 2:29:24 PM test.TestServlet doGet
WARNING: add amount: 5
8/22/2011 2:29:30 PM test.TestServlet doGet
WARNING: add amount: 5

Please note that there was a decent amount of time between calls, seconds ... the computer was not loaded at all, powerful enough (4-core hair dryer with 8GB of RAM), but for some reason, information about the increase in Test.amount was not saved with every call.
In addition, during the tests, I encountered situations when the record created earlier was simply not displayed as a result of the select query, respectively, in this case, several records were created. It is clear that in the correct implementation of this particular task, it would be possible in advance (in the code) to independently determine the unique key of the object, but by itself this is not always possible!
ps almost certainly I made some kind of completely noob mistake in the code, but I can’t figure out what.
pps using the Test class method - public void addAmount() {this.amount++;} did not solve the problem, obviously the reason is somewhere in saving the data in the database, but I don’t understand how to force the changes to be saved, according to the documentation this should happen with pm.close( ) or pm.makePersistent(...)

Answer the question

In order to leave comments, you need to log in

7 answer(s)
V
vtysh, 2011-08-22
@vtysh

Didn't work specifically with JPA, but worked with Hibernate. Try calling flush after makePersistance
db.apache.org/jdo/api20/apidocs/javax/jdo/PersistenceManager.html#flush ()

R
rPman, 2011-08-22
@rPman

pm.flush() in finally didn't change anything.

R
rPman, 2011-08-22
@rPman

to clear my conscience, I checked, of course, nothing has changed, there is d=pm.getObjectById(Test.class, new_id);only for tests and output to the data log further in the code.
Guaranteed in series of 2 requests, the data is stupidly not written anywhere, while within the servlet method the data is successfully written, available on repeated requests via Query, but upon completion of the method and issuing the result to the client, the changes disappear somewhere
ps in the main project it’s still worse ... in one object data is saved, in another, written in the same method - no, the groups of objects are different, I still can’t wrap it in a transaction, I haven’t yet figured out how to beautifully combine loosely related entities into a group, according to the documentation, to do this, you need a connection like 1k1 or 1kM, or something non-trivial with keys

R
rPman, 2011-08-22
@rPman

It got even scarier! I made a mistake above in the comment, I didn’t double-check, if you request object data after data changes via Query execute () and .get (0) then the data is never written AT ALL!
By adding the code after updating the data:

q=pm.newQuery(Test.class);
qdr=(List)q.execute();
q.closeAll();
resp.getWriter().println("Test repeat read: "+d.getAmount()+", queryed:"+qdr.get(0).getAmount());

those. the output is always like this:
# curl 127.0.0.1 :8888/test
Test length:1
Test[1]: 44
Test repeat read: 45, queryed:44
# curl 127.0.0.1 :8888/test
Test length:1
Test[1]: 44
Test repeat read : 45, queryed:44
# curl 127.0.0.1 :8888/test
Test length:1
Test[1]: 44
Test repeat read: 45, queryed:44

R
rPman, 2011-08-22
@rPman

I uploaded the application to appspot.com (High Replication database settings), Test.amount increases successfully, but this pops up:

# curl blablabla.appspot.com/test
Test length:1
Test[1]: 9
Test repeat read: 10, queryed:9
# curl blablabla.appspot.com/test
Test length:1
Test[1]: 10
Test repeat read : 11, queryed:10
# curl blablabla.appspot.com/test
Test length:1
Test[1]: 11
Test repeat read: 12, queryed:12
# curl blablabla.appspot.com/test
Test length:1
Test[1 ]: 12
Test repeat read: 13, queryed:12
# curl blablabla.appspot.com/test
Test length:1
Test[1]: 13
Test repeat read: 14, queryed:13

Those. there is no guarantee that the Query will return the correct data, but somehow the data still changes correctly.
ps I'm already thinking about excluding any Query from the project and working with data exclusively by id (and implement special lists on my own) I still hope that I made a mistake somewhere, because this is unrealistically stupid database behavior

M
Mecid, 2011-08-22
@Mecid

Something I have not encountered such problems as you have, I have been using App Engine for almost 2 years.

V
vtysh, 2011-11-26
@vtysh

The example haunted me for a long time. I don’t know how much more relevant, but it seems that something has been fixed in the latest versions of GAE. Now I can't reproduce the problem even without using transactions.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question