2

ネットワーク ドライブ上にデータベースがある可能性があります。私が達成したいことが2つあります。

  1. 最初のユーザーが読み取り専用モードで接続した場合 (その場所への読み取り/書き込みアクセス権がないか、データベースが読み取り専用である場合)、他のユーザーも読み取り専用接続を使用する必要があります ( RW アクセスを持っている)。
  2. 最初のユーザーが RW モードで接続すると、他のユーザーはデータベースにまったく接続できなくなります。

私は SQLite を使用していますが、同時に 10 人以上がデータベースを使用してはならないため、同時実行性が問題になることはありません。

更新:これは私が機能させようとしているサンプルなので、プログラム自体に実装できます。ほとんどすべてを変更できます。

更新: @CLが何であるかをようやく理解したとき。私に言っていました、私はそれを機能させました、そしてこれは更新されたコードです。

using System.Diagnostics;
using System.Linq;
using System.IO;
using DbSample.Domain;
using DbSample.Infrastructure;
using NHibernate.Linq;
using NHibernate.Util;


namespace DbSample.Console
{
    class Program
    {
        static void Main(string[] args)
        {
            IDatabaseContext databaseContext = null;

            databaseContext = new SqliteDatabaseContext(args[1]);

        var connection = LockDB(args[1]);
        if (connection == null) return;

        var sessionFactory = databaseContext.CreateSessionFactory();
        if (sessionFactory != null)
        {

            int insertCount = 0;

            while (true) 
            {

                try
                {

                    using (var session = sessionFactory.OpenSession(connection))
                    {
                        string result;
                        session.FlushMode = NHibernate.FlushMode.Never;

                        var command = session.Connection.CreateCommand();

                        command.CommandText = "PRAGMA locking_mode=EXCLUSIVE";
                        command.ExecuteNonQuery();


                        using (var transaction = session.BeginTransaction(ReadCommited))
                        {
                            bool update = false;
                            bool delete = false;
                            bool read = false;
                            bool readall = false;
                            int op = 0;
                            System.Console.Write("\nMenu of the day:\n1: update\n2: delete\n3: read\n4: read all\n0: EXIT\n\nYour choice: ");
                            op = System.Convert.ToInt32(System.Console.ReadLine());
                            if (op == 1)
                                update = true;
                            else if (op == 2)
                                delete = true;
                            else if (op == 3)
                                read = true;
                            else if (op == 4)
                                readall = true;
                            else if (op == 0)
                                break;
                            else System.Console.WriteLine("Are you retarded? Can't you read?");




                            if (delete)
                            {
                                System.Console.Write("Enter the ID of the object to delete: ");
                                var objectToRemove = session.Get<MyObject>(System.Convert.ToInt32(System.Console.ReadLine()));

                                if (!(objectToRemove == null))
                                {
                                    session.Delete(objectToRemove);
                                    System.Console.WriteLine("Deleted {0}, ID: {1}", objectToRemove.MyName, objectToRemove.Id);
                                    deleteCount++;
                                }
                                else
                                    System.Console.WriteLine("\nObject not present in the database!\n");


                            }

                            else if (update)
                            {
                                System.Console.Write("How many objects to add/update? ");
                                int number = System.Convert.ToInt32(System.Console.ReadLine());
                                number += insertCount;
                                for (; insertCount < number; insertCount++)
                                {

                                    var myObject = session.Get<MyObject>(insertCount + 1);

                                    if (myObject == null)
                                    {
                                        myObject = new MyObject
                                            {
                                                MtName = "Object" + insertCount,
                                                IdLegacy = 0,
                                                                                           };
                                        session.Save(myObject);
                                        System.Console.WriteLine("Added {0}, ID: {1}", myObject.MyName, myObject.Id);
                                    }
                                    else
                                    {
                                        session.Update(myObject);
                                        System.Console.WriteLine("Updated {0}, ID: {1}", myObject.MyName, myObject.Id);
                                    }
                                }

                            }

                            else if (read)
                            {

                                System.Console.Write("Enter the ID of the object to read: ");
                                var objectToRead = session.Get<MyObject>(System.Convert.ToInt32(System.Console.ReadLine()));
                                if (!(objectToRead == null))
                                    System.Console.WriteLine("Got {0}, ID: {1}", objectToRead.MyName, objectToRead.Id);
                                else
                                    System.Console.WriteLine("\nObject not present in the database!\n");

                            }

                            else if (readall)
                            {

                                System.Console.Write("How many objects to read? ");
                                int number = System.Convert.ToInt32(System.Console.ReadLine());
                                for (int i = 0; i < number; i++)
                                {
                                    var objectToRead = session.Get<MyObject>(i + 1);
                                    if (!(objectToRead == null))
                                        System.Console.WriteLine("Got {0}, ID: {1}", objectToRead.MyName, objectToRead.Id);
                                    else
                                        System.Console.WriteLine("\nObject not present in the database! ID: {0}\n", i + 1);


                                }

                            }
                            update = false;
                            delete = false;
                            read = false;
                            readall = false;

                            transaction.Commit();
                        }
                    }    
                }
                catch (System.Exception e)
                {
                    throw e;
                }


            }
            sessionFactory.Close();
        }

    }

    private static SQLiteConnection LockDbNew(string database)
    {
        var fi = new FileInfo(database);
        if (!fi.Exists)
            return null;
        var builder = new SQLiteConnectionStringBuilder { DefaultTimeout = 1, DataSource = fi.FullName, Version = 3 };

        var connectionStr = builder.ToString();
        var connection = new SQLiteConnection(connectionStr) { DefaultTimeout = 1 };
        var cmd = new SQLiteCommand(connection);

        connection.Open();

        // try to get an exclusive lock on the database
        try
        {
            cmd.CommandText = "PRAGMA locking_mode = EXCLUSIVE; BEGIN EXCLUSIVE; COMMIT;";
            cmd.ExecuteNonQuery();
        }
        // if we can't get the exclusive lock, it could mean 3 things
        // 1: someone else has locked the database
        // 2: we don't have a write acces to the database location
        // 3: database itself is a read-only file
        // So, we try to connect as read-only
        catch (Exception)
        {
            // we try to set the SHARED lock
            try
            {
                // first we clear the locks
                cmd.CommandText = "PRAGMA locking_mode = NORMAL";
                cmd.ExecuteNonQuery();
                cmd.CommandText = "SELECT COUNT(*) FROM MyObject";
                cmd.ExecuteNonQuery();

                // then set the SHARED lock on the database
                cmd.CommandText = "PRAGMA locking_mode = EXCLUSIVE";
                cmd.ExecuteNonQuery();
                cmd.CommandText = "SELECT COUNT(*) FROM MyObject";
                cmd.ExecuteNonQuery();

                readOnly = true;
            }
            catch (Exception)
            {
                // if we can't set EXCLUSIVE nor SHARED lock, someone else has opened the DB in read-write mode and we can't connect at all
                connection.Close();
                return null;
            }

        } 
        return connection;
    }

 }

}

4

2 に答える 2

2

PRAGMA locked_mode=EXCLUSIVEを設定して、トランザクションの終了後に SQLite がロックを解放しないようにします。

于 2013-02-08T15:50:59.123 に答える
1

データベース内で実行できるかどうかはわかりませんが、アプリケーションで実行できます。グローバル変数 (Web アプリかデスクトップ アプリかは不明) を設定して、誰かが接続していて書き込みアクセス権があるかどうかを確認できます。その後、他のクライアントの状態を確認できます。

于 2013-02-08T15:09:24.610 に答える