views:

392

answers:

2

Hi, I'm trying to implement two-phase commit using PHP and MySQL, and coming up short.

The main block I've found is that I'm unable to store the MySQL connection resource in a place where I can find it again for the second phase. Is it possible to serialize a database handle?

Here's the case I'm trying to code for:

  1. User sends data
  2. Server starts a MySQL transaction and executes some queries based on the data it has received.
  3. Server sends a file back to the user
  4. When the user has successfully received the file, the server commits its transaction. Otherwise it rolls it back.

This seems to require two HTTP Request/Response cycles, so I need to be able to re-connect to the same database handle in the second request in order to commit the transaction. I've been failing at this part.

Any advice is welcome, even if it's "this is not possible in PHP"

+2  A: 

Since php is Request / Response based the implementation of a persistent DB connection is not possbile, AFAIK.

You could try to work around this limitation using sort of a ticketing mechanism. Your steps would be:

  1. User sends data
  2. Server starts a MySQL transaction and executes some queries based on the data it has received, assigning a 'unique' ticket to that transaction.
  3. Server sends a file and the ticket back to the user
  4. When the user has successfully received the file and sent another request containing that ticket, the server commits its transaction. Otherwise it rolls it back.
  5. refering to Cassy's comment: after a certain period of time all not commited TAs should be rolled back in order to prevent your db from beeing 'flooded' with old transactions

HTH

KB22
Nice idea! I would add a fifth bullet point though: The roll back should also happen after a specified time with no user upload. Otherwise the database would be filled with cancelled operations.
Cassy
this is what I had in mind, with the ticket being a reference to the id in shared memory where I'd stored the database handle with the pending transaction. Only problem is you can't serialize database handles in PHP, so I'm left with the problem of being unable to ensure that the second request gets the same db handle it had the first time. As I understand it, transactions have to be committed on the same database connection they were begun on. Is there a way to label transactions to make it possible to return to them later?
TomL
I don't think this ia possible after all. I'd stick to the mentioned workaround and would try to 'emulate' the transaction mechanism with an transaction table of my own. Something like STRING (here come the actual SQL-strings) BOOLEAN (to commit). The first request writes the query to the temp table, marked as toCommit = false; the second request executes the actual request. I'd agree to rojoca's question: why do you wan't to do this explicitly that way?
KB22
A: 

to answer KB22 and rojoca, the reason I need to do it this way is that the 'file' i'm referring to is actually a sqlite database that ends up as a data store on a mobile device.

The first request posts the updated sqlite database to the server, which attempts to merge in data from the sqlite tables; problems arise when the mobile device doesn't successfully receive a new sqlite database (one which reflects the mobile device's changes and any other new stuff from the web application), because it will then attempt to send the same (old) sqlite database to the web a second time, resulting in duplicate entries in the web tables for anything which was created on the mobile device.

So, the web needs to be sure that the device has the new database before committing the merge changes. Given the vagaries of networks, this only seems feasible if the device can send an explicit ACK after receiving the new sqlite database. And this is only possible if we make two requests (1. The sqlite database to merge; 2. the ACK of receipt of the new sqlite database on the device).

A thorny problem indeed, and it's useful information to find out that PHP can't manipulate database handles down to the necessary level.

[I also don't think I can use a transaction table because I need to return data to the device based on the 'real' web database tables. I think i'd run into issues with auto_increment fields if I didn't use the real tables]

Thanks for all your comments.

TomL