MySQL doesn't support COMMIT
-ROLLBACK.
The problem is
that handling COMMIT
-ROLLBACK
efficiently would require a
completely different table layout than MySQL uses today.
MySQL would also need extra threads that do automatic cleanups on
the tables and the disk usage would be much higher. This would make
MySQL about 2-4 times slower than it is today. MySQL is
much faster than almost all other SQL databases (typically at least 2-3 times
faster). One of the reasons for this is the lack of
COMMIT
-ROLLBACK
.
For the moment, we are much more for implementing the SQL server
language (something like stored procedures). With this you would very
seldom really need COMMIT
-ROLLBACK.
This would also give much
better performance.
Loops that need transactions normally can be coded with the help of
LOCK TABLES
, and you don't need cursors when you can update records
on the fly.
We have transactions and cursors on the TODO but not quite prioritized. If
we implement these, it will be as an option to CREATE TABLE
. That
means that COMMIT
-ROLLBACK
will work only on those tables,
so that a speed penalty will be imposed on those table only.
We at TcX have a greater need for a real fast database than a 100%
general database. Whenever we find a way to implement these features without
any speed loss, we will probably do it. For the moment, there are many more
important things to do. Check the TODO for how we prioritize things at
the moment. (Customers with higher levels of support can alter this, so
things may be reprioritized.)
The current problem is actually ROLLBACK
. Without ROLLBACK
, you
can do any kind of COMMIT
action with LOCK TABLES
. To support
ROLLBACK
, MySQL would have to be changed to store all old
records that were updated and revert everything back to the starting point if
ROLLBACK
was issued. For simple cases, this isn't that hard to do (the
current isamlog
could be used for this purpose), but it would be much
more difficult to implement ROLLBACK
for ALTER/DROP/CREATE
TABLE
.
To avoid using ROLLBACK
, you can use the following strategy:
-
Use
LOCK TABLES ...
to lock all the tables you want to access.
-
Test conditions.
-
Update if everything is okay.
-
Use
UNLOCK TABLES
to release your locks.
This is usually a much faster method than using transactions with possible
ROLLBACK
s, although not always. The only situation this solution
doesn't handle is when someone kills the threads in the middle of an
update. In this case, all locks will be released but some of the updates may
not have been executed.
You can also use functions to update records in a single operation.
You can get a very efficient application by using the following techniques:
-
Modify fields relative to their current value
-
Update only those fields that actually have changed
For example, when we are doing updates to some customer information, we
update only the customer data that have changed and test only that none of
the changed data, or data that depend on the changed data, have changed
compared to the original row. The test for changed data is done with the
WHERE
clause in the UPDATE
statement. If the record wasn't
updated, we give the client a message: "Some of the data you have changed
have been changed by another user". Then we show the old row versus the new
row in a window, so the user can decide which version of the customer record
he should use.
This gives us something that is similar to ``column locking'' but is actually
even better, because we only update some of the columns, using values that
are relative to their current values. This means that typical UPDATE
statements look something like these:
UPDATE tablename SET pay_back=pay_back+'relative change';
UPDATE customer
SET
customer_date='current_date',
address='new address',
phone='new phone',
money_he_owes_us=money_he_owes_us+'new_money'
WHERE
customer_id=id AND address='old address' AND phone='old phone';
As you can see, this is very efficient and works even if another client has
changed the values in the pay_back
or money_he_owes_us
columns.
In many cases, users have wanted ROLLBACK
and/or LOCK
TABLES
for the purpose of managing unique identifiers for some tables. This
can be handled much more efficiently by using an AUTO_INCREMENT
column
and either the SQL function LAST_INSERT_ID()
or the C API function
mysql_insert_id()
. mysql_insert_id()
.
At TcX, we have never had any need for row-level locking because we have
always been able to code around it. Some cases really need row
locking, but they are very few. If you want row-level locking, you
can use a flag column in the table and do something like this:
UPDATE tbl_name SET row_flag=1 WHERE id=ID;
MySQL returns 1 for the number of affected rows if the row was
found and row_flag
wasn't already 1 in the original row.
You can think of it as MySQL changed the above query to:
UPDATE tbl_name SET row_flag=1 WHERE id=ID and row_flag <> 1;