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"路径就可以

  

posted @   多见多闻  阅读(382)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示