It's easier to forget the details of SQL Transaction Isolation levels (during interview)

by Kofi Sarfo 26. June 2009 00:45

So I interviewed again yesterday with a City-based asset management company you've probably not heard of but a cash rich client is exactly what we need right now. Shaking off a cold hit-hard mid-week wasn't ideal circumstance but it wasn't feeling less than fabulous that did the trick but in part, in fact, not being able to remember how each of the SQL Server Transaction Isolation levels might impact queries on the same table.

This is partly why I like interviews. Potentially embarrassing situations during which one is able to demonstrate what one cannot remember. Here's what the MSDN entry has to say about the SET TRANSACTION ISOLATION LEVEL (Transact-SQL) command which controls the locking and row versioning behavior of Transact-SQL statements issued by a connection to SQL Server. Yay.

So the story in a nutshell is that using this command it's possible, amongst other things, to allow dirty reads if that's the desired result. In order to try the code below in SQL Management Studio use one tab to run the transaction once all the necessary database objects have been created and another tab to view the results of the different isolation levels.

We create a table to use for holding some random values.

CREATE TABLE RandomLetters
(
     ID int IDENTITY(1,1) NOT NULL
    ,Letter varchar(32) NOT NULL
) 

In order to populate this table with some random values we rely on a stored procedure inspired by one over here.

CREATE PROCEDURE sp_GenerateRandomLetters
     @Length int
    ,@randomLetters varchar(32) OUT
AS
DECLARE @counter smallint
DECLARE @RandomNumber float
DECLARE @RandomNumberInt tinyint
DECLARE @CurrentCharacter varchar(1)
DECLARE @ValidCharactersLength int
DECLARE @ValidCharacters varchar(255)

SET @ValidCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-=+&$'

SET @ValidCharactersLength = len(@ValidCharacters)
SET @CurrentCharacter = ''
SET @RandomNumber = 0
SET @RandomNumberInt = 0
SET @RandomLetters = ''

SET NOCOUNT ON

SET @counter = 1
WHILE @counter < (@Length + 1)
BEGIN
        SET @RandomNumber = Rand()
        SET @RandomNumberInt = Convert(tinyint, ((@ValidCharactersLength - 1) * @RandomNumber + 1))
        SELECT @CurrentCharacter = SUBSTRING(@ValidCharacters, @RandomNumberInt, 1)
        SET @counter = @counter + 1
        SET @RandomLetters = @RandomLetters + @CurrentCharacter
END

And because we're going to populate this table with more than the one record:

DECLARE @randomLetters varchar(32)
DECLARE @randomLettersCount int

SELECT @randomLettersCount = 0

WHILE (@randomLettersCount < 1000)
BEGIN
        EXEC sp_GenerateRandomLetters 12, @randomLetters OUT
        INSERT INTO RandomLetters (Letter)
        SELECT    @randomLetters
        SELECT @randomLettersCount = @randomLettersCount + 1
END

None of this is even nearly shattering. It's not meant to be. Also, the following ought to error the first time it's run.

DROP TABLE ##OriginalRandomLetters

Now let's make that table which gets dropped by the statement above.

CREATE TABLE ##OriginalRandomLetters
    (
         ID int NOT NULL
        ,Letter varchar(32) NOT NULL
    )

And we sync this global temporary table with those values in the permanent table created above

INSERT INTO ##OriginalRandomLetters
    SELECT ID, Letter
    FROM RandomLetters

Confirm that we are good.

SELECT * FROM ##OriginalRandomLetters

And back on that other tab and therefore using another connection...

BEGIN TRANSACTION

    DECLARE @RandomUpdateCount int
    DECLARE @RandomID int
    DECLARE    @randomLetters varchar(32)

    SELECT @RandomUpdateCount = 0

    SET NOCOUNT ON

    WHILE @RandomUpdateCount < 20000
    BEGIN
        SELECT @RandomID = 1 + RAND() * 999
        -- SELECT @RandomID '@RandomID'

        EXEC sp_GeneratePassword 12, @randomLetters OUT
        -- SELECT @randomLetters '@randomLetters'

        UPDATE    RandomLetters
        SET        Letter = @randomLetters
        WHERE    ID = @RandomID

        SELECT @RandomUpdateCount = @RandomUpdateCount + 1
    END

ROLLBACK TRANSACTION

And finally let's try one of these transaction isolation levels

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ
    SET TRANSACTION ISOLATION LEVEL SNAPSHOT
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

And the result of the following query will depend on the chosen isolation level.

SELECT * FROM RandomLetters

For example the READ UNCOMMITTED isolation level will allow you to see the changes being made to the values in the RandomLetters table whilst the transaction to update values is being run whereas most of the other isolation levels will cause SELECT * FROM RandomLetters to hang until the transaction is complete. In the case of SNAPSHOT there's an error: Snapshot isolation transaction failed accessing database 'WimiroDemo' because snapshot isolation is not allowed in this database. Use ALTER DATABASE to allow snapshot isolation.

I might be forgiven for not remembering all this behaviour during interview but not having a handle immediately on the correct strategy for ASP.NET paging and the 10 steps of the ASP.NET Page Life Cycle might have been forgetfulness too far. But that's what the internet is for, I say. Fingers crossed I get the gig anyway.

Tags:

SQL Server

Thank you, John Resig!

by Kofi Sarfo 17. June 2009 04:56

So we had the option of writing some code in order to determine browser responsiveness to see whether the code in the last post - AJAX and the URL short(ening) - was in fact asynchronous... or use jQuery which we know is most definitely AJAX. Really, we're not in the mood for poking under the hood.

There was a wee bit of pain in the why now isn't ths working stakes, some edits later and it did. Mysteriously. So I didn't touch it anymore. A case of Programming by Coincidence?


<script src="Scripts/jquery-1.2.6.js" type="text/javascript"></script>
<script type="text/javascript">
$(function() {
var getBitlyUrl = function() {

// set up default options
var defaults = {
version: '2.0.1',
login: 'bitlyapidemo',
apiKey: 'R_0da49e0a9118ff35f52f629d2d71bf07',
history: '1',
longUrl: $('#rawUrl').val()
};

// Build the URL to query
var daurl = "http://api.bit.ly/shorten?"
+ "version=" + defaults.version
+ "&longUrl=" + defaults.longUrl
+ "&login=" + defaults.login
+ "&apiKey=" + defaults.apiKey
+ "&history=" + defaults.history
+ "&format=json&callback=?";

$.getJSON(daurl, function(data) {
$('#bladder').empty();
$('#bitlyUrl').val(data.results[defaults.longUrl].shortUrl);
});
}

$('#getUrl').bind('click', getBitlyUrl);
})
(jQuery);
</script>

The body is the same as in the previous post. It's that easy. Great library.

Notes:
One of the leetlest problems we had was with receiving a 'permission denied' error when omitting "&format=json&callback=?" from the default URL. Solution and Nabble discovery all at the same time!

AJAX and the URL short(ening)

by Kofi Sarfo 16. June 2009 23:42

A popular choice for shorterning URLs on Twitter is Bit.ly. It's just so nice and tidy with great analytics. For example, not long after shortening http://cnn.com/ we discovered that there have already been 2,659 clicks to that URL via Bit.ly.

I am using the C# API from @kersney by the way and found out that Bit.ly does do the sensible thing and return the same shortened URL each time you supply an unadulterated URL. What I've not yet done is built chains of shortened URLs that lead to each... seemingly endless possibilities! What the C# API code is missing is &history=1 querystring parameter to have the shortened URL added to the list displayed in Bit.ly History.

Some Default.aspx code to give this a go:


<body>
<form id="form1" runat="server">
<div style="width: 100%;">
Original URL:
<asp:TextBox ID="TextBox1" runat="server" Width="100%"></asp:TextBox>
<div style="text-align: right; width: 100%">
<asp:Button ID="Button1" runat="server" Text="Shorten" onclick="Button1_Click" />
</div>
</div>
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
</form>
</body>

And some codebehind:

protected void Button1_Click(object sender, EventArgs e) { TextBox2.Text = API.Bit("bitlyapidemo", "R_0da49e0a9118ff35f52f629d2d71bf07", TextBox1.Text, "Shorten"); }

Now we pretend that bit.ly takes ages to return a shortened URL so we use javascript instead.


<script src="http://bit.ly/javascript-api.js
?version=latest
&login=bitlyapidemo
&apiKey=R_0da49e0a9118ff35f52f629d2d71bf07"

type="text/javascript">
</script>

<script type="text/javascript">

BitlyClient.addPageLoadEvent(function()
{
BitlyCB.shortenResponse = function(data)
{
var s = '';

var first_result;
// Results are keyed by longUrl, so we need to grab the first one.
for (var r in data.results) {
first_result = data.results[r]; break;
}
for (var key in first_result) {
s += key + ":" + first_result[key].toString() + "\n";
}

document.getElementById("bitlyUrl").value = first_result['shortUrl'];
}
});

function getBitlyUrl()
{
BitlyClient.shorten(document.getElementById("rawUrl").value, 'BitlyCB.shortenResponse');
}
</script>

No prizes for guessing the elements in the document.


<body>
<form id="formeula1" runat="server">
<div style="width: 100%;">
<br />Original URL:
<br /><input type="text" id="rawUrl" size="100" value="http://wimiro.com" />
<input value="Shorten" type="button" onclick="getBitlyUrl()"/>
<br />
<br />Bit.ly URL:
<br /><input type="text" id="bitlyUrl" size="20" />
</div>
</form>
</body>

So, there are no postbacks anymore but does this make it AJAX? Honestly, I have no idea. I see mention of callback_method_name in the bit.ly javascript api so my guess is that, yes, this is asynchronous. But shall we bother to test this or do we try and involve jQuery?

I wonder whether I can piggy-back Twitter authentication

by Kofi Sarfo 15. June 2009 00:46

Didn't really fancy maintaining credentials for an application that is designed to work in tandem with Twitter so enter OAuth.net: "An open protocol to allow secure API authorization in a simple and standard method..."

What is this new thing then and why had I not heard of it before? See October 2007 entry in Hueniverse: Beginner’s Guide to OAuth. Not so new then.

Also, a little while ago we were in a room with developers and they brayed when asked if anyone liked the ASP.NET 2.0 Membership Controls. I think the Login control was mentioned specifically. They worked fine for me. So we go looking for reasons this - their seeming unpopularity - might be. Stack Overflow (because there's been no reference in minutes) answers one question of what to use for membership in ASP.NET. We're still none the wiser.

And there's more from the timely discoveries department. Tweetsharp: "A C# fluent interface for Twitter, designed for app developers" -- downloading source. I remember being corrected for returning this (or it could have been me) circa 2004 which we did so that we could chain methods but I can't remember what the argument against it might have been.

Listening to folks talk REST whilst running 10km

by Kofi Sarfo 12. June 2009 02:24

Caught .NET Rocks show #445 with Kenn Scribner on REST. A useful discussion about REST, SOAP, the evolution of 'web services' technology and where WCF best fits in. Listen here.

Notes:

.NET Rocks talk transcript

Nuff chat. Now code.

by Kofi Sarfo 10. June 2009 01:33

We've spent the last few weeks reading, trying to get up to speed with .NET 3.5 and looking at some code. Meanwhile we've not been writing anything besides snippets for learning generics, LINQ and WCF. No ASP.NET MVC. No WPF. No Silverlight. No worries. It's time to build something.

So the concept is reviews for the Twitterati. Reviews of 120 Characters or less. Tweeviews if you like. Key characteristics should be that it's simple, clean and intuitive.

Key technical features:

  • REST-based architecture
    • API versioning
    • Caching
  • ASP.NET Webforms (initially with AJAX)
  • SQL Server 

Functional areas:

  • Category
  • Review
  • Thumb up or down (as opposed to 4/5 stars)
  • Reviewer
  • Reviewed object (restaurant, etc)

Not sure whether we call those things above entities.

Old school Microsoft approach is database design first. Data-centric rather than domain driven. I think we're still stuck in that world. Will be worth reconsidering this application and how it might have been done differently using NHibernate, Rhino Mocks, etc. Ayendeified. It ought to be an adjective.

What's interesting (for me) about this is that we've never written a publicly accessible API. We've done Web Services for both inter and intra application domain hookups (not in the .NET sense but rather as an interface between disparate applications on the same platform as well as between different platforms). We used Web Services, for example, in the Advert Framework* for FireText. No problems with SOAP. It didn't really need to be WS-* as it never made use of transactions as originally intended. Still, it was fun playing with the PHP SOAP implementation :)

Extra bits:

  • URL shortening API
  • Twitter API
  • Some reporting & filtering type UI

First pass, writing this as quickly as I can using tried/tested approach. Second attempt, a rewrite using shiny newish technology. The idea being then able to compare the old versus new, discern what real advantages the new offers and get some refactoring practice. This should be interesting...

Notes:

* It was subsequently rewritten in PHP because the engineer I handed the code to didn't fancy learning C# but a story for another time...

Full Circle on Action<T>

by Kofi Sarfo 6. June 2009 00:02

Reminded recently of a method for determining Prime Numbers (Sieve of Eratosthenes) and saw some Generic Collection Class action (p. 97 C# In Depth)

            List<int> candidates = new List<int>();

            for (int i = 2; i <= 100; i++)
            {
                candidates.Add(i);
            }
 
            for (int factor = 2; factor <= 10; factor++)
            {
                candidates.RemoveAll(delegate(int x)
                    { return x > factor && x % factor == 0; }
                );
            }
 
            candidates.ForEach(delegate(int prime)
                { Console.WriteLine(prime); }
            );

Bouncing around looking for code samples to see what we're missing in terms of Generics... we spot something. Switch on the Code: The Built-In Generic Delegate Declarations.

Difference between Func<T> and Action<T> is the latter doesn't have a return type. Too obvious to miss? Maybe. Quick search shows difference between new Action() and Lambda at Stack Overflow. Response from author of code sample above. Jon Skeet. 3900 answers on Stack Overflow in 8 months. Or 16 answers a day, every day.

Notes:

MSDN: Lambda Expressions

CodeBetter: Back to Basics - Delegates, Anonymous Methods and Lambda Expressions

Online Hang Outs Part I

by Kofi Sarfo 5. June 2009 16:56

 

I can't remember where I read something about having to read a decent amount of well written code in order to be able to understand how to code well. I think a parallel with writers and books was drawn somewhere nearby... Anyhow, this is why we've been hanging round the The Code Project since 2001 sometime and there appear excellent articles / code samples every so often; for example, the "Best C# article of April 2009" competition winner was Geoplaces. "A hybrid smart client, involving RESTful WCF/WPF and more." It's pretty.

 

It's a while since we wrote anything from scratch and those bits of code we've picked up in the last year don't look much like this. They don't look this good.

The Data Layer is all Entity Framework so happy to give that a miss but the Restful Service Layer is a nice intro into the System.ServiceModel namespace.

The Service Interface provides examples of ServiceContract and OperationContract. Backing up... MSDN: Introduction to Building Windows Communication Foundation Services. Note that this intro was written four years ago! Cut to mid 2009 and we still have indication of pain. Ayende: WCF Works in Mysterious Ways. IColloquialize: WCF Service References Generating Empty Root Proxy Classes. First takes suggest WCF might not be so straightforward.

Inversion of Control

by Kofi Sarfo 4. June 2009 16:02

Our favourite piece of code seen recently is from a while ago: Building an IoC container in 15 lines of code. We like it because the intent is really very clear. Every now and then we find some use of Spring.NET or mention of IoC. Sometimes wonder whether it's necessary or being used because Developer-X wants to indicate sophistication. So then as a refresher we often end up here: Inversion of Control Containers and the Dependency Injection pattern. Written 35 Internet Years ago.

Looking at the way applications are written circa 2008 it appears IoC is reasonably common and therefore time to incorporate. Known advantages:

  • Decoupling
  • Service Orientation (is this repetition of the first?)
  • Testability
    • Allows mocking

The fact that we've neither been tripped up by object graphs nor troubled with dependency suggests not having done anything nearly enterprise enough. That, rather than an eidetic view of object relationships. Still, there's an argument for trying to incorporate a different approach into the ordinary as a means for seeing the ordinary for being less than splendid.

Right, so which one do we go for?

The nice thing about Autofac is that it's capable of using a delegate or Lambda Expression rather than reflection for component creation. As stated elsewhere, .NET 3.0 style. We like.

Notes:

Useful to make explicit the difference between Inversion of Control and Dependency Injection. Hint: The latter is a specific form of the former. Nice one, Wikipedia!

Tags:

Why We're Sheltered Safely Behind the Curve

by Kofi Sarfo 3. June 2009 01:56

Back in 2002 we were trying to learn C# - having felt like we'd conquered VB.NET in 2001 - there was a *thrilling* chance to learn about the .NET programming model by developing creatures and introducing them into a peer-to-peer ecosystem... Terrarium! Welcome home disposable heroes.

I think we spent a week trying to get the friggin' thing to work before someone let us know that it had nothing to do with our ineptitude and everything to do with our beta version of Visual Studio. Cue decision to wait until technology beds down before adoption. Much cooler to be an Early Adopter but it required a level of patience beyond us; we watched and laughed as early versions spat out their problems. Widely anticipated, widely hyped technology seemed to disappear. Late adoption served us well. Looking down Memory Lane:

That was then. WxF looks to have good momentum - read: it's showing up on job specs - so cue once more frustration of technology adoption prior to it becoming mainstream. Pair of Snake Eyes.

Tags:

Kofi Sarfo modified theme by Mads Kristensen



Content by WIMIRO Technology is licensed under a Creative Commons Attribution-Share Alike 2.0 UK: England & Wales License.

Creative Commons License

Powered by BlogEngine.NET 1.5.0.7

About Me

Director, Wimiro Technology
London, United Kingdom

Writes in third person and first person plural; currently commutes to Moorgate.

Kiva Loans

  • Issa Sarr

    Issa Sarr

    Personal Purchases

    Requested loan: $200

    Amount raised: $75

    Dakar, Senegal

    social needs

    Loan Now »

  • Edwin

    Edwin

    Movie Tapes & DVDs

    Requested loan: $800

    Amount raised: $125

    La Paz, Bolivia

    Buy a DVD burner tower

    Loan Now »

  • Soo

    Soo

    Laundry

    Requested loan: $5375

    Amount raised: $2175

    Queens, New York, United States

    To purchase a new dry cleaning machine

    Loan Now »

 To see more entrepreneurs »

Kiva Loans