You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
6.6 KiB
194 lines
6.6 KiB
using System.Data.SQLite;
|
|
using System;
|
|
using System.Threading;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace AIK.DataAccess
|
|
{
|
|
public static class SQLiteCore
|
|
{
|
|
private static string _databasePath;
|
|
private static bool _isInitialized = false;
|
|
private static readonly object _initLock = new object();
|
|
// 连接池(线程安全队列),最大连接数控制为 5(SQLite 推荐)
|
|
private static readonly ConcurrentQueue<SQLiteConnection> _connectionPool = new ConcurrentQueue<SQLiteConnection>();
|
|
private const int MaxConnections = 5;
|
|
private static int _activeConnections = 0;
|
|
/// <summary>
|
|
/// 初始化 SQLitePCL 和数据库路径
|
|
/// </summary>
|
|
private static void Initialize()
|
|
{
|
|
lock (_initLock)
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
InitializeDatabasePath();
|
|
_isInitialized = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取池化连接(返回包装类,支持 using 自动归还)
|
|
/// </summary>
|
|
public static SqlitePooledConnection GetConnection()
|
|
{
|
|
Initialize();
|
|
|
|
// 尝试从池子里取空闲连接
|
|
if (_connectionPool.TryDequeue(out var connection) && connection.State == System.Data.ConnectionState.Open)
|
|
{
|
|
Interlocked.Decrement(ref _activeConnections);
|
|
return new SqlitePooledConnection(connection); // 用包装类包裹
|
|
}
|
|
|
|
// 池子里没有空闲连接,创建新连接
|
|
if (Interlocked.Increment(ref _activeConnections) > MaxConnections)
|
|
{
|
|
Interlocked.Decrement(ref _activeConnections);
|
|
throw new InvalidOperationException("SQLite 连接池已达最大连接数,建议优化事务执行速度或调整 MaxConnections");
|
|
}
|
|
|
|
var newConn = new SQLiteConnection($"Data Source={_databasePath}");
|
|
newConn.Open();
|
|
using (var cmd = newConn.CreateCommand())
|
|
{
|
|
cmd.CommandText = @"
|
|
PRAGMA journal_mode = WAL;
|
|
PRAGMA synchronous = NORMAL;
|
|
PRAGMA foreign_keys = ON;
|
|
PRAGMA busy_timeout = 3000;
|
|
";
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
|
|
return new SqlitePooledConnection(newConn); // 用包装类包裹
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 将连接归还到连接池(避免重复创建)
|
|
/// </summary>
|
|
public static void ReturnConnection(SQLiteConnection connection)
|
|
{
|
|
try
|
|
{
|
|
if (connection == null || connection.State != System.Data.ConnectionState.Open)
|
|
{
|
|
connection?.Dispose();
|
|
Interlocked.Decrement(ref _activeConnections);
|
|
return;
|
|
}
|
|
|
|
// 归还到池子里(供下次复用)
|
|
_connectionPool.Enqueue(connection);
|
|
Interlocked.Decrement(ref _activeConnections);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 释放所有连接(程序退出时调用)
|
|
/// </summary>
|
|
public static void DisposePool()
|
|
{
|
|
while (_connectionPool.TryDequeue(out var connection))
|
|
{
|
|
connection.Dispose();
|
|
}
|
|
_activeConnections = 0;
|
|
}
|
|
#region 单例模式
|
|
/// <summary>
|
|
/// 创建配置好的数据库连接
|
|
/// </summary>
|
|
//public static SQLiteConnection CreateConnection()
|
|
//{
|
|
// InitializeSQLitePCL();
|
|
// // 数据库文件路径
|
|
// _databasePath = DatabasePath;
|
|
|
|
// // 确保目录存在
|
|
// Directory.CreateDirectory(Path.GetDirectoryName(_databasePath));
|
|
// var connection = new SQLiteConnection($"Data Source={_databasePath}");
|
|
// connection.Open();
|
|
|
|
// // 基本优化设置
|
|
// using (var cmd = connection.CreateCommand())
|
|
// {
|
|
// cmd.CommandText = @"
|
|
// PRAGMA journal_mode = WAL;
|
|
// PRAGMA synchronous = NORMAL;
|
|
// PRAGMA foreign_keys = ON;
|
|
// ";
|
|
// cmd.ExecuteNonQuery();
|
|
// }
|
|
|
|
// return connection;
|
|
//}
|
|
//private static void InitializeSQLitePCL()
|
|
//{
|
|
// lock (_initLock)
|
|
// {
|
|
// if (!_isInitialized)
|
|
// {
|
|
// try
|
|
// {
|
|
// _isInitialized = true;
|
|
// Console.WriteLine("SQLitePCL initialized successfully.");
|
|
// }
|
|
// catch (Exception ex)
|
|
// {
|
|
// Console.WriteLine($"SQLitePCL initialization failed: {ex.Message}");
|
|
// throw;
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
#endregion
|
|
private static void InitializeDatabasePath()
|
|
{
|
|
#region(旧版本路径,未区分国内外版本)
|
|
//_databasePath = Path.Combine(
|
|
// Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
// "AIKKey", "Cache", "aikcache.db");
|
|
#endregion
|
|
// 1. 获取 AppData 基础路径
|
|
string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
|
|
|
// 2. 定义公司和应用的基础目录名
|
|
string companyName = "AIKKey";
|
|
string baseFolderName = "Cache";
|
|
string databaseFileName = "aikcache.db";
|
|
string versionFolderName;
|
|
#if CN
|
|
versionFolderName = "CN"; // 国内版使用 "CN" 子目录
|
|
#elif TEST
|
|
versionFolderName = "TEST";
|
|
#else
|
|
versionFolderName = "Global"; // 国外版使用 "Global" 子目录
|
|
#endif
|
|
_databasePath = Path.Combine(appDataPath, companyName, baseFolderName, versionFolderName, databaseFileName);
|
|
// 确保目录存在
|
|
Directory.CreateDirectory(Path.GetDirectoryName(_databasePath));
|
|
}
|
|
public static string DatabasePath
|
|
{
|
|
get
|
|
{
|
|
InitializeDatabasePath();
|
|
return _databasePath;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|