目录

没有数据库底层的操作?

在讲解的Entity一文中提到,只要属性的persistent标签设置为True,该属性就会自动保存进数据库中,同时在从数据库创建拥有该属性的Entity实体(通过API-KBEngine.createEntityFromDBID以及类似API)时,该属性会自动从数据库读取并设置。那不需要数据库底层的操作啦?引擎都帮我们做了什么?我们如果想对数据库底层进行操作,又是否可以呢?

一般在做服务器开发时,都会涉及到数据库连接、数据库ORM等专业知识,并且开发时会消耗大量人力和时间成本。

下面我们会围绕这几个问题来进行解释:

  • 如何增加一个会永久保存(即持久化、自动存取数据库)的属性?
  • 引擎都帮我们做了什么?
  • 如果想对数据库底层进行操作,又是否可以呢?

如何增加一个会永久保存(即持久化、自动存取数据库)的属性?

很简单!在def配置中的Properties属性定义块中增加一个属性,并设置Persistent为True。拿之前在讲解Entity概念时的例子,Avatar实体下有一个name属性。如下:

    <root>
        <!--属性定义-->
        <Properties>
            <!--角色的名字-->
            <name>
                <!--unicode作为名字类型-->
                <Type>              UNICODE     </Type>
                <!--长度设置为20-->
                <DatabaseLength>    20          </DatabaseLength>
                <!--cell以及所有client都有该属性,并由cell向所有客户端同步他-->
                <Flags>             ALL_CLIENTS </Flags>
                <Default>                       </Default>
                <!--需要持久化保存-->
                <Persistent>        true        </Persistent>
            </name>
        </Properties>
        ...
        ...
    </root>

这样,我们在Avatar实体中就增加了一个名为name的属性,并且设置为持久化。这个属性就会被自动保存进数据库,并在从数据库创建拥有Avatar实体(通过API-KBEngine.createEntityFromDBID以及类似API)时,该属性会自动从数据库读取并设置。

引擎帮我们做了什么?

大家可能会疑问,这么方便,都不需要操作数据库了?但是我们这些喜欢钻研的开发者肯定想一探究竟,强大的CBE引擎到底帮我们做了什么?

概览:

我们先来看下数据库中自动生成了哪些表:

1

表的介绍在下面会进行阐述,我们先来看下大致分了两种表格:

1:前缀kbe的表是引擎内部机制所需要的表格,如图中kbe_serverlog表是服务器日志记录、kbe_entitylog表是实体相关记录等。
2:前缀tbl的表是根据开发者的实体、组件、自定义数据类型的配置而自动创建的表,如本例中的tbl_Avatar表是实体Avatar的记录表。

大家肯定还会疑问,其他的表看上去有一定的规则,他们都是什么?(这些表是在开发一个mmo demo时自动生成的,这要和该demo的业务有一定关系,这里不再赘述。不过该参考图有一定的教学意义哈。)

我们来看一下表名的取名规则吧:

表名的取名规则:

1:引擎内部机制的表会以关键字kbe为前缀,如图中的kbe_serverlogkbe_entitylog等。
2:前缀为关键字tbl的表是根据开发业务的配置自动创建的表。
3:以下划线_作为分隔符进行划分。
4:第一个名字是Entity实体的名称,如tbl_Avatartbl_Avatar_combattbl_Avatar_skillBox
5:自定义数据类型,由于它需要自己独特的存储结构,所以会新建一个表进行记录。其命名按照所属实体名_所在属性名{_数据结构内的属性名}进行设置,{}内是可选,根据该自定义数据类型配置时的Properties块。(参见自定义数据类型一节)

如我们例子中:tbl_Account_characters_values,Account实体的def配置如下:

<Properties>
      <!--角色的字典-->
      <characters>
          <Type>			AVATAR_INFO_LIST    </Type>
          <Flags>			BASE                </Flags>
          <Default>                           </Default>
          <Persistent>	true                </Persistent>
      </characters>
</Properties>

其中,表名中的characters与属性characters对应,Type=AVATAR_INFO_LIST是一个自定义数据类型,我们再来看下AVATAR_INFO_LIST的申明(在{项目资产库}/scripts/entity_defs/types.xml中):

<!-- AVATAR信息列表 -->
	<AVATAR_INFO_LIST>	FIXED_DICT
		<implementedBy>AVATAR_INFO.avatar_info_list_inst</implementedBy>
		<Properties>
			<values>
				<Type>	ARRAY <of> AVATAR_INFO </of>	</Type>
			</values>
		</Properties>
	</AVATAR_INFO_LIST>

其中,表名中的values与该配置中的values对应。这样大家都了解了吧。

6:组件名紧跟实体名之后,如Avatar拥有一个skillBox组件,则名字为tbl_Avatar_skillBox。(组件的知识请参见组件的概念一节)
7:组件内的持久化属性,紧跟组件名之后。如Avatar的skillBox组件下有持久化属性skills,则名字为tbl_Avatar_skillBox_skills。SkillBox.def配置如下:

<!-- SkillBox.def中 -->
<Properties>
      <skills>
          <Type>      ARRAY <of> SKILLID </of>    </Type>
          <Flags>     CELL_PRIVATE                </Flags>
          <Persistent>true                        </Persistent>
      </skills>
</Properties>

表结构:

还记得我们例子中,我们的Avatar实体有一个name属性吗?先来看下tbl_Avatar的表结构,如图:

1

内置的列:

sm_autoLoad : 该实体是否自动加载。
sm_x_position : 该实体保存的位置,在引擎中position是实体默认拥有的属性。
sm_x_direction : 该实体保存的方向,在引擎中direction是实体默认拥有的属性。

自定义的列:

sm_name : 这就是我们定义的属性name的字段!
其他的列,是demo中的业务所需,这里不再赘述。我们来看下字段设计图:

1

引擎把属性name的配置,都自动匹配到数据库中的不同设计。如:类型UNICODE对应了varchar的数据库字段类型,DatabaseLength对应数据库中的字段长度,Default对应了数据库字段的默认值等。

原来引擎为我们做了这么多!

这样一来,我们的开发可以节省非常多的时间,同时也能节省可观的人力成本。不用关心数据库底层的东西,我们开发者只要关心上层的业务设计就好!

那么问题就来了,对于有特殊需求或者对数据库开发有深厚经验的开发人员,想要运用一些底层的技术去直接操作数据库,可不可以呢?答案是:可以!

如何对数据库底层进行操作

如果开发者还是有需求对数据库底层进行操作,引擎提供了对应的工具和API:KBEngine.executeRawDatabaseCommand,以及可以使用Python第三方库pymysql或pyredis。

引擎内置的API操作数据库底层

这个脚本函数在数据库上执行原始数据库命令,该命令将直接由相关数据库进行解析。 该API提供4个参数,分别为:
command : 交给数据库执行的指令。这个数据库命令将会因为不同数据库配置方案而不同。对于方案为MySQL数据库它是一个SQL查询语句。
callback : 可选参数,带有命令执行结果的回调对象(比如说是一个函数)。这个回调带有4个参数:
        result:结果集合。这个结果集合参数是一个行列表。 每一行是一个包含字段值的字符串列表。命令执行没有返回结果集合(比如说是DELETE命令), 或者 命令执行有错误时这个结果集合为None。
        rows:int,影响的行数。表示命令执行受影响的行数。
        insertid:自増长值,类似于实体的databaseID,当成功的向一张带有自増长类型字段的表中插入数据时,它返回该数据在插入时自増长字段所被赋于的值。
        error:错误信息,当命令执行有错误时,这个参数是一个描述错误的字符串。命令执行没有发生错误时这个参数为None。
threadID : int32,可选参数,指定一个线程来处理本条命令。用户可以通过这个参数控制某一类命令的执行先后顺序(dbmgr是多线程处理的),默认是不指定,如果threadID是实体的ID, 那么将加入到该实体的存档队列中由线程逐条写入。
dbInterfaceName : string,可选参数,指定由某个数据库接口来完成, 默认使用”default”接口。详情参见引擎配置kbengine.xml中dbmgr->dabaseInterfaces定义。

注意:使用该函数修改实体数据可能不生效,因为如果实体已经检出,被修改过的实体数据将仍会被实体存档而导致覆盖。强烈不推荐这个函数用于读取或修改实体数据。

Python第三方库操作数据库底层

这里推荐pymysql、pyredis,具体参考它们的官网资料。

PythonMySQL: https://pypi.python.org/pypi/PyMySQL

PythonRedis: https://pypi.python.org/pypi/redis


Copyright © 2018 Yolo Technologies. Publication: 2.0-025. Built: 2018-12-07.