Notes on Stored Procedures CSSE333 Intro to Database Systems--Winter 2005-2006 Outline • Application Design • Tiered Architectures • O/R Mapping • The CRUD Pattern • Why use stored procedures? • Advice • Lab Tiered Architectures • The standard three-tiered architecture consists of the presentation, application and data access tiers. • The problem is many applications require a high coupling between the bottom two tiers. Changing database architectures often dramatically affects the system at the application tier. • Can be due to poor design, but also strongly influenced by changing database connection technologies. N-Tiers and so on … • There are many designs variations based on the 3-tier architecture. • Many introduce a data services layer to abstract the database connection technology. From: www.novicksoftware.com Web Services for Data Access • Web services are Web-based enterprise applications that use open, XML-based standards and transport protocols to exchange data with calling clients. Sun.com • SOAP ("Simple Object Access Protocol") is a simple XML-based protocol to let applications exchange information over HTTP. – W3C • Useful for distributed application designs. • Can be used to reduce coupling to database connection technologies. • Especially common in modern websites. Persistence Framework • The application layer should use a persistence framework (or layer) to solve the coupling problem. • A good persistence framework will hide the fact that objects are even being stored in a relational database. O/R Mapping • Most modern business application development projects use object technology such as Java or C# to build the application software and relational databases to store the data. • There is an impedance mismatch between object and relational design methods. • Object-relational mapping (also ORM) is used to map object-oriented programming objects to relational databases. O/R Mapping - Additional Concepts • • Shadow information is any data that objects need to maintain, above and beyond their normal domain data, to persist themselves. This typically includes primary key information, particularly when the primary key is a surrogate key that has no business meaning, concurrency control markings such as timestamps or incremental counters, and versioning numbers. … A common practice is for each class to implement an isPersistent boolean flag that is set to true when the data is read in from the database and set to false when the object is newly created. Lazy Reads - An important performance consideration is whether the attribute should be automatically read in when the object is retrieved. When an attribute is very large, for example the picture of a person could be 100k whereas the rest of the attributes are less than 1k, and rarely accessed you may want to consider taking a lazy read approach. The basic idea is that instead of automatically bringing the attribute across the network when the object is read you instead retrieve it only when the attribute is actually needed. This can be accomplished by a getter method, an operation whose purpose is to provide the value of a single attribute, that checks to see if the attribute has been initialized and if not retrieves it from the database at that point. From: http://www.ambysoft.com/essays/mappingObjects.html • Another decent reference: http://www.chimu.com/publications/objectRelational/ • The CRUD Pattern • Organizes the persistence operations of an application into Create, Retrieve, Update and Delete operations that are implemented by a persistence layer. Patterns in Java, Volume 3. • The CRUD pattern is usually implemented on the database. Stored procedures are the recommended method for SQL Server. • It is suggested that they be created in an automated manner. • They will have to deal with O/R mapping, but are not expected to contain application logic!!! Why use stored procedures? The reasons for using Stored Procedures to implement the Data Storage Layer instead of allowing ad hoc SQL statements are: • The best possible performance • Removes the SQL code from the other layers of the application • Prevents SQL injection attacks • Prevents casual table browsing and modifications • Easy to create atomic transactions • Can catch exceptions • Recommended by vendors - Derived from: www.novicksoftware.com and Rob Howard's Blog There is a debate Flame war really… • Issues with performance • Issues with DBA vs Developer control • Issues with DB portability • Issues with source control • Issues with dogma • Dynamically SQL & Parameterized Queries can be preferred • In general concatenated SQL is to be avoided to prevent injection attacks. string query = "SELECT * FROM Users WHERE UserID = '" + tbxUserId.Text + "'"; Theory & Practice • Business logic often gets into data layer • Many times designers model objects after data structure (and visa versa) • Many glue layers are tedious to create and maintain manually. • A many tiered application can seem over architected and may not have immediate advantages • Abstraction increases load • Legacy code complicates things • Best solution requires consideration of case Additional Wisdom • Do not use a highly privileged SQL account (like SA) to access from the application. (Also do not use a highly privileged domain account). • Encrypt the DB connection string. • Avoid fetching static information from the DB every time you need it. Cache it in the application. • Do not use SELECT * … ALWAYS define the table columns once you have determined them. • Do not prefix user sprocs with sp_. This actually stands for ‘system procedure’. Your procedure may become inaccessible. • Use parameter validation at all layers. You may get unexpected results otherwise. Derived from Doug Seven’s “10 Things You Shouldn't Do with SQL Server” Stored Procedures Are Code!!! • Use source control. (This can be difficult.) • Always include comments, good variable names, and exception handling. • Try to re-use code. T-SQL does not support OOP. However, you can call other sprocs and UDFs. • Test and validate the code. New in SQL Server 2005 • CLR is embedded inside the database engine, meaning T-SQL functions can be converted to CLR functions for significant performance gains, and applications can be run inside the engine • A new tool called Service Broker also stands to alter the way applications are designed. The new feature is described as an asynchronous programming environment that creates a "persistent dialogue" between the client application and the server. • Offers native XML support - From SearchSQLServer.com Today’s Lab • Probably really long, but hopefully fun • May not be good example of data layer abstraction • Good opportunity to understand possibilities for stored procedures • We will try to offer hints Read Example - get_Order Details_1 --- Review products in order --------------------------------------------- Demo: -- DECLARE @Status SMALLINT -- EXEC @Status = [get_Order Details_1] 10501 -- SELECT Status = @Status -------------------------------------------- Revision History -- Created - WFM - 01/10/2005 CREATE PROCEDURE [get_Order Details_1] (@OrderID_1 [int]) AS -- Supress row count messages SET NOCOUNT ON -- Check to see if OrderID is valid IF (SELECT Count(OrderID) from Orders WHERE OrderID = @OrderID_1) <> 1 BEGIN PRINT "The OrderID " + CONVERT(varchar(30), @OrderID_1 ) + " does not exist" RETURN 1 END -- Retrieve the order details SELECT * FROM [Order Details] WHERE OrderID = @OrderID_1 -- Check for errors DECLARE @Status SMALLINT SET @Status = @@ERROR IF @Status <> 0 BEGIN -- Return error code to the calling program to indicate failure. PRINT "An error occurred getting the details for the order " + CONVERT(varchar(30), @OrderID_1) + "." RETURN(@Status) END ELSE BEGIN -- Return 0 to the calling program to indicate success. PRINT "The details for the order " + CONVERT(varchar(30), @OrderID_1) + " were retrieved successfully." RETURN(0) END GO Update Example - update_Order Details_1 --- Adjust qnty, price, or discount for products on order --- NOTE: This is script is for hints and is not a complete solution --------------------------------------------- Demo: -- DECLARE @Status SMALLINT -- EXEC @Status = [update_Order Details_1] 10501, 2 -- SELECT Status = @Status --- SELECT * FROM [Order Details] WHERE OrderID = 10501 -- SELECT * FROM Products WHERE ProductID = 2 -------------------------------------------- Revision History -- Created - WFM - 01/10/2005 CREATE PROCEDURE [update_Order Details_1] (@OrderID_1 [int], @ProductID_2 [int], @NewQuantity_4 [smallint]=0, @NewUnitPrice_3 [money] = 0, @NewDiscount_5 [real] = 0) AS -- Supress row count messages SET NOCOUNT ON -- Check to see if product needs to be reordered DECLARE @UnitsInStock INT DECLARE @ReorderLevel INT SELECT @UnitsInStock=UnitsInStock , @ReorderLevel = ReorderLevel FROM products WHERE ProductID = @ProductID_2 IF (@UnitsInStock < @ReorderLevel) BEGIN UPDATE PRODUCTS SET UnitsOnOrder = @ReorderLevel*5 WHERE ProductID = @ProductID_2 END -- Update Order Detail values UPDATE [Northwind].[dbo].[Order Details] SET [UnitPrice] = @NewUnitPrice_3, [Quantity] = @NewQuantity_4, [Discount] = @NewDiscount_5 WHERE ( [OrderID] = @OrderID_1 AND [ProductID] = @ProductID_2) GO