【问题标题】:Can't connect to MySQL/MariaDB database from vibed app无法从 vibed 应用程序连接到 MySQL/MariaDB 数据库
【发布时间】:2015-05-18 11:36:06
【问题描述】:

如果我使用自定义 main(void main() 而不是 shared static this()),一切正常。

使用默认 main 我收到“访问冲突”错误。看起来 MySQL 不允许从 localhost 连接到它,但在 my.ini 中我添加了字符串:

bind-address = 127.0.0.1

代码,如果有帮助:

import std.stdio;
import std.path;
import std.file;
import std.string;

import dini;
import vibe.d;
import colorize;
import ddbc.all;

shared static this()
{
    auto settings = new HTTPServerSettings;
    settings.port = 8080;
    settings.bindAddresses = ["::1", "127.0.0.1"];
    listenHTTP(settings, &hello);

    auto parseconfig = new ParseConfig();
    auto db = new DBConnect(parseconfig);
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
    res.writeBody("Hello, World!");
}


class ParseConfig
{
    string dbname;
    string dbuser;
    string dbpass;
    string dbhost;
    string dbport;

this()
    {
        try
        {
            //getcwd do not return correct path if run from task shoulder
            string confpath = buildPath((thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]), "config.ini");
            //writefln(thisExePath[0..((thisExePath.lastIndexOf("\\"))+1)]); // get path without extention +1 is for getting last slash

            //string confpath = buildPath(thisExePath, "config.ini");
            if (!exists(confpath)) 
                {
                    writeln("ERROR: config.ini do not exists");
                }
            auto config = Ini.Parse(confpath);
            try
            {
                this.dbname = config.getKey("dbname");
                this.dbuser = config.getKey("dbuser");
                this.dbpass = config.getKey("dbpass");
                this.dbhost = config.getKey("dbhost");
                this.dbport = config.getKey("dbport");

            }
            catch (Exception msg)
            {
                cwritefln("ERROR: Can't parse config: %s".color(fg.red), msg.msg);
            }       
        }
        catch(Exception msg)
        {
            cwriteln(msg.msg.color(fg.red));
            core.thread.Thread.sleep( dur!("msecs")(1000));
        }   
    }


}


class DBConnect
{
    Statement stmt;
    ParseConfig parseconfig;

    this(ParseConfig parseconfig)
    {
        try
            {
                this.parseconfig = parseconfig;
                MySQLDriver driver = new MySQLDriver();
                string url = MySQLDriver.generateUrl(parseconfig.dbhost, to!short(parseconfig.dbport), parseconfig.dbname);
                string[string] params = MySQLDriver.setUserAndPassword(parseconfig.dbuser, parseconfig.dbpass);

                DataSource ds = new ConnectionPoolDataSourceImpl(driver, url, params);

                auto conn = ds.getConnection();
                scope(exit) conn.close();

                stmt = conn.createStatement();
                writefln("\n[Database connection OK]");
            }
        catch (Exception ex)
        {
            writefln(ex.msg);
            writeln("Could not connect to DB. Please check settings");
        }

    }   
}

我也运行下一个命令:

GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION; FLUSH PRIVILEGES;

我也尝试了不同的bind-address,例如:0.0.0.0 和localhost,但没有结果。每次新绑定后,我都会重启 MySQL 服务。

我正在使用这个驱动程序http://code.dlang.org/packages/ddbc

怎么了?

【问题讨论】:

  • 授予后,你有flush privileges;吗?
  • 是的,我做到了flush privileges;
  • GRANT ... @'127.0.0.1'...
  • 你能把它运行到一个'runTask'中吗? (vibed.org/api/vibe.core.core/runTask) 目前您正尝试在事件循环开始之前 连接到数据库,这会在所有模块构造函数返回后发生。诸如listenHTTP(乍一看似乎阻塞)之类的东西只不过是在全局列表(github.com/rejectedsoftware/vibe.d/blob/…)上注册一个服务器上下文。
  • 好的,我现在就试试。但是为什么你说我连接之前 我认为甚至循环都以static this() 开头。因为即使循环只能在所有函数构造函数返回后才能启动,很难理解它如何完成其​​他任务。还是我有什么不明白的?

标签: mysql d mariadb vibed


【解决方案1】:

继续我的评论 (Can't connect to MySQL/MariaDB database from vibed app)。

我刚刚测试过,肯定是事件循环;)

代替:

auto parseconfig = new ParseConfig();
auto db = new DBConnect(parseconfig);

只要做:

runTask({
    auto parseconfig = new ParseConfig();
    auto db = new DBConnect(parseconfig);
});

为我工作(DMD 2.067.0 / Vibe 0.7.23 / ddbc 0.2.24 / colorize & dini master)。

回答您的评论 (Can't connect to MySQL/MariaDB database from vibed app):事件循环在主函数内部开始。 启动 D 应用程序时会发生什么?入口点是运行时内的一个 C main,它初始化它(运行时),包括模块构造函数,运行 unittest(如果你已经使用 -unittest 编译),然后调用你的 main(名称是“_Dmain” - 有用知道是否要使用 GDB 设置断点)。 当 Vibe.d 的 main 被调用时,它会解析命令行参数、一个可选的配置文件,最后启动事件循环。任何希望在事件循环开始后运行的代码都应该使用runTask 和类似的,或者createTimer。他们不应该直接从静态构造函数调用代码(这实际上是从 Vibe.d 开始时最常见的错误之一)。

【讨论】:

  • 什么是“C main inside the runtime”?我认为 main 只是启动地址。 “然后调用你的main(名称是“_Dmain”)。我再次认为只有一个main,它的地址是“他们不应该直接从静态构造函数调用代码”如果他们从构造函数调用会怎样?为什么是错误吗?
  • 或者你的意思是这是在main之前运行并且它是入口点并且在运行并完成它里面的所有代码(包括所有其他函数)之后启动main()?
  • 目前一个D程序的入口点是_d_run_main。此函数位于运行时内部:github.com/D-Programming-Language/druntime/blob/… 运行时在此函数内部初始化,here。如果您查看rt_init(),您会看到正在初始化的各种事物,最后两项是rt_moduleCtor 和rt_moduleTlsCtor。
  • [Continuing...] 相关链接:github.com/D-Programming-Language/druntime/blob/…rt_moduleCtorinitializeshared static this,和rt_moduleTlsCtorinitializestatic this。因此,如果您的构造函数之一中有阻塞代码,则永远不会调用您的 main。这就是为什么您应该在 Vibe.d 中使用 runTask 的原因:它只是存储要在事件循环中执行的委托。
  • 抱歉耽搁了这么久,我刚回到家。我尝试了您的解决方案,但在从 DB 中选择后出现错误 Task terminated with unhandled exception: Access Violation object.Error@(0): Access Violation。
【解决方案2】:

我在开发 mysql-lited(一种替代的 MySQL/MariaDB 驱动程序)时遇到了一个可能相关的问题。

我认为这个问题与 phobos/SHA1 中的模块初始化顺序错误有关,我相信它在 2.067.1 中仍然存在。建议的解决方法是改用 VibeCustomMain,并定义您自己的 main()。您可以从 appmain.d 复制默认的 main() 并使用它。

您也可以尝试mysql-lited 看看是否更适合您。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-19
    • 2020-11-26
    • 2014-04-24
    • 2020-04-21
    • 2012-10-09
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多