无法从vibed应用程序连接到MySQL/MariaDB数据库

4
如果我使用自定义主函数 (void main() 而不是 shared static this()),一切都正常。
使用默认的主函数会导致 "访问冲突" 错误。看起来 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; 命令? - Mad Dog Tannen
是的,我执行了 flush privileges; - Dmitry Bubnenkov
GRANT ... @'127.0.0.1'... - Rick James
2
你能把它跑成一个'runTask'吗?(http://vibed.org/api/vibe.core.core/runTask)目前,您正在尝试在事件循环开始之前连接到DB,这是在所有模块构造函数返回后发生的。 像listenHTTP这样的东西(乍一看似乎是阻塞的)实际上只是在全局列表上注册服务器上下文(https://github.com/rejectedsoftware/vibe.d/blob/a731634db880f7efb4482f094e92b403da6c38d4/source/vibe/http/server.d#L92)。 - Geod24
好的,我现在会尝试。但是为什么你说我在static this()之前连接呢?因为如果连循环都只能在所有函数构造函数返回后才能开始,那么它如何执行其他任务就很难理解了。或者是我没有理解到什么地方? - Dmitry Bubnenkov
并且您可以展示代码示例吗? - Dmitry Bubnenkov
2个回答

3
继续我的评论(无法从vibed应用程序连接到MySQL / MariaDB数据库)。
我刚刚测试了一下,这绝对是事件循环的问题 ;)
不要使用以下代码:
auto parseconfig = new ParseConfig();
auto db = new DBConnect(parseconfig);

Just do:

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),这很有效。

回答您的评论(无法从vibed应用程序连接到MySQL/MariaDB数据库):事件循环在主函数内部开始。 当你启动D应用程序时会发生什么?入口点是运行时内部的C main,它初始化它(运行时),包括模块构造器,运行单元测试(如果你编译了-unittest),然后调用你的main(名为"_Dmain" - 如果你想使用GDB设置断点很有用)。 Vibe.d的main被调用时,它解析命令行参数和可选配置文件,最后启动事件循环。任何希望在事件循环启动后运行的代码都应该使用 runTask 和类似的方法,或者 createTimer。它们不应该从静态构造函数直接调用代码(实际上这是刚开始使用Vibe.d时最常见的错误之一)。


“C main inside the runtime”是什么?我以为main只是启动地址。 “然后调用你的main(名为“_Dmain”)。 "再次,我认为只有一个main函数和它的地址。“他们不应该直接从静态构造函数中调用代码”,如果他们从构造函数中调用会怎样?为什么会出错? - Dmitry Bubnenkov
你的意思是这段代码在main函数之前运行,作为入口点,在其内部运行并完成所有代码(包括其他所有函数)后再开始执行main函数吗? - Dmitry Bubnenkov
D程序的入口点目前是_d_run_main。此函数位于运行时库中: https://github.com/D-Programming-Language/druntime/blob/6e55b7aaff7566d374c2f253f831d3489e7fd1a5/src/rt/dmain2.d#L290该运行时库在此函数内初始化,在这里。如果您查看rt_init(),您可以看到各种事物被初始化,最后两个项目是rt_moduleCtorrt_moduleTlsCtor - Geod24
继续阅读...相关链接:https://github.com/D-Programming-Language/druntime/blob/6e55b7aaff7566d374c2f253f831d3489e7fd1a5/src/rt/dmain2.d#L175rt_moduleCtor 初始化 shared static this,而 rt_moduleTlsCtor 初始化 static this。因此,如果您的构造函数中有阻塞代码,则不会调用主函数。这就是为什么在 Vibe.d 中应该使用 runTask 的原因:它只是将要执行的委托存储在事件循环中。 - Geod24
抱歉回复晚了,我刚回到家。 我尝试了你的解决方案,但在从数据库中进行SELECT后,我遇到了错误“Task terminated with unhandled exception: Access Violation object.Error@(0): Access Violation”。 - Suliman

0

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

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

或者,你可以尝试使用mysql-lited,看看是否更适合你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接