Can';t从vibed应用程序连接到MySQL/MariaDB数据库

Can';t从vibed应用程序连接到MySQL/MariaDB数据库,mysql,d,mariadb,vibed,Mysql,D,Mariadb,Vibed,如果我使用自定义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; impo

如果我使用自定义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");
        }

    }   
}
我还运行下一个命令:

将*.*上的所有权限授予“root”@“%”,该权限由带有授予选项的“password”标识;
同花顺特权

我还尝试了不同的
绑定地址
,比如:
0.0.0.0
localhost
,但没有结果。每次新绑定之后,我都会重新启动MySQL服务

我正在使用这个驱动程序


怎么了?

我在开发另一个MySQL/MariaDB驱动程序时遇到了一个可能与此相关的问题

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

或者,您也可以试试看这是否对您更有效。

继续我的评论()

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

而不是:

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)

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

授予后,您是否有
刷新权限?是的,我有
刷新权限
GRANT…@'127.0.0.1“…
您能将其运行到“runTask”中吗?()当前,您正在尝试在事件循环开始之前连接到DB,这将在所有模块构造函数返回后发生。类似listenHTTP(乍一看似乎是阻塞的)的功能只不过是在全局列表()上注册一个服务器上下文。但是为什么你说我在想到循环之前就连接了,甚至循环都是从
static this()
开始的呢。因为即使循环只有在所有函数构造函数返回后才能启动,也很难理解它如何执行其他任务。或者我不明白什么?什么是“运行时中的C main”?我以为main只是启动地址。然后调用main(名称为“_Dmain”)。我再次认为只有一个main,它的地址是“他们不应该直接从静态构造函数调用代码”如果他们将从构造函数中调用,会是什么情况?为什么会出错?或者您的意思是,这是在main之前运行的,它是入口点,在运行之后完成它内部的所有代码(包括所有其他函数)start main()?此时,D程序的入口点是
\u D\u run\u main
。此函数位于运行时内部:运行时在此函数内部初始化。如果查看
rt\u init()
,您可以看到各种东西正在初始化,最后两项是
rt\u modulelector
rt\u modulelsctor
。[继续…]相关链接:
rt\u moduleCtor
initialize
shared static this
,和
rt\u modulelsctor
initialize
static this
。因此,如果您的构造函数中有一个阻塞代码,则永远不会调用main。这就是为什么您应该在Vibe中使用
runTask
。d:它只存储要执行的委托事件循环中的med。很抱歉延迟太久,但我刚回到家中。我尝试了您的解决方案,但我发现错误
任务因未处理的异常而终止:访问冲突对象。错误@(0):从数据库中选择后访问冲突