http://blog.csdn.net/qinyuanpei/article/details/46812655
php
各位朋友你們好,歡迎你們關注個人博客,我是秦元培,我是博客地址是http://blog.csdn.net/qinyuanpei。在經歷了一段時間的忙碌後,博主終於有時間來研究新的東西啦,今天博客向和你們一塊兒交流的內容是在Unity3D遊戲開發中使用SQLite進行數據庫開發,坦白來說,在個人技術體系中Web和數據庫是相對薄弱的兩個部分,所以正好這段時間項目須要和服務器、數據庫進行交互,所以在接下來的文章中博主可能會更加傾向於講解這方面的內容,但願你們可以喜歡啊!java
SQLite是一款輕型的數據庫,是遵照ACID的關係型數據庫管理系統,它包含在一個相對小的C庫中,以嵌入式做爲它的設計目標,它佔用資源很是的低,所以適合在嵌入式設備如Android、Ruby on Rails等中使用。它可以支持Windows/Linux/Unix等等主流的操做系統,同時可以跟和C、C++、Ruby、Python、C#、PHP、Java等編程語言相結合。SQLite是一個以文件形式存在的關係型數據庫,儘管沒法實現分佈式和橫向擴展,但是做爲一個輕量級的嵌入式數據庫,它不須要系統提供服務支持,經過SDK直接操做文件避免了對數據庫維護的相關事務,從這個角度來說它是一個出色的數據庫。python
好了,在瞭解了SQLite後,咱們來了解下SQLite有哪些讓咱們心動的特性,或者說咱們爲何要選擇SQLite,由於在這個世界上咱們有太多的數據庫能夠選擇,諸如Oracle、MySQL、SQLServer、DB二、NoSQL、MongoDB等等:mysql
- ACID事務
- 零配置 – 無需安裝和管理配置
- 儲存在單一磁盤文件中的一個完整的數據庫
- 數據庫文件能夠在不一樣字節順序的機器間自由的共享
- 支持數據庫大小至2TB
- 足夠小, 大體13萬行C代碼, 4.43M
- 比一些流行的數據庫在大部分普通數據庫操做要快—SQLite讀寫效率如此之高,會使用其餘數據庫的理由是?
- 簡單, 輕鬆的API
- 包含TCL綁定, 同時經過Wrapper支持其餘語言的綁定
- 良好註釋的源代碼, 而且有着90%以上的測試覆蓋率
- 獨立: 沒有額外依賴
- 源碼徹底的開源, 你能夠用於任何用途, 包括出售它
- 支持多種開發語言,C, C++, PHP, Perl, Java, C#,Python, Ruby等
在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或者類都定義在這兩個文件當中,這些文件能夠從這裏直接下載。linux
PS:博主注意到在網上有使用Mono.Data.SQLiteClient.dll這個庫實如今Unity3D操做SQLite數據庫的相關文章,博主大概看了下,感受和使用Mono.Data.Sqlite.dll這個庫大同小異,你們喜歡哪一個就用哪一個吧!哈哈!博主在開源社區找到一個版本庫,聽說能夠同時支持.NET和Mono,若是你們感興趣歡迎你們去測試啊,哈哈!android
在正式開始寫代碼前,咱們首先來回顧下一般狀況下數據庫讀寫的基本流程吧!ios
- 定義數據庫鏈接字符串(ConnectionString)完成數據庫鏈接的構造,創建或者打開一個數據庫。
- 定義相關的SQL命令(Command)經過這些命令實現對數據庫的增長、刪除、更新、讀取四種基本功能。
- 在完成各類數據庫操做後及時關閉數據庫鏈接,解除對數據庫的鏈接和引用。
SQLite做爲一款優秀的數據庫,在爲其編寫數據庫相關代碼時一樣遵循這樣的流程,考慮到對數據庫的增長、刪除、更新、讀取四種操做具備相似性和統一性,所以在動手寫Unity3D腳本前,首先讓咱們來編寫一個SQLite的輔助類SQLiteHelper.cs。該類代碼定義以下:sql
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#進行重寫,我在此基礎上進行了完善,再此對兩位大神的無私付出表示感謝。這裏要說明的有三點:mongodb
1、在Unity3D編輯器下生成數據庫文件(.db)默認位於和Assets目錄同級的位置,即項目的工程文件夾中。咱們能夠經過修改路徑在改變數據庫文件的存儲位置,具體來說:
Windows平臺:data source=Application.dataPath/數據庫名稱.db
iOS平臺:data source=Application.persistentDataPath/數據庫名稱.db
Android平臺:URL=file:Application.persistentDataPath/數據庫名稱.db(我想說Android平臺就是個奇葩,搞什麼特殊化嘛)數據庫
2、確保Unity3D編輯器中的.NET版本和MonoDevelop中的.NET版本都爲2.0版本,在Unity3D中打包導出的程序可能不會保留數據庫文件,所以須要手動將數據庫文件拷貝到相應的位置,固然更加合理的方案是將數據庫文件存放到StreamingAssets文件夾下,而後在第一次加載遊戲的時候將數據庫文件複製到對應平臺上的存放位置。
3、在使用InsertValues方法時請參考SQLite中字段類型與C#中數據類型的對應關係,博主目前測試了int類型和string類型都沒有什麼問題,更多類型的數據請你們自行測試而後告訴博主測試的結果,若是你們有興趣擴展這個輔助類的話能夠自行去擴展哦,嘿嘿!
好了,千呼萬喚始出來的時候到了,下面咱們以一個實例來完成今天的項目講解,由於咱們已經定義好了SQLite的輔助類,所以咱們能夠快速地編寫出下面的腳本代碼:
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數據庫裏的數據,這樣是否是比較方便呢?哈哈!這個工具能夠從這裏下載哦!
好了,今天的內容就是這樣了,爲了寫這篇文章花了三個晚上準備,但願你們喜歡啊!若是你們以爲這篇文章有用,請繼續關注個人博客,我是秦元培,個人博客地址是http://blog.csdn.net/qinyuanpei。
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"路徑便可