How to start a transaction in ODBC? - sql-server

How do you start a transaction in ODBC? Specifically i happen to be dealing with SQL Server, but the question can work for any data source.
In native T-SQL, you issue the command:
BEGIN TRANSACTION
--...
COMMIT TRANSACTION
--or ROLLBACK TRANSACTION
In ADO.net, you call:
DbConnection conn = new SqlConnection();
DbTransaction tx = conn.BeginTransaction();
//...
tx.Commit();
//or tx.Rollback();
In OLE DB you call:
IDBInitialize init = new MSDASQL();
IDBCreateSession session = (init as IDBCreateSession).CreateSession();
(session as ITransactionLocal).StartTransaction(ISOLATIONLEVEL_READCOMMITTED, 0, null, null);
//...
(session as ITransactionLocal).Commit();
//or (session as ITransactionLocal).Rollback();
In ADO you call:
Connection conn = new Connection();
conn.BeginTrans();
//...
conn.CommitTrans();
//or conn.RollbackTrans();
What about ODBC?
For ODBC, Microsoft gives a hint on their page Transactions in ODBC:
An application calls SQLSetConnectAttr to switch between the two ODBC modes of managing transactions:
Manual-commit mode
All executed statements are included in the same transaction until it is specifically stopped by calling SQLEndTran.
Which means i just need to know what parameters to pass to SQLSetConnectAttr:
HENV environment;
SQLAllocEnv(&environment);
HDBC conn;
SQLAllocConnect(henv, &conn);
SQLSetConnectAttr(conn, {attribute}, {value}, {stringLength});
//...
SQLEndTran(SQL_HANDLE_ENV, environment, SQL_COMMIT);
//or SQLEndTran(SQL_HANDLE_ENV, environment, SQL_ROLLBACK);
But the page doesn't really give any hint about which parameter will start a transaction. It might be:
SQL_COPT_SS_ENLIST_IN_XA
To begin an XA transaction with an XA-compliant Transaction Processor (TP), the client calls the Open Group tx_begin function. The application then calls SQLSetConnectAttr with a SQL_COPT_SS_ENLIST_IN_XA parameter of TRUE to associate the XA transaction with the ODBC connection. All related database activity will be performed under the protection of the XA transaction. To end an XA association with an ODBC connection, the client must call SQLSetConnectAttr with a SQL_COPT_SS_ENLIST_IN_XA parameter of FALSE. For more information, see the Microsoft Distributed Transaction Coordinator documentation.
But since i've never heard of XA, nor do i need MSDTC to be running, i don't think that's it.
maruo answered it. But to clarify:
HENV environment;
SQLAllocEnv(&environment);
HDBC conn;
SQLAllocConnect(henv, &conn);
SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, SQL_IS_UINTEGER);
//...
SQLEndTran(SQL_HANDLE_ENV, environment, SQL_COMMIT);
//or SQLEndTran(SQL_HANDLE_ENV, environment, SQL_ROLLBACK);
SQLSetConnectAttr(conn, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER);

ODBC can operate in two modes: AUTOCOMMIT_ON and AUTOCOMMIT_OFF. Default is AUTOCOMMIT_ON. When Autocommit is ON each command you start using a Session Handle associated with that Connection will be Auto-Committed.
Let's see how "manual commit" (alias AUTOCOMMIT_OFF) works.
First you switch AUTOCOMMIT OFF Using something like this:
if (!SQL_SUCCEEDED(Or=SQLSetConnectAttr(Oc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_OFF,
SQL_IS_UINTEGER))) {
// error handling here
}
Where "Oc" is the connection handle.
Second You run all commands as usual: Prepare / Execute statements, Bind Parameters, etc.... There's NO specific command to "START" a transaction. All commands after you switched Autocommit OFF are part of the transaction.
Third You commit:
if (!SQL_SUCCEEDED(Or=SQLEndTran(SQL_HANDLE_DBC, Oc, SQL_COMMIT))) {
// Error handling
}
And - again - all new commands from now on are automatically part of a new transaction that you will have to commit using another SQLEndTran command as show here above.
Finally... to switch AUTOCOMMIT_ON Again:
if (!SQL_SUCCEEDED(Or=SQLSetConnectAttr(Oc, SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_ON, SQL_IS_UINTEGER))) {
// Error Handling
}

Related

Isolation level not working in spring boot

Recently I started working with isolation levels, but specifying isolation level in #Transactional annotation does not seems to work in spring boot. I tried a lot of different things but I cannot get it to work, below is my code.
#Transactional(isolation=Isolation.READ_UNCOMMITTED)
public void updateWalletAddresses(List<RegisterWallet> walletMetaCollection) throws Exception{
Transaction tx =null;
Session session =null;
if(sessionFactory == null){
return;
}
session = sessionFactory.openSession();
try{
String sql = "select * from user";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(User.class);
List<User> userlist=query.list();
int i=0;
while(i<userlist.size()){
System.out.println(userlist.get(i).getEmail());
i++;
}
}catch(Exception e){
throw e;
}
}
before executing the above walletservice method I am starting a transaction
in mysql client but I am not committing it so that I have dirty data.
After that I executed above code but it does not print uncommitted data even though I specified transaction read uncommitted.
code for starting transaction in mysql is
set autocommit=0;
start transaction;
insert into user (name,email,password,roleid,username)
values("prashank","myemail#gmail.com","password",1,"prashank");
Note: as I am not committing the transaction then above insert cause dirty read problem. I am not able to read uncommitted data
Note: Similarly any other isolation level are not working .
Please help
Double check your DB engine with
SHOW TABLE STATUS LIKE 'table_name';
If is MyISAM, then transactional is not supported,
use below to create InnoDB, which support transaction, then your case should work
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect
Also I don't think
set autocommit=0;
is required bcz start transaction will automatically disable it

How to use prepared statements in lua-dbi?

I want to use prepared statements in my lua scripts. As mentioned in my previous post, people recommend using lua-dbi. Unfortunately there is little documentation available. I just need a basic script that connects to the database with credentials, and use prepared statements (prefered with a bind function to names in the query). Anyone experienced with this?
You can find it on the project's wiki pages:
Establishing connection: https://code.google.com/p/luadbi/wiki/DBDDriverConnection
require('DBI')
-- Create a connection
local dbh = assert(DBI.Connect('Driver', db, username, password, host, port))
-- set the autocommit flag
-- this is turned off by default
dbh:autocommit(true)
-- check status of the connection
local alive = dbh:ping()
-- prepare a connection
local sth = assert(dbh:prepare(sql_string))
-- commit the transaction
dbh:commit()
-- finish up
local ok = dbh:close()
where, you'd update the part dbh:prepare as per your needs.

setTransactionIsolation() does not work

What options can be? Why the isolation level of DataBase doesn't change?
I have local DataBase and connect to them with:
connect = DriverManager.getConnection("jdbc:sqlserver://"
+ "localhost;IntegratedSecurity=True;"
+ "databaseName=" + TestsConstants.DB_NAME + "; ");
Then I use this method for set TRANSACTION_READ_UNCOMMITTED level:
public static void setTransaction() {
try {
connect.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
connect.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
I recheck isolation level:
System.out.println(connect.getTransactionIsolation());
And receive 1. That's right.
Then I insert some data in my DB, and stops on BreackPoint in my Java code.Transaction not close yet.
Now I try to read data with SELECT operator from other process, for example from "Microsoft SQL Server Management Studio" or from "Micosoft Visual Studio" or from my local WebSite. And it`s fail.
Query execution freezes until Transaction is not commiting from Java code.
Help me, please, what is wrong in this algorithm?
What can I do for READ_UNCOMMITTED changes from DB?
In this way I set up the isolation-penetrating ability of my transaction but not the isolation of it. To reach the data from another transaction I have to change the isolation level of this another transaction.

Hibernate Lock table

Seam 2.2 , Jboss 6.1, hibernate 3.5.6 and MSQL Server 2008
and have a function like this.
public void deliverFile() {
EntityManager jobbEntityManager = (EntityManager)Component.getInstance("jobbEntityManager");
JobbStatusInterface jobbStatus = new JobbStatus();
jobbStatus.setStatus(PluginStatus.INITIATED);
jobbEntityManager.persist(jobbStatus);
/**
Code here to save a file that takes a minutes
**/
jobbStatus.setStatus(PluginStatus.DONE);
jobbEntityManager.flush();
}
public void checkJobb(){
EntityManager jobbEntityManager = (EntityManager)Component.getInstance("jobbEntityManager");
jobbEntityManager.createQuery("from JobbStatus", JobbStatus.class).getResultList();
}
i have a poll on checkJobb every 10 seconds so if the deliveryFile() function is executed.
the checkJobb queues upp and stops at the query, so when deliveryFile() functions finishes it finish all 6 checkJobbs() at once.
Even if i select from the database directly it is locked and finishes it's query after deliveryFile() is done.
Is there anyway to solove this so i can do my checkJobb() while deliveryFile is executing?
Not sure what you want to achieve using the above code. If you want to check whether a job is initiated by loading the job status in-between..it may not be possible. Since the data is not committed yet and you are using a different session in the other function..you may not be able to see the data.
Only the last value of the status will be committed to the database.
READ_COMMITTED_SNAPSHOT instead to normal READ_COMMITTED isolation.
ALTER DATABASE <dbname> SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
ALTER DATABASE <dbname> SET READ_COMMITTED_SNAPSHOT ON;
ALTER DATABASE <dbname> SET MULTI_USER;

SQL Server transactions - whole db locked?

I have a problem on specific SQL Server 2008 customer installation. I wrote the code below to simulate the problem which happens in more complex system. There are two connections (each one with own transaction) opened and each connection modifies a table. Modified tables do not relate to each other. On development platform and other existing customer installations the code works fine. Only at one specific customer we have a problem that the second update in nested transaction hangs. I could make a workaround by moving the first update after commit of nested transaction.
I assume in that specific installation the db is configured to lock down the whole db when a transaction is started. But using DBCC useroptions results in very similar output on systems where the code works and this one.
How can I identify what's wrong here ?
Here's DBCC useroptions output from the problematic DB (SQL Server 2008) and my simplified test code:
textsize 2147483647
language Deutsch
dateformat dmy
datefirst 1
lock_timeout -1
quoted_identifier SET
arithabort SET
ansi_null_dflt_on SET
ansi_warnings SET
ansi_padding SET
ansi_nulls SET
concat_null_yields_null SET
isolation level read committed
DbCommand command1 =null, command2 = null;
try
{
const string cs = "Provider=SQLOLEDB.1;...";
// open command and a transaction with default isolation level
command1 = DbAccessFactory.CreateInitialzedCommand("System.Data.OleDb", cs, true);
// select something
command1.CommandText = "select * from plannerOrderHeaders where ...";
DataSet ds = BusinessCasesHelper.Fill(command1, null, "plannerOrderHeaders");
// make some changes in the table
...
// update the table in DB
BusinessCasesHelper.Update(command1, ds, true);
// open command and a transaction with default isolation level on the same CS as command1
command2 = DbAccessFactory.CreateInitialzedCommand("System.Data.OleDb", cs, true);
// select something
command2.CommandText = "select * from mdOmOrders where ...";
ds = BusinessCasesHelper.Fill(command2, null, "mdOmOrders");
// make some changes
...
// update the db
BusinessCasesHelper.Update(command2, ds, true);
command2.Transaction.Commit();
cmd2Commited = true;
command1.Transaction.Commit();
}
catch (Exception e) {...}
And why do you use ""Provider=SQLOLEDB.1" to access MS SQL Server?
And why do you commit instead of closing and disposing?
I can only guess how the mentioned BusinessCasesHelper, DbAccessFactory, etc. are implemented.
But your question implies that your consider your snippet opening transaction inside another transaction in the same context (i.e. on one connection) while I see that they are probably opening two connections which are not being disposed.

Resources