Unity连接sqlite数据库,在windows Unity软件中成功连接,但是发布为EXE后,无法连接

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity连接sqlite数据库,在windows Unity软件中成功连接,但是发布为EXE后,无法连接相关的知识,希望对你有一定的参考价值。

我使用Unity连接sqlite,在windows Unity 5.1.0f3 (64-bit)下连接正常。但是把该项目发布为EXE后,无法就连接sqlite啦。很奇怪。
我把Unity工程包附上:http://pan.baidu.com/s/1gd71OnL。请大神帮我解答一下,纠结半个月啦。
在开发环境下一切正常

发布为EXE后,sqlite连接不成功。我经过调试发现:连 File.Exists(path)这个函数也不能被调用

创建数据库

选择开始菜单中→程序→【Management SQL Server 2008】→【SQL Server Management Studio】命令,打开【SQL Server Management Studio】窗口,并使用Windows或 SQL Server身份验证建立连接。

在【对象资源管理器】窗口中展开服务器,然后选择【数据库】节点

右键单击【数据库】节点,从弹出来的快捷菜单中选择【新建数据库】命令。

执行上述操作后,会弹出【新建数据库】对话框。在对话框、左侧有3个选项,分别是【常规】、【选项】和【文件组】。完成这三个选项中的设置会后,就完成了数据库的创建工作,

在【数据库名称】文本框中输入要新建数据库的名称。例如,这里以“新建的数据库”。

在【所有者】文本框中输入新建数据库的所有者,如sa。根据数据库的使用情况,选择启用或者禁用【使用全文索引】复选框。

在【数据库文件】列表中包括两行,一行是数据库文件,而另一行是日记文件。通过单击下面的【添加】、【删除】按钮添加或删除数据库文件。

切换到【选项页】、在这里可以设置数据库的排序规则、恢复模式、兼容级别和其他属性。

切换到【文件组】页,在这里可以添加或删除文件组。

完成以上操作后,单击【确定】按钮关闭【新建数据库】对话框。至此“新建的数据”数据库创建成功。新建的数据库可以再【对象资源管理器】窗口看到。
参考技术A 这个问题我也遇到了,我是这样解决的。先介绍环境:我是在windows7上运行Unity5.6.6,数据库也是sqlite,最终发布成EXE文件,也是在PC上运行。
发布前,我的数据库文件db放在unity的Asset目录下。
(1)象网上许多友友介绍的一样,先在C:\Program Files\Unity 5.6.6f2(64-bit)\Editor\Data\Mono\lib\mono\2.0目录下,把:Mono.Data.Sqlite.dll、sqlite3.dll、System.Data.dll这三个文件复制到你的工程文件Asset\Plugins\目录中。
然后直接发布,比如发布后的文件分别有两项:ex.EXE,ex_Data(这是目录)。
(2)此时,你把工程文件Asset\的数据库文件db,复制到发布后的ex_Data\目录下就可以了。我试过了四、五次,都没出现问题。
但愿你能成功!!!

为 Unity 设置数据库 (SQLite)

【中文标题】为 Unity 设置数据库 (SQLite)【英文标题】:Setup Database (SQLite) for Unity 【发布时间】:2018-11-18 02:20:10 【问题描述】:

我查看了太多教程,无法列出,它们都推荐相同的东西。但是,他们并没有帮助解决我的问题。

我试图在我的项目中包含一个 SQLite DB,并且在为 PC、MAC 和 Linux Standalone 构建(在 Windows 机器上测试)时,该数据库按预期工作。在 Android 设备上进行测试时,出现以下错误。

   E/Unity: ArgumentException: Invalid ConnectionString format for parameter "/storage/emulated/0/Android/data/com.tbltools.tbl_project/files/TBLDatabase.db"
          at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in <filename unknown>:0 
          at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in <filename unknown>:0 
          at UIHandler+<RequestAllStudentNames>c__Iterator2.MoveNext () [0x00000] in <filename unknown>:0 
          at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in <filename unknown>:0 

我认为对 connectionString 进行修改应该很简单,但这并没有解决我的问题。这是我目前所拥有的:

   if (Application.platform != RuntimePlatform.Android)
        
            // The name of the db.
             tblDatabase = "URI=file:" + Application.dataPath + "/TBLDatabase.db"; //returns the complete path to database file exist.
        
        else
        
              tblDatabase = Application.persistentDataPath + "/TBLDatabase.db";

            if (!File.Exists(tblDatabase))
            
                // if it doesn't ->
                Debug.LogWarning("File \"" + tblDatabase + "\" does not exist. Attempting to create from \"" + Application.dataPath + "!/assets/" + "TBLDatabase.db");
                // open StreamingAssets directory and load the db ->

                // #if UNITY_ANDROID
                var loadDb = new WWW("jar:file://" + Application.dataPath + "!/assets/" + "TBLDatabase.db");  // this is the path to your StreamingAssets in android
                while (!loadDb.isDone)    // CAREFUL here, for safety reasons you shouldn't let this while loop unattended, place a timer and error check
                                            // then save to Application.persistentDataPath
                File.WriteAllBytes(tblDatabase, loadDb.bytes);
            
        
        //open db connection
        var connection = new SqliteConnection(tblDatabase);
        connection.Open();
        var command = connection.CreateCommand();

我使用了 adb shell 并从我的 Android 设备中提取了数据库,一切都符合预期(数据库确实存在并且它不是空的)。

我相信我拥有所有相关的 dll 文件,但如果有人能给我一些指导,我将不胜感激。

**************************************************** ****编辑********************************************* *

此后,我根据给出的建议进行了以下更改。

我现在正在调用以下方法来启动我的连接并处理数据库请求StartCoroutine(RunDbCode(dbFileName, jsonStudentID, jsonIndiNames, jsonIndiStudentNumbers));

那我有以下方法:

IEnumerator RunDbCode(string fileName, List jsonStudentID, List jsonIndiNames, List jsonIndiStudentNumbers)
    
        //Where to copy the db to
        string dbDestination = Path.Combine(Application.persistentDataPath, "data");
        dbDestination = Path.Combine(dbDestination, fileName);

        //Check if the File do not exist then copy it
        if (!File.Exists(dbDestination))
        
            //Where the db file is at
            string dbStreamingAsset = Path.Combine(Application.streamingAssetsPath, fileName);

            byte[] result;

            //Read the File from streamingAssets. Use WWW for Android
            if (dbStreamingAsset.Contains("://") || dbStreamingAsset.Contains(":///"))
            
                WWW www = new WWW(dbStreamingAsset);
                yield return www;
                result = www.bytes;
            
            else
            
                result = File.ReadAllBytes(dbStreamingAsset);
            
            Debug.Log("Loaded db file");

            //Create Directory if it does not exist
            if (!Directory.Exists(Path.GetDirectoryName(dbDestination)))
            
                Directory.CreateDirectory(Path.GetDirectoryName(dbDestination));
            

            //Copy the data to the persistentDataPath where the database API can freely access the file
            File.WriteAllBytes(dbDestination, result);
            Debug.Log("Copied db file");
        

        //Now you can do the database operation
        //open db connection
        var connection = new SqliteConnection(dbDestination);
        connection.Open();
        var command = connection.CreateCommand();

        // Drop the table if it already exists.
        command.CommandText = "DROP TABLE IF EXISTS existing_individual;";
        command.ExecuteNonQuery();

        var sql = "CREATE TABLE existing_individual (studentID VARCHAR(23), fullName VARCHAR(50), studentNumber VARCHAR(20))";
        command.CommandText = sql;
        command.ExecuteNonQuery();

        //Inserting the exisiting student names returned, into the SQLite DB 

        int count = 0;

        foreach (var individuals in jsonStudentID)
        
            //looping through the existing students registered for the individual quiz - below has been written to avoid SQL injection
            sql = "INSERT INTO existing_individual (studentID, fullName, studentNumber) VALUES (@jsonStudentID, @jsonIndiNames, @jsonIndiStudentNumbers)";
            command.Parameters.AddWithValue("@jsonStudentID", jsonStudentID[count]);
            command.Parameters.AddWithValue("@jsonIndiNames", jsonIndiNames[count]);
            command.Parameters.AddWithValue("@jsonIndiStudentNumbers", jsonIndiStudentNumbers[count]);

            command.CommandText = sql;
            command.ExecuteNonQuery();

            count++;
        

        //close the connection
        command.Dispose();
        command = null;
        connection.Close();
        connection = null; 
    

但是,我仍然收到以下错误:

06-08 15:26:56.498 16300-16315/? E/Unity: ArgumentException: Invalid ConnectionString format for parameter "/storage/emulated/0/Android/data/com.tbltools.tbl_project/files/data/TBLDatabase.db"
      at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in <filename unknown>:0 
      at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in <filename unknown>:0 
      at UIHandler+<RunDbCode>c__Iterator3.MoveNext () [0x00000] in <filename unknown>:0 
      at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in <filename unknown>:0 
    UnityEngine.MonoBehaviour:StartCoroutineManaged2(IEnumerator)
    UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
    <RequestAllStudentNames>c__Iterator2:MoveNext()
    UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

    (Filename:  Line: -1)
06-08 15:26:56.502 16300-16315/? E/Unity: ArgumentException: Invalid ConnectionString format for parameter "URI"
      at Mono.Data.Sqlite.SqliteConnection.ParseConnectionString (System.String connectionString) [0x00000] in <filename unknown>:0 
      at Mono.Data.Sqlite.SqliteConnection.Open () [0x00000] in <filename unknown>:0 
      at UIHandler.CreateIndiButton () [0x00000] in <filename unknown>:0 
      at UIHandler+<RequestAllStudentNames>c__Iterator2.MoveNext () [0x00000] in <filename unknown>:0 
      at UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) [0x00000] in <filename unknown>:0 

我还将我的数据库添加到“StreamingAssets”文件夹中,如下图所示:

下面还显示了包含我的 dll 文件的插件文件夹的图像。

【问题讨论】:

你把数据库文件放在你项目的什么地方了? @Programmer 我尝试将数据库文件存储在 assets 文件夹中,并在 assets 文件夹中创建 StreamingAssets 文件夹并将副本也存储在其中。然而,这并没有帮助。 嗨@Programmer! - chat.***.com/rooms/info/172973 ? 【参考方案1】:

有关此主题的大多数教程都已过时。

查看了代码并发现了一些问题,但我不知道这些是否是您收到此错误的原因。 WWW 应该在协程函数中使用,以便您可以通过在 while 循环中添加 yield return null 来让出或等待 loadDb.isDone 完成。您也可以生成 WWW 请求本身,这就是我将在回答中使用的方法。

另外,jar:file://" + Application.dataPath 是旧代码。为此使用Application.streamingAssetsPath。此外,您不需要"URI=file:" + Application.dataPath。只需为此使用Application.persistentDataPath

我只是说明如何进行设置。

设置 MANAGED 代码部分:

1.转到您的 Unity 安装路径

<UnityInstallationDirecory>\Editor\Data\Mono\lib\mono\2.0

复制以下文件:

I18N.MidEast.dll I18N.Other.dll I18N.Rare.dll I18N.West.dll Mono.Data.Sqlite.dll Mono.Data.SqliteClient.dll System.Data.dll

到项目的&lt;ProjectName&gt;\Assets\Plugins 路径。

这将允许您从 Mono.Data.Sqlite 命名空间编译 API 而不会出现任何错误。


设置 UNMANAGED 代码部分:

在此步骤中,您将需要获取本机 Sqlite 库。你可以得到source code,构建它并使用它或者使用已经预编译的binray。

1.获取 Windows

的本机库

从here下载预编译好的Windows 64位sqlite3.dll,放到&lt;ProjectName&gt;\Assets\Plugins\x86_64路径下。

如果使用 Windows 32 位,则从 here 获取 sqlite3.dll 版本并将其放入 &lt;ProjectName&gt;\Assets\Plugins\x86 路径中。


2.获取Android

的原生库

Android ARM 处理器下载预编译的libsqlite3.so here 并将其放在&lt;ProjectName&gt;\Assets\Plugins\Android\libs\armeabi-v7a 路径中。

Android Intel x86 处理器下载预编译的libsqlite3.so here 并将其放在&lt;ProjectName&gt;\Assets\Plugins\Android\libs\x86 路径中。

这涵盖了大多数在 Android 设备上使用的processors。


3.获取UWP

的本机库

A。下载 WSA 文件夹,然后将 WSA 文件夹放入 &lt;ProjectName&gt;\Assets\Plugins 路径。该文件夹包含本机部分。

B。在 &lt;ProjectName&gt;\Assets 路径中创建 2 个名为 "mcs.rsp""csc.rsp" 的文件。 p>

C。在 "mcs.rsp""csc.rsp" 文件中添加以下内容:

-r:I18N.MidEast.dll

-r:I18N.Other.dll

-r:I18N.Rare.dll

-r:I18N.West.dll

-r:Mono.Data.Sqlite.dll

-r:Mono.Data.SqliteClient.dll

-r:System.Data.dll

D。为 UWP 构建时,您必须将托管 dll 移动到项目的 root 文件夹。因此,将I18N.MidEast.dllI18N.Other.dllI18N.Rare.dllI18N.West.dllMono.Data.Sqlite.dllMono.Data.SqliteClient.dllSystem.Data.dll 移动到 &lt;ProjectName&gt; 路径 not &lt;ProjectName&gt;\Assets\Plugins 路径。


4。对于 iOS、Linux 和 Mac,您似乎无需为它们下载任何其他内容或执行此步骤。它们通常内置原生预编译的 Sqlite 库。


在构建中包含数据库文件:

1。在您的&lt;ProjectName&gt;\Assets 文件夹中创建一个文件夹并将其命名为StreamingAssets。拼写很重要,并且区分大小写。

2。将数据库文件 (TBLDatabase.db) 放入此 StreamingAssets 文件夹中。


在构建项目后访问数据库文件

Sqlite 无法处理构建中 StreamingAssets 文件夹中的文件,因为这是只读路径。此外,Android 要求您使用 WWW API 而不是标准的 System.IO API 从 StreamingAssets 文件夹中读取数据。您必须将 db 文件从 Application.streamingAssetsPath/filename.db 复制到 Application.persistentDataPath/filename.db

在某些平台上,您需要在Application.persistentDataPath 内创建一个文件夹并将数据保存到该文件夹​​中。总是这样做。下面示例代码中的文件夹是“data”,因此将变为Application.persistentDataPath/data/filename.db

3.由于上面的语句,检查数据库文件是否存在于 Application.persistentDataPath/data/filename.db。如果是,请使用Application.persistentDataPath/data/filename.db 作为数据库操作的路径。如果没有,请从 #4 继续。

4.读取StreamingAssets文件夹中的数据库文件并将其复制到Application.persistentDataPath

在某些平台上,您需要在Application.persistentDataPath 中创建一个文件夹并将数据保存到该文件夹​​中。总是这样做。下例中的文件夹为“data”。

检测这是否是Android并使用WWWApplication.streamingAssetsPath/filename.db读取文件。使用 File.ReadAllBytes 在 Android 以外的任何其他设备上阅读它。在您的示例中,您为此使用了Application.platform。在我的示例中,我将简单地检查路径是否包含 "://":/// 来执行此操作。

5。读取文件后,将刚刚读取的数据写入Application.persistentDataPath/data/filename.dbFile.WriteAllBytes。现在,您可以使用此路径进行数据库操作。

6.前缀 "URI=file:"Application.persistentDataPath/data/filename.db 路径,这是在使用 Sqlite API 进行数据库操作时应该使用的路径。


理解所有这些非常重要,以便在发生变化时修复它,但我已经完成了下面的步骤 #3#6

IEnumerator RunDbCode(string fileName)

    //Where to copy the db to
    string dbDestination = Path.Combine(Application.persistentDataPath, "data");
    dbDestination = Path.Combine(dbDestination, fileName);

    //Check if the File do not exist then copy it
    if (!File.Exists(dbDestination))
    
        //Where the db file is at
        string dbStreamingAsset = Path.Combine(Application.streamingAssetsPath, fileName);

        byte[] result;

        //Read the File from streamingAssets. Use WWW for Android
        if (dbStreamingAsset.Contains("://") || dbStreamingAsset.Contains(":///"))
        
            WWW www = new WWW(dbStreamingAsset);
            yield return www;
            result = www.bytes;
        
        else
        
            result = File.ReadAllBytes(dbStreamingAsset);
        
        Debug.Log("Loaded db file");

        //Create Directory if it does not exist
        if (!Directory.Exists(Path.GetDirectoryName(dbDestination)))
        
            Directory.CreateDirectory(Path.GetDirectoryName(dbDestination));
        

        //Copy the data to the persistentDataPath where the database API can freely access the file
        File.WriteAllBytes(dbDestination, result);
        Debug.Log("Copied db file");
    

    try
    
        //Tell the db final location for debugging
        Debug.Log("DB Path: " + dbDestination.Replace("/", "\\"));
        //Add "URI=file:" to the front of the url beore using it with the Sqlite API
        dbDestination = "URI=file:" + dbDestination;

        //Now you can do the database operation below
        //open db connection
        var connection = new SqliteConnection(dbDestination);
        connection.Open();

        var command = connection.CreateCommand();
        Debug.Log("Success!");
    
    catch (Exception e)
    
        Debug.Log("Failed: " + e.Message);
    

用法

string dbFileName = "TBLDatabase.db";

void Start()

    StartCoroutine(RunDbCode(dbFileName));

【讨论】:

我建议删除你当前的插件 sqlite 和文件夹。删除文件夹,然后重新开始。请注意,如果您不关闭 Unity,这可能不起作用,因为 Unity 会用已经加载的旧 dll 覆盖您的新 dll。 非常感谢您在过去几天一直陪伴我解决这个问题。我刚刚测试过,它现在可以在所有平台上运行。如果可以,我会请你喝啤酒! @Displayname 欢迎您。我还尝试添加 WebGL 支持,因为在任何地方都没有视觉上的支持,但是在编译 c 源代码后它不起作用。没有时间继续试验,但如果我有时间再次使用 WebGL,我会再次更新。 好吧,我认为您所做的工作是一个很棒的文档,许多其他人将来会从中受益。再次感谢,我会尽量让你一个人呆一会儿! 没有被打扰,是的,其他人会从中受益。编码愉快。【参考方案2】:

当我们尝试在 Unity 2019 或更高版本中使用 SQLite 时会出现此错误。由于缺少 Unity 2019 或更高版本的 Mono 库而发生此错误。如果您使用的是 Unity 2018 或更低版本,则不会出现此错误。

如果您安装了 Unity 2018 或以下版本,请转到安装目录&lt;UnityInstallationDirecory&gt;\Editor\Data\Mono\lib\mono\2.0 并复制以下文件:

I18N.MidEast.dll
I18N.Other.dll
I18N.Rare.dll
I18N.West.dll
Mono.Data.Sqlite.dll
Mono.Data.SqliteClient.dll
System.Data.dll

到项目的&lt;ProjectName&gt;\Assets\Plugins 路径。

或者您可以通过将 Unity 版本降级到 2018 或更低版本来解决此错误。

【讨论】:

以上是关于Unity连接sqlite数据库,在windows Unity软件中成功连接,但是发布为EXE后,无法连接的主要内容,如果未能解决你的问题,请参考以下文章

unity之SQLite数据库的基本使用

Unity3D之SQLite让数据库开发更简单

Unity的本地数据库和服务器数据库分别用啥好

Sqlite,数据库连接和windows phone 8.1(silverlight)

数据库之Sqlite文件在Unity的应用

Unity3d在各个平台读取Sqlite3数据库