所以在和PDO进行了大量的斗争之后,我缩小了我问题的根源。当我将属性ATTR_EMULATE_PREPARES设置为false时,我的insert查询将毫无错误地运行,但不会向数据库表中添加条目。
但是,当我通过phpmyadmin或将ATTR_EMULATE_PREPARES设置为true运行查询时,它将成功执行。
这让我有些沮丧,因为没有什么好的理由说明它不起作用。
这是我直接通过phpmyadmin执行的查询。
INSERT INTO account (guid, displayname, password_hash, password_salt, email, superuser) VALUES (UNHEX('fcfd7f2355f211e5acfd2174e316c493'), 'bob', 'test', 'test', 'test', 1);
$db = null;
try
{
$db = new PDO($pdo_connectionstring, $pdo_username, $pdo_password);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
}
catch (PDOException $ex)
{
die('[FATAL ERROR] Could not connect to the Database: '.$ex->getMessage());
}
try
{
$stmt = $db->prepare("INSERT INTO `account` (`guid`, `displayname`, `password_hash`, `password_salt`, `email`, `superuser`) VALUES (UNHEX(:guid), :displayname, :passwordhash, :passwordsalt, :email, :superuser);");
$stmt->bindValue(':guid', $guid, PDO::PARAM_STR);
$stmt->bindValue(':displayname', $displayname, PDO::PARAM_STR);
$stmt->bindValue(':passwordhash', $hash, PDO::PARAM_STR);
$stmt->bindValue(':passwordsalt', $salt, PDO::PARAM_STR);
$stmt->bindValue(':email', $email, PDO::PARAM_STR);
$stmt->bindValue(':superuser', $superuser, PDO::PARAM_BOOL);
$stmt->execute();
}
catch (Exception $ex)
{
$jsonresult['generalerror'] = 'Failed to create user. Please contact your GM: ' . $ex->getMessage();
}
superuser被定义为tinyint(1),尽管它是一种常见的布尔存储数据类型,但在绑定值时需要PDO::PARAM_INT。第二部分是当pdo驱动程序在PDO::ATTR_EMULATE_PREPARES设置为false的情况下运行时,只有当本地pdo驱动程序遇到问题时,如果数据库返回错误消息,它才不会抛出错误或异常。PDOStatement::execute()返回关于查询是否成功的布尔值。如果PDOStatement::errorCode()返回false,则由开发人员手动检查PDOStatement::errorInfo()和execute()。这在事务处理期间特别值得注意,因为如果其中一个语句失败,回滚事务非常重要。pdo的一个恼人的怪癖是,如果您设置了错误的数据类型,即PDO::PARAM_BOOL而不是像我那样PDO::PARAM_INT,那么返回的errorInfo()将几乎是空的,这会让您挠头到底出了什么问题。ATTR_EMULATE_PREPARES设置为false时,使用额外的错误捕获,如果有问题不起作用,请检查并重新检查数据类型。
最佳答案
问题是,当使用emulate_prepares作为false时,查询将失败,并且不会从PDO引发异常。TL;DR:转到:测试设置和说明TL;DR:转到:测试和结果TL;DR:转到:结论
pdo准备查询处理综述mysql驱动程序:
它不理解named placeholders,只使用?来标记bind variables的位置。
如果每个命令成功,则返回有用信息;如果无法完成请求,则返回false。
其结果是,当您拥有PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION时,PDO有责任将其转换为Exception。
通过PDO执行查询时预期发生的情况概述:prepare:使用PDO将查询发送到named placeholders。PDO将其格式化为“?”并发送给mysql驱动程序。mysql驱动程序向它发送实际的mysql服务器,该服务器对它进行处理,并返回解释它如何返回到mysql驱动程序的信息。mysql驱动程序将结果发送回PDO。PDO检查并根据需要将其转换为有用的结果或error codes或exceptions。
可以看到,有比我们想象的更多的地方,让混乱发生。
为了调试正在发生的事情,我想知道mysql server收到了什么,返回了什么。
为此,mysql server提供general logging for queries请参见:5.2.3 The General Query Log。
我提供了一些实用程序来控制打开和关闭general log以便写入log files和写入mysql.general_log表。
测试代码:IMysqlGeneralLogging: Control the MySQL General Logging Facility和class。
调试并解释实际的O/P代码:
我已经提供了PHPUnit测试脚本来运行o/p代码并进行检查。我使用它作为“执行和报告”工具,而不是测试任何东西。
这真的是在解释我的发现并展示它。花了相当长的时间和相当多的“试错”。重点是“错误”。;-)
测试设置和说明
/**
* Test Data for all tests...
*/
protected $guid = '420D4B65565311E5958000FFD7CBE75F';
protected $displayname = 'Example User 42';
protected $hash = '$2y$17$12345678901234567890121234567890123456789012345678942';
protected $salt = '$2y$17$1234567890123456789042$';
protected $email = 'example42@example.com';
protected $superuser = true;
/**
* Expected Results
* Must be static so they are not reset with each test
*/
protected static $rcExpected = array(
'prepare' => true,
'execute' => true,
'exception' => false,
'exceptionMsg' => '',
);
/**
* Actual results stored in here.
*/
protected static $rcActual = array(
'prepare' => false,
'execute' => false,
'exception' => false,
'exceptionMsg' => '',
);
// these change for each test...
$this->userPDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->userPDO->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
try
{
self::$rcActual['exception'] = false;
$stmt = $this->userPDO->prepare(
"INSERT INTO `account`
(`guid`, `displayname`, `password_hash`, `password_salt`, `email`, `superuser`)
VALUES
(UNHEX(:guid), :displayname, :passwordhash, :passwordsalt, :email, :superuser);");
self::$rcActual['prepare'] = $stmt !== false; // record result
$stmt->bindValue(':guid', $this->guid, PDO::PARAM_STR);
$stmt->bindValue(':displayname', $this->displayname, PDO::PARAM_STR);
$stmt->bindValue(':passwordhash', $this->hash, PDO::PARAM_STR);
$stmt->bindValue(':passwordsalt', $this->salt, PDO::PARAM_STR);
$stmt->bindValue(':email', $this->email, PDO::PARAM_STR);
$stmt->bindValue(':superuser', $this->superuser, PDO::PARAM_BOOL);
self::$rcActual['execute'] = $stmt->execute(); // record result
$this->assertTrue(self::$rcActual['execute']);
$this->assertFalse(self::$rcActual['exception']);
}
catch (\Exception $e) {
self::$rcActual['exception'] = true;
self::$rcActual['exeptionMsg'] = $e->getCode() .' : '. $e->getMessage();
$this->assertTrue(self::$rcActual['exception']);
}
mysql general logging到跟踪文件的代码: $testFilename = $this->logging->newTraceFilename('Test_01_EmulatesOn_ExceptionOn'));
$this->logging->setLogFile($testFilename);
$this->logging->startLoggingToFile(); // start logging...
$this->logging->stopLogging();
$this->userPDO->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->userPDO->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
prepare : Expected: true, Actual: true
execute : Expected: true, Actual: true
exception : Expected: false, Actual: false
exceptionMsg : Expected: '', Actual: ''
150914 14:15:30 569 Query INSERT INTO `account`
(`guid`, `displayname`, `password_hash`, `password_salt`, `email`, `superuser`)
VALUES
(UNHEX('420D4B65565311E5958000FFD7CBE75F'), 'Example User 42', '$2y$17$12345678901234567890121234567890123456789012345678942', '$2y$17$1234567890123456789042$', 'example42@example.com', 1)
prepare和execute语句发送到服务器。有趣吗? $stmt->bindValue(':superuser', $this->superuser, PDO::PARAM_BOOL);
prepare : Expected: true, Actual: true
execute : Expected: true, Actual: false
exception : Expected: false, Actual: false
exceptionMsg : Expected: '', Actual: ''
errorCode : '00000', ErrorMsg: array (
0 => '00000',
1 => NULL,
2 => NULL,
)
150915 11:37:12 693 Prepare INSERT INTO `account`
(`guid`, `displayname`, `password_hash`, `password_salt`, `email`, `superuser`)
VALUES
(UNHEX(?), ?, ?, ?, ?, ?)
unexpected!;prepare statement!execute命令。PDO execute语句返回false但未引发exception!errorCode或errorInfo消息。PDO或mysql driver不喜欢“pdo::param_bool”或提供给它的实际值。SQL statement失败的唯一方法是检查单个prepare和execute语句返回的结果!而且,你也不知道为什么会失败!PDO::PARAM_INT $stmt->bindValue(':superuser', $this->superuser, PDO::PARAM_INT);
prepare : Expected: true, Actual: true
execute : Expected: true, Actual: true
exception : Expected: false, Actual: false
exceptionMsg : Expected: '', Actual: ''
errorCode : '00000', ErrorMsg: ''
150915 12:06:07 709 Prepare INSERT INTO `account`
(`guid`, `displayname`, `password_hash`, `password_salt`, `email`, `superuser`)
VALUES
(UNHEX(?), ?, ?, ?, ?, ?)
709 Execute INSERT INTO `account`
(`guid`, `displayname`, `password_hash`, `password_salt`, `email`, `superuser`)
VALUES
(UNHEX('420D4B65565311E5958000FFD7CBE75F'), 'Example User 42', '$2y$17$12345678901234567890121234567890123456789012345678942', '$2y$17$1234567890123456789042$', 'example42@example.com', 1)
prepare和execute语句。PDO execute语句返回trueerrorCode或errorInfo消息。binding paramater被改变了。PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTIONPDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTIONfalse语句返回PDO execute。PDO prepare返回的值和从PDO execute返回的值是否为false。
关于php - 如果ATTR_EMULATE_PREPARES为false,则Prepared Insert不会执行任何操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32451215/
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article
我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更