What I am trying to do is to call a function whenever there is an update to the DB. I use the 'Committed transaction information' aspect to get the status on the DB update.
pg_xact_commit_timestamp(xid)
SELECT pg_xact_commit_timestamp(xmin) ts FROM "TABLE_NAME" WHERE pg_xact_commit_timestamp(xmin) IS NOT NULL;
The problem: After the first-iteration of update to the DB. The commit_timestamp(xmin) would never be empty. Is there a way that once the functions is executed we can set the commit_timestamp list to be empty?
My requirement: To execute a function only when there is an new (without any information on the previous update) update
I understand that, this is over use of an inbuilt-function.
E.g.
Connection DBconn = DBConnection.connect(url,user,password);
Boolean DBStatus = checkDBStatus(DBconn, configuration);
if(DBStatus) {
System.out.println("DB updated recently");
feedbackStatusJSON = runBusinessLogic();
}
else {
System.out.println("DB not updated");
}
Related
If I call a stored procedure using JdbcIO.Write is it possible to capture the ID (primary key) if the stored procedure returns this data?
public JdbcIO.Write<MyObject> writeMyObject() {
final String UPSERT_MY_OBJECT = "EXEC [MySchema].[UspertMyObject] ?,?,?";
// If my stored procedure returns the generated or existing ID
// is it possible to update the object I'm writing with the ID?
return JdbcIO.<MyObject>write()
.withDataSourceConfiguration(myDataSourceConfig)
.withStatement(UPSERT_MY_OBJECT)
.withPreparedStatementSetter((JdbcIO.PreparedStatementSetter<MyObject>) (myObject, ps) -> {
ps.setInt(1, myObject.getFieldOne());
ps.setString(2, myObject.getFieldTwo());
ps.setString(3, myObject.getFieldThree());
});
}
I don't think it's possible but, as a workaround, you can wait for write's finish (with Wait transform, see an example there) and then read them from database.
I am using entity framework but doing my operations with raw queries. My operations are like following:
Check if recırd exist with integration_id
Delete record if exit
Insert new record
So I am using transaction
using (var transaction = await _context.Database.BeginTransactionAsync())
{
var isExist = await IsExist(id);
if (isExist)
{
var deleteQuery = "delete from ....";
await _context.Database.ExecuteSqlRawAsync(deleteQuery);
}
var insertQuery = "insert into ...";
await _context.Database.ExecuteSqlRawAsync(insertQuery);
}
if insert operation fails, does deleted record rollback?
UPD: https://learn.microsoft.com/en-us/ef/core/saving/transactions#controlling-transactions
transaction will auto-rollback when disposed if either commands fails
So, my code below may be overkill on the catch side, but Commit is still essential :)
======================
I believe the correct way of using transaction would be following:
using (var transaction = await _context.Database.BeginTransactionAsync())
{
try
{
var isExist = await IsExist(id);
if (isExist)
{
var deleteQuery = "delete from ....";
await _context.Database.ExecuteSqlRawAsync(deleteQuery);
}
var insertQuery = "insert into ...";
await _context.Database.ExecuteSqlRawAsync(insertQuery);
// there we tell DB to finish the transaction,
// mark all changes as permanent and release all locks
transaction.Commit();
}
catch (Exception ex)
{
// there we tell DB to discard all changes
// made by this transaction that may be discarded
transaction.Rollback();
// log error
}
}
But I never used BeginTransaction*Async* personally before.
This method doesn't start transaction on it's own. If you need to execute queries in transaction you need to first call
BeginTransaction(DatabaseFacade, IsolationLevel) or UseTransaction.
Reference
learn.microsoft.com
So in your case it will execute queries in a transaction and roll back all the queries if any of the query failed
I would like to safely drop Firebird table. I have 3 transactions, one to recreate table, one to do something with the table (just inserting a single row to keep it simple) and the last one to drop the table.
If all these txns are executed using single connection these works. If I use a different connection, then the drop command fails with
lock conflict on no wait transaction
unsuccessful metadata update
object TABLE "DEMO" is in use
private static void Test() {
using var conn1 = new FbConnection(ConnectionString);
using var conn2 = new FbConnection(ConnectionString);
using var conn3 = new FbConnection(ConnectionString);
conn1.Open();
conn2.Open();
conn3.Open();
ExecuteTxn(conn1, cmd => {
cmd.CommandText = "recreate table demo (id int primary key)";
cmd.ExecuteNonQuery();
});
ExecuteTxn(conn2, cmd => {
cmd.CommandText = "insert into demo (id) values (1)";
cmd.ExecuteNonQuery();
});
ExecuteTxn(conn3, cmd => {
cmd.CommandText = "drop table demo";
cmd.ExecuteNonQuery();
});
}
private static void ExecuteTxn(FbConnection conn, Action<FbCommand> todo) {
using (var txn = conn.BeginTransaction())
using (var cmd = conn.CreateCommand()) {
cmd.Transaction = txn;
todo(cmd);
txn.Commit();
}
}
I realized that changing the transaction options as
txn = conn.BeginTransaction(new FbTransactionOptions { TransactionBehavior = FbTransactionBehavior.Wait }))
seems to help. But I'm not sure if this the right thing to do or just a coincidence...
Using Firebird 3.0.6, FirebirdSql.Data.FirebirdClient.dll 7.5.0.0
As far as I understand it, the problem has to do with how Firebird caches certain metadata, which might result in existence locks being retained, which will prevent deletion of the object. In addition, it is possible - this is a guess! - that the Firebird ADO.net provider retains the statement handle with the insert statement prepared, which will also result in an existence lock being retained.
Executing in a WAIT transaction (optionally with a timeout) is considered an appropriate workaround by the Firebird core developers.
For reference, see the following tickets:
CORE-3766 - Transaction can`t change metadata if it is run in no_wait and there is another connect that once had queried these metadata
CORE-6382 - Triggers accessing a table prevent concurrent DDL command from dropping that table
In certain cases, switching from Firebird ClassicServer or Firebird SuperClassic to Firebird SuperServer can also prevent this problem.
However, if you want a more in-depth explanation, it might be worthwhile to ask this question on the firebird-devel mailing list.
Which Transaction IsolationLevel is the best to guarantee that only 1 Datarow get created.
Assuming SQL Server 2012 and EntityFramework 6 is used.
using(var db = new XyzContext())
{
using(var dbContextTransaction = db.Database.BeginTransaction(???))
{
try
{
Item obj = db.Item.SingleOrDefault(o => o.Hashcode.Equals(hashCode));
//it is possible that 2 threads are coming through here and both have obj == null
if(obj == null)
{
obj = db.Item.Add(new Item
{
Hashcode = hashCode,
State = 0,
});
}
db.SaveChanges();
dbContextTransaction.Commit();
}
catch(Exception)
{
dbContextTransaction.Rollback();
}
}
}
If your scenario was update, then Snapshot is good,(which is a default behavior of ef 6).
But in your case which is insert, then most of methods would not work properly.
You must be sure that your lock escalation level is table(which is default).
Then apply RepeatableRead transaction mode.
It prevents other threads from reading the table, until first thread is done.
It's better to have a unique constraint column on one of your columns instead of this method.
Or create a special table in your sql server database, then put row lock on specific record of that table before your main query & insert, then do your works, there is not bottle neck for your other operations with that table and is fast enough.
Good luck
I have this method that delete object if exist and insert the new instance any way :
internal void SaveCarAccident(WcfContracts.BLObjects.Contract.Dtos.CarAccident DTOCarAccident)
{
using(var context = BLObjectsFactory.Create())
{
context.ContextOptions.ProxyCreationEnabled = false;
CarAccident NewCarAccident = ConvertToCarAccident(DTOCarAccident);
CarAccident carFromDB = context.CarAccident.FirstOrDefault(current => current.CarAccidentKey.Equals(NewCarAccident.CarAccidentKey));
if(carFromDB != null)
context.CarAccident.DeleteObject(carFromDB);
context.CarAccident.AddObject(NewCarAccident);
context.SaveChanges();
}
}
I sometimes get exception that the key already exist in table.
I wnted to know if the way I save the changes is a problem (saving after delete and insert and not after each one)
At the time I got the exception there were few clients that activate the method at the same time I blocked other clients from writing already, but is this may be the problem ?
Thanks
Eran