当你写你的第一个Web应用程序,机会是你要查询的数据库。当你用PHP编写它,没准它会是这样的:

$mysqli = new mysqli("example.com", "user", "password", "database");$结果= $ mysqli->查询( “SELECT * FROM产品”);行=结果美元- > fetch_assoc ();

不久,你必须开始处理用户输入装置,该装置逃逸:

$mysqli = new mysqli("example.com", "user", "password", "database");$mysqli->查询("SELECT * FROM product WHERE name = ")mysqli_real_escape_string (mysqli, product_name美元));行=结果美元- > fetch_assoc ();

随着应用程序的发展,您开始大量编写类似这样的代码。您可能开始将其封装在DAO中,但是它们除了在这些嵌合代码周围筑起围墙之外几乎没有什么作用。“好吧,”你说。“这很好,因为只有我一个人。我是一个负责任的工程师,我不需要为自己粉饰什么。但很快,这个项目就会大获成功。你已经有了一支队伍,还有一支更大的队伍,现在没有足够大的地毯可以把这堆乱七八糟的东西藏起来。如果您决定需要连接池或任何其他资源管理,那么麻烦就来了。

解决这个问题的一个办法是ORM。但是,有些人更喜欢对数据库交互进行“管理”,而不是“抽象”。相反,你的代码应该看起来更像这样:

$pdo = new pdo ("mysql:host=example.com;dbname=database", "user", "password");$statement = $pdo->准备("SELECT * FROM product WHERE name =:name");声明- > bindParam(“:名称”,product_name美元);声明- > execute ();行=声明- >获取美元(PDO:: FETCH_ASSOC);

确实有点啰嗦,但也更容易阅读,更少出错。这是PDO。这是一个PHP扩展,提供了一个与厂商无关的接口,各种关系数据库。这对一个结构良好的API与一系列不同的数据库执行查询司机

当Wayfair开始采用PDO时,我们的数据库访问是相对管理的。内部库在请求过程中管理连接,但是构建查询涉及到大量的字符串连接。复杂的查询会变得很笨拙。有PDO经验的工程师想知道为什么我们不使用它。然而,为了让新接触PDO的工程师相信它会使他们的工作更轻松,它必须和现有库的摩擦一样小,并且以相同的格式生成输出。

简化PDO的语法是比较容易的部分。从技术上讲,给出的例子是错误处理害羞。PDO构造可以抛出异常。相关函数返回一个布尔值,表明他们是否成功。因此,一个“正确”的PDO例子是这样的:

pdo美元=零;试试{$pdo = new pdo ("mysql:host=example.com;dbname=database", "user", "password");} catch (Exception $e) {// logging,等等,如果你想在你无法获得连接的时候注意到}$statement = false;if ($ PDO) {$statement = $ PDO ->prepare("SELECT * FROM product WHERE name =:name");} $row = null;bindParam(":name", $product_name);if ($statement->execute()) {$row = $statement->fetch(PDO::FETCH_ASSOC);}} //现在,对$row执行一些操作

真棒,我知道,对不对?当然,PDO的API是,就整体而言,“更好”,但没有人会想对付它,如果他们被迫通过这类箍跳。谁又能责备你呢?在Wayfair,我们发生了很多的开发者的人体工程学值。这些都是我们努力解决好推出新的内部工具时的问题。我们降落在一个轻微的扩展,PDO会产生这样的语法:

$statement = PDO::new_statement("PT", "SELECT * FROM product WHERE name =:name");//第一个参数引用所需的主机/数据库$语句->bindParam(":name", $product_name);声明- > execute ();行= $声明- > fetch ();// PDO::FETCH_ASSOC现在是默认的获取样式

我们拉所有的样板到工厂功能。它做了必要的错误处理和报告。如果一切成功,它会返回一个标准问题PDO语句对象。如果有错误,它会返回其作用像是一个失败的声明中的特殊对象,但如果要求将返回空的结果集。我们感觉很舒服,这将去除大部分的摩擦周围使用PDO同时保留底层接口。谁想要更为细化的控制仍可以利用股票API。

更棘手的问题是“使输出相同”。虽然每个驾驶员的PDO看起来都是一样的,但是驾驶员的行为并不一定是一样的。文档并不总是清楚地说明这些差异。我们需要做大量的测试和源代码阅读,以弄清效果。

虽然我的例子使用的是MySQL,但Wayfair是一个MSSQL商店。我们一直在用MSSQL延期。它使用一个C API名为DBLIB交谈的服务器。微软不维护的开源版本。188金博宝备用freetds的是常用的自由实现。其中一个PDO驱动程序也使用DBLIB,但是它以不同的方式返回列数据。PDO DBLIB驱动程序将所有内容都作为字符串返回,而不是将字符串作为字符串返回,或将整数作为整数返回。我们不得不补丁它使用预期的数据类型。为了能够引用字符串为VARCHAR与NVARCHAR,我们还增加了一个区分参数类型。我们还增加了支持设置连接超时(PDO定义PDO :: ATTR_TIMEOUT恒定的,但它与DBLIB司机没有影响)。

我们第一次吸引到PDO的另一个原因是为准备好的语句。由于MSSQL支持它们,这似乎是一个提高性能的机会。然而,在深入研究了驱动程序的内部之后,我们发现DBLIB驱动程序只模拟它们。微软有一个适用于Linux ODBC驱动程序。我们与PDO的ODBC驱动程序一起测试,但发现两者是矛盾的。我们能够得到它与普通工作ODBC扩展,但是(令人惊讶的)发现准备好的语句比常规查询要慢。由于使用预准备语句将需要对编码风格进行重大更改,所以我们决定不调查速度差异。

我们正在进行部署SQL继电器。初步测试已经证明了它减轻网络负荷不增加多少开销。它有一个PDO驱动程序,所以我们可以把它换到我们的堆栈,而无需更改查询是如何制造。