Zend: Rollback a commit? - postgresql

Let's say I start a transaction and then finish it with a commit:
$db->beginTransaction();
// sql insert
// another sql insert
// a sql update
// another sql update
$db->commit();
Is there a function I can run after commit() to revert all the changes made by between beginTransaction and commit() ?

After commit you cannot revert changes for reverting you should call rollback instead.
Rollback action done mainly if any one entity in a transaction fails.Therefore to catch a failure you should use try{}catch{}
$db->beginTransaction();
try{
$db->commit();//writes all data to database and reach to new state
}catch(Exception $e)
{
$db->rollback();//roll back all changes made to database
echo $e->getTraceAsString();
}

This will revert changes from the current transaction:
$db->rollBack();
However, you cannot rollback after you have committed.
If you are trying to prevent inserting on errors etc. I would try this:
try
{
$db->beginTransaction();
// sql insert
// another sql insert
// a sql update
// another sql update
$db->commit();
}
catch( Zend_Exception $e)
{
$db->rollBack();
}
This will commit if there are no errors, and rollback if there are.

Related

MAJ EF Core 3.1 using Transaction, MultipleContext and Trigger

I want to update multiple databases but i have a error : "An exception has been raised that is likely due to a transient failure. Consider enabling transient error resiliency by adding 'EnableRetryOnFailure()' to the 'UseMySql' call."
During the Context2.SaveChanges() i have the inner exception is: "Lock wait timeout exceeded; try restarting transaction", because the table B has a trigger "after update" and he read into table A in the context1.
I use a TransactionScope and two different context:
using (TransactionScope transactionScope = new
TransactionScope(TransactionScopeOption.Required, _timeSpan))
{
....
//update the first database, table A
Context1.SaveChanges();
....
//update the second database, table B
Context2.SaveChanges();
.....
// Commit transaction if all commands succeed, transaction will auto-rollback when disposed if either commands fails.
transactionScope.Complete();
return result;
}
The trigger update a table in the Context2 and he read in the Context1 in the table A.
Somebody have you a idea for a solution ?

When is better to call UPDATE STATISTICS? before or after a COMMIT TRANS

I'm working on an ETL project, actively populating tables with data. Sometimes if something is missing, a whole block of data modifications must be undone, so I'm using a transaction. When something goes wrong, a rollback applies, if not, an UPDATE STATISTICS could help efficiency.
So my question is what would be more efficient, to UPDATE STATISTICS inside the TRANSACTION or after the COMMIT?
Currently working fine as:
BEGIN TRY
BEGIN TRAN
UPDATE stuffs SET ...
INSERT things VALUES(...
UPDATE STATISTICS stuffs
UPDATE STATISTICS things
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK TRAN
RAISERROR( ... -- RAISERROR prevents from executing past this point
END CATCH
IF ##TRANCOUNT > 0 COMMIT TRAN
But maybe this is better
BEGIN TRY
BEGIN TRAN
UPDATE stuffs SET ...
INSERT things VALUES(...
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0 ROLLBACK TRAN
RAISERROR( ... -- RAISERROR prevents from executing past this point
END CATCH
IF ##TRANCOUNT > 0 COMMIT TRAN
UPDATE STATISTICS stuffs
UPDATE STATISTICS things
I've tried both with virtually the same results, but with more data or more rollbacks could be different.
I will use the second one.
The transaction will be rolled back when it raises the error(s) if you put them in the try block.
I believe you still need 'update statistics' to improve efficiency even after a rollback applies to your transaction. If so, it is better to keep 'update statistics' after the transaction commits.

Entity Framework Optimistic Concurrency Exception with Multiple records updated

When updating multiple records in the database via the entity framework database context, one record is throwing an optimistic concurrency exception and that record is not updated in the database. But I am finding the other records updated are persisted to the database. Should the optimistic concurrency exception not roll back all changes made prior to the optimistic concurrency exception?
I bet exception is thrown by EF library whenever update was expected, but SQL Server response indicates none was made.
Exception thrown by DbContext when it was expected that SaveChanges for an entity would result in a database update but in fact no rows in the database were affected. This usually indicates that the database has been concurrently updated such that a concurrency token that was expected to match did not actually match. Note that state entries referenced by this exception are not serialized due to security and accesses to the state entries after serialization will return null.
Also Entity Framework translates into single SQL UPDATE statement per object e.g.
exec sp_executesql N'SET NOCOUNT ON;
UPDATE [Students] SET [Name] = #p0
WHERE [StudentId] = #p1;
SELECT ##ROWCOUNT;
UPDATE [Students] SET [Name] = #p2
WHERE [StudentId] = #p3;
SELECT ##ROWCOUNT;
UPDATE [Students] SET [Name] = #p4
WHERE [StudentId] = #p5;
SELECT ##ROWCOUNT;
',N'#p1 int,#p0 nvarchar(4000),#p3 int,#p2 nvarchar(4000),#p5 int,#p4
nvarchar(4000)',
#p1=1,#p0=N'Bill',#p3=2,#p2=N'Steve',#p5=3,#p4=N'James'
go
Which means everything is okay by SQL Server and transaction is commited by Entity Framework. Only EF throws exception to let you know something went wrong. In your case one of those statements updates nothing and number of updated rows was/is 0.
If you need to rollback all changes during such an update you have to encapsulate it with another transaction. Commit and rollback as needed.
using (var dbContextTransaction = context.Database.BeginTransaction())
{
try
{
// Do your stuff
context.SaveChanges();
dbContextTransaction.Commit();
}
catch (DbUpdateConcurrencyException)
{
// Expected
dbContextTransaction.Rollback();
}
catch (Exception)
{
// Unexpected
dbContextTransaction.Rollback();
}
}
Relevant reading:
More about DbUpdateConcurrencyException Class
More about Update Data in Disconnected Scenario in Entity Framework Core (Update Multiple Entities)
More about Entity Framework Working with Transactions

Npgsql with PostgreSQL: Can't see uncommitted changes with UNCOMMITTED READ

I'm using Npsql with PostgreSQL. I want to see uncommitted changes of one transaction in a different one.
This is how I create my connection and transaction:
// create connection
m_Connection = new NpgsqlConnection(connectionString);
m_Connection.Open();
//create transaction
m_Transaction = m_Connection.BeginTransaction(IsolationLevel.ReadUncommitted);
In one thread I insert a row like so:
NpgsqlCommand command = CreateCommand("INSERT INTO TABLEA ....", parameters, commandTimeout)
command.ExecuteNonQuery();
and process something else without committing or rolling back the transaction.
In a different thread I read a row like so:
NpgsqlCommand command = CreateCommand("SELECT COUNT(*) FROM TABLEA", parameters, commandTimeout);
command.ExecuteScalar();
but somehow I don't see the results of the first INSERT. I don't see the results of the insert in pgAdmin either (even after running SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED).
What am I doing wrong? Any help will be appreciated.
PostgreSQL does not support uncommitted reads.
You will never be able to see changes from other transactions that are not committed.

PSQLException: current transaction is aborted, commands ignored until end of transaction block

I am seeing the following (truncated) stacktrace in the server.log file of JBoss 7.1.1 Final:
Caused by: org.postgresql.util.PSQLException:
ERROR: current transaction is aborted, commands ignored until end of
transaction block
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:512)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:374)
at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:302)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.6.0_23]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [rt.jar:1.6.0_23]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [rt.jar:1.6.0_23]
at java.lang.reflect.Method.invoke(Method.java:597) [rt.jar:1.6.0_23]
at org.postgresql.ds.jdbc23.AbstractJdbc23PooledConnection$StatementHandler.invoke(AbstractJdbc23PooledConnection.java:455)
at $Proxy49.executeUpdate(Unknown Source) at org.jboss.jca.adapters.jdbc.WrappedStatement.executeUpdate(WrappedStatement.java:371)
at org.infinispan.loaders.jdbc.TableManipulation.executeUpdateSql(TableManipulation.java:154) [infinispan-cachestore-jdbc-5.1.2.FINAL.jar:5.1.2.FINAL]
... 154 more
Inspecting the Postgres log file reveals the following statements:
STATEMENT: SELECT count(*) FROM ISPN_MIXED_BINARY_TABLE_configCache
ERROR: current transaction is aborted, commands ignored until end of transaction block
STATEMENT: CREATE TABLE ISPN_MIXED_BINARY_TABLE_configCache(ID_COLUMN VARCHAR(255) NOT NULL, DATA_COLUMN BYTEA, TIMESTAMP_COLUMN BIGINT, PRIMARY KEY (ID_COLUMN))
ERROR: relation "ispn_mixed_binary_table_configcache" does not exist at character 22
I am using the Infinispan shipped with JBoss 7.1.1 Final, which is 5.1.2.Final.
So this is what I think is happening:
Infinispan attempts to run the SELECT count(*)... statement in order to see if there are any records in the ISPN_MIXED_BINARY_TABLE_configCache;
Postgres, for some reason, does not like this statement.
Infinispan ignores this and plows ahead with the CREATE TABLE statement.
Postgres barfs because it still thinks it's the same transaction, which Infinispan has failed to roll back, and this transaction is shafted from the first SELECT count(*)... statement.
What does this error mean and any idea how to work around it?
I got this error using Java and PostgreSQL doing an insert on a table. I will illustrate how you can reproduce this error:
org.postgresql.util.PSQLException: ERROR:
current transaction is aborted, commands ignored until end of transaction block
Summary:
The reason you get this error is because you have entered a transaction and one of your SQL Queries failed, and you gobbled up that failure and ignored it. But that wasn't enough, THEN you used that same connection, using the SAME TRANSACTION to run another query. The exception gets thrown on the second, correctly formed query because you are using a broken transaction to do additional work. PostgreSQL by default stops you from doing this.
I'm using: PostgreSQL 9.1.6 on x86_64-redhat-linux-gnu, compiled by gcc (GCC) 4.7.2 20120921 (Red Hat 4.7.2-2), 64-bit".
My PostgreSQL driver is: postgresql-9.2-1000.jdbc4.jar
Using Java version: Java 1.7
Here is the table create statement to illustrate the Exception:
CREATE TABLE moobar
(
myval INT
);
Java program causes the error:
public void postgresql_insert()
{
try
{
connection.setAutoCommit(false); //start of transaction.
Statement statement = connection.createStatement();
System.out.println("start doing statement.execute");
statement.execute(
"insert into moobar values(" +
"'this SQL statement fails, and it " +
"is gobbled up by the catch, okfine'); ");
//The above line throws an exception because we try to cram
//A string into an Int. I Expect this, what happens is we gobble
//the Exception and ignore it like nothing is wrong.
//But remember, we are in a TRANSACTION! so keep reading.
System.out.println("statement.execute done");
statement.close();
}
catch (SQLException sqle)
{
System.out.println("keep on truckin, keep using " +
"the last connection because what could go wrong?");
}
try{
Statement statement = connection.createStatement();
statement.executeQuery("select * from moobar");
//This SQL is correctly formed, yet it throws the
//'transaction is aborted' SQL Exception, why? Because:
//A. you were in a transaction.
//B. You ran a SQL statement that failed.
//C. You didn't do a rollback or commit on the affected connection.
}
catch (SQLException sqle)
{
sqle.printStackTrace();
}
}
The above code produces this output for me:
start doing statement.execute
keep on truckin, keep using the last connection because what could go wrong?
org.postgresql.util.PSQLException:
ERROR: current transaction is aborted, commands ignored until
end of transaction block
Workarounds:
You have a few options:
Simplest solution: Don't be in a transaction. Set the connection.setAutoCommit(false); to connection.setAutoCommit(true);. It works because then the failed SQL is just ignored as a failed SQL statement. You are welcome to fail SQL statements all you want and PostgreSQL won't stop you.
Stay being in a transaction, but when you detect that the first SQL has failed, either rollback/re-start or commit/restart the transaction. Then you can continue failing as many SQL queries on that database connection as you want.
Don't catch and ignore the Exception that is thrown when a SQL statement fails. Then the program will stop on the malformed query.
Get Oracle instead, Oracle doesn't throw an exception when you fail a query on a connection within a transaction and continue using that connection.
In defense of PostgreSQL's decision to do things this way... Oracle was making you soft in the middle letting you do dumb stuff and overlooking it.
Check the output before the statement that caused current transaction is aborted. This typically means that database threw an exception that your code had ignored and now expecting next queries to return some data.
So you now have a state mismatch between your application, which considers things are fine, and database, that requires you to rollback and re-start your transaction from the beginning.
You should catch all exceptions and rollback transactions in such cases.
Here's a similar issue.
I think that the best solution is to use java.sql.Savepoint.
Before you execute a query which can throw SQLException, use the method Connection.setSavepoint(), and if an exception is thrown you only rollback to this savepoint, not the whole transaction.
Example code:
Connection conn = null;
Savepoint savepoint = null;
try {
conn = getConnection();
savepoint = conn.setSavepoint();
//execute some query
} catch(SQLException e) {
if(conn != null && savepoint != null) {
conn.rollback(savepoint);
}
} finally {
if(conn != null) {
try {
conn.close();
} catch(SQLException e) {}
}
}
There's been some work done on the postgresql JDBC Driver, related to this behaviour:
see https://github.com/pgjdbc/pgjdbc/pull/477
It is now possible, by setting autosave=always in the connection (see https://jdbc.postgresql.org/documentation/head/connect.html) to avoid the 'current transaction is aborted' syndroma. Overhead due to handling a savepoint around the statement execution is kept very low (see link above for details).
Try this COMMIT;
I run that in pgadmin4. It may help.
It has to do with the previous command stopping prematurely
In Ruby on Rails PG, I had created a migration, migrated my DB, but forgot to restart my development server. I restarted my server and it worked.
The reason for this error is that there are other database before the wrong operation led to the current database operation can not be carried out(i use google translation to translate my chinese to english)
You need to rollback. The JDBC Postgres driver is pretty bad. But if you want to keep your transaction, and just rollback that error, you can use savepoints:
try {
_stmt = connection.createStatement();
_savePoint = connection.setSavepoint("sp01");
_result = _stmt.executeUpdate(sentence) > 0;
} catch (Exception e){
if (_savePoint!=null){
connection.rollback(_savePoint);
}
}
Read more here:
http://www.postgresql.org/docs/8.1/static/sql-savepoint.html
The issue has been fixed in Infinispan 5.1.5.CR1: ISPN-2023
I had the same issue but then realised there is a table with the same name in the database. After deleting that I was able to import the file.
This can happen if you are out of disk space on the volume.
For me issues was, driver wasn't installed. I downloaded the driver and pasted in ~/Library/Tableau/Driver(mac) folder & it worked.
I faced this error in my DB application tool because there is one uncommited transaction.
And i'm trying to run a select query. so that gave me this error.
You can fix these either running
commit;
or
rollback;
This is very weird behavior of PostgreSQL, it is even not " in-line with the PostgreSQL philosophy of forcing the user to make everything explicit" - as the exception was caught and ignored explicitly. So even this defense does not hold. Oracle in this case behaves much more user-friendly and (as for me) correctly - it leaves a choice to the developer.
I just encounter the same error. I was able to figure out the root cause by enabling the log_statement and log_min_error_statement in my local PostgreSQL.
I Referred this
I am using JDBI with Postgres, and encountered the same problem, i.e. after a violation of some constraint from a statement of previous transaction, subsequent statements would fail (but after I wait for a while, say 20-30 seconds, the problem goes away).
After some research, I found the problem was I was doing transaction "manually" in my JDBI, i.e. I surrounded my statements with BEGIN;...COMMIT; and it turns out to be the culprit!
In JDBI v2, I can just add #Transaction annotation, and the statements within #SqlQuery or #SqlUpdate will be executed as a transaction, and the above mentioned problem doesn't happen any more!
In my case i was getting this error because my file was corrupt. While iterating the records of files it was giving me the same error.
May be in future it will help to anyone. That's the only reason to post this answer.
I use spring with #Transactional annotation, and I catch the exception and for some exception I will retry 3 times.
For posgresql, when got exception, you can't use same Connection to commit any more.You must rollback first.
For my case, I use the DatasourceUtils to get current connection and call connection.rollback() manually. And the call the method recruive to retry.
Change the isolation level from repeatable read to read committed.
I was working with spring boot jpa and fixed by implementing
#EnableTransactionManagement
Attached file may help you.
I was working with spring boot jpa and fixed by implementing
#EnableTransactionManagement
Attached file may help you.