Skip to content

database_zh

基础配置

当你需要使用数据库增删改查功能时,可直接使用CORE_DB(/std/database.c),这个文件提供了一系列的方法链式操作数据库。

c
void test()
{
    /**
     * @brief 初始化数据库连接
     *
     */
    object DB = new(CORE_DB, host, db, user);

    // ...
}

或者使用 setConnection() 方法配置数据库:

c
void test()
{
    object DB = new(CORE_DB);
    mapping db = ([
        "host":"127.0.0.1",
        "database":"mud",
        "user":"root",
    ]);
    DB->setConnection(db);
}

上以配置使用以的是系统默认数据库类型__DEFAULT_DB__,如果要指定数据库类型可以使用以下方式:

c
void test()
{
    // 初始化时指定type
    object DB = new(CORE_DB, host, db, user, type);
    // 通过配置指定type(使用SQLITE3)
    mapping db = ([
        "host":"",
        "database":"/data/mudlite.db",
        "user":"",
        "type":__USE_SQLITE3__
    ]);
    DB->setConnection(db);
}

数据库类型可以使用宏定义:__USE_MYSQL____USE_SQLITE3____USE_POSTGRE____DEFAULT_DB__


查询

从数据表中查询所有行

使用DB对象的table方法指定要查询的数据表并返回一个查询对象,使用get方法获取所有结果,返回值为结果二维数组,示例代码:

c
inherit CORE_DB;

void test()
{
    mixed res;

    // 获取 users 表的所有结果
    res = DB->table("users")->get();
    printf("%O\n", res);
}

从数据表中获取单行或单列

使用first方法可以获取查询结果的第一行,返回值为一维数组结果,如果指定数组做为参数,只查询指定的列,另外你可以使用where方法限制查询条件,核心代码:

c
// 查询用户表中的第一条数据
res = DB->table("users")->first();
// 查询用户表中的第一条数据的name和email
res = DB->table("users")->first("name", "email");
// 查询用户表中用户名为 ivy 的数据
res = DB->table("users")->where("name", "ivy")->first();

如果不需要整行数据,则可以使用value方法从记录中获取单个值。该方法将直接返回该字段的值:

c
// 获得用户 ivy 的 email
email = DB->table("users")->where("name", "ivy")->value("email");
// 获取随机用户的 email
email = DB->table("users")->inRandomOrder()->value("email");

如果是通过 id 字段值获取一行数据,可以使用 find 方法:

c
// 获取 ID 为 1 的用户数据
res = DB->table("users")->find(1);

获取一列的值

如果你想获取单列数据的集合,则可以使用 pluck 方法。在下面的例子中,我们将获取角色表中所有邮箱:

c
// 返回所有用户的邮箱数组
res = DB->table("users")->pluck("email");

聚合

查询构造器还提供了各种聚合方法,比如 countmaxminavg,还有 sum。你可以在构造查询后调用任何方法:

c
// 获取用户总数
users = DB->table("users")->count();
// 获取等级最高的用户
level = DB->table("users")->max("level");

同样,你可以通过条件查询限制聚合查询:

c
// 返回ID为9的用户发贴的访问量之和
res = DB->table("topics")->where("user_id", 9)->sum("view_count");
// 判断用户mudren是否存在
count = DB->table("users")->where("name", "mudren")->count();

Where Clauses

where 语句

在构造 where 查询实例中,你可以使用 where 方法。调用 where 最基本的方式是需要传递三个参数:第一个参数是列名,第二个参数是任意一个数据库系统支持的运算符,第三个是该列要比较的值。如:

c
user = DB->table("users")->where("name", "=", "mudren")->get();

为了方便,如果你只是简单比较列值和给定数值是否相等,可以将数值直接作为 where 方法的第二个参数:

c
user = DB->table("users")->where("name", "mudren")->get();

当然,你也可以使用其他的运算符来编写 where 子句:

c
users = DB->table("users")
                ->where("id", ">=", 100)
                ->get();

users = DB->table("users")
                ->where("id", "<>", 100)
                ->get();

users = DB->table("users")
                ->where("email", "like", "%@mud.ren")
                ->get();

你还可以传递条件数组到 where 函数中实现 AND 查询:

c
// 相当于 WHERE user_id>7 AND category_id=4
res = DB->table("topics")->where(({ ({"user_id", ">", 7}), ({"category_id", 4}) }))->get();

你也可以对 where 函数链式调用,以上查询可以使用以下方式:

c
// 相当于 WHERE user_id>7 AND category_id=4
res = DB->table("topics")->where("user_id", ">", 7)->where("category_id", 4)->get();

orWhere 语句

你可以一起链式调用 where 约束,也可以在查询中添加 or 字句。 orWhere 方法和 where 方法接收的参数一样:

c
// 相当于 WHERE user_id>7 OR category_id=4
res = DB->table("topics")->where("user_id", ">", 7)->orWhere("category_id", 4)->get();

请注意:orWhere方法之前必须至少有一次where调用,否则报错。

附加 Where 语句

除了基础的 whereorWhere,还有以下语句可用:

whereBetween / orWhereBetween / whereNotBetween / orWhereNotBetween

验证字段值是否在给定的两个值之间或之外:

c
users = DB->table("users")
           ->whereBetween("votes", ({1, 100}))
           ->get();

whereNull / orWhereNull / whereNotNull / orWhereNotNull

验证指定的字段是否是 NULL

c
users = DB->table("users")
           ->whereNull("updated_at")
           ->get();

Ordering, Grouping, Limit & Offset

orderBy

orderBy 方法允许你通过给定字段对结果集进行排序。 orderBy 的第一个参数应该是你希望排序的字段,第二个参数控制排序的方向,可以是 ascdesc

c
users = DB->table("users")
                ->orderBy("name", "desc")
                ->get();

如果你需要使用多个字段进行排序,你可以多次引用 orderBy

c
users = DB->table("users")
                ->orderBy("name", "desc")
                ->orderBy("email", "asc")
                ->get();

inRandomOrder

inRandomOrder 方法被用来将结果进行随机排序。例如,你可以使用此方法随机找到一个用户:

c
randomUser = DB->table("users")
                ->inRandomOrder()
                ->first();

limit / offset

要限制结果的返回数量,或跳过指定数量的结果,你可以使用 limitoffset 方法:

c
users = DB->table("users")
                ->offset(10)
                ->limit(5)
                ->get();

插入

查询构造器还提供了 insert 方法用于插入记录到数据库中。 insert 方法接收映射形式的字段名和字段值进行插入操作:

c
DB->table("users")->insert((["name":"test", "email":"test@mud.ren"]));

更新

查询构造器也可以通过 update 方法更新已有的记录。 update 方法和 insert 方法一样,接受包含要更新的字段及值的映射。你可以通过 where 子句对 update 查询进行约束:

c
DB->table("users")->where("id", ">", 120)->limit(5)->update((["level":777]));

删除

查询构造器也可以使用 delete 方法从表中删除记录。 在使用 delete 前,可以添加 where 子句来约束 delete 语法:

c
DB->table("migrations")->where("id",">", 55)->limit(5)->delete();

原生语句

除了使用封装好的方法外,查询构造器还提供了原生SQL语句的使用,通过使用 sql 方法执行,注意对 SELECT 语句可以使用 getfirstpluckvalue方法获取查询结果,而 INSERTUPDATEDELETE 语句使用 exec 执行。

c
// 查询
res = DB->sql("select * from users")->get();
res = DB->sql("select * from users")->pluck("name");
res = DB->sql("select * from users where name='mudren'")->value("email");
// 删除
res = DB->sql("delete from users where id>130 limit 5")->exec();

长连接

需要注意的是,CORE_DB 默认使用的是短连接,所有数据库操作完成后自动释放 db_handle ,如果需要大量或高频次查询,最好改为长连接,并自己在必要时操作释放 db_handle 。

如需长连接,请使用 setAutoClose(0) 方法禁用自动释放,并在执行结束时调用 close(1) 方法释放 db_handle。

c
void test()
{
    // 初始化数据库连接
    object DB = new(CORE_DB, host, db, user);
    // 禁用自动关闭连接
    DB->setAutoClose(0);

    // ...数据库操作

    // 关闭数据库连接
    DB->close(1);
}

调试

您可以使用 dump 方法来输出最近一次查询SQL:

c
printf(DB->dump());

调试输出结果类似以下:

-*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-
db_host = 127.0.0.1
db_db = mud
db_user = root
db_handle = 1
db_error = 0
db_table = topics
db_table_column = ({ /* sizeof() == 2 */
"user_id",
"title"
})
db_sql = SELECT user_id,title FROM topics WHERE user_id > '7' AND category_id='4'
-*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*--*-

如果你只是简单查询,可以通过继承CORE_DB的方式,而不需要用 new() 方法生成数据库连接对象,示例如下:

c
inherit CORE_DB;

void test()
{
    mixed res;

    /**
     * @brief 配置数据库连接
     *
     */
     mapping db = ([
     	"host":"127.0.0.1",
        "database":"mud",
        "user":"root"
     ]);
    DB::setConnection(db);

    // 获取 users 表的所有结果
    res = DB::table("users")->get();
    printf("%O", res);
}