What is useLocalSessionState used for? - mysql

I had an issue with MySQL db where the setAutocommit were being logged many times even though there was no autocommit mode change. For example, if I call setautocommit(false) 5 times, I see 5 queries in the query log saying set autommit=0;
This is usually not supposed to happen as the autocommit mode hasnt changed. The query should be sent only when I am changing the autocommit mode i.e. say 1 to 0.
When I did some looking in the MySQL connection class implementation, I figured that they check useLocalSessionState value to decide whether they want to execute the query or not?
if ((getUseLocalSessionState()) && (this.autoCommit == autoCommitFlag)) {
needsSetOnServer = false;
}
So, even though this.autocommit & autocommit flag are same, needsSetOnServer is NOT set to false becuase useLocalSessionState is defaulted to false.
Once I add useLocalSessionState = true in my connection URL, I dont see the unnecessary query logs.
So, my questions are :
What is the significance of useLocalSessionState ? Why is it used generally?
Is it safe to set useLocalSessionState = true?
PS : I see that SQL Server handles this kind of a scenario without any such dependencies i.e. (Code snippet from SQLServerConnection
if (paramBoolean == this.databaseAutoCommitMode) {
return;
}

Referring to http://dev.mysql.com/doc/connector-j/en/connector-j-reference-configuration-properties.html:
Should the driver refer to the internal values of autocommit and transaction isolation that are set by Connection.setAutoCommit() and Connection.setTransactionIsolation() and transaction state as maintained by the protocol, rather than querying the database or blindly sending commands to the database for commit() or rollback() method calls?
My interpretation of this (after looking to the code of the MySQL JDBC driver) is that instead of issuing e.g. a SELECT ##session.tx_read_only, it checks the readOnly property of the connection class:
ConnectionImpl.java (MySQL JDBC connecotr 5.1.31):
public boolean isReadOnly() throws SQLException {
return this.isReadOnly(true);
}
public boolean isReadOnly(boolean useSessionStatus) throws SQLException {
if(useSessionStatus && /*...*/ && !this.getUseLocalSessionState()) {
//...
rs = stmt.executeQuery("select ##session.tx_read_only");
//...
} else {
return this.readOnly;
}
}
Furthermore, it only issues a SQL command for setting the read only state if useLocalSessionState is false:
public void setReadOnlyInternal(boolean readOnlyFlag) throws SQLException {
if((/*...*/ !this.getUseLocalSessionState()) {
this.execSQL((StatementImpl)null, "set session transaction " + (readOnlyFlag?"read only":"read write"), -1, (Buffer)null, 1003, 1007, false, this.database, (Field[])null, false);
}
this.readOnly = readOnlyFlag;
}
I assume that the same applies for the auto-commit and transaction isolation level properties.

Related

executeUpdate in createQuery does not update my database

public void updateUserState(User user) {
Session sess=getSession();
sess.setFlushMode(FlushMode.MANUAL);
String queryStr = "update User usr set usr.logCount = :logCount , usr.isLocked = :isLocked , usr.lastLogin = :lastLogin where usr.userId=:userId";
Query query=null;
query = sess.createNativeQuery(queryStr);
query.setParameter("logCount", user.getLogCount());
query.setParameter("isLocked", user.getIsLocked());
query.setParameter("lastLogin", user.getLastLogin());
query.setParameter("userId", user.getUserId());
query.executeUpdate();
}
This is my code. This does not update mu user table in database , neither does this throw any error. It reflects the correct value till set parameter but after executeUpdate, I cannot see any update in my table. It would be really nice if anyone of you can tell me, where am I going wrong. Thanks in advance!
According to the hibernate documentation flush type MANUAL assume:
The Session flushing is delegated to the application, which must call Session.flush() explicitly in order to apply the persistence context changes.
So, you should explicitly call Session.flush() in the end of your method.
Also your updateUserState method should be ran inside a transaction:
Session sess = getSession();
sess.setFlushMode(FlushMode.MANUAL);
Transaction txn = sess.beginTransaction();
// ...
query.executeUpdate();
sess.flush();
txn.commit();
session.close();

java.sql.ResultSet.next() description

I've a question about the same point in the next(), previous() & absolute()
in these boolean methods
Does the position of the cursor change if it returns false
for example:
1)Incase of next():
ResultSet rs = new Result();
while (rs.next())
System.out.println(rs.getInt(1));
rs.next(); // it will return false but will the cursor be after after last ?!
2)Incase of absolute():
ResultSet rs = new Result();
rs.absolute(15); //assuming I've only 10 rows it will return false but will the cursor be advanced ?
if the answer is that they change only when they return true so why there is a method gets me out of the range of rows as afterLast() ?
BTW I've checked java docs and I didn't found an answer to my question...
afterLast() can be used to forcefully exhaust a RestulSet. Another usage, if the ResultSet is scroallable, is to iterate over it backwards with the previous() method:
ResultSet rs = ...;
rs.afterLast();
while (rs.previous()) {
// do something.
}
Admittedly, I can't fathom any good reason to do this, but it's doable.
EDIT:
With regard to the question what will happen if you call next() on a ResultSet that's already positioned after the last row - it depends on the implementation of the JDBC driver. Some drivers just silently return false and do not change the state of the ResultSet, while some may fail the call with an SQLException. More specifically, do quote the documentation:
If the result set type is TYPE_FORWARD_ONLY, it is vendor specified whether their JDBC driver implementation will return false or throw an SQLException on a subsequent call to next.

sql transactionscope row level locking

Question on locking scope in SQL Server (SQL Azure to be precise).
Scenario
A bunch of records are selected using a select statements.
We loop through the records
Each record is updated within a transactionscope -
(each record is independent of the other and there is no need for a table lock)
Am I right in assuming that the above would result in a row level lock of just that particular record row?
Framing the question within the context of a concrete example.
In the below example would each item in itemsToMove be locked one at a time?
var itemsToMove = ObjectContext.Where(emp => emp.ExpirationDate < DateTime.Now)
foreach(Item expiredItem in itemsToMove)
{
bool tSuccess = false;
using (TransactionScope transaction = new TransactionScope())
{
try
{
//We push this to another table. In this case Azure Storage.
bool bSuccess = PushToBackup();
if(bSuccess)
{
ObjectContext.DeleteObject(expiredItem);
}
else
{
//throw an exception or return
return false;
}
ObjectContext.SaveChanges();
transaction.Complete();
tSuccess = true;
}
catch (Exception e)
{
return cResults;
}
}
}
if (tSuccess)
{
ObjectContext.AcceptAllChanges();
}
Provided that there isn't any outer / wrapper transaction calling your code, each call to transaction.Complete() should commit and release any locks.
Just a couple of quick caveats
SQL will not necessarily default to row level locking - it may use page level or higher locks (recommend that you leave SQL to its own devices, however)
Note that the default isolation level of a new TransactionScope() is read serializable. This might be too pessimistic for your scenario.

Symfony/Doctrine: Transaction involving multiple objects/functions

I want to perform a certain set of operations on multiple models/tables using Doctrine with Symfony. Here is what I'm doing:
public function myFunc()
{
$conn = Doctrine_Manager::connection();
try {
$conn->beginTransaction();
$prop_trans->save($conn);
self::doSomething1($conn);
$bill_appor->save($conn);
// Final Committ
$conn->commit();
return $prop_trans;
} catch (Exception $exc) {
if ($conn)
$conn->rollback();
throw $exc;
}
}
public function doSomething($conn)
{
$obj = new Trans();
// this function might create & save another child record
$obj->doSomething2($conn);
$obj->save($conn);
}
However, when there is an exception (code or db level), I wonder if the rollback works, as I see some records being saved.
My understanding is that, as long as I've opened a connection, begun a transaction, all methods using the connection $conn are running in the same transaction. If something fails, all rollback.
I also tried to use savepoints, but I haven't been able to work with them. Can someone pl tell me if passing the connection around is enough to make everything run the transaction?
Is it because a MySQL auto_committ attribute is set or something?
Thanks
Well, transactions are supported only over InnoDB tables and I believe, that some of your tables are MyISAM. So, rollback works only on InnoDB ones and you see changes to MyISAM ones left intact.
just try
catch (Exception $exc) {
$conn->rollback();
}
in your try ctach
or
just put try catch on your other function as well

Linq to SQL concurrency problem

Hallo,
I have web service that has multiple methods that can be called. Each time one of these methods is called I am logging the call to a statistics database so we know how many times each method is called each month and the average process time.
Each time I log statistic data I first check the database to see if that method for the current month already exists, if not the row is created and added. If it already exists I update the needed columns to the database.
My problem is that sometimes when I update a row I get the "Row not found or changed" exception and yes I know it is because the row has been modified since I read it.
To solve this I have tried using the following without success:
Use using around my datacontext.
Use using around a TransactionScope.
Use a mutex, this doesn’t work because the web service is (not sure I am calling it the right think) replicated out on different PC for performance but still using the same database.
Resolve concurrency conflict in the exception, this doesn’t work because I need to get the new database value and add a value to it.
Below I have added the code used to log the statistics data. Any help would be appreciated very much.
public class StatisticsGateway : IStatisticsGateway
{
#region member variables
private StatisticsDataContext db;
#endregion
#region Singleton
[ThreadStatic]
private static IStatisticsGateway instance;
[ThreadStatic]
private static DateTime lastEntryTime = DateTime.MinValue;
public static IStatisticsGateway Instance
{
get
{
if (!lastEntryTime.Equals(OperationState.EntryTime) || instance == null)
{
instance = new StatisticsGateway();
lastEntryTime = OperationState.EntryTime;
}
return instance;
}
}
#endregion
#region constructor / initialize
private StatisticsGateway()
{
var configurationAppSettings = new System.Configuration.AppSettingsReader();
var connectionString = ((string)(configurationAppSettings.GetValue("sqlConnection1.ConnectionString", typeof(string))));
db = new StatisticsDataContext(connectionString);
}
#endregion
#region IStatisticsGateway members
public void AddStatisticRecord(StatisticRecord record)
{
using (db)
{
var existing = db.Statistics.SingleOrDefault(p => p.MethodName == record.MethodName &&
p.CountryID == record.CountryID &&
p.TokenType == record.TokenType &&
p.Year == record.Year &&
p.Month == record.Month);
if (existing == null)
{
//Add new row
this.AddNewRecord(record);
return;
}
//Update
existing.Count += record.Count;
existing.TotalTimeValue += record.TotalTimeValue;
db.SubmitChanges();
}
}
I would suggest letting SQL Server deal with the concurrency.
Here's how:
Create a stored procedure that accepts your log values (method name, month/date, and execution statistics) as arguments.
In the stored procedure, before anything else, get an application lock as described here, and here. Now you can be sure only one instance of the stored procedure will be running at once. (Disclaimer! I have not tried sp_getapplock myself. Just saying. But it seems fairly straightforward, given all the examples out there on the interwebs.)
Next, in the stored procedure, query the log table for a current-month's entry for the method to determine whether to insert or update, and then do the insert or update.
As you may know, in VS you can drag stored procedures from the Server Explorer into the DBML designer for easy access with LINQ to SQL.
If you're trying to avoid stored procedures then this solution obviously won't be for you, but it's how I'd solve it easily and quickly. Hope it helps!
If you don't want to use the stored procedure approach, a crude way of dealing with it would simply be retrying on that specific exception. E.g:
int maxRetryCount = 5;
for (int i = 0; i < maxRetryCount; i++)
{
try
{
QueryAndUpdateDB();
break;
}
catch(RowUpdateException ex)
{
if (i == maxRetryCount) throw;
}
}
I have not used the sp_getapplock, instead I have used HOLDLOCK and ROWLOCK as seen below:
CREATE PROCEDURE [dbo].[UpdateStatistics]
#MethodName as varchar(50) = null,
#CountryID as varchar(2) = null,
#TokenType as varchar(5) = null,
#Year as int,
#Month as int,
#Count bigint,
#TotalTimeValue bigint
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRAN
UPDATE dbo.[Statistics]
WITH (HOLDLOCK, ROWLOCK)
SET Count = Count + #Count
WHERE MethodName=#MethodName and CountryID=#CountryID and TokenType=#TokenType and Year=#Year and Month=#Month
IF ##ROWCOUNT=0
INSERT INTO dbo.[Statistics] (MethodName, CountryID, TokenType, TotalTimeValue, Year, Month, Count) values (#MethodName, #CountryID, #TokenType, #TotalTimeValue, #Year, #Month, #Count)
COMMIT TRAN
END
GO
I have tested it by calling my web service methods by multiple threads simultaneous and each call is logged without any problems.