Unity Asynchronous 多线程安全操作Sqlit
2020-08-29 本文已影响0人
贼噶人
using System.Collections;
using System.Data.Common;
using System;
using System.Threading;
using System.Data;
using System.Threading.Tasks;
using UnityEngine;
using Mono.Data.Sqlite;
using UnityEngine.SceneManagement;
public class DatabaseManager : MonoBehaviour
{
private System.Object dblock = new System.Object();
private SqliteConnection connection;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public static DatabaseManager manager { get; private set; }
public static void Init()
{
if (null == manager)
{
GameObject databaseManagerGO = new GameObject();
databaseManagerGO.name = "DatabaseManager";
manager = databaseManagerGO
.AddComponent<DatabaseManager>();
SceneManager.MoveGameObjectToScene(databaseManagerGO
, SceneManager.GetActiveScene());
}
}
private void OnDestroy()
{
using (cancellationTokenSource)
{
cancellationTokenSource.Cancel();
}
if (null != connection)
{
using (connection)
{
}
}
manager = null;
}
private void Start()
{
OpenDatabase();
DontDestroyOnLoad(this);
}
private void OpenDatabase()
{
try
{
connection = new SqliteConnection($"data source={Application.streamingAssetsPath}/demo.db");
connection.StateChange += (sender, state) => { Debug.Log(state.CurrentState); };
connection.Open();
Debug.Log("open db ok!");
}
catch (Exception e)
{
Debug.Log($"open db fail! {e.Message}");
}
}
public class ExecuteQueryCoroutine : IEnumerator
{
private bool isFinish;
private DbDataReader result;
public ExecuteQueryCoroutine(DatabaseManager manager
, string sql, CancellationToken token)
{
manager.ExecuteReaderAsync(sql, token, (result) =>
{
this.result = result;
isFinish = true;
});
}
public object Current { get => result; }
public bool MoveNext()
{
return !isFinish;
}
public void Reset()
{
isFinish = false;
result = null;
}
}
public class ExecuteNonQueryCoroutine : IEnumerator
{
private bool isFinish;
private int result;
public ExecuteNonQueryCoroutine(DatabaseManager manager, string sql
, CancellationToken token)
{
manager.ExecuteNonQueryAsync(sql, token, (result) =>
{
this.result = result;
isFinish = true;
});
}
public object Current { get => result; }
public bool MoveNext()
{
return !isFinish;
}
public void Reset()
{
isFinish = false;
result = -1;
}
}
public void ExecuteNonQueryAsync(string sql, CancellationToken cancellationToken
, Action<int> action = null)
{
if (cancellationToken == CancellationToken.None)
{
cancellationToken = cancellationTokenSource.Token;
}
if (!string.IsNullOrEmpty(sql) && null != connection
&& connection.State == ConnectionState.Open)
{
Task.Run(() =>
{
lock (dblock)
{
SqliteTransaction transaction = null;
try
{
if (!cancellationToken.IsCancellationRequested)
{
transaction = connection.BeginTransaction();
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
var result = command.ExecuteNonQuery();
using (transaction)
{
transaction.Commit();
}
if (null != action)
{
action.Invoke(result);
}
}
}
else
{
if (null != action)
{
action.Invoke(-1);
}
}
}
catch (Exception e)
{
if (null != transaction)
{
using (transaction)
{
transaction.Rollback();
}
}
if (null != action)
{
action.Invoke(-1);
}
Debug.LogError(e);
}
}
}, cancellationToken);
}
else
{
if (null != action)
{
action.Invoke(-1);
}
}
}
public void ExecuteReaderAsync(string sql, CancellationToken cancellationToken
, Action<DbDataReader> action = null)
{
if (cancellationToken == CancellationToken.None)
{
cancellationToken = cancellationTokenSource.Token;
}
if (!string.IsNullOrEmpty(sql) && null != action && null != connection && connection.State
== ConnectionState.Open)
{
Task.Run(() =>
{
lock (dblock)
{
SqliteTransaction transaction = null;
try
{
if (!cancellationToken.IsCancellationRequested)
{
transaction = connection.BeginTransaction();
using (var command = connection.CreateCommand())
{
command.CommandText = sql;
var result = command.ExecuteReader();
using (transaction)
{
transaction.Commit();
}
if (cancellationToken.IsCancellationRequested)
{
using (result)
{
action.Invoke(null);
}
}
else
{
action.Invoke(result);
}
}
}
else
{
action.Invoke(null);
}
}
catch (Exception e)
{
if (null != transaction)
{
using (transaction)
{
transaction.Rollback();
}
}
if (null != action)
{
action.Invoke(null);
}
Debug.LogError(e);
}
}
}, cancellationToken);
}
else
{
if (null != action)
{
action.Invoke(null);
}
}
}
}