TEngine框架学习 SQLite存档模块

本文章都是建立在Winodws平台下测试的,其他平台是否同样适用还未进行验证。
TE框架还在更新中,未来可能有较大变动。

TEngine: 6.1.3

前言

所有的功能和代码的演示都是基于以下项目演示的,欢迎大家参考。
GitHub: 基于TEngine框架实现的塔防Demo

本文章的代码也参考了下面这篇文章Unity3D游戏开发之SQLite让数据库开发更简单 ,这篇文章很好的阐述了为什么选择SQLite和Unity中导入SQLite的基本操作,推荐大家看看。

TEngine本身没有存档模块,其他大佬也有使用EasySave3插件的,这也是一个很好的选择。这里博主使用SQLite的目的很简单,对于大多数中小型项目,SQLite足够了,主打的就是为一个成熟可靠。

DLL下载和引入

需要三个DLL,分别是:

  • sqlite3.dll
  • Mono.Data.Sqlite.dll
  • System.Data.dll

sqlite3.dll可以从SQLite官方网站下载,可以根据需要下载相应的平台,如果是多平台开发则会有复数个。

为了能在Unity中使用SQLite,除了DLL文件外,我们还需要System.Data.dll和Mono.Data.Sqlite.dll这两个动态链接库,这两个链接库在unity的安装目录里找到,这里给一个参考链接:

1
C:\xxx\Unity\Hub\Editor\2022.xxx\Editor\Data\MonoBleedingEdge\lib\mono\unityjit-win32

将上面的的DLL放入Plugins即可。

文件夹构造

代码实现

总共三个脚本即可,分别是SQLiteHelperISaveModuleSaveModule,其中SQLiteHelper脚本是SQLite增删改查和链接数据库的实现,ISaveModule定义了Module的接口,SaveModule是实现具体的方法。其中ISaveModule还包含PlayerPrefs的封装。

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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using System.Collections;
using Mono.Data.Sqlite;
using System;

namespace TEngine
{
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);
}
}
}
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TEngine
{
public interface ISaveModule
{
public void RemoveAllKey();

public int GetInt(string key, int defaultValue = 0);
public float GetFloat(string key, float defaultValue);
public string GetString(string key, string defaultValue);
public bool GetBool(string key, bool defaultValue);
public void SetInt(string key, int value);
public void SetFloat(string key, float value);
public void SetString(string key, string value);
public void SetBool(string key, bool value);

public void RemoveKey(string key);

public int GetIntLocal(string key, int defaultValue = 0);
public float GetFloatLocal(string key, float defaultValue);
public string GetStringLocal(string key, string defaultValue);
public bool GetBoolLocal(string key, bool defaultValue);
public void SetIntLocal(string key, int value);
public void SetFloatLocal(string key, float value);
public void SetStringLocal(string key, string value);
public void SetBoolLocal(string key, bool value);

public void RemoveKeyLocal(string key);
}
}
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TEngine
{
public class SaveModule : Module, ISaveModule
{
/// <summary>
/// SQLite数据库辅助类
/// </summary>
private SQLiteHelper sql;

public override void OnInit()
{
string dbPath = "URI=file:" + Application.persistentDataPath + "/save.db";
sql = new SQLiteHelper(dbPath);

// 检查是否存在表
var reader = sql.ExecuteQuery("SELECT name FROM sqlite_master WHERE type='table' AND name='SaveTable';");
if (!reader.HasRows)
{
sql.CreateTable(
"SaveTable",
new string[] { "Key", "Value", "Type" },
new string[] { "TEXT PRIMARY KEY", "TEXT", "TEXT" }
);
Debug.Log("✅ 创建数据表 SaveTable 成功");
}
else
{
Debug.Log("✅ 数据表 SaveTable 已存在,跳过创建");
}
reader.Close();
}

public override void Shutdown()
{
if (sql != null)
{
sql.CloseConnection();
sql = null;
}
}

private void SetValue(string key, string value, string type)
{
// 先检查是否存在
var reader = sql.ExecuteQuery($"SELECT key FROM SaveTable WHERE key='{key}'");
bool exists = reader.Read();
reader.Close();

if (exists)
{
sql.ExecuteQuery($"UPDATE SaveTable SET value='{value}', type='{type}' WHERE key='{key}'");
}
else
{
sql.ExecuteQuery($"INSERT INTO SaveTable (key, value, type) VALUES ('{key}', '{value}', '{type}')");
}
}

private string GetValue(string key)
{
var reader = sql.ExecuteQuery($"SELECT value FROM SaveTable WHERE key='{key}'");
string result = null;
if (reader.Read())
{
result = reader["value"].ToString();
}
reader.Close();
return result;
}

public void RemoveAllKey()
{
// 清空数据库
sql.ExecuteQuery("DELETE FROM SaveTable");

// 清空 PlayerPrefs
PlayerPrefs.DeleteAll();
PlayerPrefs.Save();
}

public int GetInt(string key, int defaultValue = 0)
{
string v = GetValue(key);
if (int.TryParse(v, out int result)) return result;
return defaultValue;
}

public float GetFloat(string key, float defaultValue = 0)
{
string v = GetValue(key);
if (float.TryParse(v, out float result)) return result;
return defaultValue;
}

public string GetString(string key, string defaultValue = null)
{
string v = GetValue(key);
return string.IsNullOrEmpty(v) ? defaultValue : v;
}

public bool GetBool(string key, bool defaultValue = false)
{
string v = GetValue(key);
if (v == null) return defaultValue;
return v == "1" || v.ToLower() == "true";
}

public void SetInt(string key, int value)
{
SetValue(key, value.ToString(), "int");
}

public void SetFloat(string key, float value)
{
SetValue(key, value.ToString(), "float");
}

public void SetString(string key, string value)
{
SetValue(key, value, "string");
}

public void SetBool(string key, bool value)
{
SetValue(key, value ? "1" : "0", "bool");
}

public void RemoveKey(string key)
{
sql.ExecuteQuery($"DELETE FROM SaveTable WHERE key='{key}'");
}


public int GetIntLocal(string key, int defaultValue = 0)
{
return PlayerPrefs.GetInt(key, defaultValue);
}

public float GetFloatLocal(string key, float defaultValue = 0)
{
return PlayerPrefs.GetFloat(key, defaultValue);
}

public string GetStringLocal(string key, string defaultValue = null)
{
return PlayerPrefs.GetString(key, defaultValue);
}

public bool GetBoolLocal(string key, bool defaultValue = false)
{
return PlayerPrefs.GetInt(key, defaultValue ? 1 : 0) == 1;
}

public void SetIntLocal(string key, int value = 0)
{
PlayerPrefs.SetInt(key, value);
}

public void SetFloatLocal(string key, float value = 0)
{
PlayerPrefs.SetFloat(key, value);
}

public void SetStringLocal(string key, string value = null)
{
PlayerPrefs.SetString(key, value);
}

public void SetBoolLocal(string key, bool value = false)
{
PlayerPrefs.SetInt(key, value ? 1 : 0);
}

public void RemoveKeyLocal(string key)
{
PlayerPrefs.DeleteKey(key);
}
}
}

GameModule脚本中仿照其他模块接入,Shutdown中同样要记得清除。

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
/// <summary>
/// 获取存档模块
/// </summary>
public static ISaveModule Save => _save ??= Get<ISaveModule>();

private static ISaveModule _save;

public static void Shutdown()
{
Log.Info("GameModule Shutdown");

_base = null;
_debugger = null;
_fsm = null;
_procedure = null;
_resource = null;
_audio = null;
_ui = null;
_scene = null;
_timer = null;
_localization = null;
_entity = null;
_save = null; // Shutdown中要调用清除

Application.Quit();
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#endif
return;
}

下面的例子中有SQLite

1
2
3
4
5
6
7
// 使用PlayerPrefs存储和读取数据
GameModule.Save.SetIntLocal("TestKey", 100);
int test = GameModule.Save.GetIntLocal("TestKey");

// 使用SQLite存储和读取数据
GameModule.Save.SetIntLocal("TestKey2", 100);
int test2 = GameModule.Save.GetIntLocal("TestKey2");

TEngine框架学习 SQLite存档模块
https://blog.meo39.com/2025/10/10/TEngineLean5/
作者
daydayasobi
发布于
2025年10月10日
许可协议