C#中SQLite的使用及工具类
SQLite简介
SQLite是一款轻型的数据库,一个数据库就是一个文件,详细介绍参考官网:https://www.sqlite.org/index.html
SQLite 数据类型是一个用来指定任何对象的数据类型的属性。SQLite 中的每一列,每个变量和表达式都有相关的数据类型。
您可以在创建表的同时使用这些数据类型。SQLite 使用一个更普遍的动态类型系统。在 SQLite 中,值的数据类型与值本身是相关的,而不是与它的容器相关。
SQLite数据与常见的MySQL、SQL等的数据库不一样,它是动态类型数据库,每个值在数据库占的存储空间根据值的大小确定,使用时需要注意数据类型的问题。
存储类
每个存储在 SQLite 数据库中的值都具有以下存储类之一:
| 存储类 | 描述 |
|---|---|
| NULL | 值是一个 NULL 值。 |
| INTEGER | 值是一个带符号的整数,根据值的大小存储在 1、2、3、4、6 或 8 字节中。 |
| REAL | 值是一个浮点值,存储为 8 字节的 IEEE 浮点数字。 |
| TEXT | 值是一个文本字符串,使用数据库编码(UTF-8、UTF-16BE 或 UTF-16LE)存储。 |
| BLOB | 值是一个 blob 数据,完全根据它的输入存储。 |
亲和类型
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的存储方式。 |
引用System.Data.SQLite.dll
在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开发团队执行。
System.Data.SQLite的下载页面选项太多,一般人进来都不清楚要下载那些内容,下面对下载界面中的软件包做一个简单介绍。
软件包分类
下载内容按类型分为安装包、非静态连接的二进制包和静态连接的二进制包三种,区别如下:
- 安装程序包仅用于在开发人员计算机上安装,然后仅在需要VisualStudio的设计时组件时安装,不建议安装在客户机器上(理论上也可以)。
- 安装包会安装相关的动态库到系统内,并注册到GAC(Global Assembly Cache)。
- 二进制软件包旨在供开发人员使用,以便获得开发所需的汇编二进制文件,并通过XCOPY部署将其应用程序部署到客户机上。
- 两种二进制包的区别在于非托管部分的连接方式不同,非静态连接的二进制包在使用时需要VC运行时库的支持。
注:如果所有目标机器已经安装了VisualC++运行时,或者可以容易地部署,则应该避免“静态”包。
每个类型都按.NET版本分成了若干小组,每个.NET版本又分为32位和64位两组:
- 支持的.NET版本有 2.0 SP2 、 3.5 SP2 、4.0 、 4.5 、 4.5.1 、4.6 。
- 选用32位还是64位是根据使用系统来决定的,如开发时是64位(使用64位dll)系统而发布后运行在32位(使用32位dll)系统上。
注:虽然.NET高版本兼容低版本,但强烈建议选择与目标.NET Framework版本匹配的包。
在每个.NET版本-位数分组中都有2个文件包,一个带有“bundle”字样,另一个没有:
- 带有“bundle”字样的表示动态库是按混合模式编译的,在使用的时候只需要System.Data.SQLite.dll就可以了。
- 不带“bundle”的则是将非托管部分和托管部分分别编译,System.Data.SQLite.dll不能独立使用,还需要有SQLite.Interop.dll才能使用。
注:除非认为绝对必要,否则应避免使用“bundle”包。
根据上面的介绍,如果开发机器和客户机器可能具有不同的处理器体系结构,则可能需要一个以上的二进制程序包。
使用本机库预加载
本机库预加载功能从1.0.80.0版本开始可用,并且默认情况下已启用,能够自动适应当前系统的位数。为了利用此功能,必须将单独的托管程序集和互操作程序集与XCOPY部署一起使用(混合模式程序集、安装软件包部署不支持此功能)。
使用本机库预加载功能时,应用程序部署看起来如下( bin 表示将在目标计算机上部署应用程序二进制文件的目录):
- bin \ App.exe(可选,仅受管应用程序可执行程序集)
- bin \ App.dll(可选,仅托管应用程序库程序集)
- bin \ System.Data.SQLite.dll(必需,仅受管核心程序集)
- bin \ System.Data.SQLite.Linq.dll(可选,仅托管LINQ程序集)
- bin \ System.Data.SQLite.EF6.dll(可选,仅托管EF6程序集)
- bin \ x86 \ SQLite.Interop.dll(必需,x86本机互操作程序集)
- bin \ x64 \ SQLite.Interop.dll(必需,x64本机互操作程序集)
启用本机库预加载功能并显示上面的应用程序部署后,System.Data.SQLite仅限托管程序集将尝试自动检测当前进程的处理器体系结构并预加载适当的本机库,此时不用考虑客户机器的是64位还是32位。
常用部署包
我把.NET的4.0 、4.5版本对应的软件包按本机库预加载功能的要求重新组装,使用时直接复制到Debug目录下即可:
- sqlite-netFx45-binary-Win32-x64-2012-1.0.113.0.zip 提取码: r4yy
- sqlite-netFx40-binary-Win32-x64-2010-1.0.113.0.zip 提取码: j88h
- sqlite-netFx45-static-binary-Win32-x64-2012-1.0.113.0.zip 提取码: 33kp
- sqlite-netFx40-static-binary-Win32-x64-2010-1.0.113.0.zip 提取码: iqr2
注:官方建议不使用静态的二进制包,我个人则喜欢用静态的二进制包,这样就不用考虑客户机器上是否安装有对应的VC运行时库了。
工具类
工具类大部分内容来自c# 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_time
sbr.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();
}
参考资料
- c# Sqlite帮助类
- 让使用SQLite的.NET应用自适应32位/64位系统
- System.Data.SQLite
- sqlite3自增key设定(创建自增字段)
- Sqlite如何自动更新时间字段
C#中SQLite的使用及工具类的更多相关文章
- Nutz中那些好用的工具类
Nutz 是国产的精品开源框架,它全无依赖,只以1兆多的身材,就可以实现SSH全部功能的90%以上.内容主要涵盖了:Ioc.Aop.MVC.Dao.Json等WEB开发的方方面面. 它不仅轻巧,而且 ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- Java中的AES加解密工具类:AESUtils
本人手写已测试,大家可以参考使用 package com.mirana.frame.utils.encrypt; import com.mirana.frame.constants.SysConsta ...
- 【深度精讲】JFinal中的Ret和Kv工具类的区别,你用对了吗?
在JFinal中有两个类Map的工具类,一个是有状态的Ret,一个是无状态的Kv,各种自己的应用场景,你用对了吗? 下面我们从多个方面来探究一下,JFinal针对这两个类的设计: 一.位置-com.j ...
- java中redis的分布式锁工具类
使用方式 try { if(PublicLock.getLock(lockKey)){ //这里写代码逻辑,执行完后需要释放锁 PublicLock.freeLock(lockKey); } } ca ...
- java高并发系列 - 第16天:JUC中等待多线程完成的工具类CountDownLatch,必备技能
这是java高并发系列第16篇文章. 本篇内容 介绍CountDownLatch及使用场景 提供几个示例介绍CountDownLatch的使用 手写一个并行处理任务的工具类 假如有这样一个需求,当我们 ...
- java.util.concurrent中的几种同步工具类
java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...
- java中使用反射做一个工具类,来为指定类中的成员变量进行赋值操作,使用与多个类对象的成员变量的赋值。
//------------------------------------------------我是代码的分割线 // 首选是一个工具类,在该工具类里面,定义了一个方法,public void s ...
- Spring中内置的一些工具类
学习Java的人,或者开发很多项目,都需要使用到Spring 这个框架,这个框架对于java程序员来说.学好spring 就不怕找不到工作.我们时常会写一些工具类,但是有些时候 我们不清楚,我们些的工 ...
随机推荐
- 星空值、SPC、算力组成三元永动机制!VAST带你把握时代!
目前中心化金融体系为用户提供的服务在便捷性和易用性方面已经达到了新高度,但随着时代发展,大众对于金融安全性和可控性的需求进一步提升,需要去中心化金融服务商来提供更具创意的解决方案.盛大公链为此在应用层 ...
- EFCodeFirst关系映射约定
EFCodeFirst关系映射约定 EFCodeFirst 关系映射约定 默认多重关系的一些约定规则: 1.一对多关系 两个类中分别包含一个引用和一个集合属性. 两个类中一个类包含另一个类的引用属性. ...
- AXU2CGB开发板验证Vitis加速基本平台创建
Vitis 加速基本平台创建 1.Vivado 工程创建,硬件平台bd 图如下所示 1.1.双击Block图中ZYNQ核,配置相关参数 1.1.1.Low Speed 配置,在 I/O Configu ...
- Docker镜像构建原理解析(不装docker也能构建镜像)
在devops流程里面 构建镜像是一个非常重要的过程,一般构建镜像是写dockerfile文件然后通过docker client来构建的image. docker client 会先检查本地有没有im ...
- HTTP头Content-Type类型记录
默认发POST格式 Content-Type: application/x-www-form-urlencoded Content-Type: application/x-www-form-urlen ...
- Serverless 2.0,鸡蛋还是银弹?
简介: 本篇旨在介绍 Serverless 如今应用到应用(非病句)的各种困境,以及帮助用户如何去规避一些问题,提前了解方向. 浪潮 从 2014 年 Serverless 冒头至今,已经有无数的勇士 ...
- POJ-3468(线段树+区间更新+区间查询)
A Simple Problem With Integers POJ-3468 这题是区间更新的模板题,也只是区间更新和区间查询和的简单使用. 代码中需要注意的点我都已经标注出来了,容易搞混的就是up ...
- 从客流统计到营销赋能,Re-ID加速实体商业数字化转型 | 爱分析洞见
2020年中国实体商业受到突发疫情的重大影响.以危机为契机,实体商业加速数字化转型,利用创新应用服务自身业务.在此阶段,基于Re-ID(Person Re-identification,即行人再识别) ...
- SQL注入绕过waf的一万种姿势
绕过waf分类: 白盒绕过: 针对代码审计,有的waf采用代码的方式,编写过滤函数,如下blacklist()函数所示: 1 ........ 2 3 $id=$_GET['id']; 4 5 $ ...
- HTB系列之七:Bastard
出品|MS08067实验室(www.ms08067.com) 这次挑战的是 HTB 的第7台靶机:Bastard 技能收获: PHP Unserilaize CMS Version Identify ...