【Mongodb教程 第十六课 】 分享NO-SQL开发实战

最近研究了一下NOSQL,现整理目录如下:

一、关系数据库的瓶颈;

二、NOSQL概述;

三、NOSQL中的热门数据库MongoDB介绍及安装配置;

四、MongoDB开发模式及实战;

一、关系数据库的瓶颈

从90年代到至今,关系数据库扮演了最重要的角色,它的性能,可扩展性、稳定性、数据的备份和恢复机制等都非常好,关系数据库发展到现在已经非常成熟,它提供给使用者的是一整套体系,包括数据存储、数据备份恢复、数据加解密、应用开发驱动、图形化配置维护工具、安全策略等等。图1中展示了世界上各种数据库的使用比例,从这个图上我们明显看得出它的霸主地位。

                  图1:各种数据库的使用比例

不过随着信息技术的快速发展,Web发展也从Web1.0发展到了Web2.0时代,网站开始快速发展,博客、电子商务、微博、社区等Web应用已经引领了时代潮流,它们的网络流量非常巨大,为了解决这个问题,很多IT公司都采取了一系列优化措施,主要优化措施如下:

1、Cache+SQL;

为了提高网站的性能,我们经常会把一些读取访问频率比较高,更新频率低的数据存储在内存中,一方面可以提高用户的体验,另外一方面可以减轻数据库的访问压力;

2 、读写分离;

还有一种好的方式就是读写分离,例如我们可以把内网应用系统产生的数据对称的发布到互联网的数据库中,这样互联网应用的访问都是从外网数据库中读取,内网数据库大部分都是增、删、改等操作,这样也能大幅度提高应用的性能;

3、分表分库;

随着Web2.0的高速发展,在Cache+SQL、数据库主从复制读写分离的优化的情形下,关系数据库主库的写压力出现瓶颈,数据量的持续猛增,访问的高并发情况之下,关系数据库会出现严重的锁问题,这时开始流行分表分库的方式来缓解写压力和数据增长的扩展问题,很早之前我做的一个应用系统,就出现了这个需求,随着数据量的沉淀,数据库变得非常庞大,数据库和日志文件达到了10几个G,有些表里面有上千万条数据,用户在使用过程中,进行操作时经常会卡住,有时候一等就是几秒或几十秒,客户非常不满意,后来我们讨论之后就采取了数据库方面,一年一个库进行分库,某些数据量大的表采用拆分,例如一个月产生一个表,还有把一个表中的字段拆分到多个表中等;

通过以上优化我们系统的性能会提高很大一块,每秒查询率方面可以达到:几百qps到几千qps不等,数据库大小可以达到1T左右,不过随着访问量和数据量的加大,关系数据库很难继续高效率的担当,采用分表分库可以在一定程度上降低这个瓶颈,不过它降低了应用的可扩展性,带来了巨大的技术和开发成本,例如一个需求的变更,可能就会导致一种新的分库分表方式。

关系数据库中基本上都会存储一些大文本和附件信息,导致数据库非常的大,在做数据库恢复的时候就会非常的慢,例如1000万3KB的大文本就接近30G的大小、100万200K的附件就是200G,如果能把这些大文本和大附件从关系数据库中省去,我们的关系数据库将会变得很小从而很容易优化。

综上,关系数据库很强大,但是它并不能很好的应付所有的应用场景。关系数据库的扩展性差(需要复杂的技术来实现),大数据下IO压力大,表结构更改困难,正是当前使用关系数据库的开发人员面临的问题。

二、NOSQL概述

1、什么是NOSQL?

随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性。NoSQL概念在2009年被提了出来。NoSQL最常见的解释是“non-relational”,“Not Only SQL”也被很多人接受。(“NoSQL”一词最早于1998年被用于一个轻量级的关系数据库的名字。)

NoSQL被我们用得最多的当数key-value存储,当然还有其他的文档型的、列存储、图型数据库、xml数据库等,见图2。在NoSQL概念提出之前,这些数据库就被用于各种系统当中,但是却很少用于web互联网应用。

图2:非关系数据库种类

2、NOSQL的发展状况如何?

目前NOSQL相当火爆,微博、电子商务、博客、社区、论坛等大数据量高并发的互联网应用中基本都用到了它,大的IT巨头们都在各自的互联网架构中加入了NOSQL解决方案,甚至拥有自己的NOSQL产品,各种NOSQL产品百花齐放,如图3,在2010年之后NOSQL达到井喷之势,其中mongoDb发展势头最猛也最火热。

图3:NOSQL发展趋势

3、NOSQL和关系数据库的关系?

我觉得关系数据库和NOSQL是一种相辅相成紧密结合的关系,我们需要根据具体的应用场景来选择对应数据库,如果你的应用的数据量很小,那么关系数据库就足够了,而且性能、效率、稳定性、安全都是有保证的;如果你的应用场景中涉及超大的数据量(包含大文本、多附件),例如量级在几百G或T级,那么可以考虑用关系数据库和NOSQL结合的方式来解决,关系数据库存储相应的关系数据,NOSQL数据库存储像大文本、对象、附件等类型数据,这样是一种最优的解决方案;

三、NOSQL中MongoDB介绍及安装配置

1、概念

MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种。它在许多场景下可用于替代传统的关系型数据库或键/值存储方式。Mongo使用C++开发,理解方面可参考图3:

图3:mongDB内部组成

Mongo的官方网站地址是:http://www.mongodb.org/

这里给大家推荐一本MongoDB入门的书籍《MongoDB权威指南》,这个有中文版本。

2、特性

面向集合存储,易存储对象类型的数据。

模式自由。

支持动态查询。

支持完全索引,包含内部对象。

支持查询。

支持复制和故障恢复。

使用高效的二进制数据存储,包括大型对象(如视频等)。

自动处理碎片,以支持云计算层次的扩展性 .

支持Python,PHP,Java,C#,Javascript等语言的驱动程序.

文件存储格式为BSON(一种JSON的扩展)。

可通过网络访问。

3、功能

面向集合的存储:适合存储对象及JSON形式的数据。

动态查询:Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。

完整的索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。

查询监视:Mongo包含一个监视工具用于分析数据库操作的性能。

复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目标是提供冗余及自动故障转移。

高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)

自动分片以支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器

4、使用场景

网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。

缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源 过载。

大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。

高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。Mongo的路线图中已经包含对MapReduce引擎的内置支持。

用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储及查询。

5、安装过程

第一步:下载安装包:官方下载地址←单击此处,如果是win系统,注意是64位还是32位版本的,请选择正确的版本。

第二步:新建目录“D:\MongoDB”,解压下载到的安装包,找到bin目录下面全部.exe文件,拷贝到刚创建的目录下。

第三步:在“D:\MongoDB”目录下新建“data”文件夹,它将会作为数据存放的根文件夹。

  配置Mongo服务端:

  打开CMD窗口,按照如下方式输入命令:
  > d:
  > cd D:\MongoDB
  > mongod --dbpath D:\MongoDB\data

  配置成功后会看到如下图4:

图4:启动成功界面

第四步:安装为windows服务

mongod --install --serviceName MongoDB --serviceDisplayName MongoDB --logpath D:\MongoDB\log\MongoDB.log --dbpath D:\MongoDB\data --directoryperdb,执行成功之后在windows服务中可以看到名称为MongoDB的服务,开启就可以了,这样能避免exe CMD命令框的烦恼;

四、MongoDB开发模式及实战

1、开发模式

对于MongoDB的开发模式,我们可以采用类似高速服务框架HSF的模式进行架构,见图5,首先在基础构件层中我们把MongoDB的驱动封装到基类库Inspur.Finix.DAL中,

然后在领域层采用小三层架构模式调用基础构件层的数据服务,展现层在通过AJAX+JSON+Filter方式通过服务的形式调用业务层,展现层就可以很好的利用返回的JSON串实现页面的功能。

图5:开发模式

2、开发实战

C#驱动有很多种比较常用的是官方驱动和samus驱动。samus驱动除了支持一般形式的操作之外,还支持linq方式操纵数据

(1)基础构件层封装我们采用samus驱动进行封装,代码如下:

 public class MongoDBAccess : IDisposable
    {
        /// <summary>
        /// 数据库别名
        /// </summary>
        private string _dataBaseAlias = "Noah.MongoDB";
        /// <summary>
        /// 集合名
        /// </summary>
        public string _collectionName { get; set; }
        // 定义mongo服务
        private Mongo _mongo = null;
        // 获取databaseName对应的数据库,不存在则自动创建
        private IMongoDatabase _mongoDatabase = null;
        public MongoCollection<Document> MongoCollection;
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dataBaseAlias"></param>
        /// <param name="collectionName"></param>
        public MongoDBAccess(string dataBaseAlias, string collectionName)
        {
            _dataBaseAlias = dataBaseAlias;
            _collectionName = collectionName;
            init();
        }
        /// <summary>
        /// 初始化
        /// </summary>
        private void init()
        {
            DatabaseConfigManager dcm = DatabaseConfigManager.Create();
            // 根据别名得到连接串
            string connStr = dcm.GetPrimaryConnection(_dataBaseAlias);
            // 把conn进行拆分
            StringTokenizer st = new StringTokenizer(connStr, ";");
            string conn = st.GetValueByIndex(0);
            // 定义mongo服务
            _mongo = new Mongo(conn);
            _mongo.Connect();
            st = new StringTokenizer(st.GetValueByIndex(1), "=");
            string databaseName = st.GetValueByIndex(1);
            // 获取databaseName对应的数据库,不存在则自动创建
            if (string.IsNullOrEmpty(databaseName) == false)
                _mongoDatabase = _mongo.GetDatabase(databaseName);
            //获取collectionName对应的集合,不存在则自动创建
            MongoCollection = _mongoDatabase.GetCollection<Document>(_collectionName) as MongoCollection<Document>;

        }

        /// <summary>
        /// 切换到指定的数据库
        /// </summary>
        /// <param name="dbName"></param>
        /// <returns></returns>
        public IMongoDatabase UseDb(string dbName)
        {
            if (string.IsNullOrEmpty(dbName))
                throw new ArgumentNullException("dbName");

            _mongoDatabase = _mongo.GetDatabase(dbName);
            return _mongoDatabase;
        }

        /// <summary>
        /// 获取当前连接的数据库
        /// </summary>
        public IMongoDatabase CurrentDb
        {
            get
            {
                if (_mongoDatabase == null)
                    throw new Exception("当前连接没有指定任何数据库。请在构造函数中指定数据库名或者调用UseDb()方法切换数据库。");

                return _mongoDatabase;
            }
        }

        /// <summary>
        /// 获取当前连接数据库的指定集合【依据类型】
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IMongoCollection<T> GetCollection<T>() where T : class
        {
            return this.CurrentDb.GetCollection<T>();
        }

        /// <summary>
        /// 获取当前连接数据库的指定集合【根据指定名称】
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name">集合名称</param>
        /// <returns></returns>
        public IMongoCollection<T> GetCollection<T>(string name) where T : class
        {
            return this.CurrentDb.GetCollection<T>(name);
        }
        /// <summary>
        /// 使用GridFS保存附件
        /// </summary>
        /// <param name="byteFile"></param>
        /// <returns></returns>
        public string GridFsSave(byte[] byteFile)
        {
            string filename = Guid.NewGuid().ToString();
            //这里GridFile构造函数有个重载,bucket参数就是用来替换那个创建集合名中默认的"fs"的。
            GridFile gridFile = new GridFile(_mongoDatabase);
            using (GridFileStream gridFileStream = gridFile.Create(filename))
            {
                gridFileStream.Write(byteFile, 0, byteFile.Length);
            }
            return filename;
        }
        /// <summary>
        /// 读取GridFs附件
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public byte[] GridFsRead(string filename)
        {
            GridFile gridFile = new GridFile(_mongoDatabase);
            byte[] bytes;
            using (GridFileStream gridFileStream = gridFile.OpenRead(filename))
            {
                bytes = new byte[gridFileStream.Length];
                gridFileStream.Read(bytes, 0, bytes.Length);
            }
            return bytes;
        }
        public void GridFsDelete(string filename)
        {
            GridFile gridFile = new GridFile(_mongoDatabase);
            gridFile.Delete(new Document("filename", filename));
        }
        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            if (_mongo != null)
            {
                _mongo.Dispose();
                _mongo = null;
            }

        }
    }

(2)领域层部分代码

public class KNOWLEDGE_SOCKDAL
    {
        public KNOWLEDGE_SOCKDAL()
        {
        }
        /// <summary>
        /// 保存一个对象
        /// </summary>
        /// <param name="model"></param>
        public void Add(KNOWLEDGE_SOCK model)
        {
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    mm.GetCollection<KNOWLEDGE_SOCK>().Insert(model);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
        }
        /// <summary>
        /// 保存附件
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        public string  SaveAttach(byte[] file)
        {
            string fileName = string.Empty;
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    fileName = mm.GridFsSave(file);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return fileName;
        }
        /// <summary>
        /// 读取附件
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public byte[] ReadAttach(string fileName)
        {
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    mm.GetCollection<KNOWLEDGE_SOCK>();
                    return  mm.GridFsRead(fileName);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return null;
        }
        /// <summary>
        /// 删除附件
        /// </summary>
        /// <param name="fileName"></param>
        public void DeleteAttach(string fileName)
        {
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    mm.GetCollection<KNOWLEDGE_SOCK>();
                    mm.GridFsDelete(fileName);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="model"></param>
        public void Update(KNOWLEDGE_SOCK model)
        {
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    var query = new Document("Know_Code", model.Know_Code);
                    mm.GetCollection<KNOWLEDGE_SOCK>().Update(model, query);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        public void Delete(string id)
        {
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    var query = new Document("Know_Code", id);
                    mm.GetCollection<KNOWLEDGE_SOCK>().Remove(query);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
        }
        /// <summary>
        /// 查询特定一条
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public KNOWLEDGE_SOCK FindOne(string id)
        {
            KNOWLEDGE_SOCK catalog = new KNOWLEDGE_SOCK();
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    var query = new Document("Know_Code", id);
                    catalog = mm.GetCollection<KNOWLEDGE_SOCK>().FindOne(query);
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return catalog;
        }
        /// <summary>
        /// 根据条件查询
        /// </summary>
        /// <param name="js"></param>
        /// <returns></returns>
        public List<KNOWLEDGE_SOCK> Find(string js)
        {
            List<KNOWLEDGE_SOCK> catalogs = new List<KNOWLEDGE_SOCK>();
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    string jsStr = @"
                    function(){
                        return " + js + ";}";
                    catalogs = mm.GetCollection<KNOWLEDGE_SOCK>().Find(Op.Where(jsStr)).Documents.ToList();
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return catalogs;
        }
        /// <summary>
        /// 查询全部
        /// </summary>
        /// <returns></returns>
        public List<KNOWLEDGE_SOCK> FindAll()
        {
            List<KNOWLEDGE_SOCK> catalogs = new List<KNOWLEDGE_SOCK>();
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    catalogs = mm.GetCollection<KNOWLEDGE_SOCK>().FindAll().Documents.ToList();
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return catalogs;
        }
        /// <summary>
        /// 返回数量
        /// </summary>
        /// <param name="js"></param>
        /// <returns></returns>
        public int GetCount(string js)
        {
            int count = 0;
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    string jsStr = @"
                    function(){
                        return " + js + ";}";
                    count = mm.GetCollection<KNOWLEDGE_SOCK>().Find(Op.Where(jsStr)).Documents.Count();
                }

            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return count;
        }
        public List<KNOWLEDGE_SOCK> Find(string js, int pageSize, int pageIndex)
        {
            List<KNOWLEDGE_SOCK> list = new List<KNOWLEDGE_SOCK>();
            try
            {
                using (MongoDBAccess mm = new MongoDBAccess(cConfig.Noah_MongoDB, ""))
                {
                    string jsStr = @"
                    function(){
                        return " + js + ";}";
                    list = mm.GetCollection<KNOWLEDGE_SOCK>().Find(Op.Where(jsStr)).Documents.OrderBy(x=>x.Know_CreateTime).Skip(pageSize * (pageIndex-1)).Take(pageSize).ToList();
                }
            }
            catch (Exception ex)
            {
                ExceptionManager.Handle(ex);
            }
            return list;
        }
    }

时间: 2024-10-21 22:27:26

【Mongodb教程 第十六课 】 分享NO-SQL开发实战的相关文章

【Mongodb教程 第十四课 】MongoDB 投影

mongodb 投影意思是只选择必要的数据而不是选择一个文件的数据的整个.如果一个文档有5个字段,需要显示只有3个,然后选择其中只有3个字段. find() 方法 MongoDB 的find()方法,在 MongoDB查询 文档解释接受第二个可选参数是要检索的字段列表.在MongoDB中,当执行find()方法,那么它会显示一个文档所有字段.要限制这一点,需要设置的字段列表值1或0. 1用来显示字段而0是用来隐藏字段. 语法: find()方法具有投影基本语法如下 >db.COLLECTION_

【Mongodb教程 第十五课 】MongoDB 限制记录

Limit() 方法 要限制 MongoDB 中的记录,需要使用 limit() 方法. limit() 方法接受一个数字型的参数,这是要显示的文档数. 语法: limit() 方法的基本语法如下 >db.COLLECTION_NAME.find().limit(NUMBER) 示例 考虑集合myycol具有以下的数据 { "_id" : ObjectId(5983548781331adf45ec5), "title":"MongoDB Overvi

【Mongodb教程 第十八课 】MongoDB常用命令 数据库命令 集合操作命令

面向文档的 NoSQL 数据库主要解决的问题不是高性能的并发读写,而是保证海量数据存储的同时,具有良好的查询性能. 条件操作符 <, <=, >, >=  这个操作符就不用多解释了,最常用也是最简单的 db.collection.find({ "field" : { $gt: value } } );    //  大于:    field > value db.collection.find({ "field" : { $lt: va

【Mongodb教程 第十二课 】PHP mongodb 的使用

mongodb 不用过多的介绍了,NOSQL的一种,是一个面向文档的数据库,以其方便灵活的数据结构,对于开发者来说是比较友好的,同时查询的速度也是比较快的,现在好多网站 开始使用mongodb ,具体的介绍可以网上查找. 今天是进行PHP 连接mongodb.主要是进行环境的搭建,只有搭建好开发环境才能更好的进行PHP mongodb 的开发. 不多说了开发准备开发环境的软件: 1.mongodb . 网上百度一下在官网额可以下载到. 我使用的是mongodb-win32-i386-2.4.5

【Mongodb教程 第十九课 】PHP与MONGODB的条件查询

与普通的关系型数据库类似,在对数据的删.改.查的时候,会用到查询条件,如mysql中的 where… 而MongoDB中,经过php来做的所有的操作指令都是用array来包裹的: MongoCollection::update  ( array $criteria , array $newobj  [, array $options = array()  ] )public MongoCursor MongoCollection::find  ([ array $query = array() 

NeHe OpenGL教程 第三十六课:从渲染到纹理

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十六课:从渲染到纹理 放射模糊和渲染到纹理: 如何实现放射状的滤镜效果呢,看上去很难,其实很简单.把渲染得图像作为纹理提取出来,在利用OpenGL本身自带的纹理过滤,就能实现这种效果,不信,你试试. 嗨,我是Dario Corn

NeHe OpenGL教程 第四十六课:全屏反走样

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十六课:全屏反走样 全屏反走样 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据.看看吧,驱动程序为你做完了一切. 在图形的绘制中,直线的走样是非常影响美观的,我们可以使用反走样解决这个问题.在众多的解决

OpenGL教程翻译 第十六课 基本的纹理贴图

OpenGL教程翻译 第十六课 基本的纹理贴图 原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载) Background 纹理贴图就是将任意一种类型的图片应用到3D模型的一个或多个面.图片(也可以称之为纹理)内容可以是任何东西,但是他们一般都是一些比如砖,叶子,地面等的图案,纹理贴图增加了场景的真实性.例如,对比下面的两幅图片. 为了进行纹理贴图,你需要进行三个步骤:将图片加载到OpenGl中,定义模型顶点的纹理坐标(以对其进行贴图),用纹理坐标对图片进行

2018-08-24 第三十六课

第三十六课 非关系统型数据库-mangodb 目录 二十四 mongodb介绍 二十五 mongodb安装 二十六 连接mongodb 二十七 mongodb用户管理 二十八 mongodb创建集合.数据管理 二十九 php的mongodb扩展 三十 php的mongo扩展 三十一 mongodb副本集介绍 三十二 mongodb副本集搭建 三十三 mongodb副本集测试 三十四 mongodb分片介绍 三十五 mongodb分片搭建 三十六 mongodb分片测试 三十七 mongodb备份