将双类型数据(地理定位)保存到数据库

时间:2015-06-29 11:22:44

标签: mysql yii geolocation double yii2

我有两个用于存储地理位置数据的字段,在我的MySQL数据库中定义为双精度数据:

`address_geo_latitude` float(10,6) NOT NULL,
`address_geo_longitude` float(10,6) NOT NULL

我正在使用Yii2的double验证器而不是用户传递的值:

public function rules()
{
    return [
        [['address_geo_latitude', 'address_geo_longitude'], 'double', 'min'=>0, 'max'=>360]
    ];
}

(虽然我的测试似乎证明,这个问题与Yii2验证器无关)

在测试期间,我观察到值的奇怪(?)变化,即:

  • 359.90变为359.8999940,000006差异),
  • 359.80变为359.7999880,000012差异),
  • 311.11变为311.1099850,000015差异),
  • 255.55变为255.550003-0,000003差异),
  • 205.205变为205.205002-0,000002差异),
  • 105.105变为105.105003-0,000003差异)。

但:

  • 359.899994仍为359.899994
  • 311.109985仍为311.109985
  • 311仍为311
  • 255仍为255
  • 200仍为200
  • 75.75仍为75.75
  • 11.11仍为11.11

我错过了什么?我看不出这些背后的任何模式或逻辑。

这是因为我对这种数据的MySQL字段声明不正确吗?如果是,那么正确的是什么?几个不同的答案:

建议,如果不使用MySQL的spatial extensions,使用float(10,6)是最好的选择。

我的测试似乎证明,这个问题与Yii2验证器无关,因为在重新读取数据库之前值仍然正确:

print_r(Yii::$app->request->post()); //Correct!
print_r($lab->address_geo_latitude); //Correct!

if ($lab->load(Yii::$app->request->post(), 'Lab') && $lab->save()) {
    print_r($lab->address_geo_latitude); //Correct!

    $lab2 = $this->findModel($lab->id);
    print_r($lab2->address_geo_latitude); //<-- HERE! Incorrect!
}

我的问题与this one相反。我的数字获得,而不是失败,准确!并且仅限于某些数字,并非总是如此。

1 个答案:

答案 0 :(得分:2)

这不是因为Yii,而是因为浮点值如何存储在二进制系统上。

正如您可以阅读MySQL documentation“浮点值问题”:

  

浮点数有时会引起混淆,因为它们是   近似值并未存储为精确值。浮点值为   用SQL语句编写的值可能与值不同   内部代表。

Here you can find the great explanation通过示例解决了这个问题。正如你所看到的那样,数字可以变得更大,更小或者根本没有变化,但你总是要记住这只是一个近似值。

对于凝胶定位数据,您可以使用简单DECIMAL type来确保值在数据库中保持不变,或者使用Spacial Data type优化来存储和查询表示几何空间中定义的对象的数据。