473,626 Members | 3,245 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Very Strange MySQL Problem

I have RH9 and am using the PHP and MySQL that came with it. I was
doing fine with all manner of my web pages for this app until I
started having this very strange problem.

It's a work order mgmt system. I have 3 tables for the orders:
TicketsOpen, TicketsVoided, and TicketsResolved . When one wants to
void a ticket, they click it, choose Void, and it is copied to the
TicketsVoided table, then removed from the TicketsOpen. And I can
imagine you can apply that same concept to the TicketsResolved table.
Likewise, I have a process where one can unvoid and reopen (unresolve)
a ticket, copying back to TicketsOpen, and deleting from the previous
table.

(What I'm about to mention below will take some brain cells. Use em if
you got em. Otherwise, skip this posting.)

The Void.php web page will SELECT the ticket from TicketsOpen. I use 2
IDs for a ticket. One is the identity column: ID. The other is a
TRACKING_NUMBER (TN for short), which is a random, non-unique
alphanumeric string that is used for informing the customer. It's
simply based on month, day, a random number in the thousands, and then
is Base36 encoded to shorten it up. The Void.php page is told what the
ID is, so it reads the record into variables. Then, it changes the TN
variable to (TN . ' capture') -- we'll call that TN2 for short. Then,
it does an INSERT to write this record data to TicketsVoided. Then, it
does a SELECT on TN from TicketsVoided for the TN2 value. When it
finds it, it gets the new ID. (ID2, let's call it.) Then, it does an
UPDATE where record ID is ID2, setting the TN (that had a value of
TN2) back to TN w/o ' capture'. Then, it does a DELETE on TicketsOpen
by the original ID. It concludes by providing a link to go back to the
ticket queue for TicketsOpen. Again, the pseudocode is:

id1 = initial ticket ID of TicketsOpen that we want to void
orec = select our void request on id = ID1 from TicketsOpen
tn1 = orec.tn
tn2 = orec.tn + ' capture'
orec.tn = tn2
insert orec into TicketsVoided
vrec = select from TicketsVoided where tn = tn2
id2 = vrec.id
vrec.tn = tn1
update TicketsVoided with vrec where tn = tn2
delete from TicketsOpen where id = id1

Well, this runs just fine if I go slow. But if I start firing void.php
faster with my mouse, mostly likely by the fourth or fifth time it
will run without an error message, but return an incorrect result in a
variety of ways. Sometimes it never deletes the original record from
TicketsOpen. Sometimes it creates two records in TicketsVoided but
with only one of them having the TN set to TN2, while the other is set
to TN1.

And I bet you anything that if I move the whole project to PostgreSQL,
this problem won't occur.
Jul 17 '05 #1
4 2830

On 9-Nov-2003, go********@hotp op.com (Google Mike) wrote:

I have RH9 and am using the PHP and MySQL that came with it. I was
doing fine with all manner of my web pages for this app until I
started having this very strange problem.

It's a work order mgmt system. I have 3 tables for the orders:
TicketsOpen, TicketsVoided, and TicketsResolved . When one wants to
void a ticket, they click it, choose Void, and it is copied to the
TicketsVoided table, then removed from the TicketsOpen. And I can
imagine you can apply that same concept to the TicketsResolved table.
Likewise, I have a process where one can unvoid and reopen (unresolve)
a ticket, copying back to TicketsOpen, and deleting from the previous
table.

(What I'm about to mention below will take some brain cells. Use em if
you got em. Otherwise, skip this posting.)

The Void.php web page will SELECT the ticket from TicketsOpen. I use 2
IDs for a ticket. One is the identity column: ID. The other is a
TRACKING_NUMBER (TN for short), which is a random, non-unique
alphanumeric string that is used for informing the customer. It's
simply based on month, day, a random number in the thousands, and then
is Base36 encoded to shorten it up. The Void.php page is told what the
ID is, so it reads the record into variables. Then, it changes the TN
variable to (TN . ' capture') -- we'll call that TN2 for short. Then,
it does an INSERT to write this record data to TicketsVoided. Then, it
does a SELECT on TN from TicketsVoided for the TN2 value. When it
finds it, it gets the new ID. (ID2, let's call it.) Then, it does an
UPDATE where record ID is ID2, setting the TN (that had a value of
TN2) back to TN w/o ' capture'. Then, it does a DELETE on TicketsOpen
by the original ID. It concludes by providing a link to go back to the
ticket queue for TicketsOpen. Again, the pseudocode is:

id1 = initial ticket ID of TicketsOpen that we want to void
orec = select our void request on id = ID1 from TicketsOpen
tn1 = orec.tn
tn2 = orec.tn + ' capture'
orec.tn = tn2
insert orec into TicketsVoided
vrec = select from TicketsVoided where tn = tn2
id2 = vrec.id
vrec.tn = tn1
update TicketsVoided with vrec where tn = tn2
delete from TicketsOpen where id = id1 Well, this runs just fine if I go slow. But if I start firing void.php
faster with my mouse, mostly likely by the fourth or fifth time it
will run without an error message, but return an incorrect result in a
variety of ways. Sometimes it never deletes the original record from
TicketsOpen. Sometimes it creates two records in TicketsVoided but
with only one of them having the TN set to TN2, while the other is set
to TN1.

And I bet you anything that if I move the whole project to PostgreSQL,
this problem won't occur.


Just a thought, but are you using ignore_user_abo rt() to prevent the script
from terminating mid transaction?

Why are you using TN instead of id in your where clauses? If TN is not
unique, you are risking some very weird db problems down the road. Why not
use the unique record id instead of the random number in composing the TN so
it will be unique or don't use TN as the key in your select/insert/updates.

You might consider one table for tickets and marking them with a status or
having a status table which could prevent the problem caused by having to
move records between tables.

--
Tom Thackrey
www.creative-light.com
tom (at) creative (dash) light (dot) com
do NOT send email to ja*********@wil lglen.net (it's reserved for spammers)
Jul 17 '05 #2
Thanks to the programmers of PHP, they made the SharedMemory API. That
solved the problem. You see, it appears that the API in PHP that
writes to MySQL works somewhat asynchronously sometimes, especially
when forced by someone hitting pages very rapidly. If one wants to do
an insert, followed by an update, they may end up with two different
records in some cases where they don't use the unique ID column, but
some other column or set of columns. The resolution I used was to make
one single insert with everything, including the unique ID, but the
trick question I had for awhile was, "How do I ensure that I'm going
to be the one holding the record with the unique ID, and not some
other process take that ID?"

The answer, you see, is shared memory, but let's back up a bit and see
the process.

1) I need to select a record from the TicketsOpen table and I happen
to know it's ID. This record has an ID column with a guaranteed unique
ID, and a tracking number (TN) with an approximate unique ID.

(The TN is short and is used to give out to customers. It cannot be
guessed easily, so customers cannot fib. We only use the TN ID when we
want to zoom in on the record approximately. We have to ask further
questions to ensure we are working with the right ticket. The
algorithm for TN is based on second, month, day, and a small random
number.)

2) Okay, now I need to void this record, so I need to move this to the
TicketsVoided table.

(Why not just have a Void bit on the record in the TicketsOpen table?
Well, there's two reasons: (a) table size is an issue, and (b) we want
faster SELECTS. Even though I can restrict a SELECT to ignore a Void
bit, it still is faster if there are no voided records in the opened
tickets table. You see?)

I now do a SELECT MAX(ID) FROM TicketsVoided. And, of course, I want
to increment that var with ++. But that won't work, will it? I mean,
another user could be on this same web page, doing the same thing with
another record, and we could end up clobbering each other's records.

The solution is to use shared memory in PHP. I create a shared memory
variable that stores my username if I'm currently doing the write
process to the target table. Then, when I'm finished, I clear the
variable to nothing. So, before any user can do SELECT MAX(ID)...,
they must wait in a small loop until the shared memory var is free.
Then, they can stick their username in there. While waiting, I use
usleep(500) to sleep a series of half seconds, up to 4 seconds max,
until this var is free. If that 4 seconds is up, then I assume
something is wrong and I just go ahead and let the user use the shared
memory var and start doing SELECT MAX(ID).

3) Okay, now that I have guaranteed without a doubt 100% that I now
have the latest ID for a record to insert into TicketsVoided, I do an
INSERT to write it there.

4) I now delete the record from the source table (TicketsOpen).

5) Now the record is moved, so I clear the shared memory variable,
freeing up any other process that's waiting to have the permission to
do a move to this table.

In a sense, shared memory is my workaround for transactions.

And so why didn't I do this with MySQL's transactions, or another
database? Because I'm trying to stay ANSI-92 here, and I want to
produce something that could use almost any database backend,
including PostgreSQL, MS SQL, Oracle, etc.
Jul 17 '05 #3

On 10-Nov-2003, go********@hotp op.com (Google Mike) wrote:
Thanks to the programmers of PHP, they made the SharedMemory API. That
solved the problem. You see, it appears that the API in PHP that
writes to MySQL works somewhat asynchronously sometimes, especially
when forced by someone hitting pages very rapidly. If one wants to do
an insert, followed by an update, they may end up with two different
records in some cases where they don't use the unique ID column, but
some other column or set of columns. The resolution I used was to make
one single insert with everything, including the unique ID, but the
trick question I had for awhile was, "How do I ensure that I'm going
to be the one holding the record with the unique ID, and not some
other process take that ID?"

The answer, you see, is shared memory, but let's back up a bit and see
the process.

1) I need to select a record from the TicketsOpen table and I happen
to know it's ID. This record has an ID column with a guaranteed unique
ID, and a tracking number (TN) with an approximate unique ID.

(The TN is short and is used to give out to customers. It cannot be
guessed easily, so customers cannot fib. We only use the TN ID when we
want to zoom in on the record approximately. We have to ask further
questions to ensure we are working with the right ticket. The
algorithm for TN is based on second, month, day, and a small random
number.)

2) Okay, now I need to void this record, so I need to move this to the
TicketsVoided table.

(Why not just have a Void bit on the record in the TicketsOpen table?
Well, there's two reasons: (a) table size is an issue, and (b) we want
faster SELECTS. Even though I can restrict a SELECT to ignore a Void
bit, it still is faster if there are no voided records in the opened
tickets table. You see?)

I now do a SELECT MAX(ID) FROM TicketsVoided. And, of course, I want
to increment that var with ++. But that won't work, will it? I mean,
another user could be on this same web page, doing the same thing with
another record, and we could end up clobbering each other's records.

The solution is to use shared memory in PHP. I create a shared memory
variable that stores my username if I'm currently doing the write
process to the target table. Then, when I'm finished, I clear the
variable to nothing. So, before any user can do SELECT MAX(ID)...,
they must wait in a small loop until the shared memory var is free.
Then, they can stick their username in there. While waiting, I use
usleep(500) to sleep a series of half seconds, up to 4 seconds max,
until this var is free. If that 4 seconds is up, then I assume
something is wrong and I just go ahead and let the user use the shared
memory var and start doing SELECT MAX(ID).

3) Okay, now that I have guaranteed without a doubt 100% that I now
have the latest ID for a record to insert into TicketsVoided, I do an
INSERT to write it there.

4) I now delete the record from the source table (TicketsOpen).

5) Now the record is moved, so I clear the shared memory variable,
freeing up any other process that's waiting to have the permission to
do a move to this table.

In a sense, shared memory is my workaround for transactions.

And so why didn't I do this with MySQL's transactions, or another
database? Because I'm trying to stay ANSI-92 here, and I want to
produce something that could use almost any database backend,
including PostgreSQL, MS SQL, Oracle, etc.


An alternative to the shared memory would be a table to store the used ids,
just add a row and retrieve the id it generated. If someone else is doing
the same they'll get a different row/id.

--
Tom Thackrey
www.creative-light.com
tom (at) creative (dash) light (dot) com
do NOT send email to ja*********@wil lglen.net (it's reserved for spammers)
Jul 17 '05 #4
"Tom Thackrey" <us***********@ nospam.com> wrote
An alternative to the shared memory would be a table to store the used ids,
just add a row and retrieve the id it generated. If someone else is doing
the same they'll get a different row/id.


Yeah. No duh. Man, I must have been stupid. I forgot that I want this
app to be web-farmable, and have taken every effort to make all
session state be in encrypted browser cookies. Well, when I have to
use shared memory to manage transaction queues of users trying to move
records between the various tables, I completely forgot that this only
works in a one-server environment. So, it looks I'm going to have to
use the idea you suggest. Of course, if I didn't have this MySQL
problem where the INSERTS and UPDATES didn't seem to run
asynchronously in a web page if the page is hammered, I wouldn't need
this, but I guess I'm going to need this.
Jul 17 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1870
by: Bruce A. Julseth | last post by:
My MySQL.user table (user, host, password) looks like the following: +---------+-----------+---------------------+ | user | host | password | +---------+-----------+---------------------+ | root | localhost | | | root | % | | | | localhost | 3823a5ee1f831626 | | | % |...
14
1636
by: smilesinblues | last post by:
Hi all, I have a table with a lot of songs. All songs have a field called hits. Everytime a song page is seen hits becomes hit++, everything smooth going. I also have a page where I run the query select * from table order by hits DESC
0
2134
by: Neculai Macarie | last post by:
Hi! Using Union and Order By gives strange behaviour in the following test-case: drop table if exists gallery; drop table if exists gallery_categ; # create test tables create table gallery (d_image_small char(100), d_image_big char(100)); create table gallery_categ (d_image char(100)); # insert test data
0
1870
by: Nedelcho Stanev | last post by:
Hello All, I have strange problem with libodbc++ ( 0.2.3 or 0.2.2 ). i'm using mysql-4.0.14 , MyODBC-3.51.06 and unixODBC-2.2.6 configured with following options 1.MySQL ../configure --prefix=/usr/local/test --with-openssl --with-mysqld-user=root --enable-thread-safe-client --with-pthread --enable-shared
0
2940
by: Steve | last post by:
Hi, Yesterday I signed up for another dedicated linux server with the hosting company I use and I am having problems getting MySQL 4.1.3 working on it. I've tried just about everything I can think of to login via the MySQL client but get a variation of the following error every time: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES)
3
2054
by: Sven Reifegerste | last post by:
Hi, i have a table with INT columns id,key,b1,b2,c1,c2, having 1.500.000 rows. 'key' and 'id' are indexed (Kardinality 385381) and id (Kardinality 1541525). Performing a SELECT * FROM table WHERE key IN (10,11,12) OR key BETWEEN 20000 AND 28000 AND b1<4500000 AND b2>3954545 AND c1<4543554 AND c2>4400000
4
15594
by: 21novembre | last post by:
Hi all, I got a quite strange problem when I tried to setup a database backup shell. I put it this way: "bin/mysqldump --opt --user=xxx --password=xxx DB > DB.bak" However, error 1045 came to me to say "Access denied for user 'xxx'@'localhost' (using password: YES) when trying to connect". None the less, I'm absolutely full of confidence on my correct username and password, simply because if I do it this way: "bin/mysqldump --opt...
11
17546
by: DJJ | last post by:
I am using the MySQL ODBC 3.51 driver to link three relatively small MySQL tables to a Microsoft Access 2003 database. I am finding that the data from the MySQL tables takes a hell of a long time to load making any kind linkage with my Access data virtually useless. I have the MySQL driver setup in as a USER DSN. The MySQL data is sitting out on a server and the Access database is running locally. The network connection is very...
9
1689
by: Dave | last post by:
Hi guys, I have just set up a duplicate server running: apache 2.54, mysql 5.04 and php 5.04 This is the same setup as as the server we are using now, apart from the hardware inside. I have copied across the database and website, with exact same permissions as the first server. The problem is that part of the php code is executing but others
0
8269
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
8368
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
6125
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5576
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4094
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4206
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
2630
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system
1
1815
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1515
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.