第八节_我的日记本开发手记(8)——sqlite数据库与c#
一、SQLite介紹
(一)基本介紹
1. 數據庫(database,DB):一個以某種有組織的方式存儲的數據集合。數據庫中的數據按一定的數學模型組織、描述和存儲,具有較小的冗余,較高的數據獨立性和易擴展性,并可為各種用戶共享。
SQLite:是一個進程內的庫,是遵守ACID的關聯式數據庫管理系統,實現了自給自足的、無服務器的、零配置的、事務性的 SQL 數據庫引擎。它的設計目標是嵌入式的,而且目前已經在很多嵌入式產品中使用了它,它占用資源非常的低,在嵌入式設備中,可能只需要幾百K的內存就夠了。它是一個零配置的數據庫,這意味著與其他數據庫不一樣,您不需要在系統中配置。
2. ACID具有:
(1) 原子性:同一個事物的2個步驟同時進行,一榮俱榮,一損俱損;一致性:一個事務操作前后狀態一致;持久性:事務結束后數據不隨外界原因導致數據丟失;隔離性:多個事務同時進行互不影響。
(2) 隔離級別:臟讀:一個事務讀取另一個事務未提交的數據;
不可重復讀:在一個事務內讀取表中的某一行數據,多次讀取結果不同(這個不一定是錯誤,只是某些場合不對);虛讀:是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取不一致(一般是行影響,多了一行)。
優點:嵌入式,關系型數據庫(采用了關系模型來組織數據的數據庫),速度快。
(二)存儲數據類型
1. 存儲類型
SQLite將數據值的存儲劃分為以下幾種存儲類型:
| NULL | 值是一個 NULL 值。 |
| INTEGER | 值是一個帶符號的整數,根據值的大小存儲在 1、2、3、4、6 或 8 字節中。 |
| REAL | 值是一個浮點值,存儲為 8 字節的 IEEE 浮點數字。 |
| TEXT | 值是一個文本字符串,使用數據庫編碼(UTF-8、UTF-16BE 或 UTF-16LE)存儲。 |
| BLOB | 值是一個 blob 數據,完全根據它的輸入存儲。 |
2. 親和類型
SQLite支持列的親和類型概念,任何列仍然可以存儲任何類型的數據,當數據插入時該字段的數據將會優先采用親和類型作為該值的存儲方式。創建 SQLite3 表時可使用的各種數據類型名稱及相應的親和類型,如下:
| INT,INTEGER,TINYINT,SMALLINT,MEDIUMINT,BIGINT,UNSIGNED BIG INT,INT2,INT8 | INTEGER:對于親緣類型為INTEGER的字段,其規則等同于NUMERIC,唯一差別是在執行CAST表達式時。 |
| CHARACTER(20),VARCHAR(255),VARYING CHARACTER(255),NCHAR(55),NATIVE CHARACTER(70),NVARCHAR(100),TEXT,CLOB | TEXT:數值型數據在被插入之前,需要先被轉換為文本格式,之后再插入到目標字段中 |
| BLOB,no datatype specified | NONE:不做任何的轉換,直接以該數據所屬的數據類型進行存儲。 |
| REAL,DOUBLE,DOUBLE PRECISION,FLOAT | REAL:其規則基本等同于NUMERIC,唯一的差別是不會將"30000.0"這樣的文本數據轉換為INTEGER存儲方式。 |
| NUMERIC,DECIMAL(10,5),BOOLEAN,DATE,DATETIME | NUMERIC 當文本數據被插入到親緣性為NUMERIC的字段中時:如果轉換操作不會導致數據信息丟失以及完全可逆,那么SQLite就會將該文本數據轉換為INTEGER或REAL類型的數據;如果轉換失敗,SQLite仍會以TEXT方式存儲該數據。對于NULL或BLOB類型的新數據,SQLite將不做任何轉換,直接以NULL或BLOB的方式存儲該數據。注:對于浮點格式的常量文本,如"30000.0",如果該值可以轉換為INTEGER同時又不會丟失數值信息,那么SQLite就會將其轉換為INTEGER的存儲方式。 |
二、可視化管理工具SQLiteStudio使用
對于sqlite數據庫的可視化管理工具,我推薦使用sqlitestudio,綠色單文件,體積小,功能強大,比起其它SQLite管理工具,我喜歡用這個。很方便易用,不用安裝的單個可執行文件,支持中文。
(一)下載
首先去官網下載(官網下載地址:https://sqlitestudio.pl/),如圖1;
圖1
下載并解壓,直接運行SQLiteStudio.exe文件,界面如圖2所示。
圖2
(二)新建數據庫
單擊菜單Database->Add a database(如圖3),
圖3
彈出數據庫屬性對話框,如圖4,
圖4
單擊綠色加好,選擇數據庫保存位置,并添加數據名稱為MythDiary.db,結果如圖5所示。
圖5
(三)新建表格
步驟2完成后,在左側的列表中會出現我們剛才新建的數據庫,如圖6所示。
圖6
在數據庫上單擊右鍵,選擇Connect to the database,鏈接數據庫,如圖7所示;
圖7
展開數據庫,會出現連個菜單,一是Tables,一個是Views,在Tables上單擊右鍵選擇Create Table新建表格,如圖8所示。
圖8
在右側會出現表格屬性設置界面,如圖9所示,在這個界面我們可以設置表格的字段和表格的名稱。
圖9
先在表格名稱里面輸入adminuser,然后單擊操作工具欄上的綠色打鉤按鈕進行保存(如圖10),這樣表格就已經保存成功,這里特別說明一下:
“WITHOUT ROWID”這個復選框:在SQLiteStudio中,我們新建一個表格,如果這個復選框不被選擇,SQLiteStudio會自動給表格添加一個字段RowID,這個字段是一個隱含的字段,自動加一;如果選擇不會添加這個隱形字段。
(四)添加字段。
保存完成后,單擊操作工具欄上的添加字段按鈕,彈出字段屬性對話框,如圖11所示,在這里我們可以設置字段名稱,數據類型、大小等。目前我們需要完成3個表格的設計,一個是adminuser表格,一個是DiaryType,最后一個是Articles,具體字段如下:
1. DiaryType 數據字段
| TypeName | VARCHAR | 分類名稱 | |
| ParentID | INT | 父類ID | |
| TypeIcon | VARCHAR | 分類小圖標 | |
| CreateTime | DATETIME | DEFAULT (datetime(‘now’, ‘localtime’) ) | 創建時間 |
2. Articles數據字段
| Title | VARCHAR | 標題 | |
| Content | TEXT | 內容 | |
| Pic | VARCHAR | 文章圖片 | |
| KeyWord | VARCHAR | 文章關鍵字 | |
| Desc | VARCHAR | 文章描述 | |
| UserID | INT | 0 | 作者ID |
| CreateTime | DATETIME | DEFAULT (datetime(‘now’, ‘localtime’) ) | 創建時間 |
| EditTime | DATETIME | DEFAULT (datetime(‘now’, ‘localtime’) ) | 修改時間 |
| ViewCount | INT | 0 | 查看次數 |
| State | INT | 0 | 文章狀態,0表示不公開;1表示公開 |
| IsBackUp | INT | 0 | 是否備份到服務器:0未備份;1已備份 |
3. Adminuser 數據字段
| UserName | VARCHAR | 用戶名稱 | |
| PassWord | VARCHAR | 用戶密碼 | |
| HeadPic | VARCHAR | 用戶頭像照片地址 | |
| OneKey | VARCHAR | 一句話宣言 | |
| CreateTime | DATETIME | DEFAULT (datetime(‘now’, ‘localtime’) ) | 創建時間 |
| LastLoginTime | DATETIME | DEFAULT (datetime(‘now’, ‘localtime’) ) | 最后登錄時間 |
三、c#操作sqlite數據庫
在C#中使用SQLite數據庫需要引用System.Data.SQLite.dll,下載鏈接:http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
注:System.Data.SQLite是SQLite的ADO.NET提供程序,兩者是兩個不同的開源項目,現在System.Data.SQLite的開發和維護工作大部分由SQLite開發團隊執行。
(一)操作基礎類
public class SQLiteHelper {/// <summary>/// 數據庫列表/// </summary>public static Dictionary<string, SQLiteHelper> DataBaceList = new Dictionary<string, SQLiteHelper>();/// <summary>/// 構造函數/// </summary>/// <param name="filename">數據庫文件名</param>public SQLiteHelper(string filename=null) {DataSource = filename; }/// <summary>/// 數據庫地址/// </summary>public string DataSource { get; set; } /// <summary>/// 創建數據庫,如果數據庫文件存在則忽略此操作/// </summary>public void CreateDataBase() {string path = Path.GetDirectoryName(DataSource);if ((!string.IsNullOrWhiteSpace(path)) && (!Directory.Exists(path))) Directory.CreateDirectory(path);if (!File.Exists(DataSource)) SQLiteConnection.CreateFile(DataSource); }/// <summary>/// 獲得連接對象/// </summary>/// <returns>SQLiteConnection</returns> public SQLiteConnection GetSQLiteConnection(){string connStr =string.Format("Data Source={0}", DataSource); var con = new SQLiteConnection(connStr);return con;}/// <summary>/// 準備操作命令參數/// </summary>/// <param name="cmd">SQLiteCommand</param>/// <param name="conn">SQLiteConnection</param>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">參數數組</param>private static void PrepareCommand(SQLiteCommand cmd, SQLiteConnection conn, string cmdText, Dictionary<String, String> data){if (conn.State != ConnectionState.Open)conn.Open();cmd.Parameters.Clear();cmd.Connection = conn;cmd.CommandText = cmdText;cmd.CommandType = CommandType.Text;cmd.CommandTimeout = 30;if (data != null && data.Count >= 1){foreach (KeyValuePair<String, String> val in data){cmd.Parameters.AddWithValue(val.Key, val.Value);}}}/// <summary>/// 查詢,返回DataSet/// </summary>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">參數數組</param>/// <returns>DataSet</returns>public DataSet ExecuteDataset(string cmdText, Dictionary<string, string> data = null){var ds = new DataSet();using (SQLiteConnection connection = GetSQLiteConnection()){var command = new SQLiteCommand();PrepareCommand(command, connection, cmdText, data);var da = new SQLiteDataAdapter(command);da.Fill(ds);}return ds;}/// <summary>/// 查詢,返回DataTable/// </summary>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">參數數組</param>/// <returns>DataTable</returns>public DataTable ExecuteDataTable(string cmdText, Dictionary<string, string> data = null){var dt = new DataTable();using (SQLiteConnection connection = GetSQLiteConnection()){var command = new SQLiteCommand();PrepareCommand(command, connection, cmdText, data);SQLiteDataReader reader = command.ExecuteReader();dt.Load(reader);}return dt;}/// <summary>/// 返回一行數據/// </summary>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">參數數組</param>/// <returns>DataRow</returns>public DataRow ExecuteDataRow(string cmdText, Dictionary<string, string> data = null){DataSet ds = ExecuteDataset(cmdText, data);if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)return ds.Tables[0].Rows[0];return null;}/// <summary>/// 執行數據庫操作/// </summary>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">傳入的參數</param>/// <returns>返回受影響的行數</returns>public int ExecuteNonQuery(string cmdText, Dictionary<string, string> data=null){using (SQLiteConnection connection = GetSQLiteConnection()){var command = new SQLiteCommand();PrepareCommand(command, connection, cmdText, data);return command.ExecuteNonQuery();}}/// <summary>/// 返回SqlDataReader對象/// </summary>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">傳入的參數</param>/// <returns>SQLiteDataReader</returns>public SQLiteDataReader ExecuteReader(string cmdText, Dictionary<string, string> data = null){var command = new SQLiteCommand();SQLiteConnection connection = GetSQLiteConnection();try{PrepareCommand(command, connection, cmdText, data);SQLiteDataReader reader = command.ExecuteReader(CommandBehavior.CloseConnection);return reader;}catch{connection.Close();command.Dispose();throw;}}/// <summary>/// 返回結果集中的第一行第一列,忽略其他行或列/// </summary>/// <param name="cmdText">Sql命令文本</param>/// <param name="data">傳入的參數</param>/// <returns>object</returns>public object ExecuteScalar(string cmdText, Dictionary<string, string> data = null){using (SQLiteConnection connection = GetSQLiteConnection()){var cmd = new SQLiteCommand();PrepareCommand(cmd, connection, cmdText, data);return cmd.ExecuteScalar();}}/// <summary>/// 分頁查詢/// </summary>/// <param name="recordCount">總記錄數</param>/// <param name="pageIndex">頁牽引</param>/// <param name="pageSize">頁大小</param>/// <param name="cmdText">Sql命令文本</param>/// <param name="countText">查詢總記錄數的Sql文本</param>/// <param name="data">命令參數</param>/// <returns>DataSet</returns>public DataSet ExecutePager(ref int recordCount, int pageIndex, int pageSize, string cmdText, string countText, Dictionary<string, string> data = null){if (recordCount < 0)recordCount = int.Parse(ExecuteScalar(countText, data).ToString());var ds = new DataSet();using (SQLiteConnection connection = GetSQLiteConnection()){var command = new SQLiteCommand();PrepareCommand(command, connection, cmdText, data);var da = new SQLiteDataAdapter(command);da.Fill(ds, (pageIndex - 1) * pageSize, pageSize, "result");}return ds;}/// <summary>/// 重新組織數據庫:VACUUM 將會從頭重新組織數據庫/// </summary>public void ResetDataBass(){using (SQLiteConnection conn = GetSQLiteConnection()){var cmd = new SQLiteCommand();if (conn.State != ConnectionState.Open)conn.Open();cmd.Parameters.Clear();cmd.Connection = conn;cmd.CommandText = "vacuum";cmd.CommandType = CommandType.Text;cmd.CommandTimeout = 30;cmd.ExecuteNonQuery();}}}(二)類的使用
static void Main(string[] args) {SQLiteHelper testDb = new SQLiteHelper("test.db");SQLiteHelper.DataBaceList.Add("TEST", testDb);//建庫testDb.CreateDataBase();//建表 StringBuilder sbr = new StringBuilder();sbr.AppendLine("CREATE TABLE IF NOT EXISTS `test_table`(");sbr.AppendLine("`id` INTEGER PRIMARY KEY AUTOINCREMENT,");//自增id主鍵sbr.AppendLine("`name` VARCHAR(100) NOT NULL,");sbr.AppendLine("`password` VARCHAR(40) NOT NULL,");sbr.AppendLine("`create_time` datetime DEFAULT CURRENT_TIMESTAMP,");sbr.AppendLine("`update_time` datetime DEFAULT CURRENT_TIMESTAMP );"); sbr.AppendLine();sbr.AppendLine("CREATE TRIGGER IF NOT EXISTS `trigger_test_table_update_time` ");//觸發器-自動更新update_timesbr.AppendLine("AFTER UPDATE ON `test_table` ");sbr.AppendLine("FOR EACH ROW ");sbr.AppendLine("BEGIN ");sbr.AppendLine("UPDATE `test_table` SET `update_time` = CURRENT_TIMESTAMP WHERE id = old.id; ");sbr.AppendLine("END;");string cmdText = sbr.ToString();int val = testDb.ExecuteNonQuery(cmdText); Console.WriteLine("影響行數:" + val);//增sbr.Clear();sbr.Append("INSERT INTO test_table (name,password) VALUES ");sbr.Append("(11,111), ");sbr.Append("(12,222); ");cmdText = sbr.ToString();val = testDb.ExecuteNonQuery(cmdText);Console.WriteLine("影響行數:" + val);//刪sbr.Clear();sbr.Append("DELETE FROM test_table ");sbr.Append("WHERE id=1;");cmdText = sbr.ToString();val = testDb.ExecuteNonQuery(cmdText);Console.WriteLine("影響行數:" + val);//改sbr.Clear();sbr.Append("UPDATE test_table SET ");sbr.Append("name='13', ");sbr.Append("password='333' ");sbr.Append("WHERE id=@id;");cmdText = sbr.ToString();Dictionary<string, string> data = new Dictionary<string, string>();data.Add("@id", "2"); val = testDb.ExecuteNonQuery(cmdText, data);Console.WriteLine("影響行數:" + val);//查sbr.Clear();sbr.Append("SELECT name,password FROM test_table ");sbr.Append("WHERE id=@id;");cmdText = sbr.ToString();DataTable dt = testDb.ExecuteDataTable(cmdText, data);Console.WriteLine("結果行數:" + dt.Rows.Count); //刪除表sbr.Clear();sbr.Append("DROP TABLE test_table;");cmdText = sbr.ToString();val = SQLiteHelper.DataBaceList["TEST"].ExecuteNonQuery(cmdText);Console.WriteLine("影響行數:" + val);//重組數據庫SQLiteHelper.DataBaceList["TEST"].ResetDataBass();Console.ReadKey(); }(三)sqlite事務
事務定義了一組 SQL 命令,這組命令或者作為一個整體被全部執行,或者都不執行,這被稱為數據庫完整性的原子性原則。這種關系的典型例子就是銀行轉賬,假設銀行程序從一個賬戶向另一個賬戶轉賬,轉賬程序通過如下方式進行:首先將第一個賬戶的錢轉入第二個賬戶,然后從第一個賬戶刪除對應的數目;或者首先從第一個賬戶刪除要轉賬的數目,然后向第二個賬戶插入對應的數目。無論哪種方式,都是通過兩步完成的:先插入,后刪除;或者先刪除,后插入。但是在轉賬期間,如果數據庫服務器突然奔潰或電力中斷,第二個操作沒有完成怎么辦?要么這筆錢存在于兩個賬戶(第一種方式),要么這筆錢在兩個賬戶中都不存在(第二種方式)。無論發生哪種情況,總有人無法接受。數據庫也處于不一致的狀態,關鍵是這兩步操作必須要同時被執行或者一步都不執行。這就是事務的本質。
事務使用代碼:
ok,本節就到這里
我的日記開發系列手記目錄
1.我的日記本開發手記——概述
2.我的日記本開發手記(2)——配色
3.我的日記本開發手記(3)—— 布局
4.我的日記本開發手記(4)—— UI效果圖
5.我的日記本開發手記(5)—— 效果圖轉HTML
6.我的日記本開發手記(6)——Winform運行HTML
7.第七節_我的日記本開發手記(7)——Javascript與c#交互
總結
以上是生活随笔為你收集整理的第八节_我的日记本开发手记(8)——sqlite数据库与c#的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机仿真和计算机应用与软件,计算机应用
- 下一篇: python产生随机整数数组_生成随机整