I have an application with a MySQL database. This database has a table A and a trigger when a new row is inserted in this table.
Now, when I create new entity (associated to this table), and save it with session.save(aEntity); in a transaction, but when I execute the save, MySQL activates the trigger of table A and creates a new entry in some other table, but the row in table A is not saved until I call transaction.commit().
I sometimes need do rollback transaction.rollback() but the trigger would create the new entry in other table and it won't be deleted.
How can i do it?
When you call save, Hibernate attached the entity to the Persistence Context and the database row will be added during flush. For MySQL, if you use the IDENTITY entity identifier generator, the insert will happen right away.
The trigger might add a record in some other table, but that's also part of the current database transaction (assuming you use InnoDB), so when you rollback the transaction, neither the TableA nor the other table will persist the pending changes.
So you should be fine.
Update
I'll try to explain. I have a table A and a table B. In MySQL, I have a
trigger that when a row is created in A, the trigger creates a row in B
with the same identifier of the row in A, (but without foreign key). In the
Hibernate Session, I created a transaction and make an entity of A and save it. The
trigger is activated and instantly creates an entry in B, but there
is still no entry in A because I didn't commit the transaction yet. After I do a
rollback, the table A is reverted but the row in B created by the trigger
is still there, referencing an entry in A that does not exist. B does not
have foreign keys and uses MyISAM.
This is not a typical DB setup and this is not really a Hibernate problem. You'd bump into this issue with plain JDBC too. The problem is that Table A uses the transaction-aware InnoDB storage engine while Table B works in auto-commit mode, due to being configured to use MyISAM.
Related
I'm using a transaction to make alterations to my database, this way if anything fails during the alterations i can roll back without any harm having been done.
However, since i run my queries based on a list of queries that puts my database in it's final state (any time i need to make changes, i simply add a new rule to the list), it fails when i try to drop a column that was added during the same transaction.
Example:
START TRANSACTION;
ALTER TABLE "servers" ADD COLUMN "test" INTEGER NOT NULL;
ALTER TABLE "servers" DROP COLUMN "test";
COMMIT;
When I run this, i get something along the lines of
column "test" in the middle of being added, try again later
I understand why this is happening, since the transaction hasn't been committed yet the column doesn't exist to be dropped. However is there a way around this specifically so that I can drop the column in the same transaction? Or at least queue it to be deleted once the transaction is committed.
I feel it worth noting that the queries being run within the transaction are generated using Eloquent ORM Blueprints.
MySQL doesn't support table changes in transactions. From the documentation:
Some statements cannot be rolled back. In general, these include data definition language (DDL) statements, such as those that create or drop databases, those that create, drop, or alter tables or stored routines.
I need to rename two tables in one atomic operation so that user will never be able to see the database in its intermediate state.
I'm using MySQL and noticed that this case is perfectly described in the documentation:
13.3.3 Statements That Cause an Implicit Commit
The statements listed in this section (and any synonyms for them)
implicitly end any transaction active in the current session, as if
you had done a COMMIT before executing the statement
[...]
Data definition language (DDL) statements that define or modify
database objects. ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME,
ALTER EVENT, ALTER PROCEDURE, ALTER SERVER, ALTER TABLE, ALTER VIEW,
CREATE DATABASE, CREATE EVENT, CREATE INDEX, CREATE PROCEDURE, CREATE
SERVER, CREATE TABLE, CREATE TRIGGER, CREATE VIEW, DROP DATABASE, DROP
EVENT, DROP INDEX, DROP PROCEDURE, DROP SERVER, DROP TABLE, DROP
TRIGGER, DROP VIEW, INSTALL PLUGIN (as of MySQL 5.7.6), RENAME TABLE,
TRUNCATE TABLE, UNINSTALL PLUGIN (as of MySQL 5.7.6).
But maybe there's some kind of workaround or something like this?
My situation looks like this:
I have a current data set in the table named current
I gathered a new data set in the table named next
I need to rename the current table to the current_%current_date_time% and the next table to the current in one atomic operation
Well, easy...
RENAME TABLE current TO current_20151221, next TO current;
as is stated in the manual. There it says that it's an atomic operation. Just to clear this up, implicit commits have nothing to do with it. That's a different story. That just says, that those statements end an open transaction.
My client wants to maintain audit at column level. He wants a table which stores all the audits i.e. at column level. I have decided on a table structure. i.e
id,tablename,tablecolumn,primarkey,oldvalue,newvalue,date
But i was wondering how will i check for each column level changes. Do i have to check each one manually like old.columnname <> new.columnname and then add into audit table ?
Is there any other way to do it.
When I was given the same task, I've created several stored procedures for modifying table data and restricted CUD operations on table to force users to use only stored procedures.
SPs were actually performing the action requested (i.e. create, update or delete a row in table) plus adding a line to the audit table for every action.
This might be quite inefficient from DB optimization point of view but I think it gives you the most of auditing as update operation and audit are automatically put in a transaction and update can not be completed without adding an audit entry.
I have implemented a typical "audit log" trigger in Mysql version 5.5. I use AFTER INSERT to copy inserted rows from table user into my 'audit_log' table.
So for this sequence:
BEGIN;
insert into user (name) values ('joe');
<--trigger fires, adds new row to audit_log table-->
COMMIT;
Then I get a new row in 'audit_log' with 'joe'. Great.
However, it appears that the results of my trigger are applied even if the insert which fired the trigger is aborted by its enclosing transaction.
So for this sequence:
BEGIN;
insert into user (name) values ('mary');
<--trigger fires, adds new row to audit_log table-->
ROLLBACK;
I STILL end up with a new row 'mary' in audit_log, which refers to data that was never committed to my user table. This seems pretty clearly wrong.
It appears that trigger updates performed in Postgres execute within the original transaction, which is what I would expect to happen. Anyone have experience with this in MySQL? Perhaps there is a setting I have wrong?
I note that this question implies that all updates happen in the original transaction. However, the answer refers to the Mysql manual page on triggers, which in fact has no mention of "transation" at all.
Turns out my audit table was using the MyISAM engine which of course prevented it from obeying the transaction properly.
My colleague says I owe Larry Ellison an apology.
Larry, I'm sorry I doubted the transactional semantics of Mysql.
i'm using mysql db & java, so in my application i need to use trigger, but i need to make it save while inserting or updating.
when insering new record in table A, trigger will do the work to insert some information in another table B.
also when doing update for records in table A, trigger will update records for table B.
if transaction during update or insrt rolledback, does this rolled back any changes done by the trigger.??!!
Yes, if the transaction is rolled back, the work done by the trigger will also be rolled back (unless you do some monkeying with transaction scoping inside the trigger to specifically prevent this)