zoukankan      html  css  js  c++  java
  • 数据库三层模型

    1,什么是三层?

    2,为什么使用三层?

    3,三层与以往使用的两层相比有什么不同?它的优势在哪里?

    4,如何学好三层?如何应用三层?

    先了解:

    1、什么是三层

    UI(表现层):主要是指用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。

     

    BLL:(业务逻辑层):UI层和DAL层之间的桥梁实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。

     

    DAL:(数据访问层):与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的。用户的需求反映给界面(UI),UI反映给BLLBLL反映给DALDAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户)

    每一层都各负其责,那么该如何将三层联系起来呢?

    1>单项引用(见下图)

    2>这时候实体层(Entity)来了。(注:当然,实体层的作用不止这些)

     

    Entity(实体层):它不属于三层中的任何一层,但是它是必不可少的一层。

    Entity在三层架构中的作用(也叫模型层model):

    1,实现面向对象思想中的"封装";

    2,贯穿于三层,在三层之间传递数据;

    注:确切的说实体层贯穿于三层之间,来连接三层)

    3,对于初学者来说,可以这样理解:每张数据表对应一个实体,即每个数据表中的字段对应实体中的属性(注:当然,事实上不是这样。为什么?1>,可能我们需要的实体在数据表对应的实体中并不存在;2>,我们完全可以将所有数据表中的所有字段都放在一个实体里)

    4,每一层(UI>BLL>DAL)之间的数据传递(单向)是靠变量或实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。

    但是对于大量的数据来说,用变量做参数有些复杂,因为参数量太多,容易搞混。比如:我要把员工信息传递到下层,信息包括:员工号、姓名、年龄、性别、工资....用变量做参数的话,那么我们的方法中的参数就会很多,极有可能在使用时,将参数匹配搞混。这时候,如果用实体做参数,就会很方便,不用考虑参数匹配的问题,用到实体中哪个属性拿来直接用就可以,很方便。这样做也提高了效率。(字段转成对象的属性)

    注:这里为什么说可以暂时理解为每个数据表对应一个实体??答:大家都知道,我们做系统的目的,是为用户提供服务,用户可不关心你的系统后台是怎么工作的,用户只关心软件是不是好用,界面是不是符合自己心意。用户在界面上轻松的增、删、改、查,那么数据库中也要有相应的增、删、改、查,而增删改查具体操作对象就是数据库中的数据,说白了就是表中的字段。所以,将每个数据表作为一个实体类,实体类封装的属性对应到表中的字段,这样的话,实体在贯穿于三层之间时,就可以实现增删改查数据了)

    思想来源于生活:

    服务员:只管接待客人;

    厨师:只管做客人点的菜;

    采购员:只管按客人点菜的要求采购食材;

    他们各负其职,服务员不用了解厨师如何做菜,不用了解采购员如何采购食材;厨师不用知道服务员接待了哪位客人,不用知道采购员如何采购食材;同样,采购员不用知道服务员接待了哪位客人,不用知道厨师如何做菜。

    他们三者是如何联系的?

    比如:厨师会做:炒茄子、炒鸡蛋、炒面——此时构建三个方法( cookEggplant()cookEgg()cookNoodle())

     

    顾客直接和服务员打交道,顾客和服务员(UI层)说:我要一个炒茄子,而服务员不负责炒茄子,她就把请求往上递交,传递给厨师(BLL层),厨师需要茄子,就把请求往上递交,传递给采购员(DAL层),采购员从仓库里取来茄子传回给厨师,厨师响应cookEggplant()方法,做好炒茄子后,又传回给服务员,服务员把茄子呈现给顾客。

    这样就完成了一个完整的操作。

    在此过程中,茄子作为参数在三层中传递,如果顾客点炒鸡蛋,则鸡蛋作为参数(这是变量做参数)。如果,用户增加需求,我们还得在方法中添加参数,一个方法添加一个,一个方法设计到三层;何况实际中并不止设计到一个方法的更改。所以,为了解决这个问题,我们可以把茄子、鸡蛋、面条作为属性定义到顾客实体中,一旦顾客增加了炒鸡蛋需求,直接把鸡蛋属性拿出来用即可,不用再去考虑去每层的方法中添加参数了,更不用考虑参数的匹配问题。

    这样讲,不知道大家是不是可以明白。(待会实例解释吧)

    2,为什么使用三层?

    使用三层架构的目的:解耦!!!

    同样拿上面饭店的例子来讲:

    1)服务员(UI层)请假——另找服务员;厨师(BLL层)辞职——招聘另一个厨师;采购员(DAL)辞职——招聘另一个采购员;

    2)顾客反映:1>你们店服务态度不好——服务员的问题。开除服务员;

    2>你们店菜里有虫子——厨师的问题。换厨师;

    任何一层发生变化都不会影响到另外一层!!!

    3,与两层的区别??

    两层:

    (当任何一个地方发生变化时,都需要重新开发整个系统。“多层”放在一层,分工不明确耦合度高——难以适应需求变化,可维护性低、可扩展性低)

    三层:

    (发生在哪一层的变化,只需更改该层,不需要更改整个系统。层次清晰,分工明确,每层之间耦合度低——提高了效率,适应需求变化,可维护性高,可扩展性高)

    综上:三层架构的

    优势:1,结构清晰、耦合度低,2,可维护性高,可扩展性高;3,利于开发任务同步进行;容易适应需求变化

    劣势:1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

    2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码

    3、增加了代码量,增加了工作量

    4,三层的具体表现形式??

    models:定义用户实体模型

    namespace WeatherStationManager.Models
    {
       public class User
        {
            int userId;
    
            public int UserId
            {
                get { return userId; }
                set { userId = value; }
            }
            string userName;
    
            public string UserName
            {
                get { return userName; }
                set { userName = value; }
            }
            string userPassWord;
    
            public string UserPassWord
            {
                get { return userPassWord; }
                set { userPassWord = value; }
            }
            bool isDel;
    
            public bool IsDel
            {
                get { return isDel; }
                set { isDel = value; }
            }
            DateTime addTime;
    
            public DateTime AddTime
            {
                get { return addTime; }
                set { addTime = value; }
            }
        }
    }

    DAL:唯一直接与数据库交互的层

    1创建数据库访问公共类,负责完成 数据库访问对象的建立,数据库连接建立,sql命令的执行方法

    namespace WeatherStationManager.DAL
    {
        public class DBHelpSQL
        {
    
            private SqlConnection conn;//创建一个sql数据库打开的连接,参数是连接字符串
            /// <summary>
            /// 数据库连接对象属性
            /// </summary>
            /// 
           
            public SqlConnection Conn//封装为属性
            {
                get
                {
                  // string connectionString = ConfigurationManager.ConnectionStrings["ConnString"].ToString();
                   string connectionString = "server=.;database=WeatherStation;uid=sa;pwd=sasasa";
                    if (conn == null)
                    {
                        conn = new SqlConnection(connectionString);
                        conn.Open();
                    }
                    else if (conn.State == System.Data.ConnectionState.Closed)
                    {
                        conn.Open();
                    }
                    else if (conn.State == System.Data.ConnectionState.Broken)
                    {
                        conn.Close();
                        conn.Open();
                    }
                    return conn;
                }
            }
            /// <summary>
            /// 关闭数据库连接
            /// </summary>
            public void CloseDB()
            {
                if (conn.State == System.Data.ConnectionState.Open || conn.State == System.Data.ConnectionState.Broken)
                {
                    conn.Close();
                }
            }
    // 创建sqlDataReader对象(每次向数据库只读一条)必须调用 SqlCommand 对象的 ExecuteReader 方法,read()方法读取 ,每次读一条数据 ,查询 语句
    public SqlDataReader ExecuteReader(string sql, params SqlParameter[] parmaeters) { // SqlConnection conn = new SqlConnection(connctionString); SqlCommand cmd = new SqlCommand(sql, Conn); if (parmaeters != null) { cmd.Parameters.AddRange(parmaeters); } // conn.Open(); return cmd.ExecuteReader(CommandBehavior.CloseConnection);//返回sqlDataReader对象 } /// <summary> /// 执行sql语句 返回数据表 ,查询 /// </summary> /// <param name="safeSql">sql语句</param> /// <returns>数据表</returns> public DataTable GetDataTable(string safeSql) { //SqlConnection conn = new SqlConnection(connctionString); DataSet ds = new DataSet(); SqlCommand cmd = new SqlCommand(safeSql,Conn);
            //SqlDataAdapter是 DataSet和 SQL Server之间的桥接 SqlDataAdapter da
    = new SqlDataAdapter(cmd);//SqlCommand是sql命令,执行后通过sqlDataAdapter返回填入DataSet, da.Fill(ds); return ds.Tables[0];//将dataset的第一张表返回也就是datatable ,因为dataset是数据表集合 ,相当于内存中的数据库 } /// <summary> /// 执行sql语句 返回数据表 , 查询语句 /// </summary> /// <param name="sql">sql语句</param> /// <param name="values">sql参数列表</param> /// <returns>数据表</returns> public DataTable GetDataTable(string sql, params SqlParameter[] values) { DataSet ds = new DataSet(); SqlCommand cmd = new SqlCommand(sql, Conn); cmd.Parameters.AddRange(values); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(ds); cmd.Parameters.Clear(); return ds.Tables[0]; } /// <summary> /// 执行Command , 执行增删改 /// </summary> /// <param name="sql">sql语句</param> /// <param name="values">sql参数数组</param> /// <returns></returns> public int ExecuteCommand(string sql, params SqlParameter[] values) { SqlCommand cmd = new SqlCommand(sql, Conn); cmd.Parameters.AddRange(values); int result = cmd.ExecuteNonQuery(); //执行(增删改)的方法,返回执行命令所影响的行数(return int类型) cmd.Parameters.Clear(); return result; } /// <summary> /// 执行带sql参数的语句 /// </summary> /// <param name="sql">sql语句</param> /// <param name="values">sql参数列表</param> /// <returns></returns> public int GetScalar(string sql, params SqlParameter[] values) { object obj = null; try { SqlCommand cmd = new SqlCommand(sql, Conn); cmd.Parameters.AddRange(values); obj = cmd.ExecuteScalar();//获得查询到的结果集的第一个单元格的值,为obj类型 cmd.Parameters.Clear(); } catch (Exception ex) { throw ex; } finally { CloseDB(); } if (obj == null) return 0; else return Convert.ToInt32(obj); } } }

     2增删改查

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    using WeatherStationManager.Models;
    using System.Data.SqlClient;
    using System.Data;
    using System.Reflection;
    
    namespace WeatherStationManager.DAL
    {
        public class UserServices
        {
            DBHelpSQL dbHelper = null;  //DAL层需要用到数据库访问公共类 ,这里建立dbhelp对象
            public UserServices()
            {
                dbHelper = new DBHelpSQL();
            }
      
            #region 修改
            /// <summary>
            /// 修改学员信息
            /// </summary>
            /// <param name="model">学员实体</param>
            /// <returns></returns>
            public bool ModifyStudent(Models.User model)
            {
                StringBuilder sbSql = new StringBuilder("update [User] set ");// user 与系统关键字冲突  用[] 括起来
                Type modeType = model.GetType();//获得对象的类型
                PropertyInfo[] pros = modeType.GetProperties(); // 得到类型的所有公共属性
                List<SqlParameter> paras = new List<SqlParameter>();
                foreach (PropertyInfo pi in pros)   //反射获得属性和属性的值
                {
                    if (!pi.Name.Equals("UserId") && !pi.Name.Contains("AddTime"))//如果不是主键则追加sql字符串
                    {
                        if (pi.GetValue(model, null) != null && !pi.GetValue(model, null).ToString().Equals(""))//判断属性值是否为空
                        {
                            sbSql.Append(pi.Name + "=@" + pi.Name + ",");//SID=@SID
                            paras.Add(new SqlParameter("@" + pi.Name, pi.GetValue(model, null)));
                        }
                    }
                }
                string strSql = sbSql.ToString().Trim(','); //去掉两边的,
                strSql += " where UserId=@UserId";
                paras.Add(new SqlParameter("@UserId", model.UserId));
                return dbHelper.ExecuteCommand(strSql, paras.ToArray()) > 0;   //执行语句
            }
            #endregion
            #region 修改密码
            /// <summary>
            /// 修改学员信息
            /// </summary>
            /// <param name="model">学员实体</param>
            /// <returns></returns>
            public bool ModifyPwd(Models.User model)
            {
                string Sql = "update [User] set UserPassWord=@userpwd where UserName=@username ";
                Type modeType = model.GetType();
                SqlParameter[] parms = {
                                           new SqlParameter("@username",model.UserName),
                                           new SqlParameter("@userpwd",model.UserPassWord) 
                                       };
                return dbHelper.ExecuteCommand(Sql, parms) > 0;
            }
            #endregion
    
            #region 根据查询条件 返回 学生实体 列表  ,查询 
            /// <summary>
            /// 根据查询条件 返回 学生实体 列表 where SName=@SName and SPwd=@SPwd and SPwd=@SPwd
            /// </summary>
            /// <returns></returns>
            public List<Models.User> QueryListByCondition(SqlParameter[] paras)
            {
                Models.User model = null;
                StringBuilder sbSql = new StringBuilder("select * from [User]  where IsDel=0 ");
                if (paras != null)//如果参数数组不为空,则循环生成sql的条件语句,追加查询条件
                {
                    for (int i = 0; i < paras.Length; i++)//循环所有参数(如: and PWD=@SPWD)
                    {
                        SqlParameter p = paras[i];
                        sbSql.Append(" and ");//第二个参数开始 在前面加 and
                        sbSql.Append(p.ParameterName.Substring(1));//获得参数所对应的列名
                        sbSql.Append("=" + p.ParameterName);
                    }
                }
                //读取数据库 返回查询到的数据表(如果参数为null,则直接执行sql语句,否则带参数执行sql语句)
                DataTable dt = (paras == null) ? dbHelper.GetDataTable(sbSql.ToString()) : dbHelper.GetDataTable(sbSql.ToString(), paras);
                //准备要返回的泛型集合
                List<Models.User> list = null;
                if (dt.Rows.Count > 0)//如果查询到的行数大于0
                {
                    list = new List<Models.User>();//实例化集合对象
                    foreach (DataRow dr in dt.Rows)//循环临时表的行记录
                    {
                        model = new Models.User();//每循环一行生成一个实体
                        SetDr2Model(dr, model);//将行数据填入实体对应的属性
                        list.Add(model);//将实体对象加入集合
                    }
                }
                return list;
            }
            #endregion
            #region 新增
            public int ADD(Models.User MOD)
            {
                string sql = "insert into [User] (UserName,UserPassWord) values (@UserName,@UserPassWord);select @@identity";
                  //insert into 后获得自动插入的id(select @@identity) SqlParameter[] pars
    ={ new SqlParameter("@UserName",MOD.UserName), new SqlParameter("@UserPassWord",MOD.UserPassWord) }; int res = dbHelper.GetScalar(sql, pars); //获得插入id return res; } #endregion #region 根据id删除指定行 public int DelById(string UserId) { int res = dbHelper.ExecuteCommand("delete [User] where UserId=@UserId", new SqlParameter("@UserId", UserId)); return res; } #endregion #region 返回单个学生实体 public User GetUserByCondition(string UserName, string UserPwd) { string sql = "select * from [User] where UserName=@username and UserPassWord=@userpwd"; SqlParameter[] parms = { new SqlParameter("@username",UserName), new SqlParameter("@userpwd",UserPwd) }; SqlDataReader dr = dbHelper.ExecuteReader(sql, parms); User oneUser = null; //转换成实体对象 if (dr.Read()) { oneUser = new User(); oneUser.UserId = Convert.ToInt32(dr["UserId"]); oneUser.UserName = dr["UserName"].ToString(); oneUser.UserPassWord = dr["UserPassWord"].ToString(); oneUser.IsDel = Convert.ToBoolean(dr["IsDel"]); oneUser.AddTime = Convert.ToDateTime(dr["AddTime"]); } dr.Close();// dataReader 用完一定要关闭 return oneUser; } #endregion #region 将 数据行 转换 成 实体对象 /// <summary> /// 将 数据行 转换 成 实体对象,用于将dataset 的每一行转成实体对象 /// </summary> /// <param name="dr">数据行</param> /// <param name="model">实体对象</param> public void SetDr2Model(DataRow dr, Models.User model) { if (dr["UserId"].ToString() != "") { model.UserId = int.Parse(dr["UserId"].ToString()); } if (dr["UserName"].ToString() != "") { model.UserName = dr["UserName"].ToString(); } model.UserPassWord = dr["UserPassWord"].ToString(); if (dr["IsDel"].ToString() != "") { model.IsDel = bool.Parse(dr["IsDel"].ToString()); } if (dr["AddTime"].ToString() != "") { model.AddTime = DateTime.Parse(dr["AddTime"].ToString()); } } #endregion } }

     BLL:UI层与DAL层交互的桥梁

    namespace WeatherStationManager.BLL
    {
        public class UserManager
        {
            UserServices userServices = new UserServices();  //BLL层只需要与DAL层交互 ,这里建立 DAL层的对象
        /*    public int AddUser(User addUser)
            {
                if (!this.CheckExists(addUser.UserName,addUser.UserPassWord))
                {
                    //返回false表示不存在,则新增
                    return userServices.AddUser(addUser);
                }
                else
                {
                    throw new Exception("用户名已存在!");
                }
            }*/
            #region 修改密码
            /// <summary>
            /// 修改学员信息
            /// </summary>
            /// <param name="model">学员实体</param>
            /// <returns></returns>
            public bool ModifyPwd(Models.User model)
            {
               return userServices.ModifyPwd(model);
            }
            #endregion
            #region del
            public bool DelById(string UserId)
            {
                int res = userServices.DelById(UserId);
                bool resBool = false;
                if (res > 0)
                    resBool = true;
                else resBool = false;
                return resBool;
            }  
            #endregion
            #region add
            public bool ADD(Models.User mod)
            {
                int newId = userServices.ADD(mod);
                return newId > 0;
            } 
            #endregion
            #region updata
            /// <summary>
            /// 修改学员信息
            /// </summary>
            /// <param name="model">学员实体</param>
            /// <returns></returns>
            public bool ModifyStudent(Models.User model)
            {
                return userServices.ModifyStudent(model);
            }
            #endregion
            #region 获得所有user
            /// <summary>
            /// 获得所有列表
            /// </summary>
            /// <returns></returns>
            public List<Models.User> GetAllUsers()
            {
                return userServices.QueryListByCondition(null);
            }
            #endregion
            #region 是否存在
    
            /// <summary>
            /// 检测userName在数据库中是否存在,如果存在返回true,否则返回false
            /// </summary>
            /// <param name="typeName"></param>
            /// <returns></returns>
            public bool CheckExists(string userName, string userPwd)
            {
                User oneUser = userServices.GetUserByCondition(userName, userPwd);
                if (oneUser != null)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            } 
            #endregion
        }
    }

    我这里由于业务比较简单,其实必要的话 ,业务逻辑层是会加上一些复杂的逻辑判断的。

    这样的分层  数据层 只是访问 数据库 , 业务层做一些逻辑判断 , UI层负责显示 与输入 

    UI层 : 用户交互 

     1                 string uName = tb1.Text;  //获取用户输入
     2                 string uPwd = tb2.Text;
     3                 string apwd = tb3.Text;
     4                 bool res = false;
     5                 UserManager userManager = new UserManager();  //由于UI层只需要与BLL层交互 ,这里建立BLL对象
     6                 Models.User model=new Models.User();
     7                 if (uPwd!=apwd)
     8                 {
     9                     Response.Write("<script>alert('两次输入的密码不一致!')</script>");
    10                 }
    11                 else
    12                 {
    13                     model.UserName = uName;
    14                     model.UserPassWord = uPwd;
    15                     res = userManager.ModifyPwd(model);
    16                     Response.Write("<script>alert('修改成功!')</script>");
    17                 }
  • 相关阅读:
    iOS exit(0); 直接退出程序
    友盟推送简单调用
    KxMenu下拉菜单
    打开相册另类写法
    简洁调用字号
    十六进制颜色宏
    Swift定义单例
    不要在初始化方法和dealloc方法中使用Accessor Methods
    copyin函数
    c语言中的赋值
  • 原文地址:https://www.cnblogs.com/wangjian920110/p/5454969.html
Copyright © 2011-2022 走看看