在tp的数据库配置中, convention.php中所有的选项都没有设置,要自己在Home/conf/config.php中自己设置, 注意几个地方,一是数据库的名字是: db_name,不是db_database,二是用户密码,是db_pwd.
在创建数据库的时候, 依次是 create_definition, 和 table_options. 在table_options中, 格式是 key [=] value, 其中的等号是可以省略的, 而且 key是可以用简写的, 比如: default character set 可以简写为 default charset, 或者直接就是charset...
也可以用 参照另外的表来创建, create table foo (like foo2)
在所有的缓冲区中执行某一个ex命令是 : bufdo '....' 表示的是 buf-do buf是表示所有的缓冲区,do是执行命令...
在引入某个外部框架/功能件的 时候, 通常是 先引入css, 后引入js. css的必要属性是rel和href, js的必要属性是charset和src. js都是用javascript的,所以 css和js都不需要写type了.
kindeditor 版本是4.1.11,其示例文档不是根目录下的demo.html而是根据你使用的后台语言放在对应的php/asp/jsp等目录中的demo.php等文件.
KindEditor是用js写的,把textarea标签"隐藏性的"替换(障眼法)为一个可见即可得的富文本编辑框,即: textarea的style中要设置visibility:hidden属性.
然后将富文本编辑器框中的内容通过sync()方法"同步到"textarea中, html页面再用.val()方法获得文本框的值进行提交.
KindEditor这个js对象 是在引入kindeditor.js这个文件后创建的, lang/zh-CN.js文件是提供中文支持, 即一些符号的 中文注释.
==========================
AR操作:
M('table_name')->find(2) find方法就是要根据id来获取记录的
而getByName是AR的根据字段名来获取字段的方法.
tp的一个重要思想就是 连贯操作中支持多种格式的参数, 包括字符串,数组等. 推荐使用的是数组, 但是如果 where条件 是多个 包含变量的字符串的连接, 那么通常使用的是字符串形式的条件连接.
主要是要对tp的方法要熟悉, 比如要更新 tp管理的数据库记录, 如果是要更新多个字段, 那么使用save方法, 但是如果只是更新一个字段, 则使用setField方s法. 这个跟 getFields方法是相应的.
在tp中, 过滤字段使用的是 field方法, field就是字段的意思, "过滤字段"
而filter是用来过滤 内容的
save方法的返回值 是被影响的记录的条数, 如果返回false则表示更新出错, 因此一定要 用恒等 来判断是否更新失败
注意区别 tp的 find 和 select的区别...
如果在create方法之前 调用 field方法, 那么最后调用 add方法写入数据库时, 只有 指定的\过滤后的字段才会写入到数据对象中,其他从 $_POST获得的字段 都不会写入到数据对象$Data中. 也可以使用自定义模型来定义要添加/插入 或 更新的字段, 即 protected $insertFields和 $updateFields属性.
- 在ke中的选项,如果其值是true/false 则该选项名称就是什么 Mode, 如果其值是数字1,2, 3 等 则该选项名称就是什么 Type:比如 filterMode的值 默认是 true, 是要过滤html的, 而 resizeType的值可以是0,1,2(通常设置为1, 默认值是2, 宽度和高度都可以拖动改变). pasteType的值默认是2, 是html粘贴, 1是纯文本粘贴, 0是不许粘贴(zhan tie)
要掌握create方法所做的事情和过程.
由create产生 的数据对象中, 在进行add和save的时候, 是 安全插入的(也就是 用 create产生的数据对象你不用考虑安全问题), 因为: 如果表单中 有 数据表中不存在的字段 或者表单字段值的数据类型和 数据表中字段的数据类型不同的时候, create方法会自动过滤掉 这些非法的数据. 而不会将它们插入/添加到数据表中.
如何动态配置config.php文件中的东西? 即能否在 config.php中使用 php变量?
- 事实上, 即使是在 config.php 配置文件中, 也是可以写,可以执行 php代码的. 而且, 即使在 config.php中, 也可以用 php变量 来配置 "配置变量item" 的值 比如
'author' => $author,
- 但是, 不能在 config.php 中 的return 语句 配置数据库之前, 使用/创建数据库模型对象变量,因为数据库是要 先进行配置文件的执行, 返回后才能有数据库的配置对象, 才能进行表对象的创建. 而不能说执行配置后, 创建表对象后, 再次返回/又进入 config.php文件 来执行.
- 但是, 你可以在 执行 某个config.php 之前, 比如 在 convention.php文件中, 就进行数据库的相关配置, 那么 当进入 Home\Conf\config.php文件时, 就可以在 return语句之前 进行表对象的创建, 进行数据表的查询操作了.
<?php // Home\Conf\config.php 文件
// 在 convention.php中就已经定义了数据库的配置了, 所以, 这里是可以直接进行数据库的查询操作了...
$u = M('user');
$author = $u -> where('score=0')-> getField('name');
echo "the author of this book is : $author"; // 这个是会在 浏览器上 被输出的.
return array(
'URL_ROUTER_ON' => true,
.......
'author' => $author, // 这里也就可以用 之前得到的 php变量 来配置 "配置变量item" 的值
=========================
关于php的类定义 成员属性是否用var?
php的官方文档指出: php的类中定义成员属性, 必须使用限定词, 这个限定词是 “public,protected, private”这三个中的一个, 也可以用var, 事实上var是为了兼顾以前的旧版本而写的, var就是 public的别名。
因此, 你可以看到, 现在的类定义,成员变量都用 public或protected或private来限定了
如果没有 这些限定词, 就会报错
- sprintf是返回字符串, 而类的魔术方法 __toString必须要有返回值, 比如: 用
return sprintf("....");
=========================================
tp中的 禁止访问文件类型: 设置是 :
url_deny_suffix => 'pdf|icon|png|gif|jpg'
url_html_suffix 是tp用来支持 html 伪静态的 , 默认的伪静态后缀是html, 也可以是其他多个伪静态后缀, 设置是:url_html_suffix => 'html|xml|shtml'
等. 如果不设 则表示可以是任意的伪静态后缀.url_case_insensitive 大小写是否敏感 对 形如 UserType这样的 控制器的影响是: 如果 是true, 就要用 下划线 _ 来 分隔, 如果是 false, 则不用分隔, 就直接使用 驼峰法.
** 要特别注意的是, url_case_insensitive 是说的 对于 模块 / 控制器 和 方法 的 第一个 字母 的 大小写的区分 与否的 问题 而不是说 对于 任意 字母都不区分 大小写**tp中的ajax的使用, 在客户端 使用的是 jquery的 ajax 功能, 而不是原生的 ajax, ajax的 返回值 通过 tp的 ajaxReturn方法, **返回值 用 数组拼装 // 字符串拼装 的方式 来生成, 比如 $data_status, info_url等.
tp中的 I方法, 是用于 从 用户输入表单 来 获取 值. 需要考虑的几个问题就是 其 对应的参数, 第一个 是 获取 数据来源, 包括 'get.name/ get. ', 第二个是参数 是 如果没有获取到 , 所给的 默认值, 第三个参数 如同 tp的其他函数 一样, 同样可以/允许 有一个 过滤处理函数.
即:I('post.username', '默认值', '过滤函数 htmlspecialchars' );
关于 空控制器和 空的操作? 参考: https://blog.****.net/yexudengzhidao/article/details/54809101
当一个高手浏览你的网站的时候,你网站的报错信息将给黑客提供攻击你网站的信息。比如对于空操作、空控制器,你会暴露给给黑客你网站后台所用的框架,黑客会根据框架本省的漏洞对你网站进行攻击。因此,我们需要对空控制器、空操作进行处理,不给黑客留下任何蛛丝马迹
定义 空控制器 EmptyController 和里面的空操作方法: function _empty($method, $args)
模块可以是 application下的 任意 创建的目录都可以, 不一定 只是 拘泥于Home目录, 你可以根据需要自己任意的/随意的创建 模块, 只要 模块中的 子目录跟Home目录一样就好了, 包括 Controller/View/Model等目录就行.
控制器或模块, 其实 是 根据你 自己 的 功能的 划分来 决定的, 在 设计思想上 : 是指 实现 某个功能 / 完成 某个事务的 操作的集合既可以单独 的实现 一个 完整 的 空 控制器, 也可以 只是在 已有的控制器中 实现 一个 空操作. 目的都是: 如果 攻击者故意 去 访问某些不存在的 模块/操作时, 会 有一些 错误提示信息, 会 暴露 你 网站 所使用的 后台框架, 攻击者会根据 这些 提示或 该框架的一些 缺陷或 bug进行攻击, 因此, 空控制器和 空操作的目的就是: 为了防止在 访问不存在/不正确的 控制器或操作时, 你可以 隐藏/重定向 一些 固定的 错误提示信息(不暴露你网站的其他信息) 给攻击者.
空控制器:
- 在 目录结构中 创建文件: module_name/Controller/EmptyController.class.php
- 然后 实现它:
<?php
namespace Ano_module/Controller;
use Think/Controller;
/// 当然 要在 空 控制器 中 定义 _empty 方法了: 因为 控制器 都错了, 那么 其中的 操作 /方法 肯定 是 错了, 不存在的, 所以 必须在 EmptyController中写 _empty方法了.
/// 如果不写空控制器中的 _empty方法, tp将 还是认为 你调用的是 错误 控制器 中的 index方法, 从而 报错暴露.
class EmptyController extends Controller {
public function _empty(){
echo 'the address you have typed is not right';
}
}
如果是 在 已有的 控制器中 写 空的操作, 则 只是 在 已有 的类中 添加_empty方法就行了
- 事实上, 也可以在 每个类中 定义 __call 魔术方法, 然后 让 所有 空的 / 不存在的 操作, 都 重定向到 一个 统一的 错误处理方法, 而在 tp的 框架 Controller 类 中, 也是使用的 __call方法 只是在 __call方法中 定义 了 / 判断了是否存在 _empty, 如果有 _empty方法, 就 调用 _empty方法了.
如果没有定义 空控制器和 空 操作 , 则调用 传统的 /就是你看到的 /暴露框架 的 那个 方法:E(L(_MOTHOD_NOT_EXITS_));
(if(method_exists($this, '_empty'))...
当然 要注意 在 类中 方法的 访问修饰/限制符, 如果是要在类的 外面 访问的 魔术方法, 比如 __call 等 , 要定义成 public, 而那些类 内部的 重定向方法, 则可以是 protected.
..........
public function __call($method, $args){
// 重定向到 其中的一个固定的 处理函数:
$this -> handle($args); 或$this-> _emty($method, $args);
}
protected function handle($pa){
/////////////// .....
}
- controller类的 方法 : display 和 show的区别: 前者 通常 是用来 显示 一个模板文件, 参数是 文件名; 而后者 通常 是用来 直接显示 某些 内容 , 参数是 要显示的 内容 字符串.
比如:$this -> show('<img src="__PUBIC__/img/"'. $err_not_exits. '" style="...."/ >');
=====================
在tp中, 根据 tp的执行 流程 , 会在 控制器的 index.php 之前, 执行 一些 config.php配置文件, 当然你可以在 配置文件中去进行 一些 常规 操作, 比如操作 数据库, 查询记录等, 但绝不推荐这么做, 这么做是不好的.
tp中的正斜杠和 反斜杠?
一个原则, 凡是 关于 web地址的 , 不管是网址, 还是 网址的字符串, 由于是从 unix开始的, 所以 都 要用 正斜杠/来分隔; 而对于本地资源文件, 如果是 unix系统, 则用正斜杠, 如果是 wind系统(由于从dos而来, 在dos中正斜杠用来表示命令的参数, 所以win中 文件路径是用 反斜杠开始的. 后来由于dos被 少用, 所以正斜杠和反斜杠都是可以的).
一个 特例记住: 在类的定义中, namespace 和 use 中 , 要用 反斜杠.为了将 tp中的 系统函数库和 用户的自定义函数库区分开, 前者 用 functions.php文件名, 后者要用 function.php
tp中的 E函数 和 errror方法 的区别?
E函数 是全局函数, 仅仅只是 一个 抛出 异常的函数, 用的还是php的 异常处理机制, 即: function E($msg, $code=0) { throw new Think\Exception($msg, $code); }
而error 是 controller的一个方法, 跟 success方法相对应, 用于跳转的, 所以 跟 E函数 最大的区别是 它 是要 有跳转的 目的 url地址的. $this-> error($msg, $url, $wait_second,..);
其中 的 $url_jump地址是 可以你自己 指定的 , wait等待时间 也可以 自己设置, 通常 用于 在 中间 进行 临时的 提醒/提示 页面, 然后 再跳转到 最终页面.
- 异常 和 错误?
php中的异常根 java中的类似, 从类 的结构上来看:Object -> Throwable -> Exception -> RuntimeException | Error
异常 和 错误 都是 程序 运行 不正常的表现, 而 错误 要比 异常 更 严重: 错误可以看作是 更严重的异常, 是 unchecked exception.
异常 有两种, 一种是 checked exception, 另一种 是 unchecked exception 即 错误.
checked exception被检测的异常就是, 在 try .... catch结构 中 被 检查和 被捕获的 异常. ..
===========================================
form表单中的 按钮?
- 按钮可以有 两种方式,
- 一种是 用 input 标签, 有 button, reset, submit三种类型的
<input type="submit/reset/button" value="...">
类型 为 submit的可以提交, reset的可以重置, 而button的则不会提交; - 另一种是用 button 标签, 而button标签是 一个 容器标签, 中间是可以放置任意 html内容的 :
<button> button的显示内容 </button>
button的类型也是三种: button, reset, submit , 如果不写 type, 则默认的就是 submit 类型, 所以 不写type的 form button标签是 可以提交表单的.
如果是button的话,由于 不能 自动 提交, 所以 通常 采用 的 是 写 button按钮的 onclick 事件 来提交.
如果 不想表单 马上被提交, 要 在 提交之前 做一些 检查工作 就在 form标签中 写 onsubmit事件属性: <form onsubmit =" return false; " > ...
=======================================
mysql对数据表的结构的修改, 基本上都是直观的语义上的描述, 比如: 字段的操作:
alter table tbl_name add/drop/modify/change [column] old_column_name new_col_name 字段类型描述.
其中, modify只是 修改字段 的类型, 而 change可以对字段 进行 改名 和 类型修改.
注意的是 凡是对表的 结构进行 修改/处理的 , 在 字段名 后面 都要 重新 跟上 字段描述: column_definition 即使该字段的 描述 没有变.alter table tbl_oldname rename to tbl_newname
关于 mysql 的引擎 , 要明确的几点:
- 最开始和最古老的 引擎是myisam. 后来的引擎是 InnoDB , 前者的优点是: 查询速度很快, 快速查询和索引; 后者的 insert 和update速度更快, 支持事务, 支持 行级锁等. 要注意, myisam不支持 外键 foreign key.
- 关于版权, myisam可以随便使用, InnoDB在 "mysql classic edition"中不免费, 在"mysql community edition"中可以免费使用.
- 在数据库中的 多个表, 可以 规定/选择 不同类型的 存储引擎, 比如:可以让一个表用 myisam引擎, 另一个表用 InnoDB 引擎, 要根据具体的情况来决定. 在
creat table table_name () engine=myisam或 InnoDB ...
- 从 mysql 5.5版本开始, 5.5之前默认 的 引擎是mysql, 之后就是 InnoDB.
参考: https://www.cnblogs.com/kevingrace/p/5685355.html
.... 通过上述的分析,基本上可以考虑使用InnoDB来替代MyISAM引擎了,原因是InnoDB自身很多良好的特点,比如事务支持、存储 过程、视图、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多。另外, <font color="red"> 任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。如果不是很复杂的Web应用,非关键应用,还是可以继续考虑MyISAM的,这个具体情况可以自己斟酌。</font>
MyISAM和InnoDB两者的应用场景:
1) MyISAM管理非事务表。它提供高速存储和检索,以及 **全文搜索能力** 。如果应用中需要执行大量的SELECT查询,那么MyISAM是更好的选择。
2) InnoDB用于事务处理应用程序,具有众多特性,包括ACID事务支持。如果应用中需要执行大量的INSERT或UPDATE操作,则应该使用InnoDB,这样可以提高多用户并发操作的性能。
但是实际场景中,针对具体问题需要具体分析,一般而言可以遵循以下几个问题:
- 数据库是否有外键?
- 是否需要事务支持?
- 是否需要全文索引?
- 数据库经常使用什么样的查询模式? <font color="red"> 在写多读少的应用中还是Innodb插入性能更稳定,在并发情况下也能基本,如果是对读取速度要求比较快的应用还是选MyISAM。 </font>
- 数据库的数据有多大? 大尺寸倾向于innodb,因为事务日志,故障恢复。
在 定义字符集的时候, 最好是写成 : utf8, 不要加中间的 那个 横线. 因为有些时候, 软件 是不 认 横线的, 不解析 横线后面的字符, 于是 将 utf-8 解析成为 utf 字符集, 而实际上没有 utf 这样的字符集, 而报错.
虽然mysql引擎最后 会将 所有的 各种各样的 写法 转换成一种 标准的 格式, 比如 所有的 对表的 描述 都 转化成 大写, 并且加上 等号. 实际上, 为了效率,可以就用 最简洁的书写
===========================================================
要查看 表 或者 当前数据库 使用的 是 哪些 存储引擎?
- 查看表的 存储引擎, 用
show create table foo;
会显示 表的 engine... - 要查看数据库的存储引擎 , 用
show variables like '%storage_engine%';
就会显示:
MariaDB [test]> show variables like '%storage_engine%';
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB | //// 这里显示的 是 默认的 存储引擎就是 InnoDB 了.
| storage_engine | InnoDB | /// 当前的也是 InnoDB
+------------------------+--------+
2 rows in set (0.00 sec)
===================================
mysql中数据的唯一性
默认情况下, mysql允许有重复的数据存在
要消除重复的数据, 一是使用 primary key主键, 二是使用 unique 唯一性索引 来保证数据的唯一性。
- 语句
insert ignore into
插入数据时, 在设置了记录的唯一性后, 如果插入重复数据, 将不返回错误, 只以警告形式 返回; 而replace into
则如果存在primary 或unique, 相同的记录, 会先删除掉, 再插入新记录。
- 什么叫存储引擎? 就是 将数据存储到磁盘的 接口api的集合 mysql有 语句分析层和 存储引擎层,语句分析层是上层, 存储引擎是底层, 当分析出sql语句需要执行什么操作后, 调用存储引擎的接口即可。
理解软件分层设计和实现的思想和原理: 将一个任务、一件事情, 不是以“扁平型”的方式实现, 而是借鉴人类组织的方式, 以分层、金字塔的方式来实现, 分成多层, 每一层 实现自己规定的事情(通过函数、类等方式), 然后下一层 提供api接口给上一层使用, 上一层直接调用下一层的接口, 调用下一层实现的功能。
越是接近硬件的, 越接近io设备的, 就越是 底层, 反之, 越是接近用户的,越是接近图形界面的, 就越是上层
以后 我自己理解了这样的软件分层思想后,就采用分层的方法来写软件,或者自己写 软件的某些层的实现和功能了。
mysql的索引类型 有 unique , fulltext, spatial, 和 index/key 索引。
unique 唯一性索引, 可以在定义表结构的时候,直接加在 字段的后面, 做字段修饰或字段definition。 比如:create table user (id int(10) unsigned auto_increment primary key, name char(20) unique, age tinyint not null default 18) engine myisam default charset utf8;
duplicate: 既是动词“重复、复制”, 又是形容词“重复的,完全一样的” duplicate entry就是 插入记录时,在 unique key字段 有重复的记录;
- 如果直接是 insert into则插入的多个值 , 所有的插入都不成功, 并返回错误,如果是
insert ignore into table_name values (1,1) , (2,2) , (3,3)
等, 将会忽略重复的插入条目, 而其他条目仍然会插入成功。 - replace into ... 将会把具有重复值的条目删除, 然后再插入新的 entry 。 操作的结果是:
Query ok, 2 rows affected...
因为首先要删除一行duplicate column字段条目, 然后再插入一行新的, 所以 被affected的rows 是 2.
要查看解释 select 操作是怎么执行的, 中间牵涉到哪些特性, 使用的关键字是 explain, 但是这个只是针对 select 操作, 即:
explain select .............
关于 field连贯操作: 它是用来过滤字段的, 可以用在任意操作上, 对于 select操作, 是 过滤要选择的字段, 对于 save和 add方法, 就是 要增加和 更新的字段.
$user-> field('name, score') -> select()/ add()/ save()
注意: 连贯操作是 不分 先后顺序的! data(array(....)); data方法是准备和生成操作数据的.group方法也是 连贯操作方法之一, 通常用于结合统计函数的. 而having 是 配合group 方法 完成从分组的结果中筛选的数据.
- group是 原生sql语句的 group by的 简写.
- group 和having , 包括所有的连贯操作 都必须放在 select语句之前 , **因为 select 是 获得查询结果, 从语义上来说, 他是 最后操作 / 最后结果了. 从语法上来说, select 返回的是 一个 二维数组, 而其他 所有的连贯操作 , 都要求是用 一个 (数据库) 对象$this 来调用的, 所以, 会出现 报错: ... called by a non-object. **
- group 的参数只能是一个 字符串, 可以使用 多个 字段 来 进行分组:
group('name'), 或 group('name, workgroup')
; - having 是对 分组后的 数据进行筛选, **可以把分组后的结果 看作是一个 表/ 新表, 那么 这个表中 就只是 包含 分组字段和 聚合 函数 值了, 而having 就是 从 这个新表中 进行 筛选结果的. 所以 , having的参数 只有 一个字符串, 就是用 分组后的 聚合值进行判断 ** , 比如:
having (' avg(age)>20');
- 在 所有的 连贯操作中, field 连贯方法 通常是 放在 第一个位置的. field也可以用 数组 进行 as的 表示, 要注意, 在 where和 having等 条件语句中, 凡是 字符串/字段的值, 都应该 加上 引号, 否则, mysql 会当作是 一个字段名称 来分析的, 而事实上, 表中 并没有这样的字段 名 所以 会报错!
=====================================
关于mysql中的 not null 参考: https://www.cnblogs.com/balfish/p/7905100.html
- null 容易出错, 而且 在 索引字段时 更复杂, 更增加一个字节的存储空间, 所以, **通常, 在mysql中 推荐不要使用 null ** 而且 显式的 定义 not null 并不会造成性能上的 损失.
- 任何数值和null 运算 得到的结果都是null, 任何东西和 null 相连接 concat 得到的都是 null
- 对 null值的字段 , 在进行 统计运算count, 平均值 avg 运算时, 将不纳入统计和计算 之列. 就好象这样的 记录entry 不存在一样. 所以 你会看到在计算avg平均值的时候, avg=null的列数并没有被记入那么多的 平均数除以/除数.
终于明白: tp中的 查询 返回的 结果集的类型了: 要 返回 二维数组,返回 多条 记录记 , 则使用的是 select, 而使用 find , 则是 返回的 一个 一维数组, 是一条记录 (即使有多条记录也只是返回第一条, 注意这个方法没有 参数 , 不能带参数, 可以带参数 true或 记录id的 是 getField方法的.); 如果只是要 返回一个字段 , 则 使用 getField方法, 从 名称来说 也可以看出 getFiled的 作用.
select方法也可以 带参数 ,用于 返回 有id主键的 记录: $user -> select(1); $u-> select('1,3, 5');
- limit 在 tp中 的 几种用法: 用在 查询中的限制返回记录条数: limit (1, 10); 用于 在add和 save等更新操作中; 在 分页显示中 , 用来 限定每次要显示的 记录数.
关于数据库的冗余?
通常情况下, 有冗余要拆分, 只需要记住一点可以有冗余的地方: 对于需要 频繁读取的数据,如果进行了 去冗余,放在两个表中, 那么在查询的时候, 需要进行关联查询,由于单表查询的效率要比关联查询的要高, 所以为了效率, 对于需要频繁读取的数据, 可以、允许适当冗余地放在两张表中
- 关于主键和外键?
先要分析表和表之间的 记录对应关系, 是 "一对多还是多对多"?
对于 一对多, 可以拆分为 "主键和 外键"
对于 多对多, 主键和 外键 也不能解决, 要 重新创建一个中间表, 这个中间表 包含两个表的 主键, 比如 "学生 选课表" 就包含学生的 id, 和 课程的 id. (因为 学生 和 课程之 间 是 多对多 之间的 对应关系).
= = 如何区分 主表和从表, 父子表?
对于同 一个字段来说, 如果它在 一个表A中 是 主键, 那么这个表 就是 主表; 如果它在 另一个表 B/C /D 中 不是主键, 只是 普通字段. 那么 B CD 这些表 就叫 从表, 这个字段就叫 "主表中主键 所对应的" 外键.
- 关于数据库的约束? 可以分成 三种约束
- 是实体完整性约束: "即主键 不能为空" , 很明显, 如果主键为空了, 还怎么去唯一的标识一条记录呢?
- 参照完整性: (是指 从表 对 主表 的参照) 参照: 就是 我的值 要 看你的值而定 . 如果 主键没有的 值, 外键 肯定也不能有. 反过来说 , 外键 字段的 值必须在 主键中 有对应的 值. 比如 学生表中的 专业部id, 是 专业部 这个表 中 专业部id主键 的外键 , 那么 学生表中的 专业部必须是 专业部表 的 id 所具有的 , 否则, 哪里会发生 有一个学生 不属于 任何一个专业部的 情形呢 ??
- 用户自定义完整性约束: 指的是 用户自己设定的的一些约束, 例如字段是否为空, 字段值的取值范围等等.
====================
关于字段的 charset和 collate??
在 数据类型中, 并不是所有的字段类型 都可以设置 : charset 和 collate属性的. 通常只有 "字符/字符串" 一类的数据才能设置, 包括: char, varchar, text(tinytext, text, mediumtext, longtext), enum, set. 其他像数字/日期等类型的 数据 都不能设置 charset和collate的.
constraint 和 check 是 create_definition, 是创建表的 描述, 所以 是 放在整个表的 最后的 , 不是 对 字段的描述, 区别的是 : constraint是在 alter table 修改表的时候进行 add的, 而 check 只能在 创建表的时候, 在 字段的 后面 进行 说明的. 不能 在 alter table 中 运用 check???
为了兼容其他数据库导入过来的sql语句, mysql 可以接受check和 constraint 约束语句, 但是只是分析该字句, 并不执行它, mysql会忽略check, 不执行, 所以为了检查, 应该在字段类型中设置 enum或set数据类型。
而且 很多的数据监测 应该尽量 放在 业务逻辑中进行, 数据的检测 尽量放在 函数 /控制器 逻辑中, 不要 给 数据库 太多 的压力.
- set 和 enum的 区别?
两者的取值 列表 都是 字符串 , 注意 必须是字符串, 不要用数字 来表示, 即使是 数字的 取值列表, 也要用 字符串引起来, 否则会和 实际的 存储值 之间 发生 混淆和误会!!! ; 两者的成员数不一样: set的成员最多只能有 64 个, enum的成员个数可以有 65535个; 两者在 数据库内部 都是用 数字 来存储的, enum的结果值是 按列表顺序 依次是 : 1, 2, 3, 4,..., 而set的数值 由于是按 "位" 来进行 存储和组合的. 所以 他的值只有可能是 2的n次方, 比如: 1, 2, 4, 8, 16, 32....等最大就是 2的 64次方; enum的取值只能是 列表中的 一个, 唯一的一个, 而set可以是 取值列表中 的多个值 (组成的 位 决定的值)...
最后的 结论是, 在 php中 尽量少用 enum, set之类的 , 因为php是 弱类型, 对于 (数字型 的 enum简直就是梦魇), 所以 尽量少用 enum和 set , 尽量用tinyint 来 代替. 比如: 性别就直接用 0, 1 来表示 tinyint.
- 多表 联合查询的时候, 需要指定连接条件on。。。这个连接条件并不是随意写的, 通常是两个表都有的共同字段, 是 主键和对应的外键。
关于 union 和 union all的用法??
要将两个查询结果组合起来 ,(是将记录行进行组合, 不是对字段 进行组合 ,字段组合 是用 join 关键字)。
union 会将重复的记录行 去重, 而 union all 是不会去重 , 保留所有的记录行。
- 需要注意的是, union在 合并 记录行的时候, 两个 查询的结果要求: 1是字段的个数要一样, 2.字段的 数据类型要 相似(相同). 3. 是合并结果的字段 名称 以 第一个查询 的 字段 名称 为准.
==============================
url地址的优化?
为什么要使用剪短的url, 越短越好,要对url地址的优化: 对于用户来说, 便于记忆,对于爬虫来说, 有更高的权重.
- tp中 要进行原生的sql语句 查询 , 需要 用 query方法, 而不是 execute方法. 比如:
此时 采用 空参数 创建 模型对象: $user = M(); 或者 $user = new \Think\Model; $user-> query(select * from think_user );
这里要注意的是, 在既然使用的是 原生 的查询语句和query方法, 那么, 他里面的数据表 就要 用 原来的 真实的 表名称, 即要 带上 表 前缀, think_
tp的数据库 连接: 是惰性的, 并不是 一有 实例化的时候, 就去连接数据库, 而是 有实际的数据操作的时候 才去连接数据库. (但是 在第一次 实例化对象的 时候, 会 自动 连接 数据库获取相关 模型类对应的 数据表的字段信息). 即: 在 有数据操作 + 第一次 实例化的时候 去 连接 数据库.
如果不采用 配置文件 : THINK_PATH\CONF\convention.php中关于数据库的配置 或 APP_PATH\Common\Conf\config.php中的数据库连接配置, 也可以采用 自定义的 字符串定义方法, 这样 更快:数据库类型://用户名:密码@数据库地址:端口/数据库名#字符集
控制器的实例函数 A?
就是 在 函数中 自定义 控制器对象, 在 同一个模块中 创建 其他控制器对象 或 跨模块创建 其他控制器对象: $con = new \Home\Controller\IndexController;
在这种情况下, 就可以用 A函数 来 简洁的创建: $con = A ('Index');
效果是一样的.
PHP中是允许父类调用子类中的方法, 但是 不能 调用 父类中 并不存在的 方法: non-static method should not be called statically
method 和 function的区别? method 通常 是 指 "类 " 的 成员方法,
function 是指 全局函数 , 不包含 在 类中的
因此 : 今后, 就要 严格的 区分 方法和 函数的 区别了, 不要把 "方法" ~~~ "函数" 混淆了. 方法是 方法, 函数 是 函数 !!!
一个i类 的 protected方法, 可以在 自己的 内部, 子类的 内部, 以及 父类的 内部 都可以访问, 但是 不能 在 外部 访问.
但是 不能 在 父类的 __construct函数中 去调用 子类的 方法....
关于数据库 的连接?
- 首先是要 登录到 数据库服务器的 机器, 连接上 这个数据库机器: 使用 mysql_connect, 在tp中 配置的什么db_host, db_user, db_password等等, 这里就是 不用配置, 而是直接将这些 东西 作为参数 传递给 msyql, 即:
mysql_connect($dbhost, $user, $passwd);
- 然后是 选择数据库, 因为curd操作 都是 针对 表的, 没有包含数据库, 都是 在已知 数据库的前提下 进行的. 所以 先要选择 数据库, 这个 跟 在 mysql的 控制台下操作 是 一样的, 也是 先要 用
use database_name
先选择数据库, 然后 进行增删改查的 操作. - mysql_query是 查询语句, 返回的是 结果集的 一个 资源 id, 因此,要获得数据, 单独用这个函数 还不行, 还需要 配合 其他 函数 才能实现, 比如: mysql_fetch_row(获取结果集中的 一条记录), mysql_fetch_array, mysql_result是返回 结果集中 的 某一个字段
mysql_reseult($result, $row, $field/或$field_offset字段偏移数字
自己手动书写 的 mysql的 连接配置文件: db.config.php
<?php
$dbhost = '127.0.0.1';
$user = 'root';
$passwd = '';
$conn = @mysql_connect($dbhost, $user, $passwd) or die('connot connect to mysql server') ;
@mysql_select_db('test', $conn) or die('not able to select database');