当前位置: 首页 > 编程日记 > 正文

浅谈数据库设计技巧

说到数据库,我认为不能不先谈数据结构。1996年,在我初入大学学习计算机编程时,当时的老师就告诉我们说:计算机程序=数据结构+算法。尽管现在的程序开发已由面向过程为主逐步过渡到面向对象为主,但我还是深深赞同8年前老师的告诉我们的公式:计算机程序=数据结构+算法。面向对象的程序开发,要做的第一件事就是,先分析整个程序中需处理的数据,从中提取出抽象模板,以这个抽象模板设计类,再在其中逐步添加处理其数据的函数(即算法),最后,再给类中的数据成员和函数划分访问权限,从而实现封装。

  数据库的最初雏形据说源自美国一个奶牛场的记账薄(纸质的,由此可见,数据库并不一定是存储在电脑里的数据^_^),里面记录的是该奶牛场的收支账目,程序员在将其整理、录入到电脑中时从中受到启发。当按照规定好的数据结构所采集到的数据量大到一定程度后,出于程序执行效率的考虑,程序员将其中的检索、更新维护等功能分离出来,做成单独调用的模块,这个模块后来就慢慢发展、演变成现在我们所接触到的数据库管理系统(DBMS)——程序开发中的一个重要分支。

  下面进入正题,首先按我个人所接触过的程序给数据库设计人员的功底分一下类:
  1、没有系统学习过数据结构的程序员。这类程序员的作品往往只是他们的即兴玩具,他们往往习惯只设计有限的几个表,实现某类功能的数据全部塞在一个表中,各表之间几乎毫无关联。网上不少的免费管理软件都是这样的东西,当程序功能有限,数据量不多的时候,其程序运行起来没有什么问题,但是如果用其管理比较重要的数据,风险性非常大。
  2、系统学习过数据结构,但是还没有开发过对程序效率要求比较高的管理软件的程序员。这类人多半刚从学校毕业不久,他们在设计数据库表结构时,严格按照教科书上的规定,死扣E-R图和3NF(别灰心,所有的数据库设计高手都是从这一步开始的)。他们的作品,对于一般的access型轻量级的管理软件,已经够用。但是一旦该系统需要添加新功能,原有的数据库表差不多得进行大换血。
  3、第二类程序员,在经历过数次程序效率的提升,以及功能升级的折腾后,终于升级成为数据库设计的老鸟,第一类程序员眼中的高人。这类程序员可以胜任二十个表以上的中型商业数据管理系统的开发工作。他们知道该在什么样的情况下保留一定的冗余数据来提高程序效率,而且其设计的数据库可拓展性较好,当用户需要添加新功能时,原有数据库表只需做少量修改即可。
  4、在经历过上十个类似数据库管理软件的重复设计后,第三类程序员中坚持下来没有转行,而是希望从中找出偷懒窍门的有心人会慢慢觉悟,从而完成量变到质变的转换。他们所设计的数据库表结构有一定的远见,能够预测到未来功能升级所需要的数据,从而预先留下伏笔。这类程序员目前大多晋级成数据挖掘方面的高级软件开发人员。
  5、第三类程序员或第四类程序员,在对现有的各家数据库管理系统的原理和开发都有一定的钻研后,要么在其基础上进行二次开发,要么自行开发一套有自主版权的通用数据库管理系统。

  我个人正处于第三类的末期,所以下面所列出的一些设计技巧只适合第二类和部分第三类数据库设计人员。同时,由于我很少碰到有兴趣在这方面深钻下去的同行,所以文中难免出现错误和遗漏,在此先行声明,欢迎大家指正,不要藏私哦8)

  一、树型关系的数据表
  不少程序员在进行数据库设计的时候都遇到过树型关系的数据,例如常见的类别表,即一个大类,下面有若干个子类,某些子类又有子类这样的情况。当类别不确定,用户希望可以在任意类别下添加新的子类,或者删除某个类别和其下的所有子类,而且预计以后其数量会逐步增长,此时我们就会考虑用一个数据表来保存这些数据。按照教科书上的教导,第二类程序员大概会设计出类似这样的数据表结构:

类别表_1(Type_table_1)
名称     类型    约束条件   说明
type_id  
   int        无重复     类别标识,主键
type_name
   char(50)    不允许为空   类型名称,不允许重复
type_father   int        
不允许为空   该类别的父类别标识,如果是顶节点的话设定为某个唯一值

  这样的设计短小精悍,完全满足3NF,而且可以满足用户的所有要求。是不是这样就行呢?答案是NOWhy

  我们来估计一下用户希望如何罗列出这个表的数据的。对用户而言,他当然期望按他所设定的层次关系一次罗列出所有的类别,例如这样:
总类别
  类别1
    类别1.1
      类别1.1.1
    类别1.2
  类别2
    类别2.1
  类别3
    类别3.1
    类别3.2
  ……

  看看为了实现这样的列表显示(树的先序遍历),要对上面的表进行多少次检索?注意,尽管类别1.1.1可能是在类别3.2之后添加的记录,答案仍然是N次。这样的效率对于少量的数据没什么影响,但是日后类型扩充到数十条甚至上百条记录后,单单列一次类型就要检索数十次该表,整个程序的运行效率就不敢恭维了。或许第二类程序员会说,那我再建一个临时数组或临时表,专门保存类型表的先序遍历结果,这样只在第一次运行时检索数十次,再次罗列所有的类型关系时就直接读那个临时数组或临时表就行了。其实,用不着再去分配一块新的内存来保存这些数据,只要对数据表进行一定的扩充,再对添加类型的数量进行一下约束就行了,要完成上面的列表只需一次检索就行了。下面是扩充后的数据表结构:

类别表_2(Type_table_2)
名称     类型    约束条件                       说明
type_id  
   int        无重复                     类别标识,主键
type_name
   char(50)    不允许为空                   类型名称,不允许重复
type_father   int        
不允许为空                   该类别的父类别标识,如果是顶节点的话设定为某个唯一值
type_layer    char(6)    
限定3,初始值为000000       类别的先序遍历,主要为减少检索数据库的次数

  按照这样的表结构,我们来看看上面例子记录在表中的数据是怎样的:

type_id      type_name          type_father          type_layer
1            
总类别               0                 000000
2            
类别1                1                 010000
3            
类别1.1              2                 010100
4            
类别1.2              2                 010200
5            
类别2                1                 020000
6            
类别2.1              5                 020100
7            
类别3                1                 030000
8            
类别3.1              7                 030100
9            
类别3.2              7                 030200
10           
类别1.1.1            3                 010101
……

  现在按type_layer的大小来检索一下:SELECT * FROM Type_table_2 ORDER BY type_layer

列出记录集如下:

type_id      type_name          type_father          type_layer
1            
总类别               0                 000000
2            
类别1                1                 010000
3            
类别1.1              2                 010100
10           
类别1.1.1            3                 010101
4            
类别1.2              2                 010200
5            
类别2                1                 020000
6            
类别2.1              5                 020100
7            
类别3                1                 030000
8            
类别3.1              7                 030100
9            
类别3.2              7                 030200
……

  现在列出的记录顺序正好是先序遍历的结果。在控制显示类别的层次时,只要对type_layer字段中的数值进行判断,每2位一组,如大于0则向右移2个空格。当然,我这个例子中设定的限制条件是最多3层,每层最多可设99个子类别,只要按用户的需求情况修改一下type_layer的长度和位数,即可更改限制层数和子类别数。其实,上面的设计不单单只在类别表中用到,网上某些可按树型列表显示的论坛程序大多采用类似的设计。

  或许有人认为,Type_table_2中的type_father字段是冗余数据,可以除去。如果这样,在插入、删除某个类别的时候,就得对type_layer 的内容进行比较繁琐的判定,所以我并没有消去type_father字段,这也正符合数据库设计中适当保留冗余数据的来降低程序复杂度的原则,后面我会举一个故意增加数据冗余的案例。

  二、商品信息表的设计
  假设你是一家百货公司电脑部的开发人员,某天老板要求你为公司开发一套网上电子商务平台,该百货公司有数千种商品出售,不过目前仅打算先在网上销售数十种方便运输的商品,当然,以后可能会陆续在该电子商务平台上增加新的商品出售。现在开始进行该平台数据库的商品信息表的设计。每种出售的商品都会有相同的属性,如商品编号,商品名称,商品所属类别,相关信息,供货厂商,内含件数,库存,进货价,销售价,优惠价。你很快就设计出4个表:商品类型表(Wares_type),供货厂商表(Wares_provider),商品信息表(Wares_info)

商品类型表(Wares_type)
名称     类型    约束条件                       说明
type_id  
   int        无重复                     类别标识,主键
type_name
   char(50)    不允许为空                   类型名称,不允许重复
type_father   int        
不允许为空                   该类别的父类别标识,如果是顶节点的话设定为某个唯一值
type_layer    char(6)    
限定3,初始值为000000       类别的先序遍历,主要为减少检索数据库的次数

供货厂商表(Wares_provider)
名称     类型    约束条件                       说明
provider_id   int   
    无重复                     供货商标识,主键
provider_name char(100)  
不允许为空                   供货商名称

商品信息表(Wares_info)
名称      类型    约束条件                       说明
wares_id       int   
   无重复                       商品标识,主键
wares_name     char(100) 
不允许为空                     商品名称
wares_type
   int        不允许为空          商品类型标识,和Wares_type.type_id关联
wares_info     char(200) 
允许为空                       相关信息
provider       int       
不允许为空                     供货厂商标识,和Wares_provider.provider_id关联
setnum         int       
初始值为1                      内含件数,默认为1
stock          int       
初始值为0                      库存,默认为0
buy_price      money     
不允许为空                     进货价
sell_price     money     
不允许为空                     销售价
discount       money     
不允许为空                     优惠价

  你拿着这3个表给老板检查,老板希望能够再添加一个商品图片的字段,不过只有一部分商品有图片。OK,你在商品信息表(Wares_info)中增加了一个haspicBOOL型字段,然后再建了一个新表——商品图片表(Wares_pic)

商品图片表(Wares_pic)
名称      类型    约束条件                       说明
pic_id        int   
    无重复                       商品图片标识,主键
wares_id      int        
不允许为空                     所属商品标识,和Wares_info.wares_id关联
pic_address
  char(200)   不允许为空          图片存放路径

  程序开发完成后,完全满足老板目前的要求,于是正式启用。一段时间后,老板打算在这套平台上推出新的商品销售,其中,某类商品全部都需添加长度的属性。第一轮折腾来了……当然,你按照添加商品图片表的老方法,在商品信息表(Wares_info)中增加了一个haslengthBOOL型字段,又建了一个新表——商品长度表(Wares_length)

商品长度表(Wares_length)
名称      类型    约束条件                       说明
length_id     int   
    无重复                       商品图片标识,主键
wares_id      int        
不允许为空                     所属商品标识,和Wares_info.wares_id关联
length
       char(20)    不允许为空          商品长度说明

  刚刚改完没多久,老板又打算上一批新的商品,这次某类商品全部需要添加宽度的属性。你咬了咬牙,又照方抓药,添加了商品宽度表(Wares_width)。又过了一段时间,老板新上的商品中有一些需要添加高度的属性,你是不是开始觉得你所设计的数据库按照这种方式增长下去,很快就能变成一个迷宫呢?那么,有没有什么办法遏制这种不可预见性,但却类似重复的数据库膨胀呢?我在阅读《敏捷软件开发:原则、模式与实践》中发现作者举过类似的例子:7.3 “Copy”程序。其中,我非常赞同敏捷软件开发这个观点:在最初几乎不进行预先设计,但是一旦需求发生变化,此时作为一名追求卓越的程序员,应该从头审查整个架构设计,在此次修改中设计出能够满足日后类似修改的系统架构。下面是我在需要添加长度的属性时所提供的修改方案:

  去掉商品信息表(Wares_info)中的haspic字段,添加商品额外属性表(Wares_ex_property)和商品额外信息表(Wares_ex_info)2个表来完成添加新属性的功能。

商品额外属性表(Wares_ex_property)
名称      类型    约束条件                       说明
ex_pid        int   
    无重复                       商品额外属性标识,主键
p_name        char(20)   
不允许为空                     额外属性名称

商品额外信息表(Wares_ex_info)
名称        类型    约束条件                       说明
ex_iid          int   
    无重复                       商品额外信息标识,主键
wares_id        int        
不允许为空                     所属商品标识,和Wares_info.wares_id关联
property_id
    int         不允许为空          商品额外属性标识,和Wares_ex_property.ex_pid关联
property_value  char(200)  
不允许为空                     商品额外属性值

  在商品额外属性表(Wares_ex_property)中添加2条记录:
ex_pid            p_name
1               
商品图片
2               
商品长度

  再在整个电子商务平台的后台管理功能中追加一项商品额外属性管理的功能,以后添加新的商品时出现新的属性,只需利用该功能往商品额外属性表(Wares_ex_property)中添加一条记录即可。不要害怕变化,被第一颗子弹击中并不是坏事,坏的是被相同轨道飞来的第二颗、第三颗子弹击中。第一颗子弹来得越早,所受的伤越重,之后的抵抗力也越强8)(待续)

  三、多用户及其权限管理的设计
  开发数据库管理类的软件,不可能不考虑多用户和用户权限设置的问题。尽管目前市面上的大、中型的后台数据库系统软件都提供了多用户,以及细至某个数据库内某张表的权限设置的功能,我个人建议:一套成熟的数据库管理软件,还是应该自行设计用户管理这块功能,原因有二:
  1.那些大、中型后台数据库系统软件所提供的多用户及其权限设置都是针对数据库的共有属性,并不一定能完全满足某些特例的需求;
  2.不要过多的依赖后台数据库系统软件的某些特殊功能,多种大、中型后台数据库系统软件之间并不完全兼容。否则一旦日后需要转换数据库平台或后台数据库系统软件版本升级,之前的架构设计很可能无法重用。

  下面看看如何自行设计一套比较灵活的多用户管理模块,即该数据库管理软件的系统管理员可以自行添加新用户,修改已有用户的权限,删除已有用户。首先,分析用户需求,列出该数据库管理软件所有需要实现的功能;然后,根据一定的联系对这些功能进行分类,即把某类用户需使用的功能归为一类;最后开始建表:
  
功能表(Function_table)
名称     类型    约束条件   说明
f_id          int   
    无重复     功能标识,主键
f_name        char(20)   
不允许为空   功能名称,不允许重复
f_desc        char(50)   
允许为空     功能描述

用户组表(User_group)
名称     类型    约束条件   说明
group_id      int        
无重复        用户组标识,主键
group_name    char(20)   
不允许为空    用户组名称
group_power   char(100)  
不允许为空    用户组权限表,内容为功能表f_id的集合

用户表(User_table)
名称     类型    约束条件   说明
user_id       int        
无重复        用户标识,主键
user_name     char(20)   
无重复        用户名
user_pwd      char(20)   
不允许为空    用户密码
user_type     int        
不允许为空    所属用户组标识,和User_group.group_id关联

  采用这种用户组的架构设计,当需要添加新用户时,只需指定新用户所属的用户组;当以后系统需要添加新功能或对旧有功能权限进行修改时,只用操作功能表和用户组表的记录,原有用户的功能即可相应随之变化。当然,这种架构设计把数据库管理软件的功能判定移到了前台,使得前台开发相对复杂一些。但是,当用户数较大(10人以上),或日后软件升级的概率较大时,这个代价是值得的。


  四、简洁的批量m:n设计
  碰到m:n的关系,一般都是建立3个表,m一个,n一个,m:n一个。但是,m:n有时会遇到批量处理的情况,例如到图书馆借书,一般都是允许用户同时借阅n本书,如果要求按批查询借阅记录,即列出某个用户某次借阅的所有书籍,该如何设计呢?让我们建好必须的3个表先:

书籍表(Book_table)
名称     类型    约束条件   说明
book_id       int        
无重复        书籍标识,主键
book_no       char(20)   
无重复        书籍编号
book_name     char(100)  
不允许为空    书籍名称
……

借阅用户表(Renter_table)
名称     类型    约束条件   说明
renter_id     int        
无重复        用户标识,主键
renter_name   char(20)   
不允许为空    用户姓名
……

借阅记录表(Rent_log)
名称     类型    约束条件   说明
rent_id       int        
无重复        借阅记录标识,主键
r_id          int        
不允许为空    用户标识,和Renter_table.renter_id关联
b_id          int        
不允许为空    书籍标识,和Book_table.book_id关联
rent_date     datetime   
不允许为空    借阅时间
……

  为了实现按批查询借阅记录,我们可以再建一个表来保存批量借阅的信息,例如:

批量借阅表(Batch_rent)
名称     类型    约束条件   说明
batch_id      int        
无重复        批量借阅标识,主键
batch_no      int        
不允许为空    批量借阅编号,同一批借阅的batch_no相同
rent_id       int        
不允许为空    借阅记录标识,和Rent_log.rent_id关联
batch_date    datetime   
不允许为空    批量借阅时间

  这样的设计好吗?我们来看看为了列出某个用户某次借阅的所有书籍,需要如何查询?首先检索批量借阅表(Batch_rent),把符合条件的的所有记录的rent_id字段的数据保存起来,再用这些数据作为查询条件带入到借阅记录表(Rent_log)中去查询。那么,有没有什么办法改进呢?下面给出一种简洁的批量设计方案,不需添加新表,只需修改一下借阅记录表(Rent_log)即可。修改后的记录表(Rent_log)如下:

借阅记录表(Rent_log)
名称     类型    约束条件   说明
rent_id       int        
无重复        借阅记录标识,主键
r_id          int        
不允许为空    用户标识,和Renter_table.renter_id关联
b_id          int        
不允许为空    书籍标识,和Book_table.book_id关联
batch_no      int        
不允许为空    批量借阅编号,同一批借阅的batch_no相同
rent_date     datetime   
不允许为空    借阅时间
……

  其中,同一次借阅的batch_no和该批第一条入库的rent_id相同。举例:假设当前最大rent_id64,接着某用户一次借阅了3本书,则批量插入的3条借阅记录的batch_no都是65。之后另外一个用户租了一套碟,再插入出租记录的rent_id68。采用这种设计,查询批量借阅的信息时,只需使用一条标准T_SQL的嵌套查询即可。当然,这种设计不符合3NF,但是和上面标准的3NF设计比起来,哪一种更好呢?答案就不用我说了吧。


  五、冗余数据的取舍
  上篇的树型关系的数据表中保留了一个冗余字段,这里的例子更进一步——添加了一个冗余表。先看看例子:我原先所在的公司为了解决员工的工作餐,和附近的一家小餐馆联系,每天吃饭记账,费用按人数平摊,月底由公司现金结算,每个人每个月的工作餐费从工资中扣除。当然,每天吃饭的人员和人数都不是固定的,而且,由于每顿工作餐的所点的菜色不同,每顿的花费也不相同。例如,星期一中餐5人花费40元,晚餐2人花费20,星期二中餐6人花费36元,晚餐3人花费18元。为了方便计算每个人每个月的工作餐费,我写了一个简陋的就餐记账管理程序,数据库里有3个表:

员工表(Clerk_table)
名称     类型    约束条件   说明
clerk_id      int        
无重复        员工标识,主键
clerk_name    char(10)   
不允许为空    员工姓名

每餐总表(Eatdata1)
名称     类型    约束条件   说明
totle_id      int        
无重复        每餐总表标识,主键
persons       char(100)  
不允许为空    就餐员工的员工标识集合
eat_date      datetime   
不允许为空    就餐日期
eat_type      char(1)    
不允许为空    就餐类型,用来区分中、晚餐
totle_price   money      
不允许为空    每餐总花费
persons_num   int        
不允许为空    就餐人数

就餐计费细表(Eatdata2)
名称     类型    约束条件   说明
id            int        
无重复        就餐计费细表标识,主键
t_id          int        
不允许为空    每餐总表标识,和Eatdata1.totle_id关联
c_id          int        
不允许为空    员工标识标识,和Clerk_table.clerk_id关联
price         money      
不允许为空    每人每餐花费

  其中,就餐计费细表(Eatdata2)的记录就是把每餐总表(Eatdata1)的一条记录按就餐员工平摊拆开,是个不折不扣的冗余表。当然,也可以把每餐总表(Eatdata1)的部分字段合并到就餐计费细表(Eatdata2)中,这样每餐总表(Eatdata1)就成了冗余表,不过这样所设计出来的就餐计费细表重复数据更多,相比来说还是上面的方案好些。但是,就是就餐计费细表(Eatdata2)这个冗余表,在做每月每人餐费统计的时候,大大简化了编程的复杂度,只用类似这么一条查询语句即可统计出每人每月的寄餐次数和餐费总帐:

SELECT clerk_name AS personname,COUNT(c_id) as eattimes,SUM(price) AS ptprice FROM Eatdata2 JOIN Clerk_tabsle ON (c_id=clerk_id) JOIN eatdata1 ON (totleid=tid) WHERE eat_date>=CONVERT(datetime,'"&the_date&"') AND eat_date<DATEADD(month,1,CONVERT(datetime,'"&the_date&"')) GROUP BY c_id

  想象一下,如果不用这个冗余表,每次统计每人每月的餐费总帐时会多麻烦,程序效率也够呛。那么,到底什么时候可以增加一定的冗余数据呢?我认为有2个原则:

  1、用户的整体需求。当用户更多的关注于,对数据库的规范记录按一定的算法进行处理后,再列出的数据。如果该算法可以直接利用后台数据库系统的内嵌函数来完成,此时可以适当的增加冗余字段,甚至冗余表来保存这些经过算法处理后的数据。要知道,对于大批量数据的查询,修改或删除,后台数据库系统的效率远远高于我们自己编写的代码。
  2、简化开发的复杂度。现代软件开发,实现同样的功能,方法有很多。尽管不必要求程序员精通绝大部分的开发工具和平台,但是还是需要了解哪种方法搭配哪种开发工具的程序更简洁,效率更高一些。冗余数据的本质就是用空间换时间,尤其是目前硬件的发展远远高于软件,所以适当的冗余是可以接受的。不过我还是在最后再强调一下:不要过多的依赖平台和开发工具的特性来简化开发,这个度要是没把握好的话,后期维护升级会栽大跟头的。

转载于:https://www.cnblogs.com/sharmy/archive/2007/10/15/924775.html

相关文章:

避免神经网络过拟合的5种技术(附链接) | CSDN博文精选

作者 | Abhinav Sagar翻译 | 陈超校对 | 王琦来源 | 数据派THU(ID:DatapiTHU)(*点击阅读原文&#xff0c;查看作者更多精彩文章&#xff09;本文介绍了5种在训练神经网络中避免过拟合的技术。 最近一年我一直致力于深度学习领域。这段时间里&#xff0c;我使用过很多神经网络&a…

DllMain中不当操作导致死锁问题的分析--加载卸载DLL与DllMain死锁的关系

前几篇文章一直没有在源码级证明&#xff1a;DllMain在收到DLL_PROCESS_ATTACH和DLL_PROCESS_DETACH时会进入临界区。这个论证非常重要&#xff0c;因为它是使其他线程不能进入临界区从而导致死锁的关键。我构造了在DLL被映射到进程地址空间的场景&#xff0c;请看死锁时加载DL…

LinearLayout增加divider分割线

2019独角兽企业重金招聘Python工程师标准>>> 在android3.0及后面的版本在LinearLayout里增加了个分割线 android:divider"drawable/shape"<!--分割线图片--> android:showDividers"middle|beginning|end" <!--分割线位置--> 分割线…

JAVA游戏编程之二----j2me MIDlet 手机游戏入门开发--贪吃蛇

作者&#xff1a;雷神 QQ:38929568 QQ群&#xff1a;28048051JAVA游戏编程&#xff08;满&#xff09; 28047782&#xff08;将满&#xff09; 与前一款扫雷比较&#xff0c;这个游戏多了一个 类&#xff0c;用来显示动画&#xff0c;也是蛇要吃的物品类&#xff0c; 也有了代码…

DllMain中不当操作导致死锁问题的分析——线程中调用GetModuleFileName、GetModuleHandle等导致死锁

之前的几篇文章已经讲解了在DllMain中创建并等待线程导致的死锁的原因。是否还记得&#xff0c;我们分析了半天汇编才知道在线程中的死锁位置。如果对于缺乏调试经验的同学来说&#xff0c;可能发现这个位置有点麻烦。那么本文就介绍几个例子&#xff0c;它们会在线程明显的位置…

如何从菜鸡变成收割机,大厂面试的算法,你懂了吗?

是什么&#xff1f;让大厂面试显得逼格很高&#xff0c;是算法和数据结构吗&#xff1f;是的&#xff01;&#xff01;&#xff01;Google工程师曾总结过&#xff0c;大厂之所以爱考察算法和数据结构是因为&#xff1a;算法能力能够准确辨别一个程序员的技术功底是否扎实&#…

Ejabberd源码解析前奏--配置

一、基本配置 配置文件将在你第一次启动ejabberd时加载&#xff0c;从该文件中获得的内容将被解析并存储到内部的ejabberd数据库中&#xff0c;以后的配置将从数据库加载&#xff0c;并且任何配置文件里的命令都会被添加到数据库里。 需要注意的是&#xff1a;ejabberd从不编辑…

DllMain中不当操作导致死锁问题的分析——DllMain中要谨慎写代码(完结篇)

之前几篇文章主要介绍和分析了为什么会在DllMain做出一些不当操作导致死锁的原因。本文将总结以前文章的结论&#xff0c;并介绍些DllMain中还有哪些操作会导致死锁等问题。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; DllMain的相关特性 首先列出…

滴滴叶杰平:年运送乘客百亿次,AI如何“服务”出行领域?| BDTC 2019

出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;“如果把北京一天滴滴的轨迹数据放在一起&#xff0c;要覆盖北京所有道路差不多四百次&#xff0c;数据非常大、非常完整。”超5.5亿用户&#xff0c;年运送乘客100亿人次&#xff0c;除了中国地区&#xff0c;滴滴也在…

分析部署无线局域网的关键要素

在部署无线局域网时需要考虑的关键问题包括&#xff1a;确定单个接入点的RF覆盖&#xff0c;保证足够的支持所有用户的容量&#xff0c;以及考虑RF信号损耗因素。  单个AP的覆盖   网络设计师必须通过研究AP的服务范围来决定单个AP的覆盖。数据速率是一种距离函数&#xff…

Delphi调用java开发的WebService,传入参数出错

http://www.cnblogs.com/zhangzhifeng/p/3397053.html 调用没有参数的服务正常,当调用有参数的服务出现以下错误java.util.concurrent.ExecutionException: java.lang.NullPointerException 另外加了RIO.HTTPWebNode.UseUTF8InHeader : True;InvRegistry.RegisterInvokeOptions…

B站收藏6.1w+!这门课拯救你薄弱的计算机基础

作者 | Rocky0429来源 | Python空间大家好&#xff0c;我是 Rocky0429&#xff0c;一个对计算机基础一无所知的蒟蒻...作为一个所谓的计算机科班出身的人来说&#xff0c;特别难为情的是自己的计算机基础很差&#xff0c;比如计算机网络当年一度差点挂掉&#xff0c;多亏当时…

一种不会导致资源泄露的“终止”线程的方法

在项目工程中&#xff0c;我们可能会使用第三方开发的模块。该模块提供一个接口用于完成非常复杂和耗时的工作。我们一般不会将该API放在UI线程中执行&#xff0c;而是启动一个线程&#xff0c;用工作线程去执行这个耗时的操作。&#xff08;转载请指明出于breaksoftware的csdn…

TCP/IP详解学习笔记(9)-TCP协议概述

终于看到了TCP协议&#xff0c;这是TCP/IP详解里面最重要也是最精彩的部分&#xff0c;要花大力气来读。前面的TFTP和BOOTP都是一些简单的协议&#xff0c;就不写笔记了&#xff0c;写起来也没啥东西。TCP和UDP处在同一层---运输层&#xff0c;但是TCP和UDP最不同的地方是&…

在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎

前些天听到一个需求&#xff1a;某业务方需要我们帮忙清理用户电脑上的一些废弃文件。同事完成这个逻辑的方案便是在我们程序中加入了一个很“独立”的业务逻辑&#xff1a;检索和删除某个程序产生的废弃文件。试想&#xff0c;该“独立”的逻辑之后会如何&#xff1f;被删掉&a…

优酷智能档在大型直播场景下的技术实践

作者 | 阿里文娱高级技术专家 肖文良 本文为阿里文娱高级技术专家肖文良在【阿里文娱2019双11猫晚技术沙龙】中的演讲&#xff0c;主要内容为如何通过优酷智能档&#xff0c;降低用户卡顿尤其是双11直播场景下&#xff0c;提升用户观看体验。具体包括智能档的落地挑战、算法架…

主题:CS0016: 未能写入输出文件“c:#92;WINDOWS#92;Microsoft.NET#92;***.dll”错误处理...

刚装完.NET环境&#xff0c;在编译时出现了如下错误&#xff1a; 编译器错误信息:CS0016: 未能写入输出文件“c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary ASP.NET Files\***\*****.dll”--“拒绝访问。” 错误的处理&#xff1a; 出现CS0016的原因一般是…

关于 android 加载 res 图片 out of memory 问题 解决 同样适用于 sd卡图片

2019独角兽企业重金招聘Python工程师标准>>> 发现android 加载res图片如果过多也会崩溃 android 也是使用 Bitmap bm BitmapFactory.decodeResourceStream(res, value, is, pad, opts); 来加载图片,不同他一般不会释放,如果图片太多就崩溃了 不过解决方法就更简…

近期必读的6篇NeurIPS 2019零样本学习论文

来源 | 专知&#xff08;ID:Quan_Zhuanzhi&#xff09; 【导读】NeurIPS 是全球最受瞩目的AI、机器学习顶级学术会议之一&#xff0c;每年全球的人工智能爱好者和科学家都会在这里聚集&#xff0c;发布最新研究。NIPS 2019大会已经在12月8日-14日在加拿大温哥华举行&#xff0c…

在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统

在《在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎》开始处&#xff0c;我提到某公司被指责使用“云命令”暗杀一些软件。本文将讲述如何去模拟一个简易的“云指令”执行系统。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 首先我们思考下…

oracle9i.rar下载

甲骨文数据库&#xff19;&#xff29;转载于:https://blog.51cto.com/263054/46968

每天一道算法题(24)——自定义幂函数pow

double myPower(double base, int exponent){if(exponent0)return 1;if(exponent1)return base;if(exponent-1)//当为是负数的情况return 1.0/base;double result1.0;resultmyPower(base,exponent>>1);result*result;if(exponent&1)//绝对值为奇数result*base;return…

在windows程序中嵌入Lua脚本引擎--编写自己的Lua库

在《在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统》一文中&#xff0c;我提到了使用Lua的ffi库&#xff0c;可以让我们像写C代码一样写lua程序。这是个非常令我们这些C程序员激动的事。但是我们使用ffi库写出来的程序往往比较大&#xff0c;因为我们可…

我的C#学习笔记(1)

1.基本类型&#xff1a;基本与C\C相同decimal decimal是一个128位的高精度浮点数。bool 注意的是bool类型只有true和faulse两个可取值&#xff0c;在C#中&#xff0c;不能将bool值强制转换为值。如&#xff0c;将true转换为1或将1&#xff0c;0转换为bool值都是不行的。Parse和…

区块链人才月均薪酬1.6W?

01在上周&#xff0c;我国宣布将重点推动区块链技术的发展&#xff0c;这个消息无疑是为区块链开发者们打了一针强心剂&#xff0c;简直是喜大普奔啊 &#xff01;因为之前区块链这个技术虽然一直在圈内很火&#xff0c;但是却没有得到国家的全面认可和推广&#xff0c;所以很多…

javascript通过json数据按格式生成一个按字母分类排序的分类信息表

效果图如下 1.json数据格式 var _people[{name:朱瑞,url:aaaaaa,nick:zhu},{name:刘桂清,url:aaaaa,nick:liu}];这里按姓氏排序借用了nick&#xff0c;不用nick的话&#xff0c;需要加载一个汉字拼音对照数组&#xff0c;判断匹配2.javascript代码 1 (function ($){2 funct…

(1)学习数组,集合,IEnumerable接口,引申学习迭代器

发展:数组-->集合-->泛型 (1)数组 1. 数组数据结构是System.Array类的一个实例. 2. System.Array类的语法为 [SerializableAttribute] [ComVisibleAttribute(true)] public abstract class Array : ICloneable, IList, ICollection, IEnumerable 3. 下面看一个使用数组…

人工智能尴尬的2019:需要钱却没钱可烧了

作者 | 余洋洋编辑 | 张丽娟来源 | CV智识&#xff08;ID:CVAI2019)【导读】正需要钱的时候&#xff0c;钱却不够用了&#xff0c;人工智能领域缺钱与亟需钱的矛盾在今年集中体现了出来。2019年&#xff0c;中国人工智能领域的投融资热情大幅降低&#xff0c;交易量随之急剧下降…

WMI技术介绍和应用——WMI概述

今天&#xff0c;我要开始一系列关于微软WMI技术的介绍。通过之后若干节的介绍&#xff0c;我想WMI技术将为在windows平台上从事开发的朋友开启另外一扇窗。&#xff08;转载请指明出于breaksoftware的csdn博客&#xff09; 第一次接触WMI技术是在一年前&#xff0c;当时我接到…

综合技术 --@Autowired和@Resource

2019独角兽企业重金招聘Python工程师标准>>> 1.Autowired和Resource 的作用一样&#xff0c;都是自动注入 2.Autowired是按照byType自动注入&#xff0c;而Resource默认是按照byName自动注入。 3.Resource有两个属性比较重要&#xff0c;分别是name和type&#xff0…