1. 三层架构(不是本文重点,简单介绍一下)
1) 用户界面层(UI层),主要职责是提供可用的功能给用户。用户界面层(一般是XXXView),主要职责是响应(识别)用户的请求操作(包括UI层返回及用户的输入数据)
,由请求操作调用相应的XXXController(或XXXManager)完成相应的业务逻辑;在这一层也还要对一些错误信息进行判断和处理(错误信息是和数据库没有关系的。
2) 业务逻辑模块层(一般由XXXController或 XXXManager类模块组成),主要职责执行业务逻辑的计算,业务逻辑可以很简单,简单到只是简单的调用XXXDAO的一个save操作。也可以很复杂,复杂到要用到多个CXXXDAO(或者说是多个table表)才能完成。即使用到了多个table表,业务逻辑层也不应该直接用sql操作
table表,那样会带来维护的复杂度,这时应该新建一个能操作相关table的XXXDAO新类,让这个新类来完成业务逻辑要求的复杂的sql(或是复杂的存储过程)。
3) DAO层(即数据访问层)。主要职责完成各种各样的存储、查询操作。主要作用是向上提供不同的存储接口及查询。如saveUserAndXxx();getUserAdnXxx()等等;提供数据的简化访问的同时也屏蔽了数据库的存在,业务逻辑层不需要知道DAO层到底在用那个数据库,或者根本就没用。
理论知识说破天也就那样,关键还是实践,能把三层通过几个项目实践出来,从项目中不断认识三层架构,仔细分析架构的好处才是硬道理。
2. 事务(不是重点,简单介绍一下)
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务有四个属性(原子性、一致性、隔离性、持久性)。
原子性主要描述的是一个事务的不可分割性,要么都做要么都不做。
一致性主要描述的是数据库从一个一致性的状态变到了另外一个一致性的状态
隔离性主要描述的是事务执行的不被干扰性
持久性主要描述的是事务一旦提交那么数据库的改变是永久性的不会被其他操作影响。
3、事务在三层架构中的运用(这是重点)
网上也有许多人在议论,事务应该在三层架构中哪一层设计比较好。其实我个人认为没有好与不好之分,只有哪个在特定环境下比较合适。
我现在做着的这个项目中出现了这个问题,正好在这里唠叨唠叨。
首先说,数据事务肯定是在数据层,因为如果在数据层不写事务的话,那么涉及数据的回滚,就会出现问题。然而事务在逻辑层使用也是不可避免的,事务管理就是业务的范畴,所以事务处理应该在逻辑层中实现。(这是自己的理解,欢迎大家斧正)
通过这样的分析,就很容易知道我们要在逻辑层中事务开启、提交、异常回滚和关闭。而事务的实现其实是在数据层实现的。
我相信肯定会有人认为事务只写在数据层就行,在业务逻辑层用sqlConnection感觉很不正常,其实这个观点网上也有很多人认同,也有很多人是这样做的。那我我还是说没有正确与否,只有合适不合适,这要根据项目来确定。首先说在数据层写事务是没有问题,一样能够实现。那么两者有什么区别,这是我们要明白的,也是我们选择在哪里写事务的一个主要因素。
就像我刚才说的,我选择在业务逻辑层这样我只要在逻辑层的事务操作中只做一次连接即可,而在数据层那么我们可能就不仅仅是一次了吧!如果我们在一个多发性的操作中,可能我们就会应为这样一个连接没有处理好就会导致程序崩溃。
还是那句话,没有唯一的正确标准,只有在某种情况下适合的方案。
如果我们在逻辑层使用事务的话,那么我们势必会在业务逻辑层中开启数据库连接,而我们的数据库连接一般都会写在一个数据库助手类(sqlHelper)中,这样我们就有可能面临业务逻辑层中创建数据库助手类对象了。这样做耦合度会变得很高。那么我们可以通过事务独立成立来降低这个耦合度。具体的事务类中主要实现数据库连接,开启事务处理和关闭连接等操作。
具体事务类代码实现:
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using StuEduAdministrationModel;
using SqlHelp;
namespace StuEduAdministrationDAL
{
public class TransactionManager
{
/// <summary>
/// 定义连接
/// </summary>
SqlConnection sqlConnection = new SqlConnection();
/// <summary>
/// 定义事务
/// </summary>
SqlTransaction sqlTransaction;
/// <summary>
/// 得到连接
/// </summary>
/// <returns></returns>
public SqlConnection GetConnection()
{
sqlConnection.ConnectionString = ConfigurationManager.ConnectionStrings["StuEduAdministration"].ConnectionString;
sqlConnection.Open();
return sqlConnection;
}
/// <summary>
/// 开启事务
/// </summary>
public SqlTransaction TranBegin()
{
sqlTransaction = sqlConnection.BeginTransaction();
return sqlTransaction;
}
/// <summary>
/// 提交事务
/// </summary>
public void TranCommit()
{
sqlTransaction.Commit();
}
/// <summary>
/// 回滚事务
/// </summary>
public void TranRollback()
{
sqlTransaction.Rollback();
}
/// <summary>
/// 关闭连接
/// </summary>
public void Close()
{
sqlConnection.Close();
}
}
}
我们在sqlHelper的代码就要这样实现事务处理即可:
Public Overloads Function ExecuteNonQuery(ByVal
SqlString As String, ByVal SqlParameters As SqlParameterCollection,
ByVal objTransaction
As SqlTransaction) As Integer
Dim intTemp As Integer
Dim cmd As SqlCommand
Try
Me.InitializeConnection() '初始化连接
cmd = New SqlCommand(SqlString, m_objConnection)
cmd.Transaction = objTransaction '事物处理
'将参数集合中的参数添加到cmd中
Call Me.AddSqlParametersToCommand(cmd, SqlParameters)
intTemp = cmd.ExecuteNonQuery()
Me.FinalizeConnection() '关闭连接(与维护连接对象的方式有关)
Catch ex As Exception
Throw ex
End Try
Return intTemp
End Function
那么我们在数据层只需实例化sqlHelper类并传递从逻辑层传过来的事务类还有数据库连接参数即可:
private SqlConnection sqlCon;
private SqlTransaction sqlTra;
/// <summary>
/// 数据库助手类型
///
/// </summary>
private SqlHelper sqlHelper;
public SubCategoryScoreDAO(SqlConnection sqlCon,SqlTransaction
sqlTra)
{
this.sqlCon = sqlCon;
this.sqlTra = sqlTra;
sqlHelper = new SqlHelper(sqlCon);
}
public SubCategoryScoreDAO()
{
sqlHelper = new SqlHelper("StuEduAdministration");
}
在逻辑层中进行事务开启和关闭等操作:
<font xmlns="http://www.w3.org/1999/xhtml"></font><pre
name="code" class="csharp"><font
xmlns="http://www.w3.org/1999/xhtml"> ///
<summary>
/// 根据学号学年删除子类别参评得分信息
/// </summary>
/// <param name="strAcademicYear">学年</param>
/// <param name="strStuNo">学号</param>
public bool DeleteByStuNoAcademicYear(string strAcademicYear,
string strStuNo)
{
SqlConnection sqlCon = transactionManager.GetConnection();
//获得连接
SqlTransaction sqlTra = transactionManager.TranBegin();
//事务开启
try
{
objCategoryScoreDAO = new CategoryScoreDAO(sqlCon, sqlTra);
objEvaluateInfoDAO = new EvaluateInfoDAO(sqlCon, sqlTra);
objSubCategoryScoreDAO = new SubCategoryScoreDAO(sqlCon,
sqlTra);
objSubCategoryScoreDAO.DeleteByStuNoAcademicYear(strAcademicYear,
strStuNo);
objCategoryScoreDAO.DeleteBystuNoAcademicYear(strAcademicYear,
strStuNo);
objEvaluateInfoDAO.DeleteByStuNoAcademicYear(strAcademicYear,
strStuNo);
transactionManager.TranCommit(); //事务提交
return true;
}
catch (Exception)
{
transactionManager.TranRollback(); //事务回滚
throw;
}
finally
{
transactionManager.Close(); //事务关闭
}
}</font>
通过这样的设计,就可以在逻辑层实现事务管理,才数据层进行事务实现。
最后还是那句话,没有最好的,只有最合适的。 |