best way to create a savepoint in sqlalchemy - sqlalchemy

I have an application where users create cost models.
I would like to implement a feature where users can select a "trial" mode which allows them to make as many changes as they wish and observe the cost impact.
If the trial is a success the user should be able to commit all changes, if unsuccessful the user should be able to rollback to the state before entering trial mode.
I know I could probably store all of this in the session and simply use commit or rollback, but is that the best practice here? Is there a better mechanism to set and restore the dbs state?

There is example of savepoint usage. You can read more at here
Session = sessionmaker()
session = Session()
session.add(u1)
session.add(u2)
session.begin_nested() # establish a savepoint
session.add(u3)
session.rollback() # rolls back u3, keeps u1 and u2
session.commit() # commits u1 and u2

Related

Partially commit MySQL Transaction?

I want to know if there's a way to commit a transaction partially. I have a long running transaction in C# and when two users are running this transaction parallel to each other, the data is co-dependent and should show to them both even while in the transaction. For example say I have a table with these 3 columns
username | left_child | right_child
I am making a binary tree and whenever a new user is added into the database they end up somewhere in the tree. But I am running all of the insertions and updates in one transaction so if there's even one error the whole transaction can be rolled back and the structure of the tree is not disturbed. But the problem is the when two users are using my web app at the same time.
Say that username 'jackie_' does not have any children at the minute. Two new users 'king_' and 'robbo' enter parallel to each other and the transaction is running for both of them. Since the results of the transaction running for one user are not visible to the other user in the actual database yet, they both think that the left_child of 'jackie_' hasn't been set yet and so they both update the left_child to their own username. During the transaction since the update was successful for both of them, they both commit the transaction. Now I have two users but only one of them is actually successfully entered into the tree and the structure of the tree is disturbed completely.
So what I need is to be able to commit one transaction even during, "partially". So if 'robbo' got set the left_child of 'jackie_' first, the transaction implements the change into the database so when 'king_' tries to update the same row, he can't. But if along the way, if some other problem occurs for 'robbo' I still want to be able to rollback the whole transaction. Any other solutions which would be more practical are appreciated as well.
For all the queries that I am running, this is the way I am doing it in the transaction
string insertTreesQuery = "INSERT INTO tree (username) VALUES('king_')";
MySqlCommand insertTreesQueryCmd = new MySqlCommand(insertTreesQuery , con);
insertTreesQueryCmd.Transaction = sqlTrans;
insertTreesQueryCmd.ExecuteNonQuery();
where sqlTrans is the transaction that I am using for all the MySqlCommand objects before executing them
What you are asking is not possible. You cannot "partially" commit a transaction. I'm assuming that your example is greatly simplified since you mention the transactions are very large. In that case, it would probably be best to split it up into smaller ones that can be committed independently, thus reducing the chance of there being a conflict.

MySQL transactions implicit commit

I'm starting out with MySQL trnsactions and I have a doubt:
In the documentation it says:
Beginning a transaction causes any pending transaction to be
committed. See Section 13.3.3, “Statements That Cause an Implicit
Commit”, for more information.
I have more or less 5 users on the same web application ( It is a local application for testing ) and all of them share the same MySQL user to interact with the database.
My question is: If I use transactions in the code and two of them start a transaction ( because of inserting, updating or something ) Could it be that the transactions interfere with each other?
I see in the statements that cause an implicit commit Includes starting a transaction. Being a local application It's fast and hard to tell if there is something wrong going on there, every query turns out as expected but I still have the doubt.
The implicit commit occurs within a session.
So for instance you start a transaction, do some updates and then forget to close the transaction and start a new one. Then the first transaction will implicitely committed.
However, other connections to the database will not be affected by that; they have their own transactions.
You say that 5 users use the same db user. That is okay. But in order to have them perform separate operations they should not use the same connection/session.
With MySQl by default each connection has autocommit turned on. That is, each connection will commit each query immediately. For an InnoDb table each transaction is therefore atomic - it completes entirely and without interference.
For updates that require several operations you can use a transaction by using a START TRANSACTION query. Any outstanding transactions will be committed, but this won't be a problem because mostly they will have been committed anyway.
All the updates performed until a COMMIT query is received are guaranteed to be completed entirely and without interference or, in the case of a ROLLBACK, none are applied.
Other transations from other connections see a consistent view of the database while this is going on.
This property is ACID compliance (Atomicity, Consistency, Isolation, Durability) You should be fine with an InnoDB table.
Other table types may implement different levels of ACID compliance. If you have a need to use one you should check it carefully.
This is a much simplified veiw of transaction handling. There is more detail on the MySQL web site here and you can read about ACID compliance here

Should I commit after a single select

I am working with MySQL 5.0 from python using the MySQLdb module.
Consider a simple function to load and return the contents of an entire database table:
def load_items(connection):
cursor = connection.cursor()
cursor.execute("SELECT * FROM MyTable")
return cursor.fetchall()
This query is intended to be a simple data load and not have any transactional behaviour beyond that single SELECT statement.
After this query is run, it may be some time before the same connection is used again to perform other tasks, though other connections can still be operating on the database in the mean time.
Should I be calling connection.commit() soon after the cursor.execute(...) call to ensure that the operation hasn't left an unfinished transaction on the connection?
There are thwo things you need to take into account:
the isolation level in effect
what kind of state you want to "see" in your transaction
The default isolation level in MySQL is REPEATABLE READ which means that if you run a SELECT twice inside a transaction you will see exactly the same data even if other transactions have committed changes.
Most of the time people expect to see committed changes when running the second select statement - which is the behaviour of the READ COMMITTED isolation level.
If you did not change the default level in MySQL and you do expect to see changes in the database if you run a SELECT twice in the same transaction - then you can't do it in the "same" transaction and you need to commit your first SELECT statement.
If you actually want to see a consistent state of the data in your transaction then you should not commit apparently.
then after several minutes, the first process carries out an operation which is transactional and attempts to commit. Would this commit fail?
That totally depends on your definition of "is transactional". Anything you do in a relational database "is transactional" (That's not entirely true for MySQL actually, but for the sake of argumentation you can assume this if you are only using InnoDB as your storage engine).
If that "first process" only selects data (i.e. a "read only transaction"), then of course the commit will work. If it tried to modify data that another transaction has already committed and you are running with REPEATABLE READ you probably get an error (after waiting until any locks have been released). I'm not 100% about MySQL's behaviour in that case.
You should really try this manually with two different sessions using your favorite SQL client to understand the behaviour. Do change your isolation level as well to see the effects of the different levels too.

Database-safe Concurrency in ROR

Trying to figure out how concurrency is dealt with in Ruby On Rails.
How do I get a segment of code to lock on lines in the database and force rollbacks when needed?
More specificly, Is there a way to force a certain segment of code to complete totally and if not rollback? I'm looking to add history to transactions in my project and I don't want transactions to commit without the history being saved so if the server falls between the two actions (saving the transaction and saving the history) the database may go into an illegal state.
You want to look at ActiveRecord Transactions and Pessimistic Locking.
Account.transaction do
account = Account.find(account_id)
account.lock!
if account.balance >= 100
account.balance -= 100
account.save
end
end
Yes, you have a way of implementing a transaction in Rails. An example:
YourModel.transaction do
rec1.save!
rec2.save!
end
More info here

MySQL: automatic rollback on transaction failure

Is there any way to set MySQL to rollback any transaction on first error/warning automatically?
Now if everything goes well, it commits, but on failure it leaves transaction open and on another start of transaction it commits incomplete changes from failed transaction. So i need to rollback automatically those failed transactions..
(I'm executing queries from php, but i don't want to check in php for failure, as it would make more calls between mysql server and webserver.)
Thank you
I don't know of such feature, but I also don't see how checking for failure would mean more calls:
try:
<my code>
except:
transaction.rollback()
raise
else:
transaction.commit()
-- it's in Python/Django, but it should directly transpose to PHP - and it takes exactly the same amount of code to start new transaction, no matter if there is a problem (exception) or not.
Sorry, You are going to need to do this on your own.
I am not a PHP person, but in SQL: If you create a transaction and do several MySQL operations within the transaction, if you rollback the transaction everything will be rolled back. NOTE: You need to be using a transactional storage engine and autocommit must be set to off.
If all you are concerned about is the transaction coordination traffic then you could create a stored procedure and simply call it.
The reason the database does not automatically commit or rollback is because it does not know what you are trying to do, committing some data and rolling back other data might be acceptable in an app.
the key point to to set autocommit to false.
<?php
$database= new mysqli("sever", "user", "key", "database");
$database->autocommit(FALSE);
$error=0;
//asumming we want to delete a users infomation from two table
$database->query("delete from `pay` where `user`=1 ")?NULL:$error=1;
$database->query("delete from `users` where `id`=1 ")?NULL:$error=1;
if($error=0){
$database->commit();
} else {
$database->rollback();
}
$database->close();
?>