在使用 socket api 开发的时候,可能经常会遇到一个问题,停止 socket 服务器之后立即重启的时候,会提示端口被占用。

这是因为一般情况下,一个端口释放后得等待一会才能再被使用,而 SO_REUSEADDR 可以让端口释放后立即就可以被再次使用。

这样以来,调试的时候就不用担心停止 server 之后再启动就启动不了了。

  • 给排序字段加索引

需要注意:联合索引里面,一个字段的顺序和逆序是不一样的索引。比如

1
db.coll.createIndex({"a": 1, "b": 1})

1
db.coll.createIndex({"a": 1, "b": -1})

是两个不一样的索引

  • 使用 batchSize 选项批量获取数据

jenssegers mongodb 包默认情况下会获取 101 条记录,然后其他记录在底层通过 iterator_to_array 来获取,如果我们需要获取的数据量比较多,则会需要产生多次获取数据的操作。

所以,如果我们知道需要获取大批量数据的时候,可以指定一个比较大的 batchSize 从而减少网络往返次数。

  • 只获取需要的字段(针对大批量获取数据的情况)

主要目的:减少带宽占用,以及处理过程中可以减少内存占用。

  • 使用覆盖索引

覆盖索引的使用类似 MySQL,因为 MongoDB 的索引也是 B+ 树。如果我们在查询的时候只需要某一两个字段,可以在索引上跟查询条件组合在一起建立一个联合索引。

  • 使用 find 代替 aggregate

当我们尝试设置一个 null 变量的属性的时候,会报这个错:

1
2
$a = null;
$a->b = 1; // Creating default object from empty value

其实除了 null,值为 空字符串 或者 false 的变量,如果想设置其属性的时候也会报这个错:

1
2
$a = ''; // 或者 $a = false;
$a->b = 1; // Creating default object from empty value

这种情况只在通过 __get 获取对象属性的时候才会出现。之前也写过一篇类似的文章,但是那里阐述的报错原因没那么直观,本文指出了 laravel 里面出现这个报错的常见原因。

在 Laravel 中,有时候我们需要修改关联的某一个属性的值。这个时候我们一般会使用 $a->b->c = 1; 这种形式。

这种形式一般情况下是没有问题的,但是如果在关联的值是 null 的时候,也就是没有对应的关联的时候就会报错。

而这个报错往往让人摸不着头脑,事实上原因很简单,只是设置了 null 的属性。

报错信息

1
Indirect modification of overloaded property A::$b has no effect

测试源码(lumen)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

use Illuminate\Database\Eloquent\Model;

require_once __DIR__ . '/bootstrap/app.php';

app()->boot();

/**
* Class A
* @property-read B b
*/
class A extends Model
{
protected $table = 'as';

public function b()
{
return $this->hasOne(B::class);
}
}

class B extends Model
{
protected $table = 'bs';
}

/** @var A $a */
$a = A::query()->first();

dump($a->b); // null
$a->b->id = 2; // Indirect modification of overloaded property A::$b has no effect

解决方法

1、如果我们允许这个值为 null,并且需要在其不为 null 的时候设置其值,则可以用 optional 方法:

1
optional($a->b)->id = 2;

2、如果业务上是不会出现 null 的情况的,直接让它异常就好了,早点发现。

XML 实例文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="ISO-8859-1"?>

<bookstore>

<book>
<title lang="eng">Harry Potter</title>
<price>29.99</price>
</book>

<book>
<title lang="eng">Learning XML</title>
<price>39.95</price>
</book>

</bookstore>

选取节点

XPath 使用路径表达式在 XML 文档中选取节点。节点是通过沿着路径或者 step 来选取的。

下面列出了最有用的路径表达式:

表达式 描述
nodename 选取此节点的所有子节点
/ 从根节点选取
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

实例

在下面的表格中,我们已列出了一些路径表达式以及表达式的结果:

路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠(/),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素
//book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore//book 选取属于 bookstore 元素的后台的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
//@lang 选取名为 lang 的所有属性

谓语(Predicates)

谓语用来查找某个特定的节点或者包含某个指定的值的节点。

谓语被嵌在方括号中。

实例

在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:

路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last() - 1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position() < 3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素
//title[@lang='eng'] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00

选取未知节点

XPath 通配符可用来选取未知的 XML 元素。

通配符 描述
* 匹配任何元素节点
@* 匹配任何属性节点
node() 匹配任何类型的节点

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
//title[@*] 选取所有带有属性的 title 元素。

选取若干路径

通过在路径表达式中使用 "|" 运算符,你可以选取若干个路径。

实例

在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:

路径表达式 结果
//book/title|//book/price 选取 book 元素的所有 title 元素和 price 元素。
//title|//price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title|//price 选取属于 bookstore 元素的 book 元素的所有 title 元素以及文档中所有的 price 元素。
0%