美文网首页
Unity Asynchronous 多线程安全操作Sqlit

Unity Asynchronous 多线程安全操作Sqlit

作者: 贼噶人 | 来源:发表于2020-08-29 11:10 被阅读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);
            }
        }
    }
}

相关文章

  • Unity Asynchronous 多线程安全操作Sqlit

  • [Unity 3d] 老瓶新酒,看我基于PlayerLoopSy

    Loom :在 Unity 多线程编程中实现线程间的数据同步,避免非主线程直接操作 Unity 对象。在本文,笔者...

  • Unity多线程管理

    Unity多线程管理 游戏中我们有许多地方还是有需求要开启多线程,例如下载文件,解压文件等操作,我们需要在Unit...

  • JAVA 多线程与锁

    JAVA 多线程与锁 线程与线程池 线程安全可能出现的场景 共享变量资源多线程间的操作。 依赖时序的操作。 不同数...

  • 多线程详解之基础

    安全是多线程编程的核心主题,但并不是只要使用多线程就一定会引发安全问题。要了解哪些操作是安全的,哪些是不安全的,就...

  • java并发关键字 Synchronized关键字

    在多线程环境下为了保证数据安全,需要用到互斥锁保证多线程对数据操作的安全性。Synchronized关键字可以修饰...

  • iOS编程各个修饰符分别

    atomic 设置成员变量的@property属性时,默认为atomic,提供多线程安全。在多线程环境下,原子操作...

  • Unity多线程(C#)

    前言 在这之前,有很多人在质疑Unity支不支持多线程,事实上Unity是支持多线程的。而提到多线程就要提到Uni...

  • 多线程知识总结

    一:多线程概念知识: 二,NSThread 的使用场景(1)耗时操作放在子线程中执行 三.多线程安全 四.GCD ...

  • 线程安全和非线程安全

    二者如何取舍非线程安全是指多线程操作同一个对象可能会出现问题。而线程安全则是多线程操作同一个对象不会有问题。线程安...

网友评论

      本文标题:Unity Asynchronous 多线程安全操作Sqlit

      本文链接:https://www.haomeiwen.com/subject/pyidsktx.html