苏飞论坛

 找回密码
 马上注册

QQ登录

只需一步,快速开始

分布式系统框架(V2.0) 轻松承载百亿数据,千万流量!讨论专区 - 源码下载 - 官方教程

HttpHelper爬虫框架(V2.7-含.netcore) HttpHelper官方出品,爬虫框架讨论区 - 源码下载 - 在线测试和代码生成

HttpHelper爬虫类(V2.0) 开源的爬虫类,支持多种模式和属性 源码 - 代码生成器 - 讨论区 - 教程- 例子

查看: 34365|回复: 18

[教程] 什么是分布式框架,结合例子来谈谈

[复制链接]
发表于 2015-1-9 17:45:47 | 显示全部楼层 |阅读模式
本帖最后由 songwenqi 于 2015-1-20 11:09 编辑

    分布式框架的目的是为了解决数据的分布,我们可以不用子查询、链表和存储过程,而是在程序中对数据进行处理,用程序来完成,用程序进行分布。在程序中配置不同的数据库连接字符串,对应的调取不同数据库中的数据,而且我们可以将这些不同数据库中的数据在业务逻辑层通过程序来进行关联和封装,来实现从不同数据之间的整合。   
   Model层(实体)
   若要实现分布,对应的实体就需要继承ModelBase这个基类,下面以LoginUserInfo 对象为例。

   
[C#] 纯文本查看 复制代码
/// <summary>[/align]/// 登录用户
/// </summary>
public class LoginUserInfo : ModelBase
{
/// <summary>
/// 用户ID
/// </summary>
public string ID { get; set; } 
}
    dao层(数据处理)
   首先我们需要定义一个数据库连接字符串。在dao层有个DbConfig.cs,用来专门定义不同的数据连接字符串。
[C#] 纯文本查看 复制代码
 /// <summary>
    /// 所有表的连接字符串都写在这里,方法统一修改
    /// </summary>
    public static class DbConfig
    {
        /// <summary>
        /// 默认的连接字符串
        /// </summary>
        public readonly static string DefaultConnection ="DefaultConnection";
        /// <summary>
        /// User表的连接字符串
        /// </summary>
        public static readonly string UserConnection ="UserConnection";
        /// <summary>
        /// LoginUser表的连接字符串
        /// </summary>
        public static readonly string LoginUserConnection = "LoginUserConnection";
}
    以LoginUserDAL.cs为例,这个类需要继承BaseDAL<T>,T就是LoginUserDAL所对应的model层的实体类,即LoginUserInfo。这里有个ConnName就是用来定义LoginUserDAL的数据库连接字符串,定义了数据库连接字符串,我们才能够连接对应的数据库进行相应的数据处理。
[C#] 纯文本查看 复制代码
public class LoginUserDAL : BaseDAL<LoginUserInfo>
    {
        /// <summary>
        /// 数据库连接字符串名称
        /// </summary>
        protected override string ConnName
        {
            get { return DbConfig.LoginUserConnection; }
        }
}
   下面就是重写了BaseDAL类的一个组织对象的方法。
[C#] 纯文本查看 复制代码
 public class LoginUserDAL : BaseDAL<LoginUserInfo>
    {/// <summary>
        /// 组织对象
        /// </summary>
        /// <param name="reader">Reader对象</param>
        /// <param name="fields">字段集合</param>
        /// <returns></returns>
        protected override LoginUserInfo FillModelFromReader(DbDataReader reader, params string[] fields)
        {
            return ModelFromReader(reader, fields);
        }

        /// <summary>
        /// 组织对象
        /// </summary>
        /// <param name="reader">Reader对象</param>
        /// <param name="fields">字段集合</param>
        /// <returns></returns>
        protected LoginUserInfo ModelFromReader(DbDataReader reader, params string[] fields)
        {
            var info = new LoginUserInfo();
            if (UtilDAL.HasFields("ID", fields)) info.ID = reader["ID"].ToString();
            if (UtilDAL.HasFields("UserName", fields)) info.UserName = reader["UserName"].ToString();
            if (UtilDAL.HasFields("UserPwd", fields)) info.UserPwd = reader["UserPwd"].ToString();
            if (UtilDAL.HasFields("UserStatus", fields)) info.UserStatus = (UserStatus)(int)reader["UserStatus"];
            if (UtilDAL.HasFields("LoginIp", fields)) info.LoginIp = reader["LoginIp"].ToString();
            if (UtilDAL.HasFields("LoginType", fields)) info.LoginType = (LoginType)(int)reader["LoginType"];

            return info;
        }
}

  在LoginUserDAL中,如果我们需要返回实体的话,就很简单了,我们可以直接调用BaseDAL类中的FindOne和FindList方法就可以直接返回该实体对象或者实体列表,无需做其他任何处理,这是因为在BaseDAL类中我们重写了组织对象的方法,BaseDAL类中的FindList方法会自动生成我们需要的类型。所以在DAL中查找对象我们可以这样写。
[C#] 纯文本查看 复制代码
public class LoginUserDAL : BaseDAL<LoginUserInfo>[/align]    {
/// <summary>
        /// 查找
        /// </summary>
        /// <param name="userId">ID</param>
        /// <returns></returns>
        public LoginUserInfo FindById(string userId)
        {
            var sql = "select * from [LoginUser] where ID=@ID";
            return FindOne(sql, UtilDAL.CreateParameter("@ID", userId));
        }
/// <summary>
        /// 分页列表
        /// </summary>
        /// <param name="strWhere">查询条件</param>
        /// <param name="field">查询字段</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页数</param>
        /// <param name="totalCount">记录总数</param>
        /// <returns></returns>
        public List<LoginUserInfo> FindListPage(string strWhere, string field, int pageIndex, int pageSize, out int totalCount)
        {

            return FindPage("LoginUser", field, strWhere, "ID desc", pageIndex, pageSize, out totalCount);
        }
}
    BLL层(业务逻辑)
   下面就是业务逻辑层BLL层了,BLL层是用来对业务逻辑进行处理,dao层只负责调取数据,分布式框架的优势在于在业务逻辑层层对分布的数据进行处理,而不去管数据从哪台服务器上来,数据处理层只负责将不同服务器上的数据提取过来,或者是说将同一台服务器上的不同数据库中的数据提取过来,业务逻辑层来将这些取来的数据进行处理,只要是这些数据之间存在某些必然联系,分布式框架就可以业务逻辑进行相应的处理将不同类型的数据放到一个实体类中,将不同的数据整合到一块,然后交给web层来得到我们想要的结果。
[C#] 纯文本查看 复制代码
public class LoginUserBLL
    {
      LoginUserDAL dal = new LoginUserDAL();

      /// <summary>
      /// 根据条件返回列表 带分页
      /// </summary>
      /// <param name="strWhere">要查询的条件</param>
      /// <param name="pageIndex">页数</param>
      /// <param name="pageSize">页码</param>
      /// <param name="totalCount">记录总数</param>
      /// <returns></returns>
      public List<LoginUserInfo> FindListPage(string strWhere, int pageIndex, int pageSize, out int totalCount)
      {
          List<LoginUserInfo> ulist = dal.FindListPage(strWhere, "", pageIndex, pageSize, out totalCount);
          if (ulist.Count <= 0)
          {
              return null;
          }
          //关联LoginUserInfo 实现两表之间的关系查询
          var userIdlist = ulist.Select(u =>"'"+ u.ID+"'");//这里需要注意
          //从这里解决链表和子查询
          UserBLL userbll = new UserBLL();
          //根据主表关联的ID去数据库查询子表数据,因为是ID,所以速度最快
          List<UserInfo> userList = userbll.FindList(userIdlist.ToList());
          //使用Foreach将数据的关键链接起来
          foreach (LoginUserInfo loginuser in ulist)
          {
              //这是就是数据关联的条件,满足这个条件的就说明是我们链接或者是要子查询的数据
              if (userList.Any(u => u.ID == loginuser.ID))
              {
                  UserInfo loginuserinfo = userList.FirstOrDefault(u => u.ID == loginuser.ID);
                  //将得到的子表数据直接添加的主表。完美解决子查询和链表问题
                  loginuser.AddExData("UserInfo", loginuserinfo);
              }
          }
          return ulist;
      }
}
    通过上面的代码我们可以看到分布式的点了,就是在这,因为LoginUserInfo和UserInfo这两个实体类对应的表之间是有联系的,它们是通过ID来建立以后总联系的,我们可以理解成这样,UserInfo这个类是用来存放用户的基本信息的,而LoginUserInfo是用来存放用户的登陆信息,它们通过ID字段进行关联。那么现在我调取LoginUserInfo的列表时我也想将它对应的用户的基本信息也取出来,传统的方法可能就是将这个实体对应的表用子查询、链表等的方式查询,但是分布式可以打破这种常规,我们可以用几个步骤来实现他们之间的关联。
1.首先查询出List<LoginUserInfo> ulist,也就是LoginUserInfo类的列表集合。
2.接着获取到我们上面查的集合里所有的IDs
3.通过获取的所有IDs来查找UserInfo类的列表集合List<UserInfo> userList
4.遍历ulist(LoginUserInfo类的列表集合),每次遍历的时候在userList(UserInfo类的列表集合)中查找UserInfo对象ID和LoginUserInfo对象ID相等的
UserInfo对象,然后添加到LoginUserInfo对象中。
      这样就完成了他们之间的关联。   
     上面的model需要继承我们分布式框架中的一个基类ModelBase.csModelBase.cs我们后续会专门探讨一下这个类的而实现原理,继承ModelBase后的实体类就具有了封装外来不同类型数据的功能了
    web层
   我们可以运行一下vs,调试一下,看看bll层的这种实现返回的列表到底是一种怎样的呈现方式,下面是截图:
    QQ截图20150120110341.png
   我们可以看到,这个LoginUserInfo列表集合里每一个LoginUserInfo对象都有一个ExData属性,这个属性里存放了我们附加进去的UserInfo对象,如此我们想要的关联已经完成,这就是如何分布的思路,下面的文章中还会继续深入讨论。
   文章开始我们提到数据库连接字符串,需要在网站项目的web.config中配置一下。
   
[C#] 纯文本查看 复制代码
<?xml version="1.0"?>[/align]
<!--
  有关如何配置 ASP.NET 应用程序的详细信息,请访问
  [url=http://go.microsoft.com/fwlink/?LinkId=169433]http://go.microsoft.com/fwlink/?LinkId=169433[/url]
  -->

<configuration>
  <connectionStrings>
    <!--默认的连接字符串-->
    <add name="DefaultConnection" connectionString="server=192.168.1.123;uid=sa;password=xxxxxxx;database=DB;" providerName="System.Data.SqlClient"/>
    <!--User表的连接字符串-->
    <add name="UserConnection" connectionString="server=192.168.1.123;uid=sa;password=xxxxxxxx;database=DB;" providerName="System.Data.SqlClient"/>
    <!--LoginUser表的连接字符串-->
    <add name="LoginUserConnection" connectionString="server=192.168.1.123;uid=sa;password=xxxxxxx;database=DB;" providerName="System.Data.SqlClient"/>
  </connectionStrings>
</configuration>
    而数据处理层负责从不同ip上或者同一ip上的数据库中提取数据就ok了,其他问题统统交给业务逻辑层来处理,当不同ip上取来的数据需要进行整合关联的话,就需要在业务逻辑层里进行处理,经过相应的处理,就实现了查询时的不同ip上的数据表的分布了。



1. 开通SVIP会员,免费下载本站所有源码,不限次数据,不限时间
2. 加官方QQ群,加官方微信群获取更多资源和帮助
3. 找站长苏飞做网站、商城、CRM、小程序、App、爬虫相关、项目外包等点这里
 楼主| 发表于 2015-1-20 10:53:45 | 显示全部楼层
自己顶一下。。。。。。重新编辑,重新写,加代码,加例子,希望大家看的更加明白
发表于 2015-4-8 17:33:40 | 显示全部楼层
我在思考:一个登录这么做会不会有点复杂了?试问为什么要舍弃数据库的存储过程才能使用这套分布式框架?
发表于 2015-4-8 17:47:43 | 显示全部楼层
还有,请问你们这样子做的分布式是否有代码生成器?像Model和BLL以及DAL的很多代码应该是一套逻辑可以生成出来的。
 楼主| 发表于 2015-4-9 08:32:17 | 显示全部楼层
912288184 发表于 2015-4-8 17:33
我在思考:一个登录这么做会不会有点复杂了?试问为什么要舍弃数据库的存储过程才能使用这套分布式框架?

这样做只是一个例子,只是为了让大家更好的理解分布式框架的思想和原理、以及分布式是如何运作的,并不是说实际开发中就用这种登录,我们做的只是例子,仅此,当数据表分布式在不同的服务器上,分布式的优势就显示出来了,分布式的思想就是可分布
发表于 2015-5-13 11:23:34 | 显示全部楼层
不太懂,数据分布  有什么表 分布,列分布  还有行分布 啥啥啥的,比如一个表每100万行存放到一个数据库, 又比如说一个表的n列存放到n个服务器上  这些都好乱 现在几乎完全搞不懂
 楼主| 发表于 2015-5-13 11:37:57 | 显示全部楼层
lyg1112 发表于 2015-5-13 11:23
不太懂,数据分布  有什么表 分布,列分布  还有行分布 啥啥啥的,比如一个表每100万行存放到一个数据库,  ...

数据库可以分布在不同的服务器上,
发表于 2015-5-13 12:03:08 | 显示全部楼层
songwenqi 发表于 2015-5-13 11:37
数据库可以分布在不同的服务器上,

这个我是知道呢  关键这些怎么实现 比如前100万条放在服务器A 后100万放在B  那么怎么实现查询呢?
 楼主| 发表于 2015-5-13 12:56:19 | 显示全部楼层
lyg1112 发表于 2015-5-13 12:03
这个我是知道呢  关键这些怎么实现 比如前100万条放在服务器A 后100万放在B  那么怎么实现查询呢?

这个分布式也是可以做到的,在程序里判断,如果取A服务器的数据就用A服务器配置的连接字符,b就用b的 同样是可以实现的
发表于 2015-11-3 10:42:51 | 显示全部楼层
淘宝的分布式难道也是这么分库吗?有没有考虑用NoSQL数据库来实现分布式呢?
您需要登录后才可以回帖 登录 | 马上注册

本版积分规则

QQ|手机版|小黑屋|手机版|联系我们|关于我们|广告合作|苏飞论坛 ( 豫ICP备18043678号-2)

GMT+8, 2024-12-25 15:37

© 2014-2021

快速回复 返回顶部 返回列表