MySQL

注意:BAE的MySQL只能被部署在BAE中的应用访问,无法通过公网或BAE的本地开发环境访问。

MySQL是百度云为开发者提供的分布式的关系型数据库服务,后端采用的是业界最为广泛使用的数据库之一MySQL,并且在前端提供与MySQL完全一致的使用方式,特点如下:

  • 应用迁移的代价几乎为零。
  • 支持百万级别的后端数据库集群,并且多机房自动冗余备份,自动读写分离,开发者不需要关注后端机器及数据库的稳定性、网络问题、机房灾难、单库压力等各种风险,像连接本地MySQL一样使用MySQL服务即可。
  • 提供数据隔离,不同应用的数据会存在于不同的数据库中而不会相互影响。
  • 提供安全性检查,对于恶意攻击性访问可及时发现并拒绝。
  • 提供免费套餐以及多种付费套餐的形式,满足不同开发者的需求。
  • 支持各语言原生的SDK访问数据库。
  • 同时支持公有服务(My SQL 5.5)和私有服务(My SQL 5.1)。

添加MySQL数据库服务

注意:

BAE目前已不支持购买私有MySQL服务,仅支持免费MySQL服务。

  1. 在“应用引擎BAE-部署列表”页面选取目标部署并单击进入后,单击左侧导航栏的“扩展服务”。
  2. 单击“添加扩展服务”,选择MySQL。

  3. 选择合适的套餐并勾选“同意”后,单击“立即购买”进入确认订单页面确认购买。

    注意:套餐标注“免费”的为公有数据库(新用户仅支持1个免费的公有数据库),标注“私有”的为私有数据库。私有服务的密码初始化时为用户的SK (Secret Access Key),创建成功后,密码会随着重置SK而变化。私有数据库与共有数据库的区别如下:

    • 相同点:

      • 支持各语言原生SDK访问数据库,用户只需更改数据库的连接信息即可使用,导入导出和phpmyadmin操作完全相同,应用迁移的代价几乎为零。
      • 数据库自动冗余备份,后端主从切换对用户完全透明。
      • 不同部署的数据存于不同的数据库,从而实现数据完全隔离。
    • 不同点:

      • 私有MySQL支持长连接,维护MySQL连接池,不受30秒断连接的限制。但应用代码里面还是要有重连机制,防止后端服务发生热切换导致连接失败。
      • 私有MySQL的并发连接数最大支持到500,且直接连接服务实例,相较于公有集群,更能满足应用高并发、低延迟的需求。
      • 私有MySQL无服务使用限制,用户独占服务资源。
      • 私有MySQL支持创建视图(create view)操作。目前公有服务暂不支持。
  4. 购买成功后返回“扩展服务列表”页面,MySQL部分显示新添加的MySQL数据库资源。

  5. 单击数据库名称进入“MySQL数据库详情”页面,展示基本信息及运行状态的同时,可对数据库进行如下操作:

    • 数据导入

      预先将导入对象存入BOS后,单击右上角的“导入”按钮,然后选择目标文件进行导入。导入结束后提示最近一次导入的执行结果。

    • 数据导出

      单击右上角的“导出”按钮,选择目标文件格式后进行导出。目前支持sql文件、zip、gzip、bzip2四种类型。

      注意: 导出前请先开通“华北-北京”区域的BOS服务创建BOS Bucket用于存放目标文件。目前数据导出只支持北京区域的Bucket。

    • 删除服务

      单击右上角的“删除服务”按钮后对数据库进行删除,确定后系统会回收相应的服务资源。

代码示例

Node.js连接MySQL

注意:一定要捕获ECONNRESET异常。

  1. 将依赖添加到package.json。

    {
        "dependencies": {
            "mysql": "2.0.0-alpha9"
        }
    }
    
  2. 添加代码连接MySQL服务。

    var mysql = require('mysql');
    //填写数据库连接信息,可查询数据库详情页
    var username = '<User_AK>';//用户AK
    var password = '<User_SK>;//用户SK
    var db_host = 'sqld.duapp.com';
    var db_port = 4050;
    var db_name = '<DB_Name>';
    var option = {
      host: db_host,
      port: db_port,
      user: username,
      password: password,
      database: db_name
    }
    //连接数据库
    function testSql(req, res) {
      var TEST_TABLE = 'baeSql';
      var client = mysql.createConnection(option);
    
      client.connect(function(err){
          if (err) {
            res.end('connect error');
            console.log(err);
            return;
          }
          res.write('connected success\n');
          createTalble(client);
    
      });
      client.on('error',function(err) {
          if (err.errno != 'ECONNRESET') {
            throw err;
          } else {
            //do nothing
          }
      });
    //至此连接已建立,可以对数据库进行操作
      function createTalble(client) {
        client.query(
          'CREATE TABLE '+ TEST_TABLE +
         '(id INT(11) AUTO_INCREMENT, '+
          'title VARCHAR(255), '+
          'text TEXT, '+
          'PRIMARY KEY (id));', function(err, results) {
            if (err && err.number != client.ERROR_TABLE_EXISTS_ERROR) {
              console.log(err);
    
              return;
            }
            res.write("create table success \n");
            insertData(client);
          }
        );
      } 
      function insertData(client) {
        client.query(
          'INSERT INTO '+ TEST_TABLE +
          ' SET title = ?, text = ?',
          ['baidu', 'welcome to BAE'],
          function(err, results) {
            if (err) {
              res.end('insertData error');
              console.log(err);
              return;
            }
            res.write('insert success \n');
            queryData(client);
          }
        );
      }
    
      function queryData (client) {
        client.query(
          'SELECT * FROM '+TEST_TABLE,
          function (err, results, fields) {
            if (err) {
              res.end('query error');
              console.log(err);
              return;
            }
            // res.end('results: ' + JSON.stringify(results) + '\n');
            res.write('query success \n');
            res.end('results length: ' + results.length);
            client.end();
          }
        );
      }
    }
    module.exports = testSql
    

PHP连接MySQL

<?php

/*替换为你自己的数据库名*/
$dbname = 'eiZrxDYAgZRYcJuTRljT';
/*填入数据库连接信息*/
$host = 'sqld.duapp.com';
$port = 4050;
$user = '<User_AK>';//用户AK
$pwd = '<User_SK>';//用户SK
 /*以上信息都可以在数据库详情页查找到*/

/*接着调用mysql_connect()连接服务器*/
/*为了避免因MySQL数据库连接失败而导致程序异常中断,此处通过在mysql_connect()函数前添加@,来抑制错误信息,确保程序继续运行*/
/*有关mysql_connect()函数的详细介绍,可参看http://php.net/manual/zh/function.mysql-connect.php*/
$link = @mysql_connect("{$host}:{$port}",$user,$pwd,true);
if(!$link) {
    die("Connect Server Failed: " . mysql_error());
}
/*连接成功后立即调用mysql_select_db()选中需要连接的数据库*/
if(!mysql_select_db($dbname,$link)) {
    die("Select Database Failed: " . mysql_error($link));
}

/*至此连接已完全建立,就可对当前数据库进行相应的操作了*/
//创建一个数据库表
$sql = "create table if not exists test_mysql(
        id int primary key auto_increment,
        no int, 
        name varchar(1024),
        key idx_no(no))";
$ret = mysql_query($sql, $link);
if ($ret === false) {
    die("Create Table Failed: " . mysql_error($link));
} else {
    echo "Create Table Succeed<br />";
}    


/*显式关闭连接,非必须*/
mysql_close($link);
?>

Python连接MySQL

  • python-web部署类型

    #-*- coding:utf-8 -*-
    
    def test_sql():
       ### 开发者直接在requirements.txt中指定依赖MySQL-python
       import MySQLdb
       dbname = "<DB_Name>" # 数据库名称
       api_key = "<User_AK>" # 用户AK
       secret_key = "<User_SK>" # 用户SK
    
       ### 连接MySQL服务
       mydb = MySQLdb.connect(
          host   = "sqld.duapp.com",
          port   = 4050,
          user   = api_key,
          passwd = secret_key,
          db = dbname)
    
       ### 执行sql命令,创建table test
       cursor = mydb.cursor()
    
       cmd = '''CREATE TABLE IF NOT EXISTS test (
             id int(4) auto_increment,
             name char(20) not null,
             age int(2),
             sex char(8) default 'man',
             primary key (id))'''
    
       cursor.execute(cmd)
    
       mydb.close()
       return 'create table test success!'
    
    def app(environ, start_response):
        status = '200 OK'
        headers = [('Content-type', 'text/html')]
        start_response(status, headers)
        try:
            return test_sql()
        except:
            return 'handle exceptions'
    
    from bae.core.wsgi import WSGIApplication
    application = WSGIApplication(app)
    
  • python-worker部署类型

    注意:python-worker部署类型主要用于长期运行的后台任务,建议的程序执行结构为一个无限循环。因故程序退出时,系统会自动尝试重启三次。

    #-*- coding:utf-8 -*-
    
    import time
    import sys
    
    def test_sql():
       ### 开发者直接在requirements.txt中指定依赖MySQL-python
       import MySQLdb
       dbname = "<DB_Name>" # 数据库名称
       api_key = "<User_AK>" # 用户AK 
       secret_key = "<User_SK>" # 用户SK
    
       ### 连接MySQL服务
       mydb = MySQLdb.connect(
          host   = "sqld.duapp.com",
          port   = 4050,
          user   = api_key,
          passwd = secret_key,
          db = dbname)
    
       ### 执行sql命令,创建table test
       cursor = mydb.cursor()
    
       cmd = '''CREATE TABLE IF NOT EXISTS test (
             id int(4) auto_increment,
             name char(20) not null,
             age int(2),
             sex char(8) default 'man',
             primary key (id))'''
    
       cursor.execute(cmd)
    
       mydb.close()
       sys.stdout.write("create table test success!\n")
       sys.stdout.flush()
    
    while True:
        time.sleep(3)
        try:
            test_sql()
        except Exception, e:
            sys.stdout.write("sql connection error!\n")
            sys.stdout.flush()
    

Java连接MySQL

public class MySQLBasic extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        Connection connection = null;
        Statement stmt = null;
        ResultSet rs = null;
        String sql = null;

        try {
            /*****填写数据库相关信息(请查找数据库详情页)*****/
            String databaseName = " <DB_Name> ";
            String host = "sqld.duapp.com";
            String port = "4050";
            String username = " <User_AK>"; //用户AK
            String password = "<User_SK>"; //用户SK
            String driverName = "com.mysql.jdbc.Driver";
            String dbUrl = "jdbc:mysql://";
            String serverName = host + ":" + port + "/";
            String connName = dbUrl + serverName + databaseName;

            /******接着连接并选择数据库名为databaseName的服务器******/
            Class.forName(driverName);
            connection = DriverManager.getConnection(connName, username,
                    password);
            stmt = connection.createStatement();
            /******至此连接已完全建立,就可对当前数据库进行相应的操作了*****/
            /******接下来就可以使用其它标准mysql函数操作进行数据库操作*****/
            //创建一个数据库表
            sql = "create table if not exists test_mysql(" +
                "id int primary key auto_increment," + "no int, " +
                "name varchar(1024)," + "key idx_no(no))";
            stmt.execute(sql);
        } catch (Exception e) {
            e.printStackTrace(resp.getWriter());
        }
    }
}

使用说明

默认字符集编码

云数据库默认字符集编码是针对于单个数据库的一个默认编码值,包含字符集和校对规则。主要功能如下:

  • 创建新表时,如果没有显示指定编码,将使用该默认编码。
  • 连接建立时,云数据库自动将连接编码设置为默认编码。连接建立后可通过set names命令修改连接编码。

例如,如果将云数据库的默认字符集编码设置为utf8(utf8_chinese_ci),用create table test(id int,name varchar(64)创建一个表,由于没有显示指定表的编码,最后表的字符集将是UTF8,校对规则为utf8_chinese_ci。连接到数据到该数据库后,该连接的字符集编码也是UTF8。

云数据库的每个数据库可以单独设置默认字符集编码并可随时改变。改变默认编码只影响新建表的默认字符集编码和新建立的连接,并不会影响到已经创建的表和已经建立好的连接。

注意:虽然云数据库支持默认字符集编码的设置,仍然建议您在创建表时显示指定表的编码,在连接建立并select_db后,显示用set names命令指定连接的编码,这样您的应用将会有更好的移植性。关于MySQL字符集的相关资源,请参考MySQL字符集支持。

数据库访问说明

  • 请求:为防止恶意攻击,云数据库采用分钟配额来限制数据库的访问,超配额的数据库将被封禁5分钟。
    • 请求数:200000个/分钟
    • CPU时间:400秒/分钟
    • 流入流量:300MB/分钟
    • 流出流量:600MB/分钟
  • 连接数:每个数据库并发连接数将视系统繁忙情况动态调整,范围为10-50。
  • 容量:每个数据库有各自的容量限制,超过配额后数据库将被封禁。请提前作好监控并及时扩容。

注意: BAE的数据库扩展服务只能被部署在BAE中的应用访问,无法通过公网或BAE的本地开发环境访问。

服务使用说明

针对公有和私有数据库的SQL操作说明参见下表。

SQL操作 公有数据库使用说明 私有数据库使用说明
create table 支持 支持
alter table 支持 支持
drop table 支持 支持
lock table 支持 支持
select 支持 支持
insert 支持 支持
replace 支持 支持
update 支持 支持
delete 支持 支持
create index 支持 支持
drop index 支持 支持
delete 支持 支持
start transaction 支持 支持
commit 支持 支持
rollback 支持 支持
triger 不支持 不支持
procedure 不支持 不支持
function 不支持 不支持
views 不支持 不支持
event 不支持 不支持

规格限制仅针对公有数据库,私有数据库没有限制。

规格限制 数值 涉及SQL
单表最大行数 10000000行 insert, replace
单库最大表数 1024个 create table
最大外排序行数 65536行 select, update, delete
最大无索引操作行数或最大limit行数 200000行 select, update, delete
查询最大操作行数 1000000行 select
更新最大操作行数 1000000行 update
删除最大操作行数 1000000行 delete
创建索引最大行数 500000行 create index
修改表最大行数 500000行 alter table

错误码

错误码 错误信息 说明 建议
13000 Server Error 服务器错误 联系云数据库管理员
13001 Protocol Packet Invalid 协议包非法 使用标准库连接云数据库
13002 Ak SK Invalid AK/SK错误 请核对连接数库时使用的参数正确性
13003 No Database Selected 没有选择数据库 请在发送任何Query前选择数据库
13004 Permission Denied 权限不允许 请正确填写AK、SK和数据库名
13005 Connect Number Exceeded 连接数超限 优化应用代码,连接及时释放
13006 Minute Quota Exceeded 分钟配额超限 联系管理员
13007 Access Forbidden 禁止访问 数据库容量超限或过期,扩容或续费
13010 Operation Not Supported 操作不支持 不使用该操作
13011 Table Number Exceeded 表数量超限 清理不需要的表
13012 Table Rows Exceeded 表行数超限 如果有需求,请联系管理员
13013 Filesort Rows Exceeded 外排序行数超限 优化表或sql
13014 Handle Rows Exceeded 操作行数超限 优化表或sql