Doctrine - How to print out the real sql, not just the prepared statement?
我们使用的是条令,一种PHP ORM。我正在创建这样的查询:
1 | $q = Doctrine_Query::create()->select('id')->from('MyTable'); |
然后在函数中,我添加了各种各样的where子句和适当的东西,像这样
1 |
号
稍后,在
1 | $q->getSQLQuery(); |
但是,这只打印出准备好的语句,而不是完整的查询。我想看看它发送给MySQL的是什么,但是它却打印出一个准备好的语句,包括
条令并没有向数据库服务器发送"真正的SQL查询":它实际上使用的是准备好的语句,这意味着:
- 发送报表,以便准备(这是
$query->getSql() 返回的内容) - 然后,发送参数(由
$query->getParameters() 返回) - 执行准备好的陈述
这意味着在PHP方面从来没有"真正的"SQL查询——因此,条令无法显示它。
一个例子……
1 2 | $qb = $this->createQueryBuilder('a'); $query=$qb->getQuery(); |
。
显示sql:EDOCX1[4]
显示参数:
如果将所有查询记录在mysql中,则可以检查应用程序执行的查询:
http://dev.mysql.com/doc/refman/5.1/en/query-log.html
将有更多的查询,不仅是您正在寻找的查询,而且您可以更好地进行查询。
但通常情况下,
编辑:
查看我使用的所有mysql查询
1 |
加上这两行:
号
重启mysql
我已经创建了一个doctrine2记录器,它可以做到这一点。它"水合物"的参数化SQL查询值使用条令2自己的数据类型转换器。
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | <?php namespace Drsm\Doctrine\DBAL\Logging; use Doctrine\DBAL\Logging\SQLLogger, Doctrine\DBAL\Types\Type, Doctrine\DBAL\Platforms\AbstractPlatform; /** * A SQL logger that logs to the standard output and * subtitutes params to get a ready to execute SQL sentence * @author [email protected] */ class EchoWriteSQLWithoutParamsLogger implements SQLLogger { const QUERY_TYPE_SELECT="SELECT"; const QUERY_TYPE_UPDATE="UPDATE"; const QUERY_TYPE_INSERT="INSERT"; const QUERY_TYPE_DELETE="DELETE"; const QUERY_TYPE_CREATE="CREATE"; const QUERY_TYPE_ALTER="ALTER"; private $dbPlatform; private $loggedQueryTypes; public function __construct(AbstractPlatform $dbPlatform, array $loggedQueryTypes=array()){ $this->dbPlatform=$dbPlatform; $this->loggedQueryTypes=$loggedQueryTypes; } /** * {@inheritdoc} */ public function startQuery($sql, array $params = null, array $types = null) { if($this->isLoggable($sql)){ if(!empty($params)){ foreach ($params as $key=>$param) { $type=Type::getType($types[$key]); $value=$type->convertToDatabaseValue($param,$this->dbPlatform); $sql = join(var_export($value, true), explode('?', $sql, 2)); } } echo $sql ." ;".PHP_EOL; } } /** * {@inheritdoc} */ public function stopQuery() { } private function isLoggable($sql){ if (empty($this->loggedQueryTypes)) return true; foreach($this->loggedQueryTypes as $validType){ if (strpos($sql, $validType) === 0) return true; } return false; } } |
。
用法示例:;以下代码的和平将在标准输出上回响使用$em实体管理器生成的任何插入、更新、删除SQL语句,
1 2 3 4 5 6 7 8 9 10 11 12 13 | /**@var \Doctrine\ORM\EntityManager $em */ $em->getConnection() ->getConfiguration() ->setSQLLogger( new EchoWriteSQLWithoutParamsLogger( $em->getConnection()->getDatabasePlatform(), array( EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_UPDATE, EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_INSERT, EchoWriteSQLWithoutParamsLogger::QUERY_TYPE_DELETE ) ) ); |
。
从技术上讲,
1 2 3 | echo $q->getSqlQuery(); foreach ($q->getFlattenedParams() as $index => $param) echo"$index => $param"; |
为了使这个模式更加可重用,有一个很好的方法,可以在来自条令查询对象的原始SQL的注释中描述。
没有其他真正的查询,这就是准备好的语句的工作方式。这些值绑定在数据库服务器中,而不是应用程序层中。
请看我对这个问题的回答:在使用PDO的PHP中,如何检查最终的SQL参数化查询?
(为了方便起见在此重复:)
Using prepared statements with parametrised values is not simply another way to dynamically create a string of SQL. You create a prepared statement at the database, and then send the parameter values alone.
So what is probably sent to the database will be a
PREPARE ... , thenSET ... and finallyEXECUTE .... You won't be able to get some SQL string like
SELECT * FROM ... , even if it would produce equivalent results, because no such query was ever actually sent to the database.
号
我的解决方案:
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /** * Get SQL from query * * @author Yosef Kaminskyi * @param QueryBilderDql $query * @return int */ public function getFullSQL($query) { $sql = $query->getSql(); $paramsList = $this->getListParamsByDql($query->getDql()); $paramsArr =$this->getParamsArray($query->getParameters()); $fullSql=''; for($i=0;$i<strlen($sql);$i++){ if($sql[$i]=='?'){ $nameParam=array_shift($paramsList); if(is_string ($paramsArr[$nameParam])){ $fullSql.= '"'.addslashes($paramsArr[$nameParam]).'"'; } elseif(is_array($paramsArr[$nameParam])){ $sqlArr=''; foreach ($paramsArr[$nameParam] as $var){ if(!empty($sqlArr)) $sqlArr.=','; if(is_string($var)){ $sqlArr.='"'.addslashes($var).'"'; }else $sqlArr.=$var; } $fullSql.=$sqlArr; }elseif(is_object($paramsArr[$nameParam])){ switch(get_class($paramsArr[$nameParam])){ case 'DateTime': $fullSql.="'".$paramsArr[$nameParam]->format('Y-m-d H:i:s')."'"; break; default: $fullSql.= $paramsArr[$nameParam]->getId(); } } else $fullSql.= $paramsArr[$nameParam]; } else { $fullSql.=$sql[$i]; } } return $fullSql; } /** * Get query params list * * @author Yosef Kaminskyi <[email protected]> * @param Doctrine\ORM\Query\Parameter $paramObj * @return int */ protected function getParamsArray($paramObj) { $parameters=array(); foreach ($paramObj as $val){ /* @var $val Doctrine\ORM\Query\Parameter */ $parameters[$val->getName()]=$val->getValue(); } return $parameters; } public function getListParamsByDql($dql) { $parsedDql = preg_split("/:/", $dql); $length = count($parsedDql); $parmeters = array(); for($i=1;$i<$length;$i++){ if(ctype_alpha($parsedDql[$i][0])){ $param = (preg_split("/[' ' )]/", $parsedDql[$i])); $parmeters[] = $param[0]; } } return $parmeters;} |
号
使用示例:
1 2 3 4 5 | $query = $this->_entityRepository->createQueryBuilder('item'); $query->leftJoin('item.receptionUser','users'); $query->where('item.customerid = :customer')->setParameter('customer',$customer) ->andWhere('item.paymentmethod = :paymethod')->setParameter('paymethod',"Bonus"); echo $this->getFullSQL($query->getQuery()); |
号
您可以使用以下方法轻松访问SQL参数。
1 2 3 4 5 6 7 8 9 10 11 12 | $result = $qb->getQuery()->getSQL(); $param_values = ''; $col_names = ''; foreach ($result->getParameters() as $index => $param){ $param_values .= $param->getValue().','; $col_names .= $param->getName().','; } //echo rtrim($param_values,','); //echo rtrim($col_names,','); |
号
因此,如果打印出
注意:如果
同时,如果您找到了另一种方法,请友好地与我们分享:)
谢谢您!
更清晰的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 | /** * Get string query * * @param Doctrine_Query $query * @return string */ public function getDqlWithParams(Doctrine_Query $query){ $vals = $query->getFlattenedParams(); $sql = $query->getDql(); $sql = str_replace('?', '%s', $sql); return vsprintf($sql, $vals); } |
您可以使用:
1 | $query->getSQL(); |
如果您使用的是MySQL,那么可以使用Workbench查看正在运行的SQL语句。您还可以使用以下命令从MySQL中查看正在运行的查询:
1 | SHOW FULL PROCESSLIST \G |
。
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 | Solution:1 ==================================================================================== function showQuery($query) { return sprintf(str_replace('?', '%s', $query->getSql()), $query->getParams()); } // call function echo showQuery($doctrineQuery); Solution:2 ==================================================================================== function showQuery($query) { // define vars $output = NULL; $out_query = $query->getSql(); $out_param = $query->getParams(); // replace params for($i=0; $i<strlen($out_query); $i++) { $output .= ( strpos($out_query[$i], '?') !== FALSE ) ?"'" .str_replace('?', array_shift($out_param), $out_query[$i])."'" : $out_query[$i]; } // output return sprintf("%s", $output); } // call function echo showQuery($doctrineQueryObject); |
。
也许它对某人有用:
1 2 3 4 5 6 7 8 |
1 2 3 4 5 6 7 8 9 | $sql = $query->getSQL(); $parameters = []; foreach ($query->getParameters() as $parameter) { $parameters[] = $parameter->getValue(); } $result = $connection->executeQuery($sql, $parameters) ->fetchAll(); |
号
我编写了一个简单的日志记录器,它可以用插入的参数记录查询。安装:
1 | composer require cmyker/doctrine-sql-logger:dev-master |
号
用途:
1 2 3 4 5 | $connection = $this->getEntityManager()->getConnection(); $logger = new \Cmyker\DoctrineSqlLogger\Logger($connection); $connection->getConfiguration()->setSQLLogger($logger); //some query here echo $logger->lastQuery; |
号
要打印条令中的SQL查询,请使用:
1 | $query->getResult()->getSql(); |
号