Unity3D游戏开发之SQLite让数据库开发更简单
在Unity3D中使用SQLite。我们首先要明确这样一件事情。即我们这里的使用的SQLite并不是是通常意义上的SQLite.NET,而是经过移植后的Mono.Data.Sqlite。由于Unity3D基于Mono,因此使用移植后的Mono.Data.Sqlite能够降低我们的项目在不同平台上出现各种各样的问题。
在Unity3D中使用的SQLite以Mono.Data.Sqlite.dll即动态链接库的形式给出,因此我们须要将这个文件放置在项目文件夹下的Plugins文件夹中,此外我们须要System.Data.dll或者Mono.Data.dll这两个文件加入到Plugins文件夹中,由于我们须要的部分数据相关的API或者类都定义在这两个文件其中,这些文件能够从这里直接下载。
PS:博主注意到在网上有使用Mono.Data.SQLiteClient.dll这个库实如今Unity3D操作SQLite数据库的相关文章。博主大概看了下,感觉和使用Mono.Data.Sqlite.dll这个库大同小异,大家喜欢哪个就用哪个吧!哈哈!博主在开源社区找到一个版本号库。据说能够同一时候支持.NET和Mono,假设大家感兴趣欢迎大家去測试啊,哈哈!
在正式開始写代码前。我们首先来回想下通常情况下数据库读写的基本流程吧!
- 定义数据库连接字符串(ConnectionString)完毕数据库连接的构造,建立或者打开一个数据库。
- 定义相关的SQL命令(Command)通过这些命令实现对数据库的添加、删除、更新、读取四种基本功能。
- 在完毕各种数据库操作后及时关闭数据库连接。解除对数据库的连接和引用。
SQLite作为一款优秀的数据库,在为其编写数据库相关代码时相同遵循这种流程,考虑到对数据库的添加、删除、更新、读取四种操作具有相似性和统一性,因此在动手写Unity3D脚本前。首先让我们来编写一个SQLite的辅助类SQLiteHelper.cs。该类代码定义例如以下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | using UnityEngine; using System.Collections; using Mono.Data.Sqlite; using System; public class SQLiteHelper { /// <summary> /// 数据库连接定义 /// </summary> private SqliteConnection dbConnection; /// <summary> /// SQL命令定义 /// </summary> private SqliteCommand dbCommand; /// <summary> /// 数据读取定义 /// </summary> private SqliteDataReader dataReader; /// <summary> /// 构造函数 /// </summary> /// <param name="connectionString">数据库连接字符串</param> public SQLiteHelper( string connectionString) { try { //构造数据库连接 dbConnection= new SqliteConnection(connectionString); //打开数据库 dbConnection.Open(); } catch (Exception e) { Debug.Log(e.Message); } } /// <summary> /// 执行SQL命令 /// </summary> /// <returns>The query.</returns> /// <param name="queryString">SQL命令字符串</param> public SqliteDataReader ExecuteQuery( string queryString) { dbCommand = dbConnection.CreateCommand(); dbCommand.CommandText = queryString; dataReader = dbCommand.ExecuteReader(); return dataReader; } /// <summary> /// 关闭数据库连接 /// </summary> public void CloseConnection() { //销毁Command if (dbCommand != null ){ dbCommand.Cancel(); } dbCommand = null ; //销毁Reader if (dataReader != null ){ dataReader.Close(); } dataReader = null ; //销毁Connection if (dbConnection != null ){ dbConnection.Close(); } dbConnection = null ; } /// <summary> /// 读取整张数据表 /// </summary> /// <returns>The full table.</returns> /// <param name="tableName">数据表名称</param> public SqliteDataReader ReadFullTable( string tableName) { string queryString = "SELECT * FROM " + tableName; return ExecuteQuery (queryString); } /// <summary> /// 向指定数据表中插入数据 /// </summary> /// <returns>The values.</returns> /// <param name="tableName">数据表名称</param> /// <param name="values">插入的数值</param> public SqliteDataReader InsertValues( string tableName, string [] values) { //获取数据表中字段数目 int fieldCount=ReadFullTable(tableName).FieldCount; //当插入的数据长度不等于字段数目时引发异常 if (values.Length!=fieldCount){ throw new SqliteException( "values.Length!=fieldCount" ); } string queryString = "INSERT INTO " + tableName + " VALUES (" + values[0]; for ( int i=1; i<values.Length; i++) { queryString+= ", " + values[i]; } queryString += " )" ; return ExecuteQuery(queryString); } /// <summary> /// 更新指定数据表内的数据 /// </summary> /// <returns>The values.</returns> /// <param name="tableName">数据表名称</param> /// <param name="colNames">字段名</param> /// <param name="colValues">字段名相应的数据</param> /// <param name="key">关键字</param> /// <param name="value">关键字相应的值</param> public SqliteDataReader UpdateValues( string tableName, string [] colNames, string [] colValues, string key, string operation, string value) { //当字段名称和字段数值不正确应时引发异常 if (colNames.Length!=colValues.Length) { throw new SqliteException( "colNames.Length!=colValues.Length" ); } string queryString = "UPDATE " + tableName + " SET " + colNames[0] + "=" + colValues[0]; for ( int i=1; i<colValues.Length; i++) { queryString+= ", " + colNames[i] + "=" + colValues[i]; } queryString += " WHERE " + key + operation + value; return ExecuteQuery(queryString); } /// <summary> /// 删除指定数据表内的数据 /// </summary> /// <returns>The values.</returns> /// <param name="tableName">数据表名称</param> /// <param name="colNames">字段名</param> /// <param name="colValues">字段名相应的数据</param> public SqliteDataReader DeleteValuesOR( string tableName, string [] colNames, string [] operations, string [] colValues) { //当字段名称和字段数值不正确应时引发异常 if (colNames.Length!=colValues.Length || operations.Length!=colNames.Length || operations.Length!=colValues.Length) { throw new SqliteException( "colNames.Length!=colValues.Length || operations.Length!=colNames.Length || operations.Length!=colValues.Length" ); } string queryString = "DELETE FROM " + tableName + " WHERE " + colNames[0] + operations[0] + colValues[0]; for ( int i=1; i<colValues.Length; i++) { queryString+= "OR " + colNames[i] + operations[0] + colValues[i]; } return ExecuteQuery(queryString); } /// <summary> /// 删除指定数据表内的数据 /// </summary> /// <returns>The values.</returns> /// <param name="tableName">数据表名称</param> /// <param name="colNames">字段名</param> /// <param name="colValues">字段名相应的数据</param> public SqliteDataReader DeleteValuesAND( string tableName, string [] colNames, string [] operations, string [] colValues) { //当字段名称和字段数值不正确应时引发异常 if (colNames.Length!=colValues.Length || operations.Length!=colNames.Length || operations.Length!=colValues.Length) { throw new SqliteException( "colNames.Length!=colValues.Length || operations.Length!=colNames.Length || operations.Length!=colValues.Length" ); } string queryString = "DELETE FROM " + tableName + " WHERE " + colNames[0] + operations[0] + colValues[0]; for ( int i=1; i<colValues.Length; i++) { queryString+= " AND " + colNames[i] + operations[i] + colValues[i]; } return ExecuteQuery(queryString); } /// <summary> /// 创建数据表 /// </summary> + /// <returns>The table.</returns> /// <param name="tableName">数据表名</param> /// <param name="colNames">字段名</param> /// <param name="colTypes">字段名类型</param> public SqliteDataReader CreateTable( string tableName, string [] colNames, string [] colTypes) { string queryString = "CREATE TABLE " + tableName + "( " + colNames [0] + " " + colTypes [0]; for ( int i=1; i<colNames.Length; i++) { queryString+= ", " + colNames[i] + " " + colTypes[i]; } queryString+= " ) " ; return ExecuteQuery(queryString); } /// <summary> /// Reads the table. /// </summary> /// <returns>The table.</returns> /// <param name="tableName">Table name.</param> /// <param name="items">Items.</param> /// <param name="colNames">Col names.</param> /// <param name="operations">Operations.</param> /// <param name="colValues">Col values.</param> public SqliteDataReader ReadTable( string tableName, string [] items, string [] colNames, string [] operations, string [] colValues) { string queryString = "SELECT " + items [0]; for ( int i=1; i<items.Length; i++) { queryString+= ", " + items[i]; } queryString += " FROM " + tableName + " WHERE " + colNames[0] + " " + operations[0] + " " + colValues[0]; for ( int i=0; i<colNames.Length; i++) { queryString+= " AND " + colNames[i] + " " + operations[i] + " " + colValues[0] + " " ; } return ExecuteQuery(queryString); } } |
SQLiteHelper类主要实现了数据库、数据表的创建以及数据表中记录的添加、删除、更新、读取四种基本功能。该类最初由国外的Unity3D开发人员公布在Unity3D官方论坛,后来经宣雨松使用C#进行重写。我在此基础上进行了完好。再此对两位大神的无私付出表示感谢。
这里要说明的有三点:
-
一、在Unity3D编辑器下生成数据库文件(.db)默认位于和Assets文件夹同级的位置。即项目的project文件夹中。我们能够通过改动路径在改变数据库文件的存储位置,详细来讲:
Windows平台:data source=Application.dataPath/数据库名称.db
IOS平台:data source=Application.persistentDataPath/数据库名称.db
Android平台:URL=file:Application.persistentDataPath/数据库名称.db(我想说Android平台就是个奇葩。搞什么特殊化嘛) -
二、确保Unity3D编辑器中的.NET版本号和MonoDevelop中的.NET版本号都为2.0版本号,在Unity3D中打包导出的程序可能不会保留数据库文件,因此须要手动将数据库文件复制到相应的位置,当然更加合理的方案是将数据库文件存放到StreamingAssets文件夹下,然后在第一次载入游戏的时候将数据库文件复制到相应平台上的存放位置。
-
三、在使用InsertValues方法时请參考SQLite中字段类型与C#中数据类型的相应关系,博主眼下測试了int类型和string类型都没有什么问题。很多其它类型的数据请大家自行測试然后告诉博主測试的结果。假设大家有兴趣扩展这个辅助类的话能够自行去扩展哦,嘿嘿!
好了。千呼万唤始出来的时候到了,以下我们以一个实例来完毕今天的项目解说,由于我们已经定义好了SQLite的辅助类,因此我们能够高速地编写出以下的脚本代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | using UnityEngine; using System.Collections; using System.IO; using Mono.Data.Sqlite; public class SQLiteDemo : MonoBehaviour { /// <summary> /// SQLite数据库辅助类 /// </summary> private SQLiteHelper sql; void Start () { //创建名为sqlite4unity的数据库 sql = new SQLiteHelper( "data source=sqlite4unity.db" ); //创建名为table1的数据表 sql.CreateTable( "table1" , new string []{ "ID" , "Name" , "Age" , "Email" }, new string []{ "INTEGER" , "TEXT" , "INTEGER" , "TEXT" }); //插入两条数据 sql.InsertValues( "table1" , new string []{ "'1'" , "'张三'" , "'22'" , "'Zhang3@163.com'" }); sql.InsertValues( "table1" , new string []{ "'2'" , "'李四'" , "'25'" , "'Li4@163.com'" }); //更新数据。将Name="张三"的记录中的Name改为"Zhang3" sql.UpdateValues( "table1" , new string []{ "Name" }, new string []{ "'Zhang3'" }, "Name" , "=" , "'张三'" ); //插入3条数据 sql.InsertValues( "table1" , new string []{ "3" , "'王五'" , "25" , "'Wang5@163.com'" }); sql.InsertValues( "table1" , new string []{ "4" , "'王五'" , "26" , "'Wang5@163.com'" }); sql.InsertValues( "table1" , new string []{ "5" , "'王五'" , "27" , "'Wang5@163.com'" }); //删除Name="王五"且Age=26的记录,DeleteValuesOR方法相似 sql.DeleteValuesAND( "table1" , new string []{ "Name" , "Age" }, new string []{ "=" , "=" }, new string []{ "'王五'" , "'26'" }); //读取整张表 SqliteDataReader reader = sql.ReadFullTable ( "table1" ); while (reader.Read()) { //读取ID Debug.Log(reader.GetInt32(reader.GetOrdinal( "ID" ))); //读取Name Debug.Log(reader.GetString(reader.GetOrdinal( "Name" ))); //读取Age Debug.Log(reader.GetInt32(reader.GetOrdinal( "Age" ))); //读取Email Debug.Log(reader.GetString(reader.GetOrdinal( "Email" ))); } //读取数据表中Age>=25的全部记录的ID和Name reader = sql.ReadTable ( "table1" , new string []{ "ID" , "Name" }, new string []{ "Age" }, new string []{ ">=" }, new string []{ "'25'" }); while (reader.Read()) { //读取ID Debug.Log(reader.GetInt32(reader.GetOrdinal( "ID" ))); //读取Name Debug.Log(reader.GetString(reader.GetOrdinal( "Name" ))); } //自己定义SQL,删除数据表中全部Name="王五"的记录 sql.ExecuteQuery( "DELETE FROM table1 WHERE NAME='王五'" ); //关闭数据库连接 sql.CloseConnection(); } } |
在上面的代码中我们是在Start方法中创建了数据库和数据表,然而在实际使用中我们须要推断数据库和数据表是否存在。因此假设你使用这段脚本提示错误信息,请确保数据库和数据表是否已经存在。
好了,以下的截图展示了程序执行的结果:
作为一个强大的数据库怎么能没有图形化的数据库管理工具呢?所以这里博主向大家推荐一个免安装的小工具SqliteStudio,使用这个工具能够帮助我们方便地管理Sqlite数据库里的数据,这样是不是比較方便呢?哈哈!
这个工具能够从这里下载哦。
在不同的平台上数据库的存储位置是不同的。在这里给出一个參考的路径。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //各平台下数据库存储的绝对路径(通用) //PC:sql = new SQLiteHelper("data source=" + Application.dataPath + "/sqlite4unity.db"); //Mac:sql = new SQLiteHelper("data source=" + Application.dataPath + "/sqlite4unity.db"); //Android:sql = new SQLiteHelper("URI=file:" + Application.persistentDataPath + "/sqlite4unity.db"); //iOS:sql = new SQLiteHelper("data source=" + Application.persistentDataPath + "/sqlite4unity.db"); //PC平台下的相对路径 //sql = new SQLiteHelper("data source="sqlite4unity.db"); //编辑器:Assets/sqlite4unity.db //编译后:和AppName.exe同级的文件夹下,这里比較奇葩 //当然能够用更任意的方式sql = new SQLiteHelper("data source="D://SQLite//sqlite4unity.db"); //确保路径存在就可以否则会错误发生 //假设是事先创建了一份数据库 //能够将这个数据库放置在StreamingAssets文件夹下然后再复制到 //Application.persistentDataPath + "/sqlite4unity.db"路径就可以 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具