精华内容
下载资源
问答
  • LSTM之文本分类实例
    千次阅读
    2018-01-12 16:13:53

    待分类数据为已经分词的文本文档,其中每一行代表一篇文章,分词较为粗糙,未进行停用词过滤,使用停用词过滤后效果应该会有明显提升。
    1、加载数据

    # -*- coding: utf-8 -*-
    
    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    
    
    def loadData(fileName):#读取分词数据,存储在list列表里,每个list列表里的每一个list代表一个句子
        f=open(fileName,'r')
        senLists=[]
        for row in f.readlines():
            senList=row.split(' ')
            sens=[]
            for word in senList:
                if word.strip() not in ['',',','。',';','!','#','?','“','”','(',')','1','2','3',':','.','《','》','【','】']:
                    sens.append(word)
            senLists.append(sens)
        print 'Has Loaded ',len(senLists),'句子列表'
        return senLists

    2、wor2vec训练词向量

    # -*- coding: utf-8 -*-
    
    import sys
    from gensim.models import Word2Vec
    from LoadData import loadData
    import pickle
    from gensim.corpora.dictionary import Dictionary
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    
    def saveWordIndex(model):
        word2vec_dict=Dictionary()
        word2vec_dict.doc2bow(model.wv.vocab.keys(),allow_update=True)
        w2v_index={w:i+1 for i,w in word2vec_dict.items()}#建立词典索引字典,如{'中国':1},索引从1开始,0目前不存储,以后存储不在字典索引里的词语
        print w2v_index.keys()[:20]
        w2v_vec={w:model[w.encode('utf-8')] for w in w2v_index.keys()}#建立词向量字典,如{'中国':['0.01','0.25',......]}
        pickle.dump(w2v_index,open('./w2v_index.pkl','w'))
        pickle.dump(w2v_vec,open('./w2v_vec.pkl','w'))
    
    
    def trainWord2Vec():#训练word2vec模型并存储
        sentences=loadData(r'./sen_cut.txt')
        model=Word2Vec(sentences=sentences,size=100,min_count=8,window=5)
        model.save('./word2vec.model')
        # model=Word2Vec.load('./word2vec.model')
        saveWordIndex(model=model)
    
    
    if __name__=='__main__':
        trainWord2Vec()
    

    3、训练LSTM模型

    # -*- coding: utf-8 -*-
    
    import sys
    from gensim.models import Word2Vec
    from LoadData import loadData
    import numpy as np
    from keras.preprocessing import sequence
    from keras.models import Sequential
    from keras.layers import Dropout,Dense,Embedding,LSTM,Activation
    import pickle
    from sklearn.model_selection import train_test_split
    from gensim.corpora.dictionary import Dictionary
    reload(sys)
    sys.setdefaultencoding('utf-8')
    
    
    
    
    # 参数设置
    vocab_dim = 100  # 向量维度
    maxlen = 150  # 文本保留的最大长度
    batch_size = 120
    n_epoch = 5
    input_length = 150
    
    def getLabels():
        labels=[]
        for label in open('./labels.txt','r'):
            labels.append(label.strip())
        return labels
    
    def text2index(index_dic,sentences):
        """
        把词语转换为数字索引,比如[['中国','安徽','合肥'],['安徽财经大学','今天','天气','很好']]转换为[[1,5,30],[2,3,105,89]]
        """
        new_sentences=[]
        for sen in sentences:
            new_sen=[]
            for word in sen:
                try:
                    new_sen.append(index_dic[word])
                except:
                    new_sen.append(0)
            new_sentences.append(new_sen)
        return new_sentences
    
    
    def train_lstm(p_n_symbols, p_embedding_weights, p_X_train, p_y_train, p_X_test, p_y_test):
        """
        :param p_n_symbols: word2vec训练后保留的词语的个数
        :param p_embedding_weights: 词索引与词向量对应矩阵
        :param p_X_train: 训练X
        :param p_y_train: 训练y
        :param p_X_test: 测试X
        :param p_y_test: 测试y
        :return: 
        """
        print u'创建模型...'
        model = Sequential()
        model.add(Embedding(input_dim=p_n_symbols,
                            output_dim=vocab_dim,
                            mask_zero=True,
                            weights=[p_embedding_weights],
                            input_length=input_length,trainable=False))
        model.add(LSTM(units=50))
        model.add(Dropout(0.3))
        model.add(Dense(1))
        model.add(Activation('sigmoid'))
    
        print u'编译模型...'
        model.compile(loss='binary_crossentropy',
                      optimizer='adam',
                      metrics=['accuracy'])
    
        print u"训练..."
        model.fit(p_X_train, p_y_train, batch_size=batch_size, epochs=n_epoch,
                  validation_data=(p_X_test, p_y_test),verbose=1)
    
        print u"评估..."
        score, acc = model.evaluate(p_X_test, p_y_test, batch_size=batch_size)
        print 'Test score:', score
        print 'Test accuracy:', acc
    
    
    def createModel():
        maxlen=150
        index_dict=pickle.load(open('./w2v_index.pkl','r'))
        vec_dict = pickle.load(open('./w2v_vec.pkl', 'r'))
        n_words=len(index_dict.keys())
        print n_words
        vec_matrix=np.zeros((n_words+1,100))
        for k,i in index_dict.items():#将所有词索引与词向量一一对应
            try:
                vec_matrix[i,:]=vec_dict[k]
            except:
                print k,i
                print vec_dict[k]
                exit(1)
        labels=getLabels()
        sentences=loadData('./sen_cut.txt')
        X_train,X_test,y_train,y_test=train_test_split(sentences,labels,test_size=0.2)
        X_train=text2index(index_dict,X_train)
        X_test = text2index(index_dict, X_test)
        print u"训练集shape: ", np.shape(X_train)
        print u"测试集shape: ", np.shape(X_test)
        y_train=np.array(y_train)
        y_test=np.array(y_test)
        print('Pad sequences (samples x time)')
        X_train = sequence.pad_sequences(X_train, maxlen=maxlen)#扩展长度不足的补0
        X_test = sequence.pad_sequences(X_test, maxlen=maxlen)
        print u"训练集shape: ", np.shape(X_train)
        print u"测试集shape: ", np.shape(X_test)
        train_lstm(n_words+1, vec_matrix, X_train, y_train, X_test, y_test)
    
    
    if __name__=="__main__":
        createModel()
    更多相关内容
  • Java 组播组中发送接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密 Java非对称...
  • 扩展于:public class LinkJOS extends LinkOAuth2(LinkOAuth2 extends JspEasy) 构造函数 LinkJOS(HttpServletRequest request,HttpServletResponse response) 京东JOS接口访问函数 public String link2(String ...
  • 2.2 应用程序、框架、文档和视图类 19 2.2.1 CWinApp(O/C/W) 20 2.2.2 CView (O/C/W) 21 2.3 其他用户界面类 22 2.3.1 通用控件类 23 2.3.2 菜单类 23 2.3.3 对话框类 24 2.3.4 控制条类 24 2.3.5 属性类 25 2.4 ...
  • Oracle 数据库实例介绍

    万次阅读 多人点赞 2018-11-23 15:44:13
    本章介绍 Oracle 数据库实例的原理,实例的参数文件诊断文件,以及实例创建数据库的打开与关闭的过程。

    文章翻译源于 Oracle Database Database Concepts, 18c

    本章介绍 Oracle 数据库实例的原理,实例的参数文件和诊断文件,以及实例创建和数据库的打开与关闭的过程。

    本章包含以下内容:

    • 数据库实例介绍
    • 实例启动与关闭
    • 检查点
    • 实例恢复
    • 参数文件
    • 诊断文件

    数据库实例介绍

    数据库实例(instance)是一组用于管理数据库文件的内存结构。

    数据库是一组位于磁盘上的物理文件,通过 CREATE DATABASE 语句创建。实例管理相关的数据,并且为数据库用户提供服务。

    每个正在运行的 Oracle 数据库至少与一个实例相关联。因为实例存在于内存中,而数据库存在磁盘上,所以实例可以独立于数据库存在,数据库也可以独立于实例存在。

    实例结构

    当一个实例启动时,Oracle 数据库分配一个称为系统全局区(SGA)的内存区域,并启动一个或多个后台进程。

    SGA 的作用包括:

    • 维护多个进程和线程并发访问的内部数据结构
    • 缓存从磁盘读取的数据块
    • 在写入在线重做日志文件之前缓冲重做数据
    • 存储 SQL 执行计划

    同一个服务器上的 Oracle 进程之间共享 SGA。Oracle 进程与 SGA 的交互方式取决于操作系统。

    一个数据库实例包括多个后台进程(background process)。服务器进程(server process),以及分配给它们的内存,也位于实例之中。实例在服务器进程结束后仍然继续存在。

    下图显示了 Oracle 数据库实例中的主要组件。
    Database Instance
    图 13- 1 数据库实例

    实例配置

    Oracle 数据库支持单实例配置和真正应用集群(Oracle RAC)配置。这两种配置只能二选其一。

    在单实例配置中,数据库和实例之间一一对应。在 Oracle RAC 中,数据库和实例存在一对多的关系。

    下图显示了两种可能的数据库实例配置。
    Database Instance Configurations
    图 13-2 数据库实例配置

    无论是单实例还是 Oracle RAC 配置,一个实例每次只能与一个数据库关联。管理员可以启动一个实例,然后加载(关联)一个数据库,但是不能同时加载两个数据库。

    注意:除非特别指出,本章讨论单实例数据库配置。

    一台服务器上可以同时运行多个实例,每个实例管理各自的数据库。例如,某台服务器上拥有两个不同的数据库:prod1 和 prod2。一个实例管理 prod1另一个实例管理 prod2。

    读写实例与只读实例

    实例支持两种模式:读写实例与只读实例。

    对于读写实例,可以处理 DML 操作,支持客户端的直接连接请求。这是默认方式。与此相反,只读实例能够运行查询,但是不能支持 DML修改操作(UPDATE、DELETE、INSERT 以及 MERGE),也不能从客户端直接进行连接。

    注意:除非另外指明,本文档中的实例都是指读写实例。

    在之前的版本中,所有的实例(除非管理一个 standby 数据库)都是读写实例。从 Oracle 数据库 12c (12.2) 开始, 一个数据库可以同时存在只读实例和读写实例。这种配置对于即查询数据又修改数据库的并行 SQL 语句非常有用,因为读写实例和只读实例都能够查询数据,而读写实例能够修改数据。

    与读写实例相比,只读实例具有以下特点:

    • 只能打开一个已经被读写实例打开的数据库
    • 禁用了许多不必要的后台进程,包检查点进程和归档进程
    • 可以加载一个被禁用的重做线程或者没有任何在线重做日期的线程

    要想将实例设置为只读模式,可以将初始化参数 INSTANCE_MODE 设置为 READ_ONLY。该参数的默认值为 READ_WRITE。

    实例生命周期

    数据库实例从 STARTUP 命令创建开始,直到被终止时结束。

    在此期间,一个实例能且只能与一个数据库相关联。进一步而言,该实例只能加载数据库一次、打开数据库一次,并且关闭数据库一次。在数据库关闭之后,必须重新启动一个实例,然后加载并打开数据库。

    下表演示了一个实例尝试重新打开之前关闭的数据库的过程。

    表 13- 1 实例生命周期

    语句注释
    SQL> STARTUP
    ORACLE instance started.
    Total System Global Area 468729856 bytes
    Fixed Size 1333556 bytes
    Variable Size 440403660 bytes
    Database Buffers 16777216 bytes
    Redo Buffers 10215424 bytes
    Database mounted.
    Database opened.
    STARTUP 命令创建一个实例,然后加载并打开数据库。
    SQL> SELECT
    TO_CHAR(STARTUP_TIME,‘MON-DD-RR HH24:MI:SS’)
    AS “Inst Start Time” FROM V$INSTANCE;

    Inst Start Time
    ------------------
    JUN-18-14 13:14:48
    该查询显示了当前实例的启动时间。
    SQL> SHUTDOWN IMMEDIATE关闭数据库和实例,结束实例的生命周期。
    SQL> STARTUP
    Oracle instance started… . .
    STARTUP 命令创建一个新的实例,然后加载并打开数据库。
    SQL> SELECT
    TO_CHAR(STARTUP_TIME,‘MON-DD-RR HH24:MI:SS’)
    AS “Inst Start Time” FROM V$INSTANCE;

    Inst Start Time
    ------------------
    JUN-18-14 13:16:40
    该查询显示了当前实例的启动时间。不同的启动时间表明了这是一个新的实例。

    实例标识

    一个主机上可以运行多个数据库实例。因此,访问时需要指定访问哪个实例。

    Oracle 最优灵活体系结构(OFA)规则是一组配置指南,可以确保组织良好的 Oracle 软件安装。本节中的示例使用 OFA 体系结构。

    本节包含以下主题:

    • Oracle 根目录
    • Oracle 主目录
    • Oracle 系统标识符(SID)

    Oracle 根目录

    Oracle 根目录(Oracle Base directory)存储 Oracle 产品的二进制文件。

    Oracle 根目录是 Oracle 数据库安装拥有者的数据库主目录。一个主机上可以按照多个 Oracle 数据库,以及多个 Oracle 数据库软件安装的拥有者。

    以下示例显示了操作系统用户 oracle 的 Oracle 根目录:

    /u01/app/oracle
    

    在路径的前缀中, /u01/ 是存储的挂载点, /u01/app/ 是安装应用软件的分支目录。

    Oracle 主目录

    Oracle 主目录(Oracle home directory)是 Oracle 数据库软件的安装位置。

    每个新的 Oracle 数据库软件安装都需要指定一个新的 Oracle 主目录。默认情况下,Oracle 主目录是 Oracle 根目录(ORACLE_BASE)下的一个子目录。

    在同一个主机上,相同的 Oracle 根目录下,可以安装不同版本的数据库软件。归属于不同系统用户的不同版本的多个数据库可以并存。

    以下示例显示了三个不同的 Oracle 主目录的完整路径名称,它们都位于相同的 Oracle 根目录(/u01/app/oracle/)下:

    /u01/app/oracle/product/12.1.0/dbhome_1
    /u01/app/oracle/product/12.1.0/dbhome_2
    /u01/app/oracle/product/18.0.0/dbhome_1
    

    路径名称中, Oracle 根目录(/u01/app/oracle/)之后的部分包含了产品版本编号(例如 12.1.0)和 Oracle 主目录的相对路径(例如 dbhome_1)目录 /u01/app/oracle/product/12.1.0/ 中包含了两个不同的 Oracle 主目录: dbhome_1 和 dbhome_2。

    从 Oracle Database 18c 开始,支持创建只读的 Oracle 主目录,将其作为一个软件的映像。只读 Oracle 主目录存储静态文件,例如二进制程序。Oracle 根主目录(ORACLE_BASE_HOME)位于 ORACLE_BASE/homes/home_name,存储与特定 Oracle 主目录相关的动态文件。Oracle 根配置目录(ORACLE_BASE_CONFIG)由 Oracle 根目录中的所有 Oracle 主目录共享,用于存储实例相关的动态文件。

    以下示例中,第一个路径是一个只读 Oracle 主目录,第二个路径是其对应的 根主目录:

    /u01/app/oracle/product/18.0.0/ro_dbhome_1
    /u01/app/oracle/homes/ro_dbhome_1
    

    Oracle SID

    系统标识符(SID) 是一个主机上的 Oracle 数据库实例的唯一名称。

    在 UNIX 和 Linux 系统上,Oracle 数据库使用 SID 和 Oracle 主目录的路径名称作为共享内存的键值。 另外,Oracle 数据库默认使用 SID 查找初始化参数文件,通过初始化文件查找其他相关文件,例如数据库控制文件。

    在大多数平台上,使用 ORACLE_SID 环境变量设置 SID,使用 ORACLE_HOME 变量设置 Oracle 主目录。客户端连接数据库实例时,可以在 Oracle Net 连接中指定 SID,或者使用一个网络服务名(service name)。 Oracle 数据库将服务名转换为 ORACLE_HOME 和 ORACLE_SID。

    传统的可读写 Oracle 主目录包含了实例相关的文件。但是,如果 Oracle 主目录改为只读,实例相关的文件单独存储在 Oracle 根目录中。无论哪种情况,名称中包含 SID 的文件存储在 Oracle 主配置目录(ORACLE_BASE_CONFIG)的 dbs 子目录中。有了这种文件分离,用户可以使用只读 Oracle 主目录中的软件创建数据库,然后使用另一个只读 Oracle 主目录中的软件启动一个实例,管理该数据库。

    实例启动与关闭

    数据库实例(database instance)为用户提供数据库访问。实例和数据库存在各种不同的状态。

    启动实例与数据库

    通常来说,管理员手动启动一个实例,然后加载并打开数据库,接受客户端连接。这些操作可以通过 SQL*Plus 的 STARTUP 命令、 Oracle 企业管理器(Enterprise Manager)或者 SRVCTL 工具完成。

    如果使用 Oracle Net 启动一个数据库实例,需要满足以下条件:

    • 数据库通过静态方式注册到 Oracle Net 监听器中。
    • 使用 SYSDBA 权限进行连接。

    监听器启动一个专用的服务器进程,用于启动数据库实例。

    下图显示了数据库从关闭到打开的处理过程。
    Instance and Database Startup Sequence
    图 13-3 实例与数据库启动顺序

    数据库从关闭状态到打开状态需要经历以下几个阶段。

    表 13-2 实例启动阶段

    阶段加载状态描述更多内容
    1启动实例,未加载数据库启动一个实例,但没有与数据库关联。启动实例
    2加载数据库实例已经启动,并且读取数据库的控制文件。数据库对用户不可用。加载数据库
    3打开数据库实例已经启动,并且打开数据库。授权用户可以访问数据文件中的数据。打开数据库

    管理员登录

    数据库的启动和关闭是非常强大的管理功能,只能由具有管理员权限的用户执行。

    普通用户无法控制数据库的当前状态。根据操作系统的不同,用户可以通过以下方式获得管理员权限:

    • 用户的操作系统权限允许他/她已管理员权限连接到数据库。
    • 用户被授予特殊的系统权限,数据库使用口令文件认证通过网络连接的管理员

    以下特殊的系统权限能够在数据库未打开时访问实例:

    • SYSDBA
    • SYSOPER
    • SYSBACKUP
    • SYSDG
    • SYSKM

    以上权限的管理不在数据库的自身范围之内。使用 SYSDBA 系统权限连接时,用户位于 SYS 模式中。使用 SYSOPER 连接时,用户位于公共模式中。SYSOPER 权限是 SYSDBA 权限的一个子集。

    启动实例

    当 Oracle 数据库启动一个实例时,需要经过几个阶段。

    实例启动阶段包括:

    1. 查找不同平台下默认位置中的服务器参数文件,如果没有找到该文件,查找文本形式的初始化参数文件(在 STARTUP 命令中指定 SPFILE 或 PFILE 参数将会覆盖默认行为)
    2. 读取参数文件,获取初始化参数的值
    3. 基于初始化参数设置分配 SGA
    4. 启动 Oracle 后台进程
    5. 打开告警日志(alert log)文件和跟踪文件(trace file),按照参数设置的语法在告警日志中写入所有显式指定的参数设置

    在这一阶段,实例还没有关联到数据库。NOMOUNT 状态的使用场景包括数据库创建以及备份与恢复操作。

    加载数据库

    实例通过加载数据库与其进行关联。

    加载数据库时,实例通过初始化参数 CONTROL_FILES 获取数据库控制文件 的名称并打开这些文件。Oracle 数据库读取控制文件,获取数据文件和在线重做日志文件的名称,在打开数据库时需要访问这些文件。

    加载之后,数据库处于关闭状态,只允许管理员访问。管理员可以在保持数据库关闭的同时执行一些特定的维护操作。但是,此时数据库还不能执行一些常规操作。

    如果 Oracle 数据库允许多个实例同时加载相同的数据库,初始化参数 CLUSTER_DATABASE 可以设置多个实例访问该数据库。具体的行为取决于该参数的值:

    • 如果第一个加载数据库的实例的 CLUSTER_DATABASE 设置为 false(默认值),只有该实例能够加载数据库。
    • 如果第一个加载数据库的实例的 CLUSTER_DATABASE 设置为 true,其他实例在 CLUSTER_DATABASE 也设置为 true 时可以加载该数据库。可以同时加载同一个数据库的实例数量由创建数据库时的预定义值决定。

    打开数据库

    打开一个已加载的数据库意味着可以对其执行常规的操作。

    任何有效的用户都可以连接到一个打开的数据库,并且访问其中的信息。通常来说,数据库管理员负责打开数据库。

    打开数据库时, Oracle 数据库将会执行以下操作:

    • 打开撤销表空间(undo tablespace)之外的其他表空间的在线数据文件

      如果一个表空间在数据库关闭之前处于离线(offline)状态,重新打开数据库时,该表空间和相应的数据文件仍然处于离线状态。

    • 获取一个撤销表空间

      如果存在多个撤销表空间,由初始化参数 UNDO_TABLESPACE 决定使用哪个表空间。如果没有设置该参数,使用第一个可用的撤销表空间。

    • 打开在线重做日志文件

    只读模式

    默认情况下,数据库以读/写模式打开。在这种模式下,用户可以修改数据,产生重做日志项。另外,数据库可以以只读模式打开,防止用户事务修改数据。

    注意:默认情况下,物理备用数据库以只读模式打开。

    只读模式下的数据库只能执行只读事务,不能写入数据文件或者在线重做日志文件。不过,数据库仍然能够执行恢复操作或者不产生重做日志的操作。例如,只读模式支持以下操作:

    • 将数据文件离线或者在线。但是,不能将永久表空间离线。
    • 恢复离线的数据文件和表空间。
    • 修改控制文件中关于数据库状态的信息。
    • 使用 CREATE TEMPORARY TABLESPACE 语句创建的临时表空间允许读写操作。
    • 写入操作系统的审计文件、跟踪文件以及告警日志。
    数据库文件检查

    如果打开数据库时,任何数据文件或重做日志文件不存在,或者它们存在但是一致性检测失败,数据库将会返回一个错误。此时需要执行介质恢复。

    关闭数据库与实例

    通常来说,管理员在执行维护操作或其他管理任务时手动关闭数据库。可以使用 SQL*Plus 的 SHUTDOWN 命令或者 Enterprise Manager 执行这些操作。

    下图演示了数据库从打开状态到一致性关闭的过程。
    Instance and Database Shutdown Sequence
    图 13-4 实例与数据库关闭顺序

    Oracle 数据库从打开到一致性关闭时自动执行以下操作。
    表 13-3 一致性关闭的步骤

    阶段加载状态描述更多内容
    1关闭数据库数据库处于加载状态,但是在线数据文件和重做日志文件被关闭。关闭数据库
    2卸载数据库实例处于启动状态,但是不再关联数据库的控制文件。卸载数据库
    3关闭实例实例被关闭,不再处于启动状态。关闭实例

    Oracle 数据库在出现实例失败或者执行 SHUTDOWN ABORT (立即终止实例)命令时,不会执行以上操作。

    关闭模式

    具有 SYSDBA 或者 SYSOPER 权限的数据库管理员可以使用 SQL*Plus 的 SHUTDOWN 命令或 Enterprise Manager 关闭数据库。SHUTDOWN 命令包含了不同的关闭选项。

    下表总结了不同的关闭模式。
    表 13-4 数据库关闭模式

    数据库行为ABORTIMMEDIATETRANSACTIONALNORMAL
    运行新用户连接
    等待当前会话结束
    等待当前事务结束
    执行检查点并关闭打开的文件

    不同的 SHUTDOWN 语句包括:

    • SHUTDOWN ABORT

      这种关闭模式用于紧急情况,例如其他模式无法关闭实例时。这种模式速度最快。但是,随后再打开数据库时需要更长的时间,因此需要执行实例恢复以确保数据文件的一致性。

      由于 SHUTDOWN ABORT 命令不对打开的数据文件执行检查点操作,重新打开数据库时必须执行实例恢复。其他的关闭模式在重新打开数据库时不需要执行实例的恢复。

      注意:在 CDB 中,针对 PDB 执行的 SHUTDOWN ABORT 命令等价于非 CDB 上的 SHUTDOWN IMMEDIATE 命令。

    • SHUTDOWN IMMEDIATE

      这种关闭模式是除了 SHUTDOWN ABORT 之外的最快方式。Oracle 数据库立即终止任何正在执行的 SQL 语句并且断开用户的连接。系统终止所有正在进行的事务,并且回滚未提交的更改。

    • SHUTDOWN TRANSACTIONAL

    这种关闭模式不允许用户开始新的事务,但会等待所有当前正在执行的事务结束,然后关闭数据库。这种模式可能需要等待很长的时间才能完成。

    • SHUTDOWN NORMAL

    这是默认的关闭模式。数据库在关闭之前等待所有连接的用户断开连接。

    关闭数据库

    关闭数据库的操作分为正常关闭和异常关闭。

    正常关闭

    当数据库使用非 ABORT 模式关闭时,会将 SGA 中的数据写入数据文件和在线重做日志文件。

    然后,数据库关闭在线数据文件和重做日志文件。离线表空间中的离线数据文件已经处于关闭状态。当数据库重新打开时,原来的离线表空间仍然处于离线状态。

    此时,数据库已经关闭,不接受正常访问。但是控制文件仍然处于打开状态。

    异常关闭

    如果使用 SHUTDOWN ABORT 命令关闭数据库或者数据库异常终止时,实例瞬间停止并关闭数据库。

    异常关闭时,Oracle 数据库不会将 SGA 缓存中的数据写入数据文件和重做日志文件。随后重新打开数据库时需要执行实例恢复,Oracle 自动执行实例的恢复操作。

    卸载数据库

    在关闭数据库之后,Oracle 将会卸载数据库,将其与实例分离。

    卸载数据库之后,Oracle 关闭数据库的控制文件。此时,实例仍然存在于内存之中。

    关闭实例

    关闭数据库的最后一步就是关闭实例。关闭实例时,系统释放 SGA 内存,并停止后台进程。

    在异常情况下,实例可能没有关闭干净。内存中仍然存在一些内存结构,或者某个后台进程仍未终止。如果之前的实例仍然部分存在,后续的实例可能会启动失败。此时,可以通过删除之前实例的残余并重新启动一个新实例,或者使用 SHUTDOWN ABORT 语句关闭之前的实例,强制启动一个新的实例。

    某些情况下,进程的清除可能会遇到错误,导致进程监控进程(PMON)或者实例的终止。动态初始化参数 INSTANCE_ABORT_DELAY_TIME 用于指定发生内部实例失败时延迟关闭的时间(秒)。延迟时间之内,管理员可以介入处理。当发生延迟的实例终止时,数据库在告警日志中写入一条消息。某些情况下,通过允许隔离某些数据库资源,可以避免实例被终止。

    检查点

    检查点(checkpoint)对于一致性数据库关闭、实例恢复以及常规数据库操作都至关重要。

    检查点操作具有以下含义:

    • 检查点位置(checkpoint position),它表示重做日志流中的系统更改号(SCN),实例恢复必须从该检查点位置开始

      检查点位置由数据库缓冲区高速缓存中最早的脏块决定。检查点位置相当于一个指向重做流的指针,它的信息存储在控制文件以及每个数据文件的头部。

    • 将数据库缓冲区高速缓存中被修改过的缓存数据写入磁盘

    检查点的作用

    Oracle 数据库使用检查点实现多个功能,包括:

    • 减少实例或介质失败时的恢复时间
    • 确保数据库定期将缓冲区高速缓存中的脏数据写入磁盘
    • 确保数据库在一致性关闭时将所有已提交的数据写入磁盘

    检查点触发时机

    检查点进程(CKPT)负责将检查点写入数据文件头部以及控制文件中。

    许多场景都会导致检查点发生。例如,Oracle 数据库包含以下检查点类型:

    • 线程检查点

      数据库在完成特定操作之前将某个重做线程修改的缓存数据写入磁盘。一个数据库的所有实例上的线程检查点集合组成数据库检查点。线程检查点在以下情况下触发:

      • 一致性数据库关闭
      • 执行 ALTER SYSTEM CHECKPOINT 语句
      • 在线重做日志切换
      • 执行 ALTER DATABASE BEGIN BACKUP 语句
    • 表空间和数据文件检查点

    数据库在完成特定操作之前将所有重做线程修改的缓存数据写入磁盘。表空间检查点包含一组数据文件检查点,每个数据文件一个检查点。这些检查点的触发事件包括:将表空间设置为只读或者正常离线,收缩数据文件,或者执行 ALTER TABLESPACE BEGIN BACKUP 命令。

    • 增量检查点

    增量检查点是一种线程检查点,作用包括避免在线重做日志切换时的大量数据块写入。DBW 至少每三秒执行一次检查,判断是否需要写入数据。当 DBW 将脏缓存写磁盘时,同时推进检查点位置,使得 CKPT 将检查点位置写入控制文件,但不会写入数据文件头部。

    其他类型的检查点包括实例与介质恢复检查点,以及删除或截断模式对象时的检查点。

    实例恢复

    实例恢复(Instance recovery)是将在线重做日志文件中的记录应用到数据文件的过程,用于重建最近的检查点之后的数据变更。

    当管理员尝试打开一个之前未能一致性关闭的数据库时,系统自动执行实例的恢复。

    实例恢复的作用

    实例恢复可以确保数据库在发生实例失败之后能够恢复到一致性的状态。数据对于变更的管理方式,导致数据库文件可能会处于一个非一致性的状态。

    日志线程(redo thread)是一个实例产生的所有变更记录。单实例数据库只有一个日志线程,而 Oracle RAC 数据库包含多个日志线程,每个实例一个日志线程。

    当事务被提交时,日志写入进程(LGWR)将内存中的重做日志项和该事务的 SCN 同时写入在线重做日志。但是,数据写入(DBW)进程以系统认为的高效方式将修改后的数据块写入数据文件。因此,未提交的更改可能会临时存在数据文件中,同时已提交的修改有可能未写入数据文件。

    如果数据库位于打开状态时发生实例失败(可能是由于 SHUTDOWN ABORT 语句或异常终止),将会导致以下状况:

    • 已提交的数据块还没有写入数据文件,只记录在在线重做日志中。这些变更必须重新应用到数据文件中。
    • 数据文件中包含一些实例失败时未提交的变更。这些变更必须进行回滚,以确保事务的一致性。

    实例恢复只利用在线重做日志文件和当前在线数据文件执行数据文件的同步,确保它们的一致性。

    实例恢复的时间

    是否需要执行实例恢复取决于日志线程的状态。

    当数据库实例以读写模式打开时,对应的日志线程被标记为打开状态,当实例一致性关闭时,日志线程被标记为关闭。如果日志线程在控制文件中是打开状态,但是没有对应的活动实例,数据库需要执行实例恢复。

    Oracle 数据库在以下情况下自动执行实例恢复:

    • 单实例数据库失败后,或者 Oracle RAC 数据库的所有实例失败后,首次打开数据库。这种形式的实例恢复也称为崩溃恢复。Oracle 数据库同时恢复所有失败实例的在线重做日志线程。
    • Oracle RAC 数据库的部分(非全部)实例失败 。集群中某个存活实例自动执行实例恢复操作。

    后台进程 SMON 负责执行实例恢复,自动应用在线重做日志。整个过程不需要管理员介入。

    检查点的重要性

    实例恢复时,使用检查点决定需要应用到数据文件中的变更。检查点位置确保了所有 SCN 小于检查点 SCN 的已提交变更都已保存到数据文件中。

    下图描绘了在线重做日志中的日志线程。
    Checkpoint Position in Online Redo Log
    图 13-5 在线重做日志中的检查点位置

    在执行实例恢复时,数据库必须应用检查点位置和日志线程终点之间的所有变更。如图 13-5 所示,某些变更可能已经写入了数据文件。但是,只有 SCN 小于检查点位置的变更确认已经写入磁盘之中。

    实例恢复步骤

    实例恢复的第一步称为缓存恢复(cache recovery)或前滚(rolling forward),将在线重做日志中的所有变更重新应用到数据文件中。

    由于在线重做日志中包含了撤销数据(undo data),前滚操作也会重建相应的撤销段(undo segment)。前滚操作应用在线重做日志文件将数据库恢复到实例失败之前的状态。完成前滚操作之后,数据块中包含了在线重做日志文件中的所有已提交变更。这些数据文件中可能还包含一些实例失败之前写入的未提交变更,或者缓存恢复时从在线重做日志中引入的未提交变更。

    前滚之后,未提交的变更需要回滚。Oracle 数据库使用检查点位置确保所有 SCN 小于检查点 SCN 的已提交变更已经写入磁盘。Oracle 数据库应用撤销块 回滚未提交的变更(包括实例失败之前写入的变更和缓存恢复时引入的变更)。这个阶段称为回滚(rolling back)或者事务恢复(transaction recovery)。

    下图演示了数据库实例恢复的两个必要步骤:前滚和回滚。
    Basic Instance Recovery Steps: Rolling Forward and Rolling Back
    图 13-6 基本实例恢复操作:前滚和回滚

    Oracle 数据库可以根据需要同时回滚多个事务。实例失败时的所有活动事务都被标记为终止。新的事务可以回滚各自的数据块以获取所需的数据,而不需要等待 SMON 进程回滚被终止的事务。

    参数文件

    启动数据库实例时,Oracle 数据库必须读取一个服务器参数文件(推荐方式)或者一个文本初始化参数文件(传统遗留方式)。这些文件中包含了一个配置参数的列表。

    手动创建一个数据库时,必须使用一个参数文件启动实例,然后执行 CREATE DATABASE 语句。实例和参数文件可以独立于数据库而存在。

    初始化参数

    初始化参数(Initialization parameter)是一些可以影响实例操作的配置参数。实例在启动时读取参数文件中的初始化参数。

    Oracle 数据库提供了许多初始化参数,用于优化不同环境下的操作。只有少数参数需要显式设置,通常只需要使用默认值即可。

    初始化参数分组

    初始化参数可以按照功能分为不同的组。

    大部分初始化参数属于以下分组之一:

    • 设置实体项目(例如文件或目录)的参数
    • 设置进程限制、数据库资源限制、或者数据库自身限制的参数
    • 影响容量的参数,例如 SGA 的大小(这些参数被称为可变参数)

    数据库管理员特别关注可变参数,因为他们可以通过这些参数优化数据库的性能。

    基本参数与高级参数

    初始化参数可以分为两类:基本参数和高级参数。

    通常来说,管理员需要设置并优化大约 30 个基本的参数,以达到合理的性能。基本参数用于设置一些特性,例如数据库名称、控制文件的位置、数据库块大小以及撤销表空间。

    在极少数情况下,管理员需要修改高级参数,以便获得最佳性能。DBA 专家通过可以高级参数调整数据库的行为,以满足特定的需求。

    Oracle 数据库在安装软件的启动初始化参数文件中提供了参数值,或者可以通过数据库配置助手(DBCA)创建这些参数。管理员可以根据自己的配置需求或者调优方案,修改 Oracle 提供的这些初始化参数,也可以增加其他参数。对于参数文件中没有涉及的相关初始化参数,Oracle 数据库提供默认值。

    服务器参数文件

    服务参数文件(server parameter file)是初始化参数的一个存储库。

    服务器参数文件具有以下主要特征:

    • 只能由 Oracle 数据库读写服务器参数文件。
    • 一个数据库只能有一个服务器参数文件。该文件必须存放在数据库服务器主机中。
    • 服务器参数文件是一个二进制文件,不能使用文本编辑器进行修改。
    • 服务器参数文件中的初始化参数是永久存储的。在数据库实例运行时对参数所做的任何更改在实例关闭和启动后仍然生效。

    服务器参数文件使得客户端应用不再需要维护多个文本初始化参数文件。服务器参数文件通过 CREATE SPFILE 语句从文本初始化参数文件创建。它可以通过数据库配置助手直接创建。

    文本初始化参数文件

    文本初始化参数文件(text initialization parameter file)是一个文本文件,内容是一个初始化参数的列表。

    这种参数文件是历史遗留的实现方式,它具有以下主要特点:

    • 当启动或者关闭数据库时,文本初始化参数文件必须位于连接到数据库的客户端主机中。
    • 文本初始化参数文件时一个文本文件,而不是二进制文件。
    • Oracle 数据库可以读取文本初始化参数文件,但是不能写入该文件。要想修改参数的值,必须通过文本编辑器手动进行修改。
    • 使用 ALTER SYSTEM 语句修改的初始化参数值只在当前实例中生效。必须手动更新文件初始化参数文件并重启实例才能永久生效。

    文本初始化参数文件中包含一系列 key=value 配置,每行一个配置。例如,以下是某个参数文件中的部分内容:

    db_name=sample
    control_files=/disk1/oradata/sample_cf.dbf
    db_block_size=8192
    open_cursors=52
    undo_management=auto
    shared_pool_size=280M
    pga_aggregate_target=29M
    .
    .
    .
    

    为了说明文本参数文件可能带来的管理问题,假设你使用了计算机 clienta 和 clientb,并且需要能够从任意一个计算机上启动数据库。此时,每个计算机上都需要一个单独的文本初始化参数文件,如图 13-7 所示。 服务参数文件可以解决参数文件的分散存储问题。
    Multiple Initialization Parameter Files
    图 13-7 多个初始化参数文件

    修改初始化参数

    管理员可以通过修改初始化参数来调整数据库的行为。参数按照修改方式分为静态(static)参数和动态(dynamic)参数。

    下列表格总结了它们的不同之处。

    表 13-5 静态初始化参数和动态初始化参数

    特性静态参数动态参数
    需要修改参数文件
    需要重启实例才能生效
    Oracle Database Reference 中显示为“Modifiable”
    只能修改数据库或实例相关的参数

    静态参数包括 DB_BLOCK_SIZE、DB_NAME 以及 COMPATIBLE。动态参数分为会话级别的参数(只影响当前会话)和系统级别的参数(影响数据库和所有会话)。例如,MEMORY_TARGET 是一个系统级参数,而 NLS_DATE_FORMAT 是一个会话级参数。

    参数变更的范围取决于变更何时生效。当实例使用服务器参数文件启动时,可以使用 ALTER SYSTEM SET 语句选择以下方式修改系统级参数:

    • SCOPE=MEMORY

      参数的变更只针对当前数据库实例生效。数据库关闭并重启后变更不会持久化。

    • SCOPE=SPFILE

      参数的变更只应用于服务器参数文件,不会影响当前实例。因此,变更只在实例重启之后生效。

      注意:对于那些在 Oracle Database Reference 中标识为不可更改的参数,修改时必须指定 SPFILE 。

    • SCOPE=BOTH

      Oracle 数据库同时将变更写入内存和服务器参数文件。这是数据库使用服务器参数文件时的默认修改范围。

    诊断文件

    Oracle 数据库提供了一个故障诊断基础架构(fault diagnosability infrastructure),用于防止、检测、诊断和解决数据库问题。这些问题包括代码错误、元数据损坏以及客户数据丢失等严重错误。

    这个高级的故障诊断基础架构的作用包括:

    • 主动发现问题
    • 检测到问题后控制损失和系统中断
    • 减少故障诊断和解决时间
    • 通过拆分跟踪文件提高可管理性,允许用户指定每个文件的大小,以及保留的最大文件数量,并且在占用的存储到达用户指定的磁盘空间后关闭跟踪
    • 方便客户与 Oracle 支持人员的交流

    多租户容器数据库(CDB)与非 CDB 的诊断架构不同。本节内容针对非 CDB,除非另有说明。

    自动诊断库

    自动诊断库(ADR)是一个基于文件的资料库,用于存储数据库的诊断数据,例如跟踪文件、告警日志、DDL 日志以及健康健康报告。

    ADR 具有以下主要特点:

    • 统一的目录结构
    • 一致的诊断数据格式
    • 统一的工具套件

    以上特性使得客户和 Oracle 支持人员能够关联和分析多个实例、组件和产品的诊断数据。

    ADR 存储在数据库之外,Oracle 数据库在物理库不可用时仍然能够访问和管理 ADR。数据库实例在创建数据库之前创建 ADR。

    问题和事件

    ADR 可以主动发现问题(problems), 它们是数据库中的一些关键错误。

    关键错误显示为内部错误,例如 ORA-600,或者其他严重错误。每个问题拥有一个问题键(problem key),它是描述该问题的文本字符串。

    当一个问题多次发生时,ADR 为每次的错误创建一个包含时间戳的事件(incident)。事件由一个数字的事件 ID 唯一确定。当一个事件发生时, ADR 将会发送一个事件告警(incident alert)到 Enterprise Manager。一个关键错误的诊断和解决通常从一个事件告警开始。

    由于一个问题可能在短时间内产生多次事件,当该事件的次数到达一个特定阈值之后,ADR 将会采用防洪控制措施。防洪控制事件只会产生一个告警日志项,而不会产生事件转储信息。ADR 通过这种方式通知用户正在发生一个严重的错误,而不会因为产生大量的诊断数据给系统带来压力。

    ADR 目录结构

    ADR base 是 ADR 的根目录。

    ADR 根目录下可以存在多个 ADR 主目录(ADR home),每个 ADR 主目录是一个 Oracle 产品或组件的实例的诊断数据所在的根目录,包括跟踪文件、转储文件以及告警日志等等。例如, 在一个使用了共享存储和 Oracle ASM 的 Oracle RAC 环境中,每个数据库实例和 Oracle ASM 实例都拥有各自的 ADR 主目录。

    图 13-8 显示了一个数据库实例的 ADR 目录层次结构。在相同的 ADR 根目录下,还可以存在其他 Oracle 产品或组件的其他 ADR 主目录,例如 Oracle ASM 或者 Oracle Net Services。
    ADR Directory Structure for an Oracle Database Instance
    图 13-8 Oracle 数据库实例的 ADR 目录结构

    以下是一个 Linux 环境的示例,当你在创建数据库之前使用一个唯一的 SID 和数据库名称启动实例时,Oracle 数据库默认在文件系统中创建一个 ADR 目录结构。SID 和数据库名称成为了 ADR 主目录中的文件路径的一部分。

    示例 13-1 创建 ADR

    % setenv ORACLE_SID osi
    % echo "DB_NAME=dbn" > init.ora
    % sqlplus / as sysdba
    .
    .
    . 
    Connected to an idle instance.
     
    SQL> STARTUP NOMOUNT PFILE="./init.ora"
    ORACLE instance started.
     
    Total System Global Area  146472960 bytes
    Fixed Size                  1317424 bytes
    Variable Size              92276176 bytes
    Database Buffers           50331648 bytes
    Redo Buffers                2547712 bytes
     
    SQL> COL NAME FORMAT a21
    SQL> COL VALUE FORMAT a60
    SQL> SELECT NAME, VALUE FROM V$DIAG_INFO;
     
    NAME                  VALUE
    --------------------- --------------------------------------------------------
    Diag Enabled          TRUE
    ADR Base              /d1/3910926111/oracle/log
    ADR Home              /d1/3910926111/oracle/log/diag/rdbms/dbn/osi
    Diag Trace            /d1/3910926111/oracle/log/diag/rdbms/dbn/osi/trace
    Diag Alert            /d1/3910926111/oracle/log/diag/rdbms/dbn/osi/alert
    Diag Incident         /d1/3910926111/oracle/log/diag/rdbms/dbn/osi/incident
    Diag Cdump            /d1/3910926111/oracle/log/diag/rdbms/dbn/osi/cdump
    Health Monitor        /d1/3910926111/oracle/log/diag/rdbms/dbn/osi/hm
    Default Trace File    /d1/3910926111/oracle/log ... osi/trace/osi_ora_6825.trc
    Active Problem Count  0
    Active Incident Count 0
    

    告警日志

    每个数据库都有一个告警日志,它是一个 XML 文件,其中包含了数据库消息和错误的时间日志。

    告警日志包含以下内容:

    • 所有内部错误(ORA-600),块损坏错误(ORA-1578)以及死锁错误(ORA-60)
    • 数据库管理操作,例如 SQL*Plus 的 STARTUP、
      SHUTDOWN、ARCHIVE LOG 以及 RECOVER 命令
    • 与共享服务器和调度进程功能相关的一些消息和错误
    • 物化视图自动刷新错误

    Oracle 数据库使用告警日志作为在 Enterprise Manager GUI 中显示信息的替代方案。如果成功执行一个管理操作,Oracle 数据库将会在告警日志中写入一个带时间戳的“已完成”的消息。

    首次启动一个实例时,Oracle 数据库在图 13-8 所示的 alert 子目录中创建一个告警日志文件,即使还没有创建数据库。该文件使用 XML 格式。在 trace 子目录中存在一个纯文本的告警日志,以下是某个告警日志的一部分:

    Fri Nov 02 12:41:58 2014
    SMP system found. enable_NUMA_support disabled (FALSE)
    Starting ORACLE instance (normal)
    CLI notifier numLatches:3 maxDescs:189
    LICENSE_MAX_SESSION = 0
    LICENSE_SESSIONS_WARNING = 0
    Initial number of CPU is 2
    Number of processor cores in the system is 2
    Number of processor sockets in the system is 2
    Shared memory segment for instance monitoring created
    Picked latch-free SCN scheme 3
    Using LOG_ARCHIVE_DEST_1 parameter default value as /disk1/oracle/dbs/arch
    Autotune of undo retention is turned on.
    IMODE=BR
    ILAT =10
    LICENSE_MAX_USERS = 0
    SYS auditing is disabled
    NOTE: remote asm mode is local (mode 0x1; from cluster type)
    Starting up:
    Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production
    With the Partitioning, Advanced Analytics and Real Application Testing options.
    .
    .
    .
    Using parameter settings in client-side pfile 
    System parameters with nondefault values:
      processes                = 100
      sessions                 = 172
    

    正如示例 13-1所示,可以查询 V$DIAG_INFO 找到告警日志文件的位置。

    DDL 日志

    DDL 日志(DDL log)的格式及基本特性和告警日志相同,但是只包含了 DDL 语句和相关细节信息。数据库将 DDL 的信息写入单独的文件,以便减少告警日志的复杂性。

    DDL 日志记录 DDL 文本,或者一些额外的信息。每个 DDL 语句记录一条日志。DDL 存储在 ADR 主目录下的 log/ddl 子目录中。

    跟踪文件

    跟踪文件(trace file)存储了用于调查问题的诊断数据。同时,跟踪文件还可以为应用程序或实例优化的提供指导。

    跟踪文件的类型

    每个服务器进程或后台进程都可以定期写入一个关联的跟踪文件。该文件中包含了进程环境、状态、活动以及错误的信息。

    SQL 跟踪工具也可以创建跟踪文件,为特定 SQL 语句提供性能相关的信息。可以以不同的方式为指定客户端标识、服务、模块、操作、会话、实例或者数据库启用跟踪。例如,可以通过执行 DBMS_MONITOR 包中的相应过程或者设置事件的方式启动跟踪。

    跟踪文件的位置

    ADR 在 trace 子目录中存储跟踪文件。跟踪文件名称取决于不同的系统,并且使用 .trc 扩展名。

    通常来说数据库后台进程的跟踪文件名称包含 Oracle SID、后台进程名以及操作系统进程编号。mytest_reco_10355.trc 是 一个 RECO 进程跟踪文件的示例。

    服务器进程的跟踪文件名称包含 Oracle SID、字符串“ora”以及操作系统进程编号。mytest_ora_10304.trc 是一个服务器进程跟踪文件的示例。

    有时候跟踪文件还拥有一个跟踪元数据文件,使用扩展名 .trm。这些文件中包含了称为跟踪映射(trace maps)的结构信息,数据库利用这些信息进行搜索和导航。

    跟踪文件的拆分

    如果设置了跟踪文件的大小限制,数据库自动将其拆分成最多五个分段。每个分段都是独立的文件,名称和活动的跟踪文件一致,只是加上了一个编号,例如 ora_1234_2.trc。

    每个分段通常是 MAX_DUMP_FILE_SIZE 参数的 20% 大小。每当所有分段的总大小超过了限制,数据库将会删除最早的分段(永远不会删除第一个分段,因为它包含了进程初始状态的相关信息),然后创建一个新的空分段文件。

    诊断转储文件

    诊断转储文件(diagnostic dump file)是一种特殊的跟踪文件,包含了关于某个状态或结构的详细时间点信息。

    跟踪往往是连续的诊断数据。与此相反,转储通常是针对某一事件的一次性诊断数据。

    跟踪转储与事件

    大多数跟踪转储由事件触发。

    当一个事件发生时,数据库在该事件的事件目录中写入一个或多个转储文件。事件转储文件的名称中还包含了事件编号。

    创建事件时,应用可能会为某个操作产生一个堆转储或者系统状态转储。这种情况下,数据库将转储名称添加到事件文件名之后,而不是默认的跟踪文件名之后。例如,由于一个进程的产生事件时,数据库创建 prod_ora_90348.trc 文件。该事件的转储操作产生 prod_ora_90348_incident_id.trc 文件,其中 incident_id 是该事件的数字 ID。随着该事件创建的堆转储操作产生一个堆转储文件 prod_ora_90348_incident_id_dump_id.trc,其中 dump_id 是跟踪转储的数字 ID。

    展开全文
  • Qt5开发及实例(完整版PDF)part1

    热门讨论 2015-03-06 13:35:41
    7.2.4 图元旋转、缩放、切变位移及实例 277 第8章 Qt 5模型/视图结构 286 8.1 概述 287 8.1.1 基本概念 287 8.1.2 模型/视图类 288 8.2 模型(Model) 290 8.3 视图(View) 295 8.4 代理(Delegate) 310 第9章...
  • Qt5开发及实例(完整版PDF).part2

    热门讨论 2015-03-06 13:37:18
    7.2.4 图元旋转、缩放、切变位移及实例 277 第8章 Qt 5模型/视图结构 286 8.1 概述 287 8.1.1 基本概念 287 8.1.2 模型/视图类 288 8.2 模型(Model) 290 8.3 视图(View) 295 8.4 代理(Delegate) 310 第9章...
  • Kotlin系列之扩展函数

    万次阅读 2018-04-17 00:22:18
    简述: 今天带来的是Kotlin浅谈系列的第五弹,这讲主要是讲利用Kotlin中的扩展函数特性让我们的代码变得更加简单整洁。扩展函数是Kotlin语言中独有的新特性,利用它可以减少很多的样板代码,大大提高开发的效率;...

    简述: 今天带来的是Kotlin浅谈系列的第五弹,这讲主要是讲利用Kotlin中的扩展函数特性让我们的代码变得更加简单和整洁。扩展函数是Kotlin语言中独有的新特性,利用它可以减少很多的样板代码,大大提高开发的效率;此外扩展函数的使用也是非常简单的。我会从以下几个方面阐述Kotlin中的扩展函数。

    • 1、为什么要使用Kotlin中的扩展函数?
    • 2、怎么去使用扩展函数和扩展属性?
    • 3、什么是扩展函数和属性?
    • 4、扩展函数和成员函数区别
    • 5、扩展函数不可以被重写

    一、为什么要使用Kotlin中的扩展函数

    我们都知道在Koltin这门语言可以与Java有非常好的互操作性,所以扩展函数这个新特性可以很平滑与现有Java代码集成。甚至纯Kotlin的项目都可以基于Java库,甚至Android中的一些框架库,第三方库来构建。扩展函数非常适合Kotlin和Java语言混合开发模式。在很多公司一些比较稳定良好的库都是Java写,也完全没必要去用Kotlin语言重写。但是想要扩展库的接口和功能,这时候扩展函数可能就会派上用场。使用Kotlin的扩展函数还有一个好处就是没有副作用,不会对原有库代码或功能产生影响。先来看下扩展函数长啥样

    • 给TextView设置加粗简单的例子
    //扩展函数定义
    fun TextView.isBold() = this.apply { 
    	paint.isFakeBoldText = true
    }
    
    //扩展函数调用
    activity.find<TextView>(R.id.course_comment_tv_score).isBold()
    

    二、怎么去使用扩展函数和扩展属性

    • 1、扩展函数的基本使用

    只需要把扩展的类或者接口名称,放到即将要添加的函数名前面。这个类或者名称就叫做接收者类型,类的名称与函数之间用"."调用连接。this指代的就是接收者对象,它可以访问扩展的这个类可访问的方法和属性。

    注意: 接收者类型是由扩展函数定义的,而接收者对象正是这个接收者类型的对象实例,那么这个对象实例就可以访问这个类中成员方法和属性,所以一般会把扩展函数当做成员函数来用。

    • 2、扩展属性的基本使用
      扩展属性实际上是提供一种方法来访问属性而已,并且这些扩展属性是没有任何的状态的,因为不可能给现有Java库中的对象额外添加属性字段,只是使用简洁语法类似直接操作属性,实际上还是方法的访问。
    //扩展属性定义
    var TextView.isBolder: Boolean
    	get() {//必须定义get()方法,因为不能在现有对象添加字段,也自然就没有了默认的get()实现
    		return this.paint.isFakeBoldText
    	}
    	set(value) {
    		this.paint.isFakeBoldText = true
    	}
    //扩展属性调用
    activity.find<TextView>(R.id.course_comment_tv_score).isBolder = true
    

    注意:

    • 扩展属性和扩展函数定义类似,也有接收者类型和接收者对象,接收者对象也是接收者类型的一个实例,一般可以把它当做类中成员属性来使用。

    • 必须定义get()方法,在Kotlin中类中的属性都是默认添加get()方法的,但是由于扩展属性并不是给现有库中的类添加额外的属性,自然就没有默认get()方法实现之说。所以必须手动添加get()方法。

    • 由于重写了set()方法,说明这个属性访问权限是可读和可写,需要使用var

    三、什么是扩展函数和属性

    我们从上面例子可以看出,kotlin的扩展函数真是强大,可以毫无副作用给原有库的类增加属性和方法,比如例子中TextView,我们根本没有去动TextView源码,但是却给它增加一个扩展属性和函数。具有那么强大功能,到底它背后原理是什么?其实很简单,通过decompile看下反编译后对应的Java代码就一目了然了。

    • 1、扩展函数实质原理

    扩展函数实际上就是一个对应Java中的静态函数,这个静态函数参数为接收者类型的对象,然后利用这个对象就可以访问这个类中的成员属性和方法了,并且最后返回一个这个接收者类型对象本身。这样在外部感觉和使用类的成员函数是一样的。

    public final class ExtendsionTextViewKt {//这个类名就是顶层文件名+“Kt”后缀,这个知识上篇博客有详细介绍
       @NotNull
       public static final TextView isBold(@NotNull TextView $receiver) {//扩展函数isBold对应实际上是Java中的静态函数,并且传入一个接收者类型对象作为参数
          Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
          $receiver.getPaint().setFakeBoldText(true);//设置加粗
          return $receiver;//最后返回这个接收者对象自身,以致于我们在Kotlin中完全可以使用this替代接收者对象或者直接不写。
       }
    }
    
    • 2、Java中调用Kotlin中定义的扩展函数

    分析完Kotlin中扩展函数的原理,我们也就很清楚,如何在Java中去调用Kotlin中定义好的扩展函数了,实际上使用方法就是静态函数调用,和我们之前讲的顶层函数在Java中调用类似,不过唯一不同是需要传入一个接收者对象参数。

    ExtendsionTextViewKt.isBold(activity.findViewById(R.id.course_comment_tv_score));//直接调用静态函数
    
    • 3、扩展属性实质原理

    扩展属性实际上就是提供某个属性访问的set,get方法,这两个set,get方法是静态函数,同时都会传入一个接收者类型的对象,然后在其内部用这个对象实例去访问和修改对象所对应的类的属性。

    public final class ExtendsionTextViewKt {
       //get()方法所对应生成静态函数,并且传入一个接收者类型对象作为参数
       public static final boolean isBolder(@NotNull TextView $receiver) {
          Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
          return $receiver.getPaint().isFakeBoldText();
       }
       //set()方法所对应生成静态函数,并且传入一个接收者类型对象作为参数和一个需要set的参数
       public static final void setBolder(@NotNull TextView $receiver, boolean value) {
          Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
          $receiver.getPaint().setFakeBoldText(true);
       }
    }
    
    • 4、Java中调用Kotlin中定义的扩展属性

    Java调用Kotlin中定义的扩展属性也很简单,就相当于直接调用生成的set(),get()方法一样。

        ExtendsionTextViewKt.setBolder(activity.findViewById(R.id.course_comment_tv_score), true);
    

    四、扩展函数和成员函数区别

    说到扩展函数和成员函数的区别,通过上面例子我们已经很清楚了,这里做个归纳总结:

    • 1、扩展函数和成员函数使用方式类似,可以直接访问被扩展类的方法和属性。(原理: 传入了一个扩展类的对象,内部实际上是用实例对象去访问扩展类的方法和属性)
    • 2、扩展函数不能打破扩展类的封装性,不能像成员函数一样直接访问内部私有函数和属性。(原理: 原理很简单,扩展函数访问实际是类的对象访问,由于类的对象实例不能访问内部私有函数和属性,自然扩展函数也就不能访问内部私有函数和属性了)
    • 3、扩展函数实际上是一个静态函数是处于类的外部,而成员函数则是类的内部函数。
    • 4、父类成员函数可以被子类重写,而扩展函数则不行

    五、扩展函数不可以被重写

    在Kotlin和Java中我们都知道类的成员函数是可以被重写的,子类是可以重写父类的成员函数,但是子类是不可以重写父类的扩展函数。

    open class Animal {
        open fun shout() = println("animal is shout")//定义成员函数
    }
    
    class Cat: Animal() {
        override fun shout() {
            println("Cat is shout")//子类重写父类成员函数
        }
    }
    
    //定义子类和父类扩展函数
    fun Animal.eat() = println("Animal eat something")
    
    fun Cat.eat()= println("Cat eat fish")
    
    //测试
    fun main(args: Array<String>) {
        val animal: Animal = Cat()
        println("成员函数测试: ${animal.shout()}")
        println("扩展函数测试: ${animal.eat()}")
    }
    

    运行结果:

    以上运行结果再次说明了扩展函数并不是类的一部分,它是声明与类外部的,尽管子类和父类拥有了相同的扩展函数,但是实际上扩展函数是静态函数。从编译内部来看,子类和父类拥有了相同的扩展函数,实际上就是定义两个同名的静态扩展函数分别传入父类对象和子类对象,那么调用的方法肯定也是父类中的方法和子类中的方法,所以输出肯定是父类的。

    欢迎关注Kotlin开发者联盟,这里有最新Kotlin技术文章,每周会不定期翻译一篇Kotlin国外技术文章。如果你也喜欢Kotlin,欢迎加入我们~~~

    Kotlin系列文章,欢迎查看:

    Kotlin邂逅设计模式系列:

    数据结构与算法系列:

    翻译系列:

    原创系列:

    Effective Kotlin翻译系列

    实战系列:

    展开全文
  • 元类具有动态改变类的能力,给编程带来了更方便的动态性能力。 新型类相比于传统类,支持更多特性机制,有更多的弹性。 文章目录 元类 类工厂 初始元类 元类属性 元类作用 面向方面元类 小结 新型类 新型类VS...

    在这里插入图片描述

    元类


    既然对象是以类为模板生成的,那么类又是以什么为模板生成的?

    事实上绝大部分情况下都都不是必须使用元类才能完成开发,但是元类动态地生成类的能力能更方便地解决下面情景的难题:

    • 类在设计时不是所有细节都能确定,有些细节需要程序运行时得到的信息才能决定。
    • 类比实例更重要的情况,如用声明性语言在类声明中直接表示了它的程序逻辑,使用元类来影响类的创建过程就相当有用。

    类工厂


    在Python老版本中,可以使用类工厂函数来创建类,返回在函数体内动态创建的类。
    类工厂的方法是通过一个函数来生产不同的类。类工厂可以是类,就像它们可以是函数一样容易。
    例如:

    def class_with_method(func):
        class klass: pass
        setattr(klass, func.__name__, func)
        return klass
    def say_tip(self):
        print('记得一键三连~')
    Tip = class_with_method(say_tip)
    tip = Tip()
    tip.say_tip()
    

    函数class_with_method是一个类工厂函数,通过setattr()方法来设置类的成员函数,并且返回该类,这个类的成员方法可以通过class_with_methodfunc参数来指定。
    在这里插入图片描述

    初始元类


    在Python2.2之后,type特殊类就是这样的类工厂,即所谓的元类,元类是类的类,类是元类的实例,对象是类的实例。
    元类type使用方法:

    def say_tip(self):
        print('记得一键三连~')
    Tip = type('Tip',(),{'say_tip':say_tip})
    tip = Tip()
    tip.say_tip()
    

    在这里插入图片描述
    元类type首先是一个类,所以比类工厂的方法梗灵活多变,可以自由的创建子类来继承扩展元类的能力。例如:

    class ChattyTypr(type):
        def __new__(cls, name, bases, dct):
            print("分配内存空间给类",name)
            return type.__new__(cls, name, bases, dct)
        def __init__(cls, name, bases, dct):
            print("初始化类", name)
            super(ChattyTypr, cls).__init__(name, bases, dct)
    a = ChattyTypr('Test',(),{})
    

    在这里插入图片描述

    其中,__new__分配创建类和__init__方法配置类是类type内置的基本方法,需要注意的是,第一个蚕食是cls(特指类本身)而非self(类的实例)。

    元类实例化一个类时,类将会获得元类所拥有方法,就像类实例化对象时对象获得类所拥有方法一样,但是注意多次实例化和多次继承的区别:
    在这里插入图片描述

    元类属性


    Python中每一个类都是经过元类实例化而来,只不过这个实例化过程在很多情况下都是由Python解释器自动完成的。那么怎么设置元类的属性?
    每个类都有一个属性__metaclass__用来说明该类的元类,该属性一般由解释器自动设置,不过用户也可以更改该属性来更改类的元类。可以在类的内部直接设置__metaclass__属性,也可以设置全局变量,那么该命名空间下定义所有类的元类都将是全局变量__metaclass__所指定的元类。

    class ChattyTypr(type):
        def __new__(cls, name, bases, dct):
            print("分配内存空间给类",name)
            return type.__new__(cls, name, bases, dct)
        def __init__(cls, name, bases, dct):
            print("初始化类", name)
            super(ChattyTypr, cls).__init__(name, bases, dct)
    class example(metaclass=ChattyTypr):
        def __init__(self):
            print('初始化')
    

    在这里插入图片描述
    在这里插入图片描述

    元类作用


    改变全局变量__metaclass就能改变类的元类,而类又是元类的实例化结果,所以元类可以改变类的定义过程。换句话说,只要改变全局变量__metaclass__就能改变类的定义,这就是元类的作用了。

    class example:
        def __init__(self):
            print('类example初始化')
        def say_tip(self):
            print('记得一键三连')
    a = example()
    a.say_tip()
    class change(type):
        def __new__(cls, name, bases, dict):
            def say_tip(self):
                print('记得点赞关注收藏~')
            dict['say_tip']=say_tip
            return type.__new__(cls, name ,bases, dict)
    class example(metaclass=change):
        def __init__(self):
            print('类example初始化')
        def say_tip(self):
            print('记得一键三连')
    a = example()
    a.say_tip()
    

    在这里插入图片描述

    面向方面和元类


    元类的作用能带来什么实用价值吗?
    实际用途确实有的,接近于面向方面编程(Aspect Oriented Programming,AOP)的核心内容,即所谓的“横切关注点”。

    使用面向对象方法构建软件系统,我们可以利用OO的特性很好地解决纵向问题,因为OO的核心概念(如继承等)都是纵向结构的。
    但是软件系统中往往很多模块/类共享某个行为,或者说某个行为存在于软件的各个部分中,看作是横向 存在于软件之中,它所关注的是软件个部分共有的一些行为,而且很多情况下这种行为不属于业务逻辑的一部分。

    一个软件系统的业务逻辑很大一部分代码都是AOP里所说的横切关注点。例如日志处理、安全检测、事务处理、权限检测等占比很大,几乎每个地方都要调用。AOP的思想就是把这些横切关注点代码都抽取出来,不再在各个软件模块中显示使用。

    以日志处理为例,一般习惯在做一些操作前写上开始模块处理的每个步骤都需要由正常日志和异常日志,那么这个软件光是写日志的代码就要成千上万行了,维护起来相当困难。

    如果部分代码不需要手工写到各个业务逻辑处理的地方,而是把这部分代码独立出来,那么在各个业务逻辑处理的地方,会在运行的时候自动调用这些横切关注点功能,这样代码量就少很多,这就是AOP的核心思想。

    要实现AOP所说的自动调用,有的语言使用AspectJ编译器,Python则使用元类。

    小结


    元类具有动态改变类的能力,给编程带来了更方便的动态性和能力。
    实际使用过程中,需要防止过度使用元类来改变类,过于复杂的元类通常会带来代码难以和可读性差的问题,所以一定要在确实需要使用是再使用元类。

    新型类


    Python在2.2版本后,新引入了两种不同的类:新型类和传统类/经典类。Python的对象世界相比也发生了重大变化。

    新型类VS传统类


    老版本的Python中不是所有的元素都是对象,内置的数值类型都不能被继承,而在版本2.2后,任何内建类型也都是继承自object类的类,凡是继承自类object或者object子类的类都是新型类,而不是继承自object或object子类的都成为传统类

    新的对象模型于传统模型相比有小但是很重要的优势,Python版本对传统类的支持主要是为了兼容性,所以使用类的时候推荐从现在开始直接使用新型类。在Python3版本将放弃兼容性,即Python3.X版本中只存在新型类。

    新型类继承自object或object子类,实际上所有的内建类型都是从object继承而来,可以用issubclass()函数验证,当存在子类和父类关系时返回True,否则返回False。
    在这里插入图片描述

    插播反爬信息 )博主CSDN地址:https://wzlodq.blog.csdn.net/

    静态方法和类方法


    新的对象模型提供了两种类的方法:静态方法和类方法。

    静态方法可以直接被类或类的实例调用,没有常规方法的那样限制(绑定、非绑定、默认第一个参数规则等),即静态函数的第一个参数不需要指定为self,也不需要只有对象(类的实例)才能调用。使用关键字@staticmethod定义。

    如下定义静态方法、常规方法(第一个参为self和不带self两种)

    class Test(object):
        @staticmethod
        def static_tip(str):
            print(str)
        def normal_tip(str):
            print(str)
        def normal_tip2(self,str):
            print(str)
    
    • 使用类调用
      直接使用类调用时,不需要传入self表示具体的类的实例,即报错只传了一个参数。
      在这里插入图片描述
    • 使用对象(类的实例)调用
      使用对象调用时,自动将类实例对象作为第一个参数传给该方法,即报错给了两个参数。
      在这里插入图片描述

    类方法不管是使用类来调用还是使用对象(类的实例)来调用,都是将类作为第一个参数传入。使用关键字@classmethod定义。
    在这里插入图片描述

    特定方法


    1. __new__方法
      当一个类C调用C(*args,**kwds)创建一个C类实例时,Python内部实际上调用的是C.__new__(C,*args,**kwds)。new方法的返回值x就是该类的实例对象,new即用来分配内存生成类的实例。
      注意第一个参数是cls(即这里写的类C),用来接受一个类参数,然后才能返回该类的实例。
      在这里插入图片描述
      使用new方法可以实现一些传统类无法做到的功能,例如让类只能实例化一次:
      在这里插入图片描述
    2. __init__方法
      当调用new方法分配内存创建一个类C对象后,Python判断该实例是该类的实例,然后会调用C.__init__(x,*args,**kwds)来初始化这个实例,x就是new方法的返回值,init即对类实例对象做初始化操作。
      注意第一个参数是self(即这里写的x)表示接受类的实例对象。
      在这里插入图片描述
      上述实例化对象代码c = C()就等价于:
      在这里插入图片描述
    3. __getattribute__方法
      __getattribute__负责实现对象属性引用的全部细节。新型类在调用它自身的类或方法是,实际上都是先通过该方法来调用。
      在这里插入图片描述
      因为新型类调用自身属性和方法时都会先调用__getattribute__方法,所以可以实现一些新功能,如隐藏父类的方法:
      在这里插入图片描述

    特定属性


    内建property类用来绑定类实例的方法,并将其返回值绑定为一个类属性,语法:
    attrib = property(fget=None, fset=None, fdel=None, doc=None)

    设类C通过property创建了属性attrib,x是类C的一个实例。

    • 当引用x.attrib时,会调用fget()方法取值;
    • 当为x.attrib赋值时,会调用fset()方法;
    • 当执行删除del x.attrib时,会调用fdel()方法;
    • doc参数为该属性的文档字符串。

    如果不定义fset()fdel()方法,那么该属性将是一个只读属性。

    property可以方便地将一个函数的返回值转换为属性,这下操作就很灵活方便了。
    比如定义一个长方形类,如果要将它的面积也作为一个属性,就可以用property将计算面积的方法绑定为一个属性:

    class Rectangle(object):
        def __init__(self,width,height):
            self.width=width
            self.height=height
        def getArea(self):
            return self.width*self.height
        area = property(getArea(),doc='长方形的面积')
    

    上述代码中,getArea()是计算面积的方法,使用property将该方法的返回值转换为属性area,这样引用Rectangle的area是,Python会自动使用getArea()计算出面积。同时由于该例中只定义了fget()方法,所以area是一个只读属性。

    super()方法


    新型类提供了一个特殊的方法super()super(aclass,obj)返回对象obj是一个特殊的超对象(superobject)。当我们调用该超对象的一个属性或方法时,就保证了每个父类的实现均被调用且仅仅调用了一次。

    以下时直接调用父类的同名方法,无法避免类A的方法被重复调用:

    class A(object):
        def test(self):
            print('A')
    class B(A):
        def test(self):
            print('B')
            A.test(self)
    class C(A):
        def test(self):
            print('C')
            A.test(self)
    class D(B,C):
        def test(self):
            print('D')
            B.test(self)
            C.test(self)
    d = D()
    d.test()
    

    在这里插入图片描述

    以下时使用super()方法,保证父类方法均调用一次:

    class A(object):
        def test(self):
            print('A')
    class B(A):
        def test(self):
            print('B')
            super(B, self).test()
    class C(A):
        def test(self):
            print('C')
            super(C, self).test()
    class D(B,C):
        def test(self):
            print('D')
            super(D, self).test()
    d = D()
    d.test()
    

    在这里插入图片描述

    小结


    新型类相比于传统类,支持更多特性和机制,有更多的弹性。例如可以定制实例化的过程,尤其时在多重继承的情况下能避免传统类存在的缺陷。而事实上Python3.X版本中已经不存在传统类了,目前传统类存在的意义主要是为了保持之前的兼容性。

    Python系列博客持续更新中

    原创不易,请勿转载本不富裕的访问量雪上加霜
    博主首页:https://wzlodq.blog.csdn.net/
    微信公众号:唔仄lo咚锵
    如果文章对你有帮助,记得一键三连❤

    展开全文
  • 为什么要学习这个东西,,,,因为我们项目中要做一个网络拓扑图,去年网上找了找用jtopo做的,然后大家说太丑了,操作也不好,反正言外之意就是要换个插件写,,,,然后我前两周就研究了一下echarts的树图关系图...
  • 以上就是卷积神经网络的最基础的知识了,下面我们一起来看看...再往后是系统的学习一下算法数据结构,因为这些是基础,必须把这些的基础打扎实了。因为本人还在学校所以还有时间系统的梳理这方面的知识,然后在好...
  • Qt文档阅读笔记-Qt Quick Controls - Wearable Demo实例解析

    千次阅读 多人点赞 2020-01-14 08:58:04
    这个实例主要是用qml玩界面。 main.qml文件以及wearable.qml分别是由ApplicationWindowStatckView。这个StackView用于做导航相关的。 代码如下: QQC2.ApplicationWindow { id: window ... header: ...
  • Dojo 1.1.1 提供了上百个包,这些包分别放入三个一级命名空间:Dojo,Dijit DojoX 。其中 Dojo 是核心功能包 , Dijit 中存放的是 Dojo 所有的Widget 组件,而 DojoX 则是一些扩展或试验功能,DojoX 中的试验功能在...
  • 《RabbitMQ开发库的完整API文档》翻译

    万次阅读 2017-12-28 21:28:38
    背景 译文链接 我的译文 概述 Connections and Channels 连接到一个代理 使用 Exchanges and Queues队列 发布消息Publishing messages 通道并发性考虑事项线程安全 通过订阅接收消息Push API ...度量
  • UML - 用例图的组成和实例

    千次阅读 多人点赞 2020-06-10 12:46:04
    一个用例图包含了多个模型元素,如系统、参与者用例,并且显示这些元素之间的各种关系,如泛化、关联依赖。它展示了一个外部用户能够观察到的系统功能模型图。 二、用例图所包含的元素 参与者(Actor) - 用一...
  • 从一个到另一个的文档的数量,内容大小可能有差异。 MongoDB 中单个对象的结构很清淅。 MongoDB 中没有复杂的连接。 MongoDB 提供深度查询的功能,因为它支持对文档的强大的动态查询。 MongoDB 很容易扩展...
  • 最近一直在说阿里云数据库RDS实例,那么看到分为基础版、高可用版、集群版和三节点企业版(原金融版)这几种不同类型。应该是针对不同用户需求开发的。今天来详细说说区别及如何选择。 在哪里查看自己的数据库属于...
  • 实例18 可扩展对话框70 实例19 利用QPalette改变控件颜色73 实例20 窗体的淡入淡出效果79 实例21 不规则窗体84 实例22 电子钟87 实例23 程序启动画面92 第4章 QMainWindow95 实例24 基本QMainWindow主窗口程序96 ...
  • 扩展 LayUI 步骤条组件,示例演示

    万次阅读 热门讨论 2019-04-10 09:37:48
    扩展 LayUI 步骤条组件,示例演示 操作演示: 代码简介: 优点: 使用扩展 LayUI 的方式,把共用模块方法以组件形式添加在 LayUI js 中,我们以熟悉的 layui.use(['jquery', 'steps'], function(){ 这种方式去使用...
  • 这篇博客是自己《数据挖掘与分析》课程讲到正则表达式爬虫的相关内容,主要简单介绍Python正则表达式爬虫,同时讲述常见的正则表达式分析方法,最后通过实例爬取作者的个人博客网站。希望这篇基础文章对您有所帮助,...
  • 单元测试利器-Mockito 中文文档

    万次阅读 多人点赞 2016-08-05 11:36:20
    Mockito 中文文档 ( 2.0.26 beta ) 由于缺乏校对,难免有谬误之处,如果发现任何语句不通顺、翻译错误,都可以在 github中的项目 提出issue。谢谢~ Mockito框架官方地址 mockito , 文档地址 。 ...
  • 超硬核!兔兔阿里p7学长给的面试知识库

    万次阅读 多人点赞 2021-05-26 22:14:07
    整理了一下超硬核系列面经系列文章,值得每个人去收藏
  • 接口测试提测--接口文档规范

    万次阅读 2016-06-28 17:57:40
    接口测试的依据,往往不是需求文档,而是接口文档。 那么,接口文档的准确性便至关重要,本文推荐两种形式的接口文档,供大家参考。 接口文档不管以什么形式存在,需要包含的内容有: 接口名称接口类型输入...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    Java 组播组中发送接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密  Java非...
  • 先贴出 分页器文档的地址:Pagination 分页器 使用步骤: 1.下载或者导入插件到你的项目; 2.在需要使用的页面引入该插件。 使用操作: 1.下载或者导入插件到你的项目; 导入的操作流程示例图: 点击使用...
  • 精通Windows.API-函数、接口、编程实例.pdf

    千次下载 热门讨论 2013-01-27 11:49:55
    仅收录该书籍以供学习讨论 包含pdf书籍及经过验证的示例 执行demo中的示例方式 在编译环境下进入demo目录,执行nmake命令在bin目录下生成可执行文件 注:demo无注释,对应书本中部分示例。 目录 第1章 Windows...
  • ENVI5.3.1使用Landsat 8影像进行辐射定标大气校正实例操作
  • 本文来自作者 gashero 在 GitChat 上分享「Python 的 C 扩展开发惯例」,「... 1.1 Python扩展模块的用途优点 1.2 设计扩展模块的流程 2 setup.py脚本 3 函数接口、参数传递、简单返回值 3.1 函数接口 3.2
  • Spring 3.0 jar 所有开发包及完整文档及源代码及开发实例 此次的发行包中未包含此前版本中的spring.jar,在以后也不会提供该jar,spring也支持用户“按需所取”。这也意味着spring已经全面支持OSGi了。 各发行包的...
  • Safari 浏览器插件(扩展)开发

    千次阅读 2020-06-22 11:14:33
    Safari Extension 旧版文档 适用于 2018 年前, Safari 12版本之前,大部分接口不可再使用 Safari App Extension 新版文档 旧版中关于与浏览器APP 相关的接口,改为通过 Swift 实现,适用于 Safari 12版本及后续版本...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 297,068
精华内容 118,827
关键字:

企业扩展分类标准和实例文档