本文节选自《LPC语言基础教程:从零学习游戏开发》,版权归@mudren,欢迎转载,但必须注明来源(mud.ren)。
LPC 支持数据库操作,相关的外部函数包括:db_close、db_commit、db_connect、db_exec、db_fetch、db_rollback、db_status。另外还有一个 apply 方法:valid_database。
最核心的几个函数介绍如下:
名称
db_connect() - 打开一个数据库连接
语法
mixed db_connect( string host, string db );
mixed db_connect( string host, string db, string user );
mixed db_connect( string host, string db, string user, int type );
描述
创建一个新的数据库连接到 `host` 上的数据库, `db` 是要连接的数据库,如果不指定用户名 `user` 将使用驱动编译时设置的值做登录ID, `type` 用来选择数据库类型,可用值取决于驱动编译时的配置,如果不指定类型将使用编译时设置的默认数据库类型。数据库密码通过主控对象中的 valid_database() 方法设置。连接成功返回一个新的数据库连接句柄(整型),否则返回失败消息(字符串型)。
名称
db_close() - 关闭一个数据库连接
语法
int db_close( int handle );
描述
通过给定句柄关闭数据库连接。
关闭成功返回 1 ,失败返回 0 ,如果指定句柄不存在会报错。
名称
db_status() - 返回数据库连接状态
语法
string db_status( void );
描述
返回一个描述数据库当前连接状态的字符串(包括所有数据库句柄)。
名称
db_exec() - 执行一个 SQL 语句
语法
mixed db_exec( int handle, string sql_query );
描述
通过指定句柄执行 SQL 语句,如果执行成功会返回结果的行数,否则返回错误消息字符串。
名称
db_fetch() - 从数据库查询结果集中获取数据数组
语法
mixed *db_fetch( int handle, int row );
描述
从数据库查询的结果集中返回指定行的数据列数组,如果失败会返回错误消息字符串。
数据库连接安全验证由主控对象中的 apply 方法 valid_database() 负责,具体说明如下:
名称
valid_database - 保护数据库相关外部函数
语法
mixed valid_database( object caller, string func, mixed *info );
描述
每个数据库操作相关外部函数在执行之前都会调用 valid_database() 方法。如果 valid_database() 返回 0 ,数据库外部函数会执行失败,如果返回 1 ,数据库相关外部函数会尝试执行。第一个参数 `caller` 是调用数据库相关外部函数的对象,第二个参数 `func` 是准备执行的数据库外部函数名(如:db_connect() 或者 db_commit()),第三个参数 'info' (如果适用)是一个附加信息数组,目前被用于 efun::db_connect() 和 efun::db_exec(),前一个函数中 `info` 的格式是 ({ string database, string host, string user }) ,后一个函数中 `info` 的格式是 ({ string sql_query }) 。
如果禁止执行数据库外部函数,valid_database() 返回 0 。但对 efun::db_connect() 应该返回连接数据库的密码,或者返回 1 。
我们在 /cmds/test/ 目录下新建示例文件 8.2.1.c 演示数据库,具体代码如下:
int main(object me, string arg)
{
#ifdef __PACKAGE_DB__
#ifndef __USE_SQLITE3__
debug("当前驱动不支持SQLITE3数据库。");
#else
mixed db, err;
if (!arg)
return notify_fail(db_status());
if (arg == "db_connect")
{
db = db_connect("", "/tmp/sqlite.db", "", __USE_SQLITE3__);
if (stringp(db)) /* error */
debug("数据库连接失败:" + db);
else
debug("数据库连接成功:" + db);
}
else
{
err = catch(db = db_close(atoi(arg)));
if (stringp(err)) /* error */
debug("数据库关闭出错:" + err);
else if (db)
debug("数据库关闭成功!");
else
debug("数据库关闭失败!");
}
#endif
#else
debug("当前驱动不支持数据库。");
#endif
return 1;
}
再新建 8.2.2.c,示例代码如下:
int main(object me, string arg)
{
#ifdef __PACKAGE_DB__
#ifndef __USE_SQLITE3__
debug("当前驱动不支持SQLITE3数据库。");
#else
mixed db, rows, *res;
db = db_connect("", "/tmp/sqlite.db", "", __USE_SQLITE3__);
if (stringp(db)) /* error */
debug("数据库连接失败:" + db);
else
{
rows = db_exec(db, "DROP TABLE IF EXISTS demo");
rows = db_exec(db, "create table IF NOT EXISTS demo(name varchar(10), value bigint);");
rows = db_exec(db, "insert into demo values('hello!', 10);");
rows = db_exec(db, "insert into demo values('goodbye', 20);");
rows = db_exec(db, "insert into demo values('largeint', 9223372036854775807);");
rows = db_exec(db, "select * from demo;");
for (int i = 0; i <= rows; i++)
{
res = db_fetch(db, i);
// printf("%O\n", res);
debug(res[0] + " " + res[1]);
}
db_close(db);
}
#endif
#else
debug("当前驱动不支持数据库。");
#endif
return 1;
}
我们输入指令可体验数据库连接和查询操作,这里使用的是SQLite3数据库测试,需要你编译驱动时开启支持。
提示:本项目已经配置了valid_database 方法允许数据库操作,代码如下:
// database
mixed valid_database(object caller, string func, mixed *info)
{
if (func == "connect")
return PASSWD; // mysql数据库密码
else
return 1;
}
如果你是在自己的项目中测试注意配置此方法,因为默认不允许操作数据库,连接数据库会报如下错误:
error("Database security violation attempted\n");
如果你不想自己写原生的SQL增删改查,推荐使用mudcore框架中提供的DB接口,具体使用参考: