从前面的初步分析来看,构建一个企业级应用系统是复杂而烦琐的,甚至让普通的程序员望而却步,但作为系统架构师却不得不考虑系统的方方面面,并且通过系统架构来控制风险,降低他们的编程门槛,以下是我作为系统架构师对各个开发层次中一些思考,希望大家补充指正:
一、数据持久层
我一直认为数据持久层的规划是企业级应用是否成功的关键点之一,在ERP实施上,有人说三分程序七分数据,我觉得这对于大型的企业级应用来说也是成立的。数据库中表、聚集索引、索引、事务和锁的设计和控制,都是影响应用高可用性的关键,但是对于普通程序员来说他们可能更熟悉的只是数据的简单的增、删、改、查。在这一个层次,我们除了依赖专业的DBA之外,作为系统架构师可以从以下几点帮助我们的程序员:
1.对于一般的场景我们可以通过编写生成模板来生成满足最佳实践的存贮过程,如对于简单表的增、删、改、查,对于常用的表的外键查询、分页查询、树状数据的维护和检索等等,都可以通过生成模板来生成,这样一般的应用需求我们的程序员甚至可以作到不用和SQL语句打交道,就可以完成开发。
2.对于手工编程的场景我们还可以提供一些标准的代码模板来规范开发。
如可以通过以下的标准存贮过程模板,来展示在创建存贮过程时该怎样控制开启事务,怎么样抛出异常等等。
代码
IF OBJECT_ID(N'[SomeSchema].[SomeProcedure]') IS NOT NULL
DROP PROCEDURE [SomeSchema].[SomeProcedure]
GO
CREATE PROCEDURE [SomeSchema].[SomeProcedure]
(
@SomeParameter nvarchar(256)
)
AS
BEGIN
BEGIN TRY
DECLARE @TranStarted bit
IF( @@TRANCOUNT = 0 )
BEGIN
BEGIN TRANSACTION
SET @TranStarted = 1
END
ELSE
BEGIN
SET @TranStarted = 0
END
-- SELECT TOP 1 * FROM [SomeSchema].[SomeTable]
-- WHERE SomeField = @SomeParameter
-- IF @@RowCount = 0
-- BEGIN
-- RAISERROR('Some Error Information!',16,1)
-- END
IF @TranStarted = 1
BEGIN
SET @TranStarted = 0
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
IF( @TranStarted = 1 )
BEGIN
SET @TranStarted = 0
ROLLBACK TRANSACTION
END
DECLARE @ErrorMessage NVARCHAR(256)
DECLARE @ErrorServerity INT
DECLARE @ErrorState INT
SET @ErrorMessage = ERROR_MESSAGE()
SET @ErrorServerity = ERROR_SEVERITY()
SET @ErrorState = ERROR_STATE()
RAISERROR(@ErrorMessage,@ErrorServerity,@ErrorState)
END CATCH
END
GO
3.而对于那些复杂的场景,我们可以专注的培养一些程序员,并通过培训或提供指导型文档来帮助他们提高他们对底层数据的理解。比如提供下面的简单的流水号生成示例来提升对锁、事务及并发的理解等等。
代码
CREATE TABLE [Platform].[Ssn](
[SsnName] [nvarchar](32) NOT NULL,
[CurrentValue] [bigint] NOT NULL,
CONSTRAINT [PK_Ssn] PRIMARY KEY CLUSTERED
(
[SsnName] ASC
))
GO
IF OBJECT_ID(N'[Platform].[GetNextSsn]') IS NOT NULL
DROP PROCEDURE [Platform].[GetNextSsn]
GO
CREATE PROCEDURE [Platform].[GetNextSsn]
(
@SsnName nvarchar(32),
@NextSsn bigint output
)
AS
BEGIN
BEGIN TRY
DECLARE @TranStarted bit
IF( @@TRANCOUNT = 0 )
BEGIN
BEGIN TRANSACTION
SET @TranStarted = 1
END
ELSE
BEGIN
SET @TranStarted = 0
END
DECLARE @CurrentValue bigint
SELECT @CurrentValue = CurrentValue
FROM Platform.Ssn WITH(UPDLOCK,ROWLOCK,HOLDLOCK)
IF @@ROWCOUNT = 0
BEGIN
SET @NextSsn = 1
--WAITFOR DELAY '00:10';
INSERT INTO Platform.Ssn(SsnName,CurrentValue)
VALUES(@SsnName, @NextSsn)
END
ELSE
BEGIN
SET @NextSsn = @CurrentValue + 1
--WAITFOR DELAY '00:10';
UPDATE Platform.Ssn
SET CurrentValue = @NextSsn
WHERE SsnName = @SsnName
END
IF @TranStarted = 1
BEGIN
SET @TranStarted = 0
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
IF( @TranStarted = 1 )
BEGIN
SET @TranStarted = 0
ROLLBACK TRANSACTION
END
DECLARE @ErrorMessage NVARCHAR(256)
DECLARE @ErrorServerity INT
DECLARE @ErrorState INT
SET @ErrorMessage = ERROR_MESSAGE()
SET @ErrorServerity = ERROR_SEVERITY()
SET @ErrorState = ERROR_STATE()
RAISERROR(@ErrorMessage,@ErrorServerity,@ErrorState)
END CATCH
END
GO