在Unity中使用SQLite(Unity + SQLite)

大家好,本文将重点介绍使用Unity的SQLite嵌入式关系数据库。 本文是由新手为初学者撰写的,旨在向您展示如何使用SQLite,假定您了解SQL的基础知识。 由于Internet上没有针对初学者的清晰教程,因此我决定占据这个位置。 在本文中,我们将编写一个用于处理此DBMS的简单类,该类可用于解决各种任务(本地化,数据存储,维护不同的表)。

什么是SQLite?为什么需要它?


SQLite是一种非常流行的紧凑型嵌入式关系数据库管理系统。 SQLite的一个重要优点是其跨平台,因此我们可以将SQLite用于各种平台。 当需要速度和紧凑性时,可以使用SQLite,因此,如果出现数据存储问题,我决定使用此DBMS解决它。

如何使用SQLite?


为了创建和编辑数据库,有大量用于浏览器的免费实用程序和插件,我个人将使用数据库浏览器(SQLite),它以其简单性吸引了我,在我看来使用浏览器中的各种插件并不十分方便。 通常,任何想要它的人都是这样。 使用DB Browser,您可以轻松创建表,在它们之间建立连接并用数据填充它们,而无需使用SQL。 另外,在数据库浏览器中,您可以使用SQLite用笔进行所有操作,因此在这里对某人来说更方便。

创建并填充测试数据库


我们在项目的Assets / StreamingAssets中创建一个数据库(我拥有db.bytes,因为Unity仅了解数据库* * bytes ,因此将使用此扩展名)。 仅以举例来说,我使用以下表格创建了这样的数据库:

1)表“玩家”,它描述了播放器的本质:

CREATE TABLE "Player" ( "id_player" INTEGER NOT NULL, "nickname" TEXT NOT NULL, PRIMARY KEY("id_player") ); 

用以下数据填充它:



2)表“分数”,用于提高数据库的规范化级别

 CREATE TABLE "Scores" ( "id" INTEGER NOT NULL, "id_player" INTEGER NOT NULL, "score" INTEGER NOT NULL, PRIMARY KEY("id"), FOREIGN KEY("id_player") REFERENCES "Player"("id_player") ); 

用以下数据填充它:



连接库


我们在项目的Assets / StreamingAssets中创建一个数据库(我有db.bytes),然后需要连接库以使用该数据库。 从官方站点下载sqlite3.dll 文件 ,以在Windows中使用SQLite。 我花了几天的时间使这个ACBD与Android成为朋友,因为本文中指出的库原来无法正常工作,我个人没有设法在Android上使用它,错误不断攀升,为此,我将此内容上传到了互联网上的某个地方Android 库版本。 我们将库放在此处-Assets / Plugins / sqlite.dllAssets / Plugins / Android / sqlite.so

完成所有这些操作后,从C:\ Program Files(x86)\ Unity \ Editor \ Data \ Mono \ lib \ mono \ 2.0复制System.Data.dllMono.Data.Sqlite.dll ,然后粘贴Unity项目的Assets / Plugins 。 我想指出的是,在2018版本中,Unity可能会写出System.Data.dll已连接并且两个相同文件存在冲突。 实际上,这很容易解决,我们不会删除新插入的System.Data.dll

库的结构应如下所示:

资产/插件/Mono.Data.Sqlite.dll-仅需:)
资产/插件/System.Data.dll-类似原因
资产/插件/ sqlite3.dll-用于在Windows上使用SQLite
资产/插件/ Android / libsqlite3.so-用于在Android上使用SQLite

编写脚本以使用数据库


最后,我们可以开始编写脚本来处理创建的数据库。 首先,创建一个MyDataBase文件并连接System.DataMono.Data.SqliteSystem.IO库,使MyDataBase类为静态,当然,还要从MonoBehaviour中删除继承。 添加3个私有变量和一个带有数据库文件名的常量。 我们应该得到这样的东西:

 using UnityEngine; using System.Data; using Mono.Data.Sqlite; using System.IO; static class MyDataBase { private const string fileName = "db.bytes"; private static string DBPath; private static SqliteConnection connection; private static SqliteCommand command; } 

当然,这一切都很好,但是我们将无法使用该数据库。 要使用数据库,我们需要获取其路径,我建议创建一个静态构造函数,该构造函数将仅获取数据库的路径(我记得该数据库位于StreamingAssets中)。

 static MyDataBase() { DBPath = GetDatabasePath(); } /// <summary>    .        ,      apk . </summary> private static string GetDatabasePath() { #if UNITY_EDITOR return Path.Combine(Application.streamingAssetsPath, fileName); #if UNITY_STANDALONE string filePath = Path.Combine(Application.dataPath, fileName); if(!File.Exists(filePath)) UnpackDatabase(filePath); return filePath; #elif UNITY_ANDROID string filePath = Path.Combine(Application.persistentDataPath, fileName); if(!File.Exists(filePath)) UnpackDatabase(filePath); return filePath; #endif } /// <summary>      . </summary> /// <param name="toPath">       . </param> private static void UnpackDatabase(string toPath) { string fromPath = Path.Combine(Application.streamingAssetsPath, fileName); WWW reader = new WWW(fromPath); while (!reader.isDone) { } File.WriteAllBytes(toPath, reader.bytes); } 

注意事项 我们需要在指定的路径(对于Windows为Application.dataPath / db.bytes,对于Android为Application.persistentDataPath / db.bytes )中解压缩数据库,因为StreamingAssets文件夹在组装后具有ReadOnly属性(Android除外),我们将无法编写任何内容然后在数据库中。 实际上,为了能够向数据库中写入内容,我们将数据库解压缩。 本文详细介绍了在哪种平台上使用哪种路径。

我们将编写用于打开连接和关闭的方法,以及将执行不需要返回值(例如INSERT,UPDATE,CREATE,DELETE,DROP)的请求的方法。

 /// <summary>      . </summary> private static void OpenConnection() { connection = new SqliteConnection("Data Source=" + DBPath); command = new SqliteCommand(connection); connection.Open(); } /// <summary>      . </summary> public static void CloseConnection() { connection.Close(); command.Dispose(); } /// <summary>     query. </summary> /// <param name="query">  . </param> public static void ExecuteQueryWithoutAnswer(string query) { OpenConnection(); command.CommandText = query; command.ExecuteNonQuery(); CloseConnection(); } 

奇迹般地,现在我们的脚本可以执行数据修改请求。 但是,一个非常重要的SELECT呢? 我决定,如果要获取1值,应执行查询以进行数据选择的方法的返回值应为DataTable类型或字符串。 为此,请编写2种方法:

 /// <summary>     query    . </summary> /// <param name="query">  . </param> /// <returns>   1  1 ,   . </returns> public static string ExecuteQueryWithAnswer(string query) { OpenConnection(); command.CommandText = query; var answer = command.ExecuteScalar(); CloseConnection(); if (answer != null) return answer.ToString(); else return null; } /// <summary>    ,      query. </summary> /// <param name="query">  . </param> public static DataTable GetTable(string query) { OpenConnection(); SqliteDataAdapter adapter = new SqliteDataAdapter(query, connection); DataSet DS = new DataSet(); adapter.Fill(DS); adapter.Dispose(); CloseConnection(); return DS.Tables[0]; } 

完成后,现在我们有了一个简单的脚本,可以请求修改和选择数据。 现在让我们编写ScoreManager脚本。 它将收到最佳结果表(按降序排列)。 为了进行验证,请在Debug.Log中显示领导者的昵称和他的观点。

 using System.Collections; using System.Collections.Generic; using System.Data; using UnityEngine; public class ScoreManager : MonoBehaviour { private void Start() { //     DataTable scoreboard = MyDataBase.GetTable("SELECT * FROM Scores ORDER BY score DESC;"); //  id   int idBestPlayer = int.Parse(scoreboard.Rows[0][1].ToString()); //     string nickname = MyDataBase.ExecuteQueryWithAnswer($"SELECT nickname FROM Player WHERE id_player = {idBestPlayer};"); Debug.Log($"  {nickname}  {scoreboard.Rows[0][2].ToString()} ."); } } 

这是我们在启动时得到的:



感谢您的关注,我将很乐意接受建设性的批评。

Source: https://habr.com/ru/post/zh-CN442954/


All Articles