Google App Engine: Different behavior locally vs deployed, error: can't operate on multiple entity groups in a single transaction.

111 views
Skip to first unread message

Jared Alexander

unread,
Aug 22, 2011, 12:08:04 AM8/22/11
to google-a...@googlegroups.com
I have a Java Google App Engine web application that allows user upload of images. Locally, it works great.  However, once I deploy it to "the cloud", and I upload an image, I get the following error:

java.lang.IllegalArgumentException: can't operate on multiple entity groups in a single transaction.

I use the blobstore to store the images (BlobStore reference: http://code.google.com/appengine/docs/java/blobstore/overview.html#Writing_Files_to_the_Blobstore).  My method is below:

    @RequestMapping(value = "/ajax/uploadWelcomeImage", method = RequestMethod.POST)
@ResponseBody
public String uploadWelcomeImage(@RequestParam("id") long id,
HttpServletRequest request) throws IOException, ServletException {
byte[] bytes = IOUtils.toByteArray(request.getInputStream());
Key parentKey = KeyFactory.createKey(ParentClass.class.getSimpleName(),
id);
String blobKey = imageService.saveImageToBlobStore(bytes);
imageService.save(blobKey, parentKey);
return "{success:true, id:\"" + blobKey + "\"}";
}

You'll notice that this method first calls "imageService.saveImageToBlobStore".  This is what actually saves the bytes of the image.  The method "imageService.save" takes the generated blobKey and wraps it in an ImageFile object, which is an object that contains a String blobKey.  My website references imageFile.blobKey to get the correct image to display.  The "saveImageToBlobStore" looks like this:

    @Transactional
public String saveImageToBlobStore(byte[] bytes) {
// Get a file service
FileService fileService = FileServiceFactory.getFileService();
// Create a new Blob file with mime-type "text/plain"
AppEngineFile file = null;
try {
file = fileService.createNewBlobFile("image/jpeg");
} catch (IOException e) {
e.printStackTrace();
}
// Open a channel to write to it
boolean lock = true;
FileWriteChannel writeChannel = null;
try {
writeChannel = fileService.openWriteChannel(file, lock);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (FinalizationException e) {
e.printStackTrace();
} catch (LockException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// This time we write to the channel using standard Java
try {
writeChannel.write(ByteBuffer.wrap(bytes));
} catch (IOException e) {
e.printStackTrace();
}
// Now finalize
try {
writeChannel.closeFinally();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Now read from the file using the Blobstore API
BlobKey blobKey = fileService.getBlobKey(file);
while (blobKey == null) { //this is hacky, but necessary as sometimes the blobkey isn't available right away
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
blobKey = fileService.getBlobKey(file);
}
// return
return blobKey.getKeyString();
}

My other save method looks like this:

    public void save(String imageFileBlobKey, Key parentKey) {
DatastoreService datastore = DatastoreServiceFactory
.getDatastoreService();
Entity imageFileEntity = new Entity("ImageFile", parentKey);
imageFileEntity.setProperty("blobKey", imageFileBlobKey);
datastore.put(imageFileEntity);
}

Like I said before, it works locally, but not deployed. The error is on the call to saveImageToBlobstore, specifically on the "fileservice.getBlobKey(file)". Commenting out this line eliminates the error, but I need this line to save the bytes of the image to the blob store.  Any ideas?  I am using GAE 1.5.2. 

  

Robert Kluin

unread,
Aug 23, 2011, 1:56:45 AM8/23/11
to google-a...@googlegroups.com
Hi,
The issue is probably that fileService.getBlobKey (and other
methods) makes a datastore call (at least the Python version does).
Since transactions can only touch one entity group, you might get some
problems. (I didn't read your code that closely, but perhaps that
will help you track it down.)

http://code.google.com/appengine/docs/java/datastore/transactions.html#What_Can_Be_Done_In_a_Transaction

Robert

> --
> You received this message because you are subscribed to the Google Groups
> "Google App Engine" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/google-appengine/-/HQPIJdRNp7EJ.
> To post to this group, send email to google-a...@googlegroups.com.
> To unsubscribe from this group, send email to
> google-appengi...@googlegroups.com.
> For more options, visit this group at
> http://groups.google.com/group/google-appengine?hl=en.
>

mr.dc

unread,
Aug 28, 2011, 11:34:16 AM8/28/11
to Google App Engine
I was getting the same error although i tried this:
txn.commit();
txn = datastore.beginTransaction();
bk=fileService.getBlobKey(file);
txn.commit();
(txn is of type "Transaction")
So although i committed stuff it still gets an error on getBlobKey for
some reason.
Weird thing is that it works locally and i'm really shure it worked
before online.(because i already saw some blob-entries from today's
tests)
Is it possible that you get such a message if you hit quota-limits or
something like that?

My average cpu-usage seems to be high but it says "and may soon exceed
its quota" ... but i'm the only one that uses my app atm. so i only
use 0.01 of 6.50 CPU hours for the day.
(... actually i have no idea why it shows that warning on the Log ...)
And yes ... i'm using a free account for now because i just wanted to
test whats possible with that google app engine.


On Aug 23, 7:56 am, Robert Kluin <robert.kl...@gmail.com> wrote:
> Hi,
>   The issue is probably that fileService.getBlobKey (and other
> methods) makes a datastore call (at least the Python version does).
> Since transactions can only touch oneentitygroup, you might get some
> problems.  (I didn't read your code that closely, but perhaps that
> will help you track it down.)
>
>    http://code.google.com/appengine/docs/java/datastore/transactions.htm...
>
> Robert
>
> On Mon, Aug 22, 2011 at 00:08, Jared Alexander
>
>
>
>
>
>
>
> <jared.marc.alexan...@gmail.com> wrote:
> > I have a Java Google App Engine web application that allows user upload of
> > images. Locally, it works great.  However, once I deploy it to "the cloud",
> > and I upload an image, I get the following error:
> > java.lang.IllegalArgumentException:can'toperateonmultipleentitygroups
> > in asingletransaction.
> > I use the blobstore to store the images (BlobStore
> > reference: http://code.google.com/appengine/docs/java/blobstore/overview.html#Wr...).
> >EntityimageFileEntity = newEntity("ImageFile", parentKey);
Reply all
Reply to author
Forward
0 new messages