原创作者:秦元培
文章出处:http://blog.csdn.net/qinyuanpei/article/details/46812655#comments
转载过来方便查看。文章末尾有我自己总结的问题解决方案。
一、什么是SQLite?
SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中,以嵌入式作为它的设计目标,它占用资源非常的低,因此适合在嵌入式设备如Android、Ruby on Rails等中使用。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟和C、C++、Ruby、Python、C#、PHP、Java等编程语言相结合。SQLite是一个以文件形式存在的关系型数据库,尽管无法实现分布式和横向扩展,可是作为一个轻量级的嵌入式数据库,它不需要系统提供服务支持,通过SDK直接操作文件避免了对数据库维护的相关事务,从这个角度来讲它是一个出色的数据库。
二、为什么要选择SQLite
好了,在了解了SQLite后,我们来了解下SQLite有哪些让我们心动的特性,或者说我们为什么要选择SQLite,因为在这个世界上我们有太多的数据库可以选择,诸如Oracle、MySQL、SQLServer、DB2、NoSQL、MongoDB等等:
- ACID事务
- 零配置 – 无需安装和管理配置
- 储存在单一磁盘文件中的一个完整的数据库
- 数据库文件可以在不同字节顺序的机器间自由的共享
- 支持数据库大小至2TB
- 足够小, 大致13万行C代码, 4.43M
- 比一些流行的数据库在大部分普通数据库操作要快—SQLite读写效率如此之高,会使用其他数据库的理由是?
- 简单, 轻松的API
- 包含TCL绑定, 同时通过Wrapper支持其他语言的绑定
- 良好注释的源代码, 并且有着90%以上的测试覆盖率
- 独立: 没有额外依赖
- 源码完全的开源, 你可以用于任何用途, 包括出售它
- 支持多种开发语言,C, C++, PHP, Perl, Java, C#,Python, Ruby等
三、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和SQLite3.dll这三个文件添加到Plugins目录中,因为我们需要的部分数据相关的API或者类都定义在这两个文件当中.
在正式开始写代码前,我们首先来回顾下通常情况下数据库读写的基本流程吧!
- 定义数据库连接字符串(ConnectionString)完成数据库连接的构造,建立或者打开一个数据库。
- 定义相关的SQL命令(Command)通过这些命令实现对数据库的增加、删除、更新、读取四种基本功能。
- 在完成各种数据库操作后及时关闭数据库连接,解除对数据库的连接和引用。
SQLite作为一款优秀的数据库,在为其编写数据库相关代码时同样遵循这样的流程,考虑到对数据库的增加、删除、更新、读取四种操作具有类似性和统一性,因此在动手写Unity3D脚本前,首先让我们来编写一个SQLite的辅助类SQLiteHelper.cs。该类代码定义如下:
using UnityEngine;using System.Collections;using Mono.Data.Sqlite;using System;public class SQLiteHelper{ private SqliteConnection dbConnection; private SqliteCommand dbCommand; private SqliteDataReader dataReader; public SQLiteHelper(string connectionString) { try{ dbConnection=new SqliteConnection(connectionString); dbConnection.Open(); }catch(Exception e) { Debug.Log(e.Message); } } public SqliteDataReader ExecuteQuery(string queryString) { dbCommand = dbConnection.CreateCommand(); dbCommand.CommandText = queryString; dataReader = dbCommand.ExecuteReader(); return dataReader; } public void CloseConnection() { if(dbCommand != null){ dbCommand.Cancel(); } dbCommand = null; if(dataReader != null){ dataReader.Close(); } dataReader = null; if(dbConnection != null){ dbConnection.Close(); } dbConnection = null; } public SqliteDataReader ReadFullTable(string tableName) { string queryString = "SELECT * FROM " + tableName; return ExecuteQuery (queryString); } 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); } 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); } 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); } 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); } 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); } 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); }}
- 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
- 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
SQLiteHelper类主要实现了数据库、数据表的创建以及数据表中记录的增加、删除、更新、读取四种基本功能。该类最初由国外的Unity3D开发者发布在Unity3D官方论坛,后来经宣雨松使用C#进行重写,我在此基础上进行了完善,再此对两位大神的无私付出表示感谢。这里要说明的有三点:
一、在Unity3D编辑器下生成数据库文件(.db)默认位于和Assets目录同级的位置,即项目的工程文件夹中。我们可以通过修改路径在改变数据库文件的存储位置,具体来讲:
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的辅助类,因此我们可以快速地编写出下面的脚本代码:
using UnityEngine;using System.Collections;using System.IO;using Mono.Data.Sqlite;public class SQLiteDemo : MonoBehaviour { private SQLiteHelper sql; void Start () { sql = new SQLiteHelper("data source=sqlite4unity.db"); 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'"}); sql.UpdateValues("table1", new string[]{"Name"}, new string[]{"'Zhang3'"}, "Name", "=", "'张三'"); 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'"}); sql.DeleteValuesAND("table1", new string[]{"Name","Age"}, new string[]{"=","="}, new string[]{"'王五'","'26'"}); SqliteDataReader reader = sql.ReadFullTable ("table1"); while(reader.Read()) { Debug.Log(reader.GetInt32(reader.GetOrdinal("ID"))); Debug.Log(reader.GetString(reader.GetOrdinal("Name"))); Debug.Log(reader.GetInt32(reader.GetOrdinal("Age"))); Debug.Log(reader.GetString(reader.GetOrdinal("Email"))); } reader = sql.ReadTable ("table1", new string[]{"ID","Name"}, new string[]{"Age"}, new string[]{">="}, new string[]{"'25'"}); while(reader.Read()) { Debug.Log(reader.GetInt32(reader.GetOrdinal("ID"))); Debug.Log(reader.GetString(reader.GetOrdinal("Name"))); } sql.ExecuteQuery("DELETE FROM table1 WHERE NAME='王五'"); sql.CloseConnection(); }}
- 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
- 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
在上面的代码中我们是在Start方法中创建了数据库和数据表,然而在实际使用中我们需要判断数据库和数据表是否存在,因此如果你使用这段脚本提示错误信息,请确保数据库和数据表是否已经存在。好了,下面的截图展示了程序运行的结果:
作为一个强大的数据库怎么能没有图形化的数据库管理工具呢?所以这里博主向大家推荐一个免安装的小工具SqliteStudio,使用这个工具可以帮助我们方便地管理Sqlite数据库里的数据,这样是不是比较方便呢?哈哈!这个工具可以从这里下载哦!
2015年11月3日更新内容:在不同的平台上数据库的存储位置是不同的,在这里给出一个参考的路径,希望大家在处理移动端的时候注意这些问题啊!
//各平台下数据库存储的绝对路径(通用) //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"路径即可
注:有的同学出现了Unty 使用SQLITE 运行时出现“database is not open‘’
错误信息如下:
InvalidOperationException: Database is not open
Mono.Data.Sqlite.SqliteCommand.InitializeForReader ()
Mono.Data.Sqlite.SqliteCommand.ExecuteReader (CommandBehavior behavior)
Mono.Data.Sqlite.SqliteCommand.ExecuteReader ()
(wrapper remoting-invoke-with-check) Mono.Data.Sqlite.SqliteCommand:ExecuteReader ()
SQLiteHelper.ExecuteQuery (System.String queryString) (at Assets/Script/SQLiteHelper.cs:51)
SQLiteHelper.CreateTable (System.String tableName, System.String[] colNames, System.String[] colTypes) (at Assets/Script/SQLiteHelper.cs:205)
SQLiteDemo.Start () (at Assets/Script/SQLiteDemo.cs:20)
原因可能是没有将SQLite3.dll文件放到指定的位置,
解决办法是将SQLITE3.DLL 放到C:\Windows\System32或者放到Unity项目中的plugins目录中,总之就是要3个dll文件都要放到plugins目录中。
CSDN社区的IT牛人,各种问题各种解决,谢谢大家!