2007年6月3日星期日

SQL Server Transactions and Error Handling

Introduction


The examples used in this article uses the Pubs database that comes as a
sample database when you install SQL Server. If you need to rebuild the Pubs
database, follow the steps to install a fresh copy :



  1. Run the osql command prompt utility and detach the Pubs database from SQL
    Server by using the sp_detach_db system stored procedure.
    osql -U sa -P "" -Q "exec sp_detach_db 'Pubs'" 

  2. Delete the database files for pubs database (pubs.mdf, pubs_log.ldf). These
    files are located in the \Data directory.


  3. Re-creating the Pubs database requires the Instpubs.sql script to be
    executed. Run the script from the command line (if the .sql files are in a
    different directory, adjust the path accordingly). You can also run this script
    file from the Query Analyzer.
     osql -U sa -P "" -i 
    "C:\Program Files\Microsoft SQL Server\MSSQL\Install\InstPubs.sql"

    (The osql utility uses case-sensitive options. If neither the -U or -P
    options are used, SQL Server 2000 attempts to connect using Windows
    Authentication Mode. More information about the osql Utility can be found in the
    Sql Server Books Online)


Transactions


Transactions group a set of tasks into a single execution unit. Each
transaction begins with a specific task and ends when all the tasks in the group
successfully complete. If any of the tasks fails, the transaction fails.
Therefore, a transaction has only two results: success or failure. Incomplete
steps result in the failure of the transaction.


Users can group two or more Transact-SQL statements into a single transaction
using the following statements:


  • Begin Transaction
  • Rollback Transaction
  • Commit Transaction

If anything goes wrong with any of the grouped statements, all changes need
to be aborted. The process of reversing changes is called rollback in SQL
Server terminology. If everything is in order with all statements within a
single transaction, all changes are recorded together in the database. In SQL
Server terminology, we say that these changes are committed to the
database.


Here is an example of a transaction :

USE pubs

DECLARE @intErrorCode INT

BEGIN TRAN
UPDATE Authors
SET Phone = '415 354-9866'
WHERE au_id = '724-80-9391'

SELECT @intErrorCode = @@ERROR
IF (@intErrorCode <> 0) GOTO PROBLEM

UPDATE Publishers
SET city = 'Calcutta', country = 'India'
WHERE pub_id = '9999'

SELECT @intErrorCode = @@ERROR
IF (@intErrorCode <> 0) GOTO PROBLEM
COMMIT TRAN

PROBLEM:
IF (@intErrorCode <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
END

Before the real processing starts, the BEGIN TRAN statement
notifies SQL Server to treat all of the following actions as a single
transaction. It is followed by two UPDATE statements. If no errors
occur during the updates, all changes are committed to the database when SQL
Server processes the COMMIT TRAN statement, and finally the stored
procedure finishes. If an error occurs during the updates, it is detected by if
statements and execution is continued from the PROBLEM label. After
displaying a message to the user, SQL Server rolls back any changes that
occurred during processing. Note: Be sure to match BEGIN TRAN with
either COMMIT or ROLLBACK.


Nested Transactions


SQL Server allows you to nest transactions. Basically, this feature means
that a new transaction can start even though the previous one is not complete.
Transact-SQL allows you to nest transaction operations by issuing nested
BEGIN TRAN commands. The @@TRANCOUNT automatic
variable can be queried to determine the level of nesting - 0 indicates no
nesting , 1 indicates nesting one level deep, and so fourth.


A COMMIT issued against any transaction except the outermost one
doesn't commit any changes to disk - it merely decrements the@@TRANCOUNT
automatic variable. A ROLLBACK, on the other hand, works
regardless of the level at which it is issued, but rolls back all transactions,
regardless of the nesting level. Though this is counterintuitive, there's a very
good reason for it. If a nested COMMIT actually wrote changes
permanently to disk, an outer ROLLBACK wouldn't be able to reverse
those changes since they would already be recorded permanently.


When you explicitly begin a transaction, the @@TRANCOUNT
automatic variable count increases from 0 to 1; when you
COMMIT, the count decreases by one; when you ROLLBACK,
the count is reduced to 0. As you see, the behavior of COMMIT and
ROLLBACK is not symmetric. If you nest transactions, COMMIT
always decreases the nesting level by 1, as you can see illustrated in
Figure 1. The ROLLBACK command, on the other hand, rolls back the
entire transaction, illustrated in Figure 2. This asymmetry between COMMIT
and ROLLBACK is the key to handling errors in nested
transactions.













border=0>
Figure 1: A COMMIT always balances a BEGIN TRANSACTION
by reducing the transaction count by one.
border=0>
Figure 2: A single ROLLBACK always rolls back the entire
transaction.

As you can see from Figure 1 and Figure 2, you can nest transactions and use
the @@TRANCOUNT automatic variable to detect the level. You also
learned that COMMIT and ROLLBACK do not behave
symmetrically; COMMIT just decreases the value of
@@TRANCOUNT, while ROLLBACK resets it to 0. The
implication is that a transaction is never fully committed until the last
COMMIT is issued. No matter how deeply you nest a set of
transactions, only the last COMMIT has any effect.


Here is an example of a nested transaction :


style="CURSOR: hand" height=9 src="http://www.codeproject.com/images/minus.gif"
width=9 preid="3"> Collapse
USE pubs
SELECT 'Before BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 0
BEGIN TRAN
SELECT 'After BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 1
DELETE sales
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 2
DELETE titleauthor
COMMIT TRAN nested
-- Does nothing except decrement the value of @@TRANCOUNT

SELECT 'After COMMIT TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 1
ROLLBACK TRAN

SELECT 'After ROLLBACK TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 0
-- because ROLLBACK TRAN always rolls back all transactions and sets
-- @@TRANCOUNT to 0.

SELECT TOP 5 au_id FROM titleauthor

In this example we see that despite the nested COMMIT TRAN, the
outer ROLLBACK still reverses the effects of the DELETE
titleauthor command.


Here is another similar example of nested transaction :

USE pubs
SELECT 'Before BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 0
BEGIN TRAN
SELECT 'After BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 1
DELETE sales
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 2
DELETE titleauthor
ROLLBACK TRAN

SELECT 'After COMMIT TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 0 because
-- ROLLBACK TRAN always rolls back all transactions and sets @@TRANCOUNT
-- to 0.

IF (@@TRANCOUNT > 0) BEGIN
COMMIT TRAN -- Never makes it here cause of the ROLLBACK
SELECT 'After COMMIT TRAN', @@TRANCOUNT
END

SELECT TOP 5 au_id FROM titleauthor

In this example, execution never reaches the out COMMIT TRAN
because the ROLLBACK TRAN reverses all
transactions currently in progress and sets @@TRANCOUNT to 0.
Unless ROLLBACK TRAN is called with a save point, ROLLBACK
TRAN
always rolls back all transactions and sets @@TRANCOUNT
to 0, regardless of the context in which it's called.


SAVE TRAN and Save Points


Savepoints offer a mechanism to roll back portions of transactions. A user
can set a savepoint, or marker, within a transaction. The savepoint defines a
location to which a transaction can return if part of the transaction is
conditionally canceled. SQL Server allows you to use savepoints via the
SAVE TRAN statement, which doesn't affect the @@TRANCOUNT
value. A rollback to a savepoint (not a transaction) doesn't affect the
value returned by @@TRANCOUNT, either. However, the rollback must
explicitly name the savepoint: using ROLLBACK TRAN without a
specific name will always roll back the entire transaction.


The following script demonstrates how savepoints can be used :


style="CURSOR: hand" height=9 src="http://www.codeproject.com/images/minus.gif"
width=9 preid="5"> Collapse
USE pubs
SELECT 'Before BEGIN TRAN main', @@TRANCOUNT
-- The value of @@TRANCOUNT is 0

BEGIN TRAN main
SELECT 'After BEGIN TRAN main', @@TRANCOUNT
-- The value of @@TRANCOUNT is 1
DELETE sales
SAVE TRAN sales -- Mark a save point
SELECT 'After SAVE TRAN sales', @@TRANCOUNT
-- The value of @@TRANCOUNT is still 1

BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 2
DELETE titleauthor
SAVE TRAN titleauthor -- Mark a save point
SELECT 'After SAVE TRAN titleauthor', @@TRANCOUNT
-- The value of @@TRANCOUNT is still 2
ROLLBACK TRAN sales

SELECT 'After ROLLBACK TRAN sales', @@TRANCOUNT
-- The value of @@TRANCOUNT is still 2

SELECT TOP 5 au_id FROM titleauthor

IF (@@TRANCOUNT > 0) BEGIN
ROLLBACK TRAN
SELECT 'AFTER ROLLBACK TRAN', @@TRANCOUNT
-- The value of @@TRANCOUNT is 0 because
-- ROLLBACK TRAN always rolls back all transactions and sets @@TRANCOUNT
-- to 0.
END

SELECT TOP 5 au_id FROM titleauthor

Error Handling


The examples presented here are specific to stored procedures as they are the
desired method of interacting with a database. When an error is encountered
within a stored procedure, the best you can do is halt the sequential processing
of the code and either branch to another code segment in the procedure or return
processing to the calling application. The @@ERROR automatic
variable is used to implement error handling code. It contains the error ID
produced by the last SQL statement executed during a client’s connection. When a
statement executes successfully, @@ERROR contains 0. To determine
if a statement executes successfully, an IF statement is used to check the value
of @@ERROR immediately after the target statement executes. It is
imperative that @@ERROR be checked immediately after the target
statement, because its value is reset to 0 when the next statement executes
successfully. If a trappable error occurs, @@ERROR will have a
value greater than 0. SQL Server resets the @@ERROR value after
every successful command, so you must immediately capture the @@ERROR
value. Most of the time, you'll want to test for changes in @@ERROR
right after any INSERT, UPDATE, or DELETE
statement.

CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11), 
@title VARCHAR(20), @title_type CHAR(12))
AS

BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)

IF (@@ERROR <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
END

INSERT titleauthor(au_id, title_id)
VALUES (@au_id, @title_id)

IF (@@ERROR <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
END

COMMIT TRAN

RETURN 0

This kind of solution contains substantial repetition especially if your
business logic requires more than two Transact-SQL statements to be implemented.
A more elegant solution is to group codes into a generic error handling
procedure:

CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11),
@title VARCHAR(20), @title_type CHAR(12))
AS

BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)

IF (@@ERROR <> 0) GOTO ERR_HANDLER

INSERT titleauthor(au_id, title_id)
VALUES (@au_id, @title_id)

IF (@@ERROR <> 0) GOTO ERR_HANDLER

COMMIT TRAN

RETURN 0

ERR_HANDLER:
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1

2007年5月24日星期四

A


2007年5月20日星期日

Prototype Javascript Framework

easing the pain of dynamic web applications
Download
API Docs
Tips and Tutorials
Blog
Contribute
Prototype articles
How Prototype extends the DOM
Introduction to Ajax
Introduction to JSON
Introduction to Ajax
Last updated on February 24th, 2007
Prototype framework enables you to deal with Ajax calls in a very easy and fun way that is also safe (cross-browser). Besides simple requests, this module also deals in a smart way with JavaScript code returned from a server and provides helper classes for polling.
Ajax functionality is contained in the global Ajax object. The transport for Ajax requests is xmlHttpRequest, with browser differences safely abstracted from the user. Actual requests are made by creating instances of the Ajax.Request object.new Ajax.Request('/some_url', { method:'get' });
The first parameter is the URL of the request; the second is the options hash. The method option refers to the HTTP method to be used; default method is POST.
Remember that for security reasons (that is preventing cross-site scripting attacks) Ajax requests can only be made to URLs of the same protocol, host and port of the page containing the Ajax request. Some browsers might allow arbitrary URLs, but you shouldn't rely on support for this.
Ajax response callbacks
Ajax requests are by default asynchronous, which means you must have callbacks that will handle the data from a response. Callback methods are passed in the options hash when making a request:new Ajax.Request('/some_url', { method:'get', onSuccess: function(transport){ var response = transport.responseText "no response text"; alert("Success! \n\n" + response); }, onFailure: function(){ alert('Something went wrong...') } });
Here, two callbacks are passed in the hash that alert of either success or failure; onSuccess and onFailure are called accordingly based on the status of the response. The first parameter passed to both is the native xmlHttpRequest object from which you can use its responseText and responseXML properties, respectively.
You can specify both callbacks, one or none - it's up to you. Other available callbacks are:
onUninitialized,
onLoading,
onLoaded,
onInteractive,
onComplete and
onException.
They all match a certain state of the xmlHttpRequest transport, except for onException which fires when there was an exception while dispatching other callbacks.
Also available are onXXX callbacks, where XXX is the HTTP response status like 200 or 404. Be aware that, when using those, your onSuccess and onFailure won't fire because onXXX takes precedence, therefore using these means you know what you're doing.
The onUninitialized, onLoading, onLoaded, and onInteractive callbacks are not implemented consistently by all browsers. In general, it's best to avoid using these.
Parameters and the HTTP method
You can pass the parameters for the request as the parameters property in options:new Ajax.Request('/some_url', { method: 'get', parameters: {company: 'example', limit: 12} });
Parameters are passed in as a hash (preferred) or a string of key-value pairs separated by ampersands (like company=example&limit=12).
You can use parameters with both GET and POST requests. Keep in mind, however, that GET requests to your application should never cause data to be changed. Also, browsers are less likely to cache a response to a POST request, but more likely to do so with GET.
One of the primary applications for the parameters property is sending the contents of a FORM with an Ajax request, and Prototype gives you a helper method for this, called Form.serialize:new Ajax.Request('/some_url', { parameters: $('id_of_form_element').serialize(true) });
If you need to push custom HTTP request headers, you can do so with the requestHeaders option. Just pass name-value pairs as a hash or in a flattened array, like: ['X-Custom-1', 'value', 'X-Custom-2', 'other value'].
If, for some reason, you have to POST a request with a custom post body (not parameters from the parameters option), there is a postBody option exactly for that. Be aware that when using postBody, parameters passed will never be posted because postBody takes precedence as a body - using the option means you know what you're doing.
Evaluating a JavaScript response
Sometimes the application is designed to send JavaScript code as a response. If the content type of the response matches the MIME type of JavaScript then this is true and Prototype will automatically eval() returned code. You don't need to handle the response explicitly if you don't need to.
Alternatively, if the response holds a X-JSON header, its content will be parsed, saved as an object and sent to the callbacks as the second argument:new Ajax.Request('/some_url', { method:'get', onSuccess: function(transport, json){ alert(json ? Object.inspect(json) : "no JSON object"); } });
Use this functionality when you want to fetch non-trivial data with Ajax but want to avoid the overhead of parsing XML responses. JSON is much faster (and lighter) than XML.
Global responders
There is an object that is informed about every Ajax request: Ajax.Responders. With it, you can register callbacks that will fire on a certain state of any Ajax.Request issued:Ajax.Responders.register({ onCreate: function(){ alert('a request has been initialized!'); }, onComplete: function(){ alert('a request completed'); } });
Every callback matching an xmlHttpRequest transport state is allowed here, with an addition of onCreate. Globally tracking requests like this can be useful in many ways: you can log them for debugging purposes using a JavaScript logger of your choice or make a global exception handler that informs the users of a possible connection problem.
Updating your page dynamically with Ajax.Updater
Developers often want to make Ajax requests to receive HTML fragments that update parts of the document. With Ajax.Request with an onComplete callback this is fairly easy, but with Ajax.Updater it's even easier!
Suppose you have this code in your HTML document:

Our fantastic products

(fetching product list ...)

The 'products' container is empty and you want to fill it with HTML returned from an Ajax response. No problem:new Ajax.Updater('products', '/some_url', { method: 'get' });
That's all, no more work. The arguments are the same of Ajax.Request, except there is the receiver element in the first place. Prototype will automagically update the container with the response using the Element.update() method.
If your HTML comes with inline scripts, they will be stripped by default. You'll have to pass true as the evalScripts option in order to see your scripts being executed.
But what if an error occurs, and the server returns an error message instead of HTML? Often you don't want insert errors in places where users expected content. Fortunately, Prototype provides a convenient solution: instead of the actual container as the first argument you can pass in a hash of 2 different containers in this form: { success:'products', failure:'errors' }. Content will be injected in the success container if all went well, but errors will be written to the failure container. By using this feature your interfaces can become much more user-friendly.
You might also choose not to overwrite the current container contents, but insert new HTML on top or bottom like you would do with Insertion.Top or Insertion.Bottom. Well, you can. Just pass the insertion object as the insertion parameter to Ajax:new Ajax.Updater('products', '/some_url', { method: 'get', insertion: Insertion.Top });
Ajax.Updater will use the given object to make the insertion of returned HTML in the container ('products') element. Nifty.
Automate requests with the Ajax.PeriodicalUpdater
You find the Ajax.Updater cool, but want to run it in periodical intervals to repeatedly fetch content from the server? Prototype framework has that, too - it's called Ajax.PeriodicalUpdater, and basically it's running Ajax.Updater at regular intervals.new Ajax.PeriodicalUpdater('products', '/some_url', { method: 'get', insertion: Insertion.Top, frequency: 1, decay: 2 });
Two new options here are frequency and decay. Frequency is the interval in seconds at which the requests are to be made. Here, it's 1 second, which means we have an Ajax request every second. The default frequency is 2 seconds. Our users might be happy because the responsiveness of the application, but our servers might be taking quite a load if enough people leave their browsers open on the page for quite some time. That's why we have the decay option - it is the factor by which the frequency is multiplied every time when current response body is the same as previous one. First Ajax request will then be made in 1 second, second in 2, third in 4 seconds, fourth in 8 and so on. Of course, if the server always returns different content, decay will never take effect; this factor only makes sense when your content doesn't change so rapidly and your application tends to return the same content over and over.
Having frequency falloff can take the load off the servers considerably because the overall number of requests is reduced. You can experiment with this factor while monitoring server load, or you can turn it off completely by passing 1 (which is default) or simply omitting it.

An Introduction To Ajax

by David Teare08/29/2005
Abstract
As J2EE developers, it seems we are constantly focused on "backend mechanics." Often, we forget that the main success of J2EE has been around the Web application; people love developing applications that utilize the Web for many reasons, but mainly because the ease of deployment allows a site to have millions of users with minimal cost. Unfortunately, over the years we have invested too much time in the back end and not enough time in making our Web user interfaces natural and responsive to our users.
This article introduces a methodology, Ajax, you can use to build more dynamic and responsive Web applications. The key lies in the combination of browser-side JavaScript, DHTML, and asynchronous communication with the server. This article also demonstrates just how easy it is to start using this approach, by leveraging an Ajax framework (DWR) to construct an application that communicates with backend services directly from the browser. If used properly, this tremendous power allows your application to be more natural and responsive to your users, thereby providing an improved browsing experience.
The sample code used in this application is available for download as a standalone WAR file.
Introduction
The term Ajax is used to describe a set of technologies that allow browsers to provide users with a more natural browsing experience. Before Ajax, Web sites forced their users into the submit/wait/redisplay paradigm, where the users' actions were always synchronized with the server's "think time." Ajax provides the ability to communicate with the server asynchronously, thereby freeing the user experience from the request/response cycle. With Ajax, when a user clicks a button, you can use JavaScript and DHTML to immediately update the UI, and spawn an asynchronous request to the server to perform an update or query a database. When the request returns, you can then use JavaScript and CSS to update your UI accordingly without refreshing the entire page. Most importantly, users don't even know your code is communicating with the server: the Web site feels like it's instantly responding.
While the infrastructure needed by Ajax has been available for a while, it is only recently that the true power of asynchronous requests has been leveraged. The ability to have an extremely responsive Web site is exciting as it finally allows developers and designers to create "desktop-like" usability with the standard HTML/CSS/JavaScript stack.
Traditionally in J2EE, developers have been so focused on developing the service and persistence layers that the usability of the user interface has lagged behind. It is common to hear phases such as, "we don't have time to invest in the UI" or "you can't do that with HTML" during a typical J2EE development cycle. The following Web sites prove that these excuses don't hold water any longer:
BackPack
Google Suggest
Google Maps
PalmSphere
All these Web sites show that Web applications don't need to rely solely on pages being reloaded from the server to present changes to the user. Everything seems to happen almost instantly. In short, when it comes to designing a responsive user interface, the bar has now been set much higher.
Defining Ajax
Jesse James Garrett at Adaptive Path defined Ajax as follows:
Ajax isn't a technology. It's really several technologies, each flourishing in its own right, coming together in powerful new ways. Ajax incorporates:
Standards-based presentation using XHTML and CSS
Dynamic display and interaction using the Document Object Model
Asynchronous server communication using XMLHttpRequest
JavaScript binding everything together
This is all fine and dandy, but why the name Ajax? Well, the term Ajax was coined by Jesse James Garrett, and as he puts it, it is "short-hand for Asynchronous JavaScript + XML."
How Does Ajax Work?
The kernel of Ajax is the XmlHttpRequest JavaScript object. This JavaScript object was originally introduced in Internet Explorer 5, and it is the enabling technology that allows asynchronous requests. In short, XmlHttpRequest lets you use JavaScript to make a request to the server and process the response without blocking the user.
By performing screen updates on the client, you have a great amount of flexibility when it comes to creating your Web site. Here are some ideas for what you can accomplish with Ajax:
Dynamically update the totals on your shopping cart without forcing the user to click Update and wait for the server to resend the entire page.
Increase site performance by reducing the amount of data downloaded from the server. For example, on Amazon's shopping cart page, when I update the quantity of an item in my basket, the entire page is reloaded, which forces 32K of data to be downloaded. If you use Ajax to calculate the new total, the server can respond with just the new total value, thereby reducing the required bandwidth 100 fold.
Eliminate page refreshes every time there is user input. For example, if the user clicks Next on a paginated list, Ajax allows you to just refresh the list with the server data, instead of redrawing the entire page.
Edit table data directly in place, without requiring the user to navigate to a new page to edit the data. With Ajax, when the user clicks Edit, you can redraw the static table into a table with editable contents. Once the user clicks Done, you can spawn an Ajax request to update the server, and redraw the table to have static, display-only data.
The possibilities are endless! Hopefully you are excited to get started developing your own Ajax-based site. Before we start, however, let's review an existing Web site that follows the old paradigm of submit/wait/redisplay and discuss how Ajax can improve the user's experience.
Example of Where Ajax Could Be Used: MSN Money
I was on the MSN Money page the other day, and it had an article about real estate investing I found intriguing. I decided to use the "Rate this article" feature of the site such that other users of the site might be encouraged to invest their time in reading the article. After I clicked the vote button and waited a second, the entire page refreshed and I was presented with a beautiful thank you where the original voting question was.
Figure 1. Thank you message
Ajax could have made the user experience more pleasant by providing a more responsive UI and eliminating the flicker of the page refresh. Currently, since the entire page is refreshed, a lot of data needs to be transmitted because the entire page must be resent. If you used Ajax, the server could have sent back a 500-byte message containing the thank you message instead of sending 26,813 bytes to refresh the entire page. Even when using high-speed Internet, the difference between transmitting 26K and 1/2 K is significant! Of equal importance, instead of redrawing the entire screen, only the small section regarding votes would need to be redrawn.
Let's implement our own rudimentary voting system that leverages Ajax.
Raw Ajax: Using the XmlHttpRequest Directly
As alluded to above, the heart of Ajax is the XmlHttpRequest JavaScript object. The following sample article ranking system was built to walk you though the low-level basics of Ajax: http://tearesolutions.com/ajax-demo/raw-ajax.html. Note: If you've already installed the ajax-demo.war in your local WebLogic container, you can navigate to http://localhost:7001/ajax-demo/raw-ajax.html.
Browse the application, cast some votes, and witness firsthand how it behaves. Once you're familiar with the application, continue reading to dig into the details of how it works.
First, you have some simple anchor tags that link to a JavaScript castVote(rank) function.function castVote(rank) {
var url = "/ajax-demo/static-article-ranking.html";
var callback = processAjaxResponse;
executeXhr(callback, url);
}
This function creates a URL for the server resource you want to communicate with, and calls your internal executeXhr function, providing a callback JavaScript function to be executed once the server response is available. Since I need this to run on a simple Apache setup, the "cast vote URL" is just a simple HTML page. In real life, the URL called would tally the votes and dynamically render a response with the vote totals.
The next step is the spawning of an XmlHttpRequest request:function executeXhr(callback, url) {
// branch for native XMLHttpRequest object
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
req.onreadystatechange = callback;
req.open("GET", url, true);
req.send(null);
} // branch for IE/Windows ActiveX version
else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req) {
req.onreadystatechange = callback;
req.open("GET", url, true);
req.send();
}
}
}
As you can see, executing a XmlHttpRequest is not trivial, but it is straightforward. As always in JavaScript land, the majority of the effort is spent ensuring browser compatibility. In this case, you first determine if the XmlHttpRequest object is available. If it is not, you are likely dealing with Internet Explorer, in which case you use the ActiveX implementation provided.
The most relevant part of the executeXhr() method is these two lines:req.onreadystatechange = callback;
req.open("GET", url, true);
The first line defines the JavaScript callback function you want to be automatically executed once the response is ready, and the "true" flag specified in the req.open() method means you want to execute this request asynchronously.
Once the XmlHttpRequest is processed by the server and returned to the browser, the callback method that you set using the req.onreadystatechange assignment will be automatically invoked:function processAjaxResponse() {
// only if req shows "loaded"
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
$('votes').innerHTML = req.responseText;
} else {
alert("There was a problem retrieving the XML data:\n" +
req.statusText);
}
}
}
This code is quite terse and uses a few magic numbers, which makes it hard at first to understand what is happening. To clarify this, the following table (borrowed from http://developer.apple.com/internet/webcontent/xmlhttpreq.html) details the common XmlHttpRequest object properties.
Property
Description
onreadystatechange
Event handler for an event that fires at every state change
readyState
Object status integer:
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete
responseText
String version of data returned from server process
responseXML
DOM-compatible document object of data returned from server process
status
Numeric code returned by server, such as 404 for "Not Found" or 200 for "OK"
statusText
String message accompanying the status code
Now the processVoteResponse() function makes a bit more sense. You first check the overall status of the XmlHttpRequest to ensure it is complete (readyStatus == 4), and then you interrogate the request status as set by the server. If everything is OK (status == 200), you proceed to rewrite the contents of the "votes" node of your DOM by using the innerHTML attribute.
Now that you see firsthand how the XmlHttpRequest object works, let's abstract away the gory details by leveraging a framework built to simplify asynchronous JavaScript communication with Java applications.
Ajax: DWR Style
Following along the same thread of the article rating system, we will implement the same functionality using the Direct Web Remoting (DWR) framework.
Assume that the articles and votes are stored in a database and that you will use some kind of object/relational mapping technique to extract them. To make it as easy as possible to deploy, no database will be used for persistent storage. Furthermore, to keep the application as generic as possible, no Web framework is used either. Instead, the application will start with a static HTML file, which you can assume is rendered dynamically by the server. Despite these simplifying assumptions, your application will use the Spring Framework to tie everything together, thereby making it easy to see how DWR can be leveraged in a "real" application.
Now would be a good time to download the sample application and familiarize yourself with it. The application is bundled as a standard WAR file so you should be able to simply drop it into any Web container—no configuration is needed. Once deployed, browse to http://localhost:7001/ajax-demo/dwr-ajax.html to run the application.
You should view the HTML source code to get an idea of how things work. The most interesting part is how simple the code is—all the interaction with the server is hidden behind the ajaxSampleSvc JavaScript object. What is even more amazing is that the ajaxSampleSvc service was not hand-coded; it was all automatically generated for us! Jump ahead to see how.

Easy Ajax with Prototype

There’s little more impressive on the web today than a appropriate touch of Ajax. Used well, Ajax brings a web interface much closer to the experience of a desktop app, and can turn a bear of an task into a pleasurable activity.
But it’s really hard, right? It involves all the nasty JavaScript that no one ever does often enough to get really good at, and the browser support is patchy, and urgh it’s just so much damn effort. Well, the good news is that – ta-da – it doesn’t have to be a headache. But man does it still look impressive. Here’s how to amaze your friends.
Introducing prototype.js
Prototype is a JavaScript framework by Sam Stephenson designed to help make developing dynamic web apps a whole lot easier. In basic terms, it’s a JavaScript file which you link into your page that then enables you to do cool stuff.
There’s loads of capability built in, a portion of which covers our beloved Ajax. The whole thing is freely distributable under an MIT-style license, so it’s good to go. What a nice man that Mr Stephenson is – friends, let us raise a hearty cup of mulled wine to his good name. Cheers! sluurrrrp.
First step is to download the latest Prototype and put it somewhere safe. I suggest underneath the Christmas tree.
Cutting to the chase
Before I go on and set up an example of how to use this, let’s just get to the crux. Here’s how Prototype enables you to make a simple Ajax call and dump the results back to the page:var url = 'myscript.php';
var pars = 'foo=bar';
var target = 'output-div';
var myAjax = new Ajax.Updater(target, url, {method: 'get', parameters: pars});
This snippet of JavaScript does a GET to myscript.php, with the parameter foo=bar, and when a result is returned, it places it inside the element with the ID output-div on your page.
Knocking up a basic example
So to get this show on the road, there are three files we need to set up in our site alongside prototype.js. Obviously we need a basic HTML page with prototype.js linked in. This is the page the user interacts with. Secondly, we need our own JavaScript file for the glue between the interface and the stuff Prototype is doing. Lastly, we need the page (a PHP script in my case) that the Ajax is going to make its call too.
So, to that basic HTML page for the user to interact with. Here’s one I found whilst out carol singing:"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">



Easy Ajax














As you can see, I’ve linked in prototype.js, and also a file called ajax.js, which is where we’ll be putting our glue. (Careful where you leave your glue, kids.)
Our basic example is just going to take a name and then echo it back in the form of a seasonal greeting. There’s a form with an input field for a name, and crucially a DIV (greeting) for the result of our call. You’ll also notice that the form has a submit button – this is so that it can function as a regular form when no JavaScript is available. It’s important not to get carried away and forget the basics of accessibility.
Meanwhile, back at the server
So we need a script at the server which is going to take input from the Ajax call and return some output. This is normally where you’d hook into a database and do whatever transaction you need to before returning a result. To keep this as simple as possible, all this example here will do is take the name the user has given and add it to a greeting message. Not exactly Web 2-point-HoHoHo, but there you have it.
Here’s a quick PHP script – greeting.php – that Santa brought me early.$the_name = htmlspecialchars($_GET['greeting-name']);
echo "

Season's Greetings, $the_name!

";
?>
You’ll perhaps want to do something a little more complex within your own projects. Just sayin’.
Gluing it all together
Inside our ajax.js file, we need to hook this all together. We’re going to take advantage of some of the handy listener routines and such that Prototype also makes available. The first task is to attach a listener to set the scene once the window has loaded. He’s how we attach an onload event to the window object and get it to call a function named init():Event.observe(window, 'load', init, false);
Now we create our init() function to do our evil bidding. Its first job of the day is to hide the submit button for those with JavaScript enabled. After that, it attaches a listener to watch for the user typing in the name field.function init(){
$('greeting-submit').style.display = 'none';
Event.observe('greeting-name', 'keyup', greet, false);
}
As you can see, this is going to make a call to a function called greet() @onkeyup@ in the greeting-name field. That function looks like this:function greet(){
var url = 'greeting.php';
var pars = 'greeting-name='+escape($F('greeting-name'));
var target = 'greeting';
var myAjax = new Ajax.Updater(target, url, {method: 'get', parameters: pars});
}
The key points to note here are that any user input needs to be escaped before putting into the parameters so that it’s URL-ready. The target is the ID of the element on the page (a DIV in our case) which will be the recipient of the output from the Ajax call.
That’s it
No, seriously. That’s everything. Try the example. Amaze your friends with your 1337 Ajax sk1llz.
About the author
Drew McLellan is a web developer, author and no-good swindler from just outside London, England. At the Web Standards Project he works on press, strategy and tools. Drew keeps a personal weblog covering web development issues and themes.

baby1

Posted by Picasa