Unity数据存储Sqlite的使用
Sqlite是一个SQL数据库引擎。
之前的项目中基本都是使用PlayerPrefs来存储数据,但是由于后期数据结构复杂的情况下,比如存储一个List的结构数据,通常是自己控制写法添加逗号,分号来将数据分隔开。如果哪里写错了,整个数据就会错位导致数据错乱,维护起来非常麻烦。由于服务器的数据存储都是使用数据库SQL,因此打算在前端也使用数据库存储数据。
转移项目出现的SQLITE错误
提示DLLNOT丢失SQLITE,去官网重新下载SQLITE.DLL,官网https://www.sqlite.org/download.html
在项目目录Assets\Plugins下创建下面两个文件夹,并将对应的DLL放入文件夹内
项目发布问题
1、plugins下的dll文件包括I18N.dll,I18N.CJK.dll,I18N.West.dll,Mono.Data.Sqlite.dll,System.Data.dll,sqlite3.dll,这几个dll文件
发布后,需要将db文件手动拷贝到发布后的Data文件夹下,路径应和项目里的路径一致,切记,切记,切记!
2.安卓环境下的一些问题。
鉴于上面遇到了无法关联库文件的问题,我在安卓手平台下做了一些测试,发现运行中会抛出和上面一样的异常,这是因为sqlite3.dll在安卓环境下不能用的,需要的是.so文件
前期准备
要在Unity中使用Sqlite需要将Mono.Data.Sqlite.dll,System.Data.dll, Sqlite3.dll 三个文件放入Plugins文件夹下。
1 | Mono.Data.Sqlite.dll |
在Unity的Editor安装目录下“ Editor\Data\Mono\lib\mono\2.0\ Mono.Data.Sqlite.dll”
System.Data.dll
在Unity的Editor安装目录下“ Editor\Data\Mono\lib\mono\2.0\ System.Data.dll”
Sqlite3.dll
在Sqlite的官网下载对应的版本即可“ https://www.sqlite.org/download.html ”
下载一个数据库查看软件Navicat Premium,通过它创建一个数据库database.db,将其放入Unity的“StreamingAssets”目录下。
数据库一般是增删改查这几项功能。
新建SqliteConnection,SqliteCommand,SqliteDataReader三个变量。
1 2 3 4 5 6 7 8 9 10 11 12 | /// /// 数据库连接 /// private SqliteConnection SqlConnection; /// /// 数据库命令 /// private SqliteCommand SqlCommand; /// /// 数据库读取 /// private SqliteDataReader SqlDataReader; |
建立数据库连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /// /// 建立数据库连接 /// public SqlData() { try { SqlConnection = new SqliteConnection(GetDataPath(PATH_DATABASE)); SqlConnection.Open(); SqlCommand = SqlConnection.CreateCommand(); } catch (System.Exception e) { Debug.Log(e.ToString()); } } |
执行查询语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /// /// 执行SQL语句 /// /// /// public SqliteDataReader ExecuteReader( string command) { #if UNITY_EDITOR Debug.Log( "SQL:ExecuteReader " + command); #endif SqlCommand.CommandText = command; SqlDataReader = SqlCommand.ExecuteReader(); return SqlDataReader; } |
创建表格
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 | /// /// 创建表格 /// /// /// public void SQL_CreateTable(List< string > col, List< string > colType) { // CREATE TABLE table_name(column1 type1, column2 type2, column3 type3,...); if (col.Count != colType.Count) { Debug.LogError( "col Count != col Type Count." ); return ; } StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "Create Table " ); stringBuilder.Append(tableName); stringBuilder.Append( " (" ); for ( int i = 0; i < col.Count; i++) { stringBuilder.Append(col[i]); stringBuilder.Append( " " ); stringBuilder.Append(colType[i]); if (i != col.Count - 1) { stringBuilder.Append( "," ); } } stringBuilder.Append( ")" ); ExecuteNonQuery(stringBuilder.ToString()); } |
插入
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 | /// /// 插入 /// /// /// /// public void SQL_Insert_String( string key, string value) { // INSERT INTO table_name(column1, column2, column3,...) VALUES(value1, value2, value3,...); StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "insert into " ); stringBuilder.Append(tableName); stringBuilder.Append( " (" ); stringBuilder.Append(_KEY); stringBuilder.Append( "," ); stringBuilder.Append(_VALUE_TYPE); stringBuilder.Append( "," ); stringBuilder.Append(_VALUE_STRING); stringBuilder.Append( ") values ('" ); stringBuilder.Append(key); stringBuilder.Append( "'," ); stringBuilder.Append((( int )EDataType.String).ToString()); stringBuilder.Append( ",'" ); stringBuilder.Append(value); stringBuilder.Append( "')" ); ExecuteNonQuery(stringBuilder.ToString()); } |
删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | /// /// 删除 /// /// /// public void SQL_Delete( string key) { // DELETE FROM table_name WHERE some_column = some_value; StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "delete from " ); stringBuilder.Append(tableName); stringBuilder.Append( " where " ); stringBuilder.Append(_KEY); stringBuilder.Append( " = '" ); stringBuilder.Append(key); stringBuilder.Append( "'" ); ExecuteNonQuery(stringBuilder.ToString()); } |
更新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /// /// 更新 /// /// /// /// public void SQL_Update_String( string key, string value) { // UPDATE table_name SET column1 = value1, column2 = value2,... WHERE some_column = some_value; StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "update " ); stringBuilder.Append(tableName); stringBuilder.Append( " set " ); stringBuilder.Append(_VALUE_STRING); stringBuilder.Append( "='" ); stringBuilder.Append(value); stringBuilder.Append( "' where " ); stringBuilder.Append(_KEY); stringBuilder.Append( "='" ); stringBuilder.Append(key); stringBuilder.Append( "'; " ); ExecuteNonQuery(stringBuilder.ToString()); } |
查找
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /// /// 查找 /// /// /// public bool SQL_Select( string key) { StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "select " ); stringBuilder.Append(key); stringBuilder.Append( " from " ); stringBuilder.Append(tableName); try { SqlDataReader = ExecuteReader(stringBuilder.ToString()); if (SqlDataReader != null ) return true ; } catch (System.Exception e) { Debug.LogError(e.ToString()); } return false ; } |
表格是否存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /// /// 表格是否存在 /// /// /// public bool ExistTable( string tableName) { // SELECT COUNT(*) FROM sqlite_master; StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "SELECT COUNT(*) FROM sqlite_master where type='table' and name='" ); stringBuilder.Append(tableName); stringBuilder.Append( "';" ); return ExecuteScalar(stringBuilder.ToString()); } |
数据库在不同平台下的路径
1 2 3 4 5 6 7 8 9 10 11 12 | public string GetDataPath( string databasePath) { #if UNITY_EDITOR return StringUtil.Concat( "data source=" , Application.streamingAssetsPath, "/" , databasePath); #endif #if UNITY_ANDROID return StringUtil.Concat( "URI=file:" , Application.persistentDataPath, "/" , databasePath); #endif #if UNITY_IOS return StringUtil.Concat( "data source=" , Application.persistentDataPath, "/" , databasePath); #endif } |
由于数据在表格中,因此我们需要使用一个HashTable来存储这些数据,一开始先载入数据库,然后读取出里面的所有数据将其存入HashTable中,后面增删改查的时候不仅针对HashTable进行操作,还要针对数据库进行操作。
1 | private Hashtable dataHashTable = new Hashtable(); |
我们存储数据的时候不一定都是String类型,同时还需要Int,Long,Float等类型,因此需要预先设置好数据库的列名,同时还需要一个数据类型字段来表明存储的数据类型,具体如下
1 2 3 4 5 6 7 | private enum EDataType { String = 1, Int = 2, Long = 3, Float = 4, } |
加载表格
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 | public void LoadData() { if (!ExistTable(tableName)) { //table 不存在 SQL_CreateTable(COL_NAMES, COL_TYPES); return ; } StringBuilder stringBuilder = StringUtil.GetShareStringBuilder(); stringBuilder.Append( "select * from " ); stringBuilder.Append(tableName); SqliteDataReader dataReader = ExecuteReader(stringBuilder.ToString()); while (dataReader.Read()) { string key = dataReader.GetString(dataReader.GetOrdinal(_KEY)); int dataType = dataReader.GetInt32(dataReader.GetOrdinal(_VALUE_TYPE)); switch ((EDataType)dataType) { case EDataType.Float: dataHashTable[key] = dataReader.GetFloat(dataReader.GetOrdinal(_VALUE_TYPE)); break ; case EDataType.Int: dataHashTable[key] = dataReader.GetInt32(dataReader.GetOrdinal(_VALUE_INT)); break ; case EDataType.Long: dataHashTable[key] = dataReader.GetInt64(dataReader.GetOrdinal(_VALUE_LONG)); break ; case EDataType.String: dataHashTable[key] = dataReader.GetString(dataReader.GetOrdinal(_VALUE_STRING)); break ; default : break ; } } dataReader.Close(); } |
设置Value
1 2 3 4 5 6 7 8 9 10 11 12 | public void SetValue_String( string key, string value) { if (ContainsKey(key)) { SQL_Update_String(key, value); } else { SQL_Insert_String(key, value); } dataHashTable[key] = value; } |
删除Value
1 2 3 4 5 6 7 8 | public void DeleteValue( string key) { if (dataHashTable.ContainsKey(key)) { dataHashTable.Remove(key); } SQL_Delete(key); } |
关闭数据库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /// /// 关闭数据库 /// public void Close() { if (SqlCommand != null ) { SqlCommand.Dispose(); SqlCommand = null ; } if (SqlDataReader != null ) { SqlDataReader.Close(); SqlDataReader = null ; } if (SqlConnection != null ) { SqlConnection.Close(); SqlConnection = null ; } } |
整个数据库相关操作已经完成,新建一个SqlManager统一管理即可
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 | using System; using System.Collections.Generic; namespace SQL { public enum ESqlType { Player, } public class SqlManager { private static SqlManager _Instance; public static SqlManager Instance { get { if (_Instance == null ) { _Instance = new SqlManager(); } return _Instance; } } private SqlPlayerData playerDataBase; private Dictionary<esqltype, sqldata= "" > sqlDatas = new Dictionary<esqltype, sqldata= "" >(); public void OnAwake() { sqlDatas.Clear(); sqlDatas.Add(ESqlType.Player, new SqlPlayerData( string .Empty)); } public void OnDestroy() { Dictionary<esqltype, sqldata= "" >.Enumerator enumerator = sqlDatas.GetEnumerator(); while (enumerator.MoveNext()) { enumerator.Current.Value.Close(); } enumerator.Dispose(); } public void SetString(ESqlType eSqlType, string key, string values) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { sqlData.SetValue_String(key, values); } } public void SetInt(ESqlType eSqlType, string key, int value) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { sqlData.SetValue_Int(key, value); } } public void SetLong(ESqlType eSqlType, string key, long value) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { sqlData.SetValue_Long(key, value); } } public void SetFloat(ESqlType eSqlType, string key, float value) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { sqlData.SetValue_Float(key, value); } } public string GetString(ESqlType eSqlType, string key, string defaultValue = "" ) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { return sqlData.GetValue_String(key, defaultValue); } return defaultValue; } public int GetInt(ESqlType eSqlType, string key, int defaultValue = 0) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { return sqlData.GetValue_Int(key, defaultValue); } return defaultValue; } public float GetFloat(ESqlType eSqlType, string key, float defaultValue = 0) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { return sqlData.GetValue_Float(key, defaultValue); } return defaultValue; } public long GetLong(ESqlType eSqlType, string key, long defaultValue = 0) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { return sqlData.GetValue_Long(key, defaultValue); } return defaultValue; } public void DeleteValue(ESqlType eSqlType, string keys) { SqlData sqlData; if (sqlDatas.TryGetValue(eSqlType, out sqlData)) { sqlData.DeleteValue(keys); } } } }</esqltype,></esqltype,></esqltype,> |
由于使用的时候需要调用的函数名太长,可以新建一个工具类封装一下
测试函数
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 | using UnityEngine; namespace SQL { public class TestSqlData : MonoBehaviour { private void Awake() { SqlManager.Instance.OnAwake(); } private void OnDestroy() { SqlManager.Instance.OnDestroy(); } // Use this for initialization void Start() { SaveUtil.SetString( "name" , "onelei" ); SaveUtil.SetInt( "score" , 99); Debug.Log( "name的值为 " + SaveUtil.GetString( "name" )); Debug.Log( "score的值为 " + SaveUtil.GetString( "score" )); //SaveUtil.DeleteValue("score"); Debug.Log( "score的值为 " + SaveUtil.GetInt( "score" )); } } } |
运行Unity,发现表格数据已经生成
同时通过C#,也将数据读取了出来
具体源码可以通过Github查看: https://github.com/onelei/SqlManager
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了