MySQL数据库的索引、外键与面向对象编程应用
1. 索引的使用
在数据库操作中,一个两列索引也可当作单列索引使用,以第一列作为索引依据。例如,在一个
joke_category
表中,若有
jokeid
和其他列构成的两列索引,当执行以下查询时,会利用该索引列出笑话ID为1所属的类别:
SELECT * FROM joke_category WHERE jokeid = 1
2. 外键的概念与约束
-
外键的定义
:在数据库设计里,一个表中的某列值与另一个表中的列值相匹配,这列就被称为外键。比如,
joke表中的authorId列指向author表中的id列,用来记录每个笑话的作者,此时authorId就是一个引用author表id列的外键。 -
外键约束的引入
:之前设计表时虽考虑了外键关系,但MySQL并未强制这些关系。例如,若不小心插入一个在
author表中无对应记录的authorId值,MySQL不会阻止。不过,MySQL支持外键约束功能,可明确记录表间关系并强制实施。- 在创建表时添加外键约束 :
CREATE TABLE joke (
id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
joketext TEXT,
jokedate DATE NOT NULL,
authorId INT,
FOREIGN KEY (authorId) REFERENCES author (id)
) DEFAULT CHARACTER SET utf8 ENGINE=InnoDB
- **对现有表添加外键约束**:
ALTER TABLE joke
ADD FOREIGN KEY (authorId) REFERENCES author (id)
-
使用MySQL Workbench创建外键约束的步骤
:
-
确保外键列(如
authorId)有索引。若使用上述两个查询语句,MySQL会自动创建索引,但在MySQL Workbench中需手动操作。 -
在
joke表的Foreign Keys选项卡中,双击Foreign Key Name列的第一行,会自动生成一个名称,此名称仅供参考。 -
将该外键命名为
fk_joke_author,以表明是在joke和author表间创建外键。 -
选择
author表作为引用表,authorId列作为列,id列作为引用列。
-
确保外键列(如
添加外键约束后,MySQL会拒绝向
joke
表插入无对应
author
表记录的
authorId
值,并且在删除
author
表中的记录前,需先删除指向该记录的
joke
记录。
3. 引用操作
-
引用操作的方式
:除了拒绝删除或更新有外键指向的记录,还可进行引用操作。可通过配置MySQL的外键约束自动解决冲突,方式有两种:一是级联操作,即删除作者时同时删除其相关的笑话;二是将受影响的外键列值设为
NULL,如将作者笑话的authorId设为NULL,这对应MySQL Workbench中外键约束的ON RESTRICT和ON UPDATE选项。 - 不建议使用引用操作的原因 :使用此功能虽方便,但会将网站逻辑分散在PHP代码和外键约束两处。例如,删除笑话时,无法仅通过查看PHP控制器了解所有操作。因此,多数有经验的PHP开发者倾向避免使用外键约束中的引用操作,甚至有人完全避免使用外键约束。
4. 数据库关系与面向对象编程
- SQL JOIN的局限性 :在构建互联网笑话数据库网站时,常需从多个表获取数据,SQL JOIN是一种解决方案,虽有性能优势,但与面向对象编程不兼容。数据库的关系型方法与面向对象编程的嵌套结构通常不匹配。在面向对象编程中,对象以层次结构存储,如作者对象封装其笑话列表,类别对象封装类别内的笑话列表。
- SQL查询示例 :若要获取作者及其所有笑话的信息,SQL查询如下:
SELECT author.name, joke.id, joke.joketext
FROM author
INNER JOIN joke ON joke.authorId = author.id
WHERE authorId = 123
- 面向对象编程的实现方式 :使用面向对象方法获取笑话列表,代码如下:
// Find the author with the id `123`
$author = $authors->findById(123);
// Get all the jokes by this author
$jokes = $author->getJokes();
// Print the text of the first joke by that author.
echo $jokes[0]->joketext;
此代码无需SQL,数据从数据库获取但在后台完成。
-
关系型与面向对象处理方式对比
:
-
关系型处理方式
:获取作者及其笑话信息需执行两个独立的
SELECT
查询:
// Find the author with the ID 123
$author = $this->authors->findById(123);
// Now find all the jokes posted by the author with that ID
$jokesByAuthor = $this->jokes->find('authorId', $authorId);
插入笑话时,代码如下:
public function saveEdit() {
$author = $this->authentication->getUser();
$joke = $_POST['joke'];
$joke['jokedate'] = new \DateTime();
$joke['authorId'] = $author['id'];
$this->jokesTable->save($joke);
header('location: /joke/list');
}
编写此代码的人需了解数据库的底层结构和表间的关系存储方式。
-
面向对象处理方式
:
public function saveEdit() {
$author = $this->authentication->getUser();
$joke = $_POST['joke'];
$joke['jokedate'] = new \DateTime();
$author->addJoke($joke);
header('location: /joke/list');
}
这种方式隐藏了底层实现,编写代码的人无需了解数据库中关系的建模方式,只需知道数据会被存储在作者实例中。
5. 面向对象编程的优势
-
实现隐藏
:面向对象编程采用层次化方法,利用数据结构建模关系,具有实现隐藏的优点。不同人可负责代码的不同部分,如编写
saveEdit方法的开发者无需了解addJoke方法的具体实现,只需知道其能保存数据且后续可检索。 -
分离关注点
:这种方式将逻辑分离,保存笑话的过程和向数据库写入数据的过程是不同的关注点。分离后增加了灵活性,
addJoke方法可在任何地方调用,且其实现方式可更改而不影响调用代码。 -
对测试驱动开发(TDD)的帮助
:这种灵活性对TDD很有用。在TDD中,可编写一个
DatabaseTable类的版本作为测试占位符,而无需使用包含相关测试数据的真实数据库。通过考虑关注点分离,可更轻松地编写自动化测试代码。
6. 对象关系映射器(ORM)
-
ORM的概念
:逐步构建的
DatabaseTable类属于对象关系映射器(ORM)。市面上有很多ORM实现,如Doctrine、Propel和ReadBeanPHP,它们的主要作用是为关系型数据库提供面向对象的接口,弥合关系型数据库的SQL查询和网站其他PHP代码间的差距。 -
从数组到对象的转变
:使用
DatabaseTable类查找作者并打印其名称时,$author变量是一个数组:
$author = $authors->findById(123);
echo $author['name'];
由于数组不能包含函数,无法在
$author
实例上实现
addJoke
方法。若要调用方法,需将
$author
变量设为对象。
-
实体类的创建
:创建一个代表作者的实体类:
namespace Ijdb\Entity;
class Author {
public $id;
public $name;
public $email;
public $password;
}
此类将直接映射到数据库中的记录,通常称为实体类。
-
实体类的公共属性
:通常类变量设为私有,可避免意外破坏类的功能。但在实体类中,应使用公共属性,因为实体类的主要目的是提供数据,若无法读取作者姓名,类就失去了意义。
-
实体类中的方法
:为
Author
类添加
getJokes
和
addJoke
方法:
<?php
namespace Ijdb\Entity;
class Author
{
public $id;
public $name;
public $email;
public $password;
private $jokesTable;
public function __construct(\Ninja\DatabaseTable $jokesTable)
{
$this->jokesTable = $jokesTable;
}
public function getJokes()
{
return $this->jokesTable->find('authorId', $this->id);
}
public function addJoke($joke) {
$joke['authorId'] = $this->id;
$this->jokesTable->save($joke);
}
}
使用示例:
$jokesTable = new \Ninja\DatabaseTable($pdo, 'joke', 'id');
$author = new \Ijdb\Entity\Author($jokesTable);
$author->id = 123;
$jokes = $author->getJokes();
在
Joke
控制器的
saveEdit
方法中使用新类保存笑话:
public function saveEdit() {
$author = $this->authentication->getUser();
$authorObject = new \Ijdb\Entity\Author($this->jokesTable);
$authorObject->id = $author['id'];
$authorObject->name = $author['name'];
$authorObject->email = $author['email'];
$authorObject->password = $author['password'];
$joke = $_POST['joke'];
$joke['jokedate'] = new \DateTime();
$authorObject->addJoke($joke);
header('location: /joke/list');
}
综上所述,在数据库开发中,合理运用索引和外键约束可提高数据操作的准确性和效率,而结合面向对象编程和ORM能让代码更具灵活性和可维护性,同时为测试驱动开发提供便利。
MySQL数据库的索引、外键与面向对象编程应用
7. 实体类方法的详细分析
-
getJokes方法 :该方法用于获取指定作者的所有笑话。它依赖于jokesTable实例来执行查询操作。具体实现如下:
public function getJokes()
{
return $this->jokesTable->find('authorId', $this->id);
}
在这个方法中,
$this->id
代表当前作者的ID,通过调用
jokesTable
的
find
方法,以
authorId
为条件进行查询,返回该作者的所有笑话记录。
-
addJoke
方法
:此方法用于为指定作者添加新的笑话。它会自动设置笑话的
authorId
为当前作者的ID,并将笑话数据保存到数据库中。代码如下:
public function addJoke($joke) {
$joke['authorId'] = $this->id;
$this->jokesTable->save($joke);
}
在调用该方法时,只需传入包含笑话信息的数组
$joke
,方法会自动处理
authorId
的设置和数据保存操作。
8. 面向对象编程在数据库操作中的优势总结
| 优势 | 描述 |
|---|---|
| 实现隐藏 |
开发者无需了解数据存储的底层细节,只需要关注方法的调用和返回结果。例如,在调用
$author->addJoke($joke)
时,不需要知道数据是如何写入数据库的,只需要知道该方法可以完成添加笑话的功能。
|
| 分离关注点 | 将不同的功能逻辑分离,使得代码的维护和扩展更加容易。如保存笑话和写入数据库是两个不同的关注点,通过面向对象编程可以将它们分开处理,提高代码的灵活性。 |
| 便于测试 |
在测试驱动开发中,由于逻辑的分离,可编写简单的测试代码来验证各个功能模块。例如,可以模拟
DatabaseTable
类的行为,对
Author
类的方法进行单元测试。
|
9. 数据库表与实体类的映射关系
数据库表和实体类之间存在着紧密的映射关系,这种映射关系使得我们可以通过操作实体类来间接操作数据库。以下是一个简单的流程图,展示了这种映射关系:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A[数据库表]:::process -->|映射| B[实体类]:::process
B -->|操作| C[数据库操作]:::process
C -->|结果| B
B -->|展示| D[应用程序]:::process
在这个流程中,数据库表的数据通过映射关系存储在实体类中,开发者可以通过操作实体类的方法来执行数据库操作,操作结果又会更新实体类的数据,最终展示在应用程序中。
10. 外键约束对数据库完整性的保障
外键约束在维护数据库的完整性方面起着至关重要的作用。以下是外键约束的主要作用和相关操作的总结:
-
防止无效数据插入
:通过外键约束,MySQL会拒绝插入在引用表中没有对应记录的外键值。例如,在
joke
表中插入
authorId
时,如果该
authorId
在
author
表中不存在,插入操作将被拒绝。
-
级联操作控制
:可以通过配置外键约束的级联操作,如级联删除或级联更新,来确保数据的一致性。例如,当删除一个作者时,可以同时删除该作者的所有笑话记录。
-
数据一致性维护
:外键约束确保了表之间的关系始终保持一致,避免了数据的不一致性问题。例如,在更新
author
表中的
id
时,如果有外键约束,相关的
joke
表中的
authorId
也会相应更新。
11. 索引对查询性能的提升
索引在数据库查询中起着关键作用,它可以显著提高查询的性能。以下是索引的使用场景和优势的总结:
-
快速定位数据
:通过索引,数据库可以快速定位到满足查询条件的记录,减少了全表扫描的时间。例如,在执行
SELECT * FROM joke_category WHERE jokeid = 1
时,使用
jokeid
索引可以快速找到相关记录。
-
提高查询效率
:对于经常进行查询操作的列,添加索引可以大大提高查询的效率。例如,在
joke
表中,经常根据
authorId
进行查询,为
authorId
添加索引可以加快查询速度。
12. 总结与展望
在数据库开发中,合理运用索引、外键约束、面向对象编程和ORM等技术,可以提高数据库的性能、数据的完整性和代码的可维护性。未来,随着数据库技术和软件开发方法的不断发展,我们可以进一步探索这些技术的应用场景和优化方法。例如,可以研究更高效的索引策略、更灵活的外键约束配置和更强大的ORM框架,以适应不断变化的业务需求。同时,在开发过程中,要始终关注代码的可测试性和可维护性,为项目的长期发展奠定坚实的基础。
超级会员免费看
11

被折叠的 条评论
为什么被折叠?



