因此,我刚刚发现MySQL中最令人沮丧的错误。
显然,该TIMESTAMP字段及其支持功能不支持比秒更高的精度!
TIMESTAMP
所以我正在使用PHP和Doctrine,我真的需要那些微秒(我正在使用actAs: [Timestampable]属性)。
actAs: [Timestampable]
我发现我可以使用一个BIGINT字段来存储值。但是学说会增加毫秒吗?我认为它只是将NOW()分配给该字段。我还担心通过代码散布的日期操作功能(在SQL中)会中断。
BIGINT
我还看到了有关编译UDF扩展的内容。这是不可接受的,因为我或将来的维护者会升级,烦恼,更改不见了。
有没有人找到合适的解决方法?
我找到了解决方法!它非常干净,不需要更改任何应用程序代码。这适用于Doctrine,也可以应用于其他ORM。
基本上,将时间戳存储为字符串。
如果日期字符串格式正确,则比较和排序有效。当传递日期字符串时,MySQL时间函数将截断微秒部分。如果不需要微秒精度,则可以date_diff。
date_diff
SELECT DATEDIFF('2010-04-04 17:24:42.000000','2010-04-04 17:24:42.999999'); > 0 SELECT microsecond('2010-04-04 17:24:42.021343'); > 21343
我最终写了一个MicroTimestampable实现此目标的类。我只是actAs:MicroTimestampable用MySQL和Doctrine来注释我的字段,等等,时间精度。
MicroTimestampable
actAs:MicroTimestampable
Doctrine_Template_MicroTimestampable
class Doctrine_Template_MicroTimestampable extends Doctrine_Template_Timestampable { /** * Array of Timestampable options * * @var string */ protected $_options = array('created' => array('name' => 'created_at', 'alias' => null, 'type' => 'string(30)', 'format' => 'Y-m-d H:i:s', 'disabled' => false, 'expression' => false, 'options' => array('notnull' => true)), 'updated' => array('name' => 'updated_at', 'alias' => null, 'type' => 'string(30)', 'format' => 'Y-m-d H:i:s', 'disabled' => false, 'expression' => false, 'onInsert' => true, 'options' => array('notnull' => true))); /** * Set table definition for Timestampable behavior * * @return void */ public function setTableDefinition() { if ( ! $this->_options['created']['disabled']) { $name = $this->_options['created']['name']; if ($this->_options['created']['alias']) { $name .= ' as ' . $this->_options['created']['alias']; } $this->hasColumn($name, $this->_options['created']['type'], null, $this->_options['created']['options']); } if ( ! $this->_options['updated']['disabled']) { $name = $this->_options['updated']['name']; if ($this->_options['updated']['alias']) { $name .= ' as ' . $this->_options['updated']['alias']; } $this->hasColumn($name, $this->_options['updated']['type'], null, $this->_options['updated']['options']); } $this->addListener(new Doctrine_Template_Listener_MicroTimestampable($this->_options)); } }
Doctrine_Template_Listener_MicroTimestampable
class Doctrine_Template_Listener_MicroTimestampable extends Doctrine_Template_Listener_Timestampable { protected $_options = array(); /** * __construct * * @param string $options * @return void */ public function __construct(array $options) { $this->_options = $options; } /** * Gets the timestamp in the correct format based on the way the behavior is configured * * @param string $type * @return void */ public function getTimestamp($type, $conn = null) { $options = $this->_options[$type]; if ($options['expression'] !== false && is_string($options['expression'])) { return new Doctrine_Expression($options['expression'], $conn); } else { if ($options['type'] == 'date') { return date($options['format'], time().".".microtime()); } else if ($options['type'] == 'timestamp') { return date($options['format'], time().".".microtime()); } else { return time().".".microtime(); } } } }