SQLite简介
SQLite数据库相较于我们常用的Mysql,Oracle而言,实在是轻量得不行(最低只占几百K的内存)。平时开发或生产环境中使用各种类型的数据库,可能都需要先安装数据库服务(server),然后才能通过代码、命令行或者客户端工具来操作数据库,但是SQLite却有点别具一格,它是一个文件型的关系数据库,完全不用你安装,也不需要任何的配置或依赖,去官网下载编译好的二进制文件解压就可以使用——第一次使用时,同事直接拷给我一个文件,说这就是SQLite了,我擦嘞还惊了一下,竟然直接对着文件就能执行CRUD命令,这完全刷新了我对数据库的认知。
而它的官网/When to use SQLite也说得特别明确:SQLite is not directly comparable to client/server SQL database engines such as MySQL, Oracle, or SQL Server since SQLite is trying to solve a different problem。是的,它的出现并不是为了和 Mysql,Oracle等数据库竞争,而是为了解决不同的问题;
那么哪些场景适合使用SQLite,哪些场景又适合client/server型数据库呢?博主本来也想问度娘的,但是发现官网中就有最最合适的解释:Client/server SQL database engines strive to implement a shared repository of enterprise data; SQLite strives to provide local data storage for individual applications and devices。意译过来就是说,client/server型的数据库适合于共享数据的存储—— 一个server端存储数据,N个客户端都可以对数据进行CRUD的操作;而SQLite就完全是一种本地化的文件存储,加之其非常的轻量,特别适合个人应用和设备,所以,你会发现SQLite在嵌入式设备开发比如移动开发中应用得非常广泛。
博主虽然不是做嵌入式开发的,但是用了一下SQLite发现特别小巧好用,建议大家如果应用程序是并发量不是特别高的本地应用,完全可以尝试使用SQLite这种轻量的数据库来代替,也省去了安装繁重的数据库服务对系统资源的占用。好了,现在正式切入正题,跟着布衣博主一起来尝试使用SQLite的一些简单招式——
库文件下载
要使用SQLite数据库,如果没有好同事拷贝给你,就自己去官网下吧。点击官网下载页就可以下载最新的SQLite版本(SQLite3),页面也给出了针对不同平台的下载版本——
对于Windows 64位操作系统,网上的一些教程都是说要把图中的 1 、2 一起下载解压在同一个文件,但是博主不太喜欢盲从,喜欢琢磨原因,一番尝试后发现,其实只需要下载工具压缩包 2 就可以进行正常的数据库操作了,而对于 1 中动态链接库文件的作用,博主也始终没搞明白,在此还望常用Sqlite的高人能指点一二,博主感激不尽!!!
数据库连接
① 命令行
上图中 1 下载的压缩包解压后会有三个文件可执行文件 sqldiff.exe、sqlite3.exe和sqlite3_analyzer.exe,开启cmd切换到解压目录,就可以直接通过sqlite3执行SQL命令来操作数据库。这里要注意,如果直接双击sqlite3打开命令行执行后续命令往往是没有效果的,博主一番尝试也无解;有效的方式是切换到该目录后以 sqlite3 + 数据库名 的方式开始令行,如果数据库存在就会直接使用,不存在就会创建一个新的数据库:
需要说明的是,博主尝试后发现创建的数据库名可以是任意的名字,并不一定是.db 结尾,只不过出于规范化的考量,最好还是加上后缀,这样一看便知是数据库文件。SQLite的命令都是点命令,也就是说都是用 . 开头,并且不以 ; 结尾,使用过程中多熟悉一下就习惯了。这里博主也只是简单演示,具体命令行可以 .help 查看或者通过百度、官网渠道查询,博主不赘述。
② 可视化工具
百度一下,你会发现SQLite有一些专门针对性的可视化连接工具,应该都比较好用,博主没有去尝试过,不过使用通用版的Navicat也可以连接SQLite,本着工具归一的原则,也就没有必要单独去下载其他连接工具了。建立数据库连接也很简单,不同于其他数据库需要IP、端口以及用户名、密码,SQLite只需要找到我们的创建的数据库文件挂载,就相当于连接到相应的数据库了;而新建也很简单,在建库目录下定义好库文件名字就就可以了,下图中1 、2 分别显示了如何连接现有的库文件和创建新的数据库——
看似简单,本来无需多言的,但是爱折腾的布衣博主却有个匪夷所思的发现:使用 Navicat Premium 本进行SQLite的连库和创建新库的过程中,根本不需要依赖自己下载解压的那两个压缩包——新建连接的时候我甚至可以挂载一个txt文件并成功建立起连接,而且能进行正常的数据库SQL操作;创建库的时候我也可以在任意位置创建任意名字、后缀名的数据库,同样能正常SQL操作。这样就有点意思了,也就是说电脑上的一切非目录文件只要你心情好都可以建立连接当成数据库来使用,太腻(bian)害(tai)了吧?博主换了不同的计算机,包括使用Linux系统,尝试过后都是如此,唯一合理的解释就是 Navicat Premium 这厮本身就内置了SQLite数据库引擎,所以才能直接连接以及创建数据库。(其实不管是Windows系统还是Linux系统你都可以在系统用户目录发现Navicat的连接对象文件)
SQLite 的存储类型
学习一个新的数据库,大体从几个方面来了解它——存储结构、操作语言以及支持存储的数据类型。既然SQLite是一种关系型数据库,那么就支持通用的SQL语言,所以你大可将你深厚的SQL功力运用到SQLite身上愉快的进行你的CRUD操作(crud是指在做计算处理时的增加(Create)、读取(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写)(当然,一些内置函数和SQL语法还是有所不同)。
SQLite比较特殊的其实在于它粗放式的数据存储类型,而且并不强制的进行类型约束,这点和其他关系型数据库有很大的不同。如此的结果就是,虽然创建表的时候你指定了某一列应该用什么数据类型,但实际上你是可以胡来的,比如向整型列中插入文本数据,向字符型中插入日期等等
(有个特殊情况就是建表时主键设置若为INTEGER PRIMARY KEY【原文:except an INTEGER PRIMARY KEY column】就只能插入整数,插入其他数据类型会报错)。至于原因,SQLite官网数据类型页面中Datatypes In SQLite段讲得很清楚,博主转述过来就是说:传统的关系型数据库采用的是静态数据类型系统,一个字段值的数据类型由存储其值的列容器决定,而SQLite采用更通用的动态数据类型系统,一个字段的数据类型只与其值本身有关,而与存储它的容器无关。
按照官网描述,SQLite支持的数据类型分为以下 5 个存储类型:
- NULL 空值
- INTEGER 带符号整型,根据其大小存储在1, 2, 3, 4, 6,或 8 字节中
- REAL 浮点型,存储为一个 8 字节的IEEE 浮点数
- TEXT 文本类型 (UTF-8, UTF-16BE 或 UTF-16LE编码格式)
- BLOB 全型(布衣博主自己给的称谓),存什么就是什么
别看只有基本的 5 种存储类型支持,但由于SQLite采用的是动态数据类型系统,而且存储类较之普通的数据类型是更加笼统的包含关系,因此能完全兼容其它静态数据类型系统的关系型数据库。
但是这种太自由化的存储还是有些问题的,比如一个数据列我同时存了一个 400 整型值和 '500' 的文本类型值,这两个值数据类型不一样,我这么比较?所以,根据SQLite官网的说法,为了最大限度与其他关系型数据库兼容,SQLite对数据类型进行了很精巧的设计,就是让数据列具有类型亲和性的特性(其实博主更喜欢某些人翻译的 类型近似 这种叫法)。当我们创建表做字段类型声明的时候,实际上只是表明了该列具有的近似类型,在正式插入数据的时候,SQLite引擎才会基于该列的近似类型优先推荐使用 5 种存储类型中的哪一种来存储你的数据——注意是推荐,并不强制,也就是说只要你想要乱搞,SQLite也并不会限制你,SQLite是列自由的。所以,建表时字段类型声明的限制在SQLite中是被弱化了的。在最新的SQLite版本中,数据库的每一列都被定义为以下 5 种近似类型的一种,其定义和规则官网/Determination Of Column Affinity段中有做出解释:
- INTEGER 整型,如果声明的字段类型包含字符串“INT”(注意,SQLite大多数情况都不区分大小写,下同),那么该字段类型被分配为INTEGER 近似类型;
- TEXT 文本,如果为字段声明的类型中包含了'CHAR'、'CLOB'或'TEXT',该字段被分配为TEXT亲和性。比如'VARCHAR'包含了'CHAR',所以被分配为TEXT 近似类型;
- BLOB 无类型,如果为字段声明的类型中包含了'BLOB',或者没有为该字段声明类型,该字段被分配为BLOB 近似类型;
- REAL 浮点型,如果为字段声明的类型中包含了'REAL'、'FLOA'或'DOUB',则该字段被分配为REAL 近似类型;
- NUMERIC 数值型,除以上情况外的类型,则被分配为NUMERIC 近似类型。
官网上/Affinity Name Examples段落中有一份表格罗列了传统数据类型作为子集与上述 5 种近似类型如何对应的关系。基于上述近似类型的列叙,可以看出SQLite是从声明类型的字符串中去匹配列的近似类型来决定数据的存储类的,因此SQLite很有意思的是创建表时类型声明可以很随意,比如我可以声明一个不存在类型的字符串”chenbenbuyi”,但SQLite会根据规则自动识别为NUMERIC的近似类型,并据此近似类型存储我的数据——
可能有些人对于上面的数据存储类还是有些疑惑——根据列的近似类型是如何推断数据存入后的最终类型呢?按博主的理解,SQLite在基于类型近似做数据存储转换的时候是有个推荐优先级的。比如上面的声明中,并不存在name声明的数据类型,所以数据库会自动匹配为NUMERIC的近似类型。当文本数据('23')被插入到该列时,如果转换操作不会导致数据信息丢失以及完全可逆,那么SQLite就会将该文本数据优先转换为INTEGER或REAL类型的数据(NULL或BLOB类型数据不做转换),转换不成功才会按照文本数据存储——这里能转换INTEGER成功;如果存储列的近似类型为TEXT,那么自然数据存储的优先存储类是TEXT,所以哪怕你存储的是整型数字,结果存的依然是TEXT。这就是类型近似在数据存储中的应用。
代码连接数据库
代码连接比较基础简单,博主简单操作一盘,权当复习,虽然实际项目中很少用得这么基础。基本上呢,代码操作数据库的步骤可以概括为:加载驱动、获取连接、创建预编译对象、执行SQL、释放资源,顺口溜一句就是“贾琏欲执释”。按照这个步骤,首先是要下载SQLite的驱动程序包,将包添加到IDE中并Build Path,然后愉快的撸码操作——
1 import java.sql.*; 2 3 public class SQLiteTest { 4 public static void main(String[] args) { 5 String driver = "org.sqlite.JDBC"; 6 String url = "jdbc:sqlite:E:\\test.db"; 7 String sql = "select * from chenbenbuyi"; 8 Connection conn = null; 9 Statement stmt = null; 10 ResultSet rs = null; 11 try { 12 //加载驱动 13 Class.forName(driver); 14 //获取连接 15 conn = DriverManager.getConnection(url); //sqlite不需要密码 16 //创建预编译对象 17 stmt = conn.createStatement(); 18 //执行sql 19 rs = stmt.executeQuery(sql); 20 while (rs.next()) { 21 String s = rs.getString("x") +":"+rs.getString("y")+":"+rs.getString("z"); 22 System.out.println(s); 23 } 24 } catch (Exception e) { 25 e.printStackTrace(); 26 } finally { 27 //释放资源:一定要在finally中确保资源被释放 28 if (null != rs) { 29 try { 30 rs.close(); 31 } catch (SQLException e) { 32 e.printStackTrace(); 33 } 34 } 35 if (null != stmt) { 36 try { 37 stmt.close(); 38 } catch (SQLException e) { 39 e.printStackTrace(); 40 } 41 } 42 if (null != conn) { 43 try { 44 conn.close(); 45 } catch (SQLException e) { 46 e.printStackTrace(); 47 } 48 } 49 } 50 51 } 52 }
其它注意项
①Sqlite没有单独的布尔存储类型,它使用INTEGER作为存储类型,0为false,1为true;
②Sqlite没有单独的日期和时间存储类,内置的sqlite日期和时间函数能够将日期和时间以TEXT,REAL或INTEGER形式存放;
③基于轻量的设计取舍,SQLite的锁粗粒比较粗,当一个写连接要写数据库,所有其它的连接被锁住,直到写连接结束了它的事务,所以多个进程可以同时对SQLIte进行SELECT操作,但在任一时刻,只能有一个进程对数据库进行更改。SQLite因为不适合于高并发的场景。
尾声
好了,作为入门,不可能对SQLite讲述得太全面,但带你入门完全够了,所以本博暂时先止于此。鉴于布衣博主的博客被copy盗取太多,百度一搜甚是气愤,在此郑重申明:转载请获得博主允许并注明出处以及给出原文链接,否则。。。中国这版权行情博主一屌丝也不能把你怎样,但你的良心就真的不会痛耶?。
结尾涕泣,不知所云。
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan
SQLite使用笔记
前言
客户端存储信息的方法有好多种,在以往的项目中采用的是序列化记录到文件中的方式,即时通信项目中客户端的一些系统配置的保存也使用的这种方式,然而客户端保存聊天记录就不能使用这种方式(保存、读取、修改都需要进行序列化操作比较费时,不同会话聊天记录到不同文件中,将需要创建大量的文件),调研相关技术后,决定使用SQLite。
SQLite
我的认知如下:
SQLite是一款轻量级文件数据库,无需部署安装,特点是嵌入式与事务(原子性、一致性、隔离性和持久性)。使用时只需创建一个db文件(db文件即代表一个数据库),然后利用ADO.NET进行连接库、创建、插入、查询、修改表就可以了,非常的简单方便。
步骤
1.添加引用
右键项目引用选择 管理Nuget程序包 搜索SQLite,选择第一个进行安装
2.创建数据库文件
string dbPath = AppDomain.CurrentDomain.BaseDirectory + "local.db"; SQLiteConnection.CreateFile(dbPath);
注意需要添加引用:using System.Data.SQLite;
3.连接SQLite
SQLiteConnection conn = new SQLiteConnection(); SQLiteConnectionStringBuilder connstr = new SQLiteConnectionStringBuilder(); connstr.DataSource = datasource; connstr.Password = "123456";//设置密码,SQLite ADO.NET实现了数据库密码保护 conn.ConnectionString = connstr.ToString(); conn.Open();
1 2 3 4 | string v = connectionString ?? $ "Data Source={contextType.Name};Mode=Memory;Cache=Shared;" ; ConfigurationManager.Default.AppSettings[contextType.Name] = v; var connection = new SqliteConnection(v); connection.Open(); |
4.创建表
SQLiteCommand cmd = new SQLiteCommand(); string sql = "CREATE TABLE FirstTable(ID varchar(36),UserName varchar(30),PassWord varchar(30))"; cmd.CommandText = sql; cmd.Connection = conn; cmd.ExecuteNonQuery();
5.增删改查
增:

SQLiteCommand cmd = new SQLiteCommand(); string sql = "INSERT INTO FirstTable VALUES('1','ading3','123')"; cmd.Connection = conn; cmd.CommandText = sql; cmd.ExecuteNonQuery();
删:

string sql = "DELETE FROM FirstTable WHERE ID = @ID"; SQLiteParameter[] parms = { new SQLiteParameter("@ID",id) }; command.CommandText = sql; command.Parameters.AddRange(parameters); int counts = command.ExecuteNonQuery();
改:

string sql= @"UPDATE FirstTable SET UserName=@UserName, PassWord=@PassWord WHERE UserName='admin' "; SQLiteParameter[] parms1 = { new SQLiteParameter("@UserName","adminading"), new SQLiteParameter("@PassWord","2622020") }; command.CommandText = sql; command.Parameters.AddRange(parameters); int counts = command.ExecuteNonQuery();
查:

string query = "SELECT * FROM FirstTable"; DataTable dt = SQLiteHelper.ExecuteQuery(query, null); List<Test> tlist = new List<Test>(); foreach (var item in dt1.Rows) { Test tt = new Test(); tt.ID=(item as DataRow)["ID"].ToString(); tt.UserName = (item as DataRow)["UserName"].ToString(); tt.PassWord = (item as DataRow)["PassWord"].ToString(); tlist.Add(tt); } public class Test { public string ID { get; set; } public string UserName { get; set; } public string PassWord { get; set; } }
帮助类

1 /// <summary> 2 /// SQLite帮助类 3 /// 说明:使用SQLite很简单,只需要Nuget搜SQLite 使用第一个System.Data.SQLite安装即可 4 /// 使用CreateDB方法 创建一个数据库文件 传入路径即可 (注意:一个数据库文件代表一个数据库) 5 /// 使用前请先指定连接字符串 使用SetConnectionString()方法 6 /// SQLite作为本地文件数据库 具有独立运行、无服务器、零配置、支持事务、低内存、原子性等特点 7 /// </summary> 8 public class SQLiteHelper 9 { 10 #region 属性 11 /// <summary> 12 /// 连接字符串 13 /// </summary> 14 private static string connectionString = string.Empty; 15 #endregion 属性 16 17 #region 设置连接字符串与创建数据库文件 18 /// <summary> 19 /// 根据数据源、密码、版本号设置连接字符串。 20 /// </summary> 21 /// <param name="datasource">数据源。</param> 22 /// <param name="password">密码。</param> 23 /// <param name="version">版本号(缺省为3)。</param> 24 public static void SetConnectionString(string datasource, string password, int version = 3) 25 { 26 connectionString = string.Format("Data Source={0};Version={1};password={2}", 27 datasource, version, password); 28 } 29 30 /// <summary> 31 /// 创建一个数据库文件。如果存在同名数据库文件,则会覆盖。 32 /// </summary> 33 /// <param name="dbName">数据库文件名。为null或空串时不创建。</param> 34 /// <param name="password">(可选)数据库密码,默认为空。</param> 35 /// <exception cref="Exception"></exception> 36 public static void CreateDB(string dbName) 37 { 38 if (!string.IsNullOrEmpty(dbName)) 39 { 40 try 41 { 42 CreateDirectory(dbName); 43 SQLiteConnection.CreateFile(dbName); 44 } 45 catch (Exception ex) 46 { 47 string errormes = ex.Message; 48 errormes += "\r\n"; 49 errormes += LogHelper.ToMessage(ex); 50 string path = string.Empty; 51 path += AppDomain.CurrentDomain.BaseDirectory; 52 path += @"Unlog\SQLiteError"; 53 path += DateTime.Now.ToString("yyyyMMddHHmm"); 54 path += ".txt"; 55 LogHelper.Instance.WriteLog(path, errormes); 56 } 57 } 58 } 59 60 #region 辅助方法 61 /// <summary> 62 /// 创建父级路径 63 /// </summary> 64 /// <param name="infoPath"></param> 65 private static void CreateDirectory(string infoPath) 66 { 67 DirectoryInfo directoryInfo = Directory.GetParent(infoPath); 68 if (!directoryInfo.Exists) 69 { 70 directoryInfo.Create(); 71 } 72 } 73 #endregion 辅助方法 74 #endregion 设置连接字符串与创建数据库文件 75 76 #region 命令参数封装 77 // <summary> 78 /// 准备操作命令参数 79 /// </summary> 80 /// <param name="cmd">SQLiteCommand</param> 81 /// <param name="conn">SQLiteConnection</param> 82 /// <param name="cmdText">Sql命令文本</param> 83 /// <param name="data">参数数组</param> 84 private static void PrepareCommand(SQLiteConnection conn, SQLiteCommand cmd, string cmdText, params SQLiteParameter[] parms) 85 { 86 if (conn.State != ConnectionState.Open) 87 conn.Open(); 88 cmd.Parameters.Clear(); 89 cmd.Connection = conn; 90 cmd.CommandText = cmdText; 91 cmd.CommandType = CommandType.Text; 92 cmd.CommandTimeout = 30; 93 if (parms != null && parms.Length > 0) 94 { 95 foreach (SQLiteParameter parameter in parms) 96 { 97 if ((parameter.Direction == ParameterDirection.Input || parameter.Direction == ParameterDirection.InputOutput) && (parameter.Value == null)) 98 { 99 parameter.Value = DBNull.Value; 100 } 101 } 102 cmd.Parameters.AddRange(parms); 103 } 104 } 105 106 #endregion 命令参数封装 107 108 #region 数据库操作 109 #region 创建表 110 /// <summary> 111 /// 创建表 112 /// </summary> 113 /// <param name="sql"></param> 114 /// <returns></returns> 115 public static bool CreateTable(string sql) 116 { 117 bool rr = true; 118 try 119 { 120 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 121 { 122 using (SQLiteCommand command = new SQLiteCommand(connection)) 123 { 124 try 125 { 126 PrepareCommand(connection, command, sql, null); 127 int count = command.ExecuteNonQuery(); 128 if (count > 0) rr = true; 129 else rr = false; 130 } 131 catch (Exception ex) 132 { 133 return false; 134 } 135 } 136 } 137 } 138 catch (Exception ex) 139 { 140 141 return false; 142 } 143 return rr; 144 } 145 #endregion 创建表 146 147 #region 增删改操作 148 /// <summary> 149 /// 对SQLite数据库执行增删改操作,返回受影响的行数。 150 /// </summary> 151 /// <param name="sql">要执行的增删改的SQL语句。</param> 152 /// <param name="parameters">执行增删改语句所需要的参数,参数必须以它们在SQL语句中的顺序为准。</param> 153 /// <returns></returns> 154 /// <exception cref="Exception"></exception> 155 public static int ExecuteNonQuery(string sql, params SQLiteParameter[] parameters) 156 { 157 int affectedRows = 0; 158 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 159 { 160 using (SQLiteCommand command = new SQLiteCommand(connection)) 161 { 162 try 163 { 164 PrepareCommand(connection, command, sql, parameters); 165 //connection.Open(); 166 //command.CommandText = sql; 167 //if (parameters.Length != 0) 168 //{ 169 // command.Parameters.AddRange(parameters); 170 //} 171 affectedRows = command.ExecuteNonQuery(); 172 } 173 catch (Exception) { throw; } 174 } 175 } 176 return affectedRows; 177 } 178 #endregion 增删改操作 179 180 #region 批量操作 181 /// <summary> 182 /// 批量处理数据操作语句。 183 /// </summary> 184 /// <param name="list">SQL语句集合。</param> 185 /// <exception cref="Exception"></exception> 186 public static void ExecuteNonQueryBatch(List<KeyValuePair<string, SQLiteParameter[]>> list) 187 { 188 using (SQLiteConnection conn = new SQLiteConnection(connectionString)) 189 { 190 try { conn.Open(); } 191 catch { throw; } 192 using (SQLiteTransaction tran = conn.BeginTransaction()) 193 { 194 using (SQLiteCommand cmd = new SQLiteCommand(conn)) 195 { 196 try 197 { 198 foreach (var item in list) 199 { 200 PrepareCommand(conn, cmd, item.Key, item.Value); 201 //cmd.CommandText = item.Key; 202 //if (item.Value != null) 203 //{ 204 // cmd.Parameters.AddRange(item.Value); 205 //} 206 cmd.ExecuteNonQuery(); 207 } 208 tran.Commit(); 209 } 210 catch (Exception) { tran.Rollback(); throw; } 211 } 212 } 213 } 214 } 215 #endregion 批量操作 216 217 #region 查询 返回第一个 218 /// <summary> 219 /// 执行查询语句,并返回第一个结果。 220 /// </summary> 221 /// <param name="sql">查询语句。</param> 222 /// <returns>查询结果。</returns> 223 /// <exception cref="Exception"></exception> 224 public static object ExecuteScalar(string sql, params SQLiteParameter[] parameters) 225 { 226 using (SQLiteConnection conn = new SQLiteConnection(connectionString)) 227 { 228 using (SQLiteCommand cmd = new SQLiteCommand(conn)) 229 { 230 try 231 { 232 PrepareCommand(conn, cmd, sql, parameters); 233 //conn.Open(); 234 //cmd.CommandText = sql; 235 //if (parameters.Length != 0) 236 //{ 237 // cmd.Parameters.AddRange(parameters); 238 //} 239 return cmd.ExecuteScalar(); 240 } 241 catch (Exception) { throw; } 242 } 243 } 244 } 245 #endregion 查询 返回第一个 246 247 #region 查询 返回DT 248 /// <summary> 249 /// 执行一个查询语句,返回一个包含查询结果的DataTable。 250 /// </summary> 251 /// <param name="sql">要执行的查询语句。</param> 252 /// <param name="parameters">执行SQL查询语句所需要的参数,参数必须以它们在SQL语句中的顺序为准。</param> 253 /// <returns></returns> 254 /// <exception cref="Exception"></exception> 255 public static DataTable ExecuteQuery(string sql, params SQLiteParameter[] parameters) 256 { 257 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 258 { 259 using (SQLiteCommand command = new SQLiteCommand(sql, connection)) 260 { 261 PrepareCommand(connection, command, sql, parameters); 262 //if (parameters != null) 263 //{ 264 // if (parameters.Length != 0) 265 // { 266 // command.Parameters.AddRange(parameters); 267 // } 268 //} 269 270 SQLiteDataAdapter adapter = new SQLiteDataAdapter(command); 271 DataTable data = new DataTable(); 272 try { adapter.Fill(data); } 273 catch (Exception) { throw; } 274 return data; 275 } 276 } 277 } 278 #endregion 查询 返回DT 279 280 #region 查询 返回SQLiteDataReader 281 /// <summary> 282 /// 执行一个查询语句,返回一个关联的SQLiteDataReader实例。 283 /// </summary> 284 /// <param name="sql">要执行的查询语句。</param> 285 /// <param name="parameters">执行SQL查询语句所需要的参数,参数必须以它们在SQL语句中的顺序为准。</param> 286 /// <returns></returns> 287 /// <exception cref="Exception"></exception> 288 public static SQLiteDataReader ExecuteReader(string sql, params SQLiteParameter[] parameters) 289 { 290 SQLiteConnection connection = new SQLiteConnection(connectionString); 291 SQLiteCommand command = new SQLiteCommand(sql, connection); 292 try 293 { 294 PrepareCommand(connection, command, sql, parameters); 295 //if (parameters.Length != 0) 296 //{ 297 // command.Parameters.AddRange(parameters); 298 //} 299 //connection.Open(); 300 return command.ExecuteReader(CommandBehavior.CloseConnection); 301 } 302 catch (Exception) { throw; } 303 } 304 #endregion 查询 返回SQLiteDataReader 305 306 #region 查询数据库中的所有数据类型信息 307 /// <summary> 308 /// 查询数据库中的所有数据类型信息。 309 /// </summary> 310 /// <returns></returns> 311 /// <exception cref="Exception"></exception> 312 public static DataTable GetSchema() 313 { 314 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 315 { 316 try 317 { 318 connection.Open(); 319 return connection.GetSchema("TABLES"); 320 } 321 catch (Exception) { throw; } 322 } 323 } 324 325 #endregion 查询数据库中的所有数据类型信息 326 327 #region 判断表是否存在 328 public static bool IsTableExist(string tableName) 329 { 330 bool isTableExist = true; 331 using (SQLiteConnection connection = new SQLiteConnection(connectionString)) 332 { 333 string sql = "SELECT name FROM sqlite_master WHERE type='table' AND name = '"; 334 sql += tableName; 335 sql += "'"; 336 using (SQLiteCommand command = new SQLiteCommand(sql, connection)) 337 { 338 PrepareCommand(connection, command, sql, null); 339 int count = command.ExecuteNonQuery(); 340 if (count <= 0) isTableExist = false; 341 } 342 } 343 return isTableExist; 344 345 } 346 #endregion 判断表是否存在 347 348 #endregion 数据库操作 349 350 #region 整理数据库 351 /// <summary> 352 /// 重新组织数据库 353 /// SQLite 的自带命令 VACUUM。用来重新整理整个数据库达到紧凑之用,比如把删除的彻底删掉等等 354 /// </summary> 355 public static void ResetDataBass() 356 { 357 using (SQLiteConnection conn = new SQLiteConnection(connectionString)) 358 { 359 var cmd = new SQLiteCommand(); 360 361 if (conn.State != ConnectionState.Open) 362 conn.Open(); 363 cmd.Parameters.Clear(); 364 cmd.Connection = conn; 365 cmd.CommandText = "vacuum"; 366 cmd.CommandType = CommandType.Text; 367 cmd.CommandTimeout = 30; 368 cmd.ExecuteNonQuery(); 369 } 370 } 371 #endregion 整理数据库 372 }
可视化工具
分享一个可视化工具,个人感觉非常好用:
SQLiteStudio :http://sqlitestudio.pl/
问题
在项目中使用,不可能是直接在客户端的项目中直接写ADO那套,一般都会封装SQLite调用层,在调用层中添加相关的引用,这样就会有一个问题,客户端项目直接调用,会报一个错误:
解决方法为:
在客户端项目中添加两个文件夹,内部添加SQLite.Interop.dll(从SQLite调用层的Debug中拷贝)
然后,右键两个dll,选择属性,更改输出目录为始终复制。
问题解决。
总结
SQLite在本地存储方面使用非常广泛,不得不说真的很好用。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?