Can I rollback changes to the database using implicit savepoints? I ended up making changes(INSERTs) through my Java code that I would want to revert back.
You can use a SAVEPOINT as outlined at How to COMMIT, ROLLBACK Oracle Transactions.
Here's the SAVEPOINT snippet from it...
SAVEPOINT
Specify a point in a transaction to which later you can roll back.
Example
insert into emp (empno,ename,sal) values (109,’Sami’,3000);
savepoint a;
insert into dept values (10,’Sales’,’Hyd’);
savepoint b;
insert into salgrade values (‘III’,9000,12000);
Now if you give
rollback to a;
Then row from salgrade table and dept will be roll backed. Now you can commit the row inserted into emp table or rollback the transaction.
If you give
rollback to b;
Then row inserted into salgrade table will be roll backed. Now you can commit the row inserted into dept table and emp table or rollback to savepoint a or completely roll backed the transaction.
If you give
rollback;
Then the whole transactions is roll backed.
If you give
commit;
Then the whole transaction is committed and all savepoints are removed.
Have a look at Using Oracle Flashback Technology. Assuming your database is already set up for it then you can flashback to a time before the inserts. Though be careful if other users are also updating this table. Also, it's ony recommended if you've made a mistake and will manually flash it back, I wouldn't build this in to any code to automatically do so.
Related
I have created the following trigger in oracle-
create or replace TRIGGER TODAY_TD_INSERT AFTER INSERT ON table1
FOR EACH ROW
DECLARE
BEGIN
INSERT INTO table2 (col1
,col2
,col3
)
VALUES (:NEW.,col1
,:NEW.,col2
,:NEW.,col3
);
END;
So if any data insert in table1 the same data is inserting in table 2 also. So my question is do i need commit the data in new table2 ? So far i know we cannot use commit from trigger.
No, you do not. The session that made the change to the table on which the trigger is placed issues the commit (or rollback), and that applies to all changes made by that session.
I read that savepoints in Oracle global temporary tables delete all the data, but when I tested on Oracle 11g they worked like heap tables. Can anybody explain?
insert into table_1 values('one');
insert into table_1 values('two');
savepoint f1;
insert into table_1 values('three');
insert into table_1 values('four');
rollback to f1;
-- the records in table are 2 records just like heap tables, but I read that
-- savepoints in GTT truncates all the data
Where did you read this? I suspect not in the Oracle SQL Reference. So the explanation is simple: the author of that assertion hadn't tested the behaviour of global temporary tables. Either that or you were reading a description of some other SQL implementation, such as DerbyDB.
For the sake of completeness, let's rule out the role of transaction or session scope. Here are two global temporary tables:
create global temporary table gtt1
( col1 varchar2(30) )
ON COMMIT PRESERVE ROWS
/
create global temporary table gtt2
( col1 varchar2(30) )
ON COMMIT DELETE ROWS
/
Let's run your experiment for the one with session scope:
SQL> insert into gtt1 values('one');
1 row created.
SQL> insert into gtt1 values('two');
1 row created.
SQL> savepoint f1;
Savepoint created.
SQL> insert into gtt1 values('three');
1 row created.
SQL> insert into gtt1 values('four');
1 row created.
SQL> rollback to f1;
Rollback complete.
SQL> select * from gtt1;
COL1
------------------------------
one
two
SQL>
Same result for the table with transaction scope:
SQL> insert into gtt2 values('five');
1 row created.
SQL> insert into gtt2 values('six');
1 row created.
SQL> savepoint f2;
Savepoint created.
SQL> insert into gtt2 values('seven');
1 row created.
SQL> insert into gtt2 values('eight');
1 row created.
SQL> rollback to f2;
Rollback complete.
SQL> select * from gtt2;
COL1
------------------------------
five
six
SQL>
Actually this is not surprising. The official Oracle documentation states:
"The temporary table definition persists in the same way as the definitions of regular tables"
Basically they are heap tables. The differences are:
the scope (visibility) of the data
the tablespace used to persist data (global temporary tables write to a temporary tablespace).
I think you misunderstand - if you rollback to a savepoint then Oracle should undo all the work done after the savepoint (while still keeping any uncommitted work that was done prior to the savepoint).
For a temporary table, Oracle lazily allocates storage (a temporary segment for your session) when you put stuff in, and that when the data is done with (either at the end of the session, or at the end of the transaction, depending on the type) it can just deallocate the storage rather than individually deleting the rows, rather like what happens when you TRUNCATE a normal table.
I was interested to find out what happened if you had a savepoint before any data was put in, and rolled back to that savepoint - would Oracle deallocate the storage or would it keep the storage and delete the rows from within it?
It turns out the former - it behaves like a truncate.
SAVEPOINT f0;
SELECT * FROM v$tempseg_usage; -- Should show nothing for your session
insert into table_1 values('one');
insert into table_1 values('two');
SELECT * FROM v$tempseg_usage; -- Should show a DATA row for your session
savepoint f1;
insert into table_1 values('three');
insert into table_1 values('four');
rollback to f1; -- Undo three and four but preserve one and two
SELECT * FROM v$tempseg_usage; -- Still shows a DATA row for your session
rollback to f0; -- Undo all the inserts
SELECT * FROM v$tempseg_usage; -- row for your session has gone
The reason this matters is that when you do a normal delete - rather than a truncate - then any full scan of the table will still have to sift through all the data blocks to see if they have any data in. DML against an empty table can potentially incur a lot of I/O if the table had a lot of data in it at some time before!
I am trying to speed up some code that is doing exactly that - it isshoving some stuff into a temporary table as a scratchpad, partly so it canjoin to a permanent table, and returning a result to its caller. The temporary table is only for the benefit of this routine, so it's safe to clear it down at the end of the routine, but it might be called many times within a parent transaction, so I can't truncate (TRUNCATE is DDL and so commits the transaction) but I can't not clear it down either, or invocations within the same transaction will pick up one anothers' rows. Clearing down by a DELETE is causing quite a bit of overhead, especially as there is no index on the table and so selects against it will always full scan.
The option I am exploring is to have a SAVEPOINT at the start of the routine, do my temporary work, and then roll back to the savepoint just before it returns the result. Another option might be to put the routine inside an autonomous transaction, but it would mean porting C code to a PL/SQL stored procedure, and wouldn't work anyway if the temporary table needs to be joined to uncommitted data inserted by the caller.
Note that I did my research in 12c - there have been some improvements to temporary tables in this release (see https://oracle-base.com/articles/misc/temporary-tables) but I don't think that affects the behaviour wrt savepoints.
I have a master stored procedure which calls multiple stored procedures to write data on multiple tables, around 9-10 in one go. And once all the inserts are done, there is one commit for all of them.
I want to use data concurrency and lock tables in individual sub procedures, which does not have any commit, so
LOCK TABLE table_name IN lock_mode
will work, but will hold the table until rest of the data is been inserted in the respective tables called after this and the final commit or rollback is called, which is not a good idea. Also I don't have dbms_lock opened.
Will locking all the tables in my master stored procedures, or locking the tables in the respective sub-stored procedures is the only option??
My master stored procedure looks like this
PROCEDURE POPULATE_ALL(P_ASOFDATE DATE, P_ENTITY VARCHAR2) IS
BEGIN
POPULATE_ABC_BOOK(P_ASOFDATE);
POPULATE_XYZ(P_ASOFDATE, P_ENTITY);
POPULATE_DEF(P_ASOFDATE, P_ENTITY);
POPULATE_AAA(P_ASOFDATE, P_ENTITY);
commit;
EXCEPTION
WHEN OTHERS THEN
rollback;
P_ERROR := SQLERRM;
RAISE_APPLICATION_ERROR(-20001,
'*** Unexpected Error in POPULATE_ALL -->' ||
P_ERROR);
END POPULATE_ALL;
where POPULATE_XYZ is populating XYZ table.
It looks like you don't need locking at all. Just do your inserts without any explicit locking.
There is no way to unlock table in the middle of transaction. This operation has no ANY sense in Oracle; it can be useful only if database supports dirty reads. Table lock finishes only if
commit,
rollback or
rollback to savepoint before lock established
executed.
I dropped a table and tried to rollback, but to no use. Will it ever work like this or am I playing wrong here?
As from most of the comments I am clear that DDL statements cannot be undone by rollback but only by FLASHBACK.
I tried undoing
DELETE FROM STUDENT;
It still it can't be undone:
My order of execution was
INSERT,
DELETE FROM ,
ROLLBACK.
I don't believe rollback will undo schema changes.
ROLLBACK without a savepoint qualifier will roll back the entire current transaction.
For DDL statements, there is no current transaction to rollback. The DDL statement implicitly generates a COMMIT before the statement starts and after it completes. So if you issue a ROLLBACK following a DROP, no work has been done in the current transaction so there is nothing to roll back.
For DML statements, you'll roll back the entire current transaction. If you do
INSERT
DELETE
ROLLBACK
your transaction begins when you execute the INSERT operation. So when you issue the ROLLBACK, you are rolling back both the INSERT and the DELETE so you're back to having no data in the table (assuming you started with no data). If you COMMIT after the INSERT then the next transaction would begin with the DELETE and your ROLLBACK will only roll back the DELETE operation. Alternately, you can declare a savepoint after the INSERT and roll back to the savepoint
SQL> create table foo( col1 number );
Table created.
SQL> insert into foo values( 1 );
1 row created.
SQL> savepoint after_insert;
Savepoint created.
SQL> delete from foo;
1 row deleted.
SQL> rollback to savepoint after_insert;
Rollback complete.
SQL> select * from foo;
COL1
----------
1
Rollback does not undo schema changes, but to undo drop table operations you can check:
http://docs.oracle.com/cd/B19306_01/backup.102/b14192/flashptr004.htm
From the documentation:
Oracle Database implicitly commits the current transaction before and after every DDL statement.
This means that you cannot ROLLBACK a DDL statement (that is, a schema change).
Rollback will never undo Data Definition commands such as drop table alter table etc.
Dropping a table changes the structure of the database (using DDL statements like CREATE, DROP, ...).
COMMIT and ROLLBACK only work on the data which is exchanged with the database using DML statements (like INSERT, UPDATE, ...).
So, no it will never work like this.
To rollback ddl changes you need to use Flashback.
Rollback:
Discard all pending changes by using the ROLLBACK statement. Following a ROLLBACK statement:
Data changes are undone.
The previous state of the data is restored.
The locks on the affected rows are released.
Example
While attempting to remove a record from the TEST table, you can accidentally empty the table. You can correct the mistake, reissue the proper statement, and make the data change permanent.
DELETE FROM test;
25,000 rows deleted.
ROLLBACK;
Rollback complete.
DELETE FROM test
WHERE id = 100;
1 row deleted.
SELECT *
FROM test
WHERE id = 100;
No rows selected.
COMMIT;
Commit complete
After giving commit we can't rollback.
Does the after Update trigger will kick off if there is a rollback?
Scenario: Lets say we update a table A and the trigger on table A kicks off and updates another table B with the details. If there is a rollback issued on table A due to some processing error, will the trigger cause the table B to rollback the change?
Yes, it will.
Triggers work in scope of the DML statement's transaction (either started by you explicitly or by the DML statement itself implicitly)
When this transaction is rolled back, all changes made by the triggers are also rolled back.
However, if you put
PRAGMA autonomous_transaction
into the trigger definition, the trigger will start its own transaction which you should commit before the trigger completes.
Just a note - if you define AFTER UPDATE statement level trigger (without FOR EACH ROW clause) it will not fire if DML statement on the table fails and is rolled back.