Конференция "Базы" » Многопользовательский доступ к БД [D6, Access]
 
  • saNat © (15.04.08 09:24) [0]
    Доброго времени суток, Мастера (о:

    Подскажите, пожалуйста, по следующей проблеме.
    Есть некая БД на Access, расположенная в папке с общим доступом с правами на чтение/запись. Есть приложение "просмотрщик" данных, которое с определенным интервалом времени считывает информацию, а так же "редактор" данных, посредством которого информация в базу заносится. Приложения написаны на Delphi 6. Соединение устанавливается посредством ADO (MS Jet 4.0 OLE DB Provider). Суть проблемы: невозможна одновременная работа нескольких пользователей: получаю ошибку подключения к БД. Подскажите, пожалуйста, что дополнительно нужно указывать в строке подключения, или ткните носом, где почитать.

    С уважением, ЕВА.
  • Виталий Панасенко(дом) (15.04.08 10:00) [1]
    Может, настроен эксклюзивный доступ ?
  • saNat © (15.04.08 10:03) [2]
    По-умолчанию стоит "Share Deny None". Если я правильно читал, то это отсутствие блокировки записи/чтения. Или я не прав?
  • sniknik © (15.04.08 10:30) [3]
    > что дополнительно нужно указывать в строке подключения
    желательно ничего... чем меньше значений и так по умолчанию устанавливаемых тем меньше вероятность ошибок.
    по умолчанию должно работать.

    > с правами на чтение/запись.
    а на редактирование? а то впечатление такое, что файл блокировок первым коннектом создается, а у следующего нет прав его изменить (вписать себя)... о и получает тода минимальные. толко на чтение.
  • saNat © (15.04.08 10:53) [4]
    Гм... Так и есть. А Вы не п\могли бы подсказать где поправить (прочитать)?
  • saNat © (15.04.08 11:11) [5]
    Возможно, следует сказать, что к общей папке дан полный доступ.
  • saNat © (15.04.08 14:07) [6]
    Вообщем удалось обнаружить такую деталь: "блокирование" происходит в том случае, если приложение подсоединяется к "локальной базе по сети". Т.е. если запустить приложение на компьютере с установленной БД, указав "сетевой путь" (\\MyPC\MyApp\MyDB.mdb), то с клиентских машин соединение не уставнавливается. Если же запускать "локально" (C:\MyApp\MyDB.mdb), то клиентские машины успешно подключаются.
    Я понимаю, что глупо на локальной машине указывать сетевой путь, но вдруг пользователь "ткнет". К тому же это наблюдение, которое я пока не могу обосновать, грубо говоря, не могу сказать "не суй пальцы в мясорубку, потому что их отрежет ножом".

    Может кто-нибудь дать направление для размышлений?

    С уважением, ЕВА
  • saNat © (15.04.08 14:18) [7]
    Возможно (хотя что тут смотреть) требуется код...
    Кнопка подключения к БД:

    Procedure TDeskTop.TestButtonClick(Sender:TObject);
    Begin
    DBModule.DBPath:='\\B0000011\Base\DBase.mdb';
    // DBModule.DBPath:='D:\test\DBase.mdb';
    DBModule.DBConnect:=True;
    If DBModule.DBConnect
     Then
      TestButton.Caption:='Офигеть! Соединение установлено.'
     Else
      TestButton.Caption:='Не работает...';
    End;


    dataModule для тестов с базой:

    Unit DBModuleUnit;

    Interface

    Uses
    ADODB,Classes,DB,SysUtils;

    Type
    TDBModule=Class(TDataModule)
      DBConnection                                         :TADOConnection;
      Procedure DataModuleCreate(Sender:TObject);
      Procedure DBConnectionBeforeConnect(Sender:TObject);
     Private
      FDBPath                                              :String;
      Function GetDBConnect:Boolean;
      Procedure SetDBConnect(Value:Boolean);
      Procedure SetDBPath(Value:String);
     Public
     Published
      Property DBConnect:Boolean
       Read GetDBConnect
       Write SetDBConnect;
      Property DBPath:String
       Read FDBPath
       Write SetDBPath;
    End;

    Var
    DBModule                                               :TDBModule;

    Implementation

    {$R *.dfm}

    Procedure TDBModule.DataModuleCreate(Sender:TObject);
    Begin
    FDBPath:='';
    End;

    Procedure TDBModule.DBConnectionBeforeConnect(Sender:TObject);
    Begin
    DBConnection.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;'+
                                   'Data Source=\"'+DBPath+'\";'+
                                   'Persist Security Info=False;'+
                                   'Jet OLEDB:Database Password=001007326';
    End;

    Function TDBModule.GetDBConnect:Boolean;
    Begin
    Result:=DBConnection.Connected;
    End;

    Procedure TDBModule.SetDBConnect(Value:Boolean);
    Begin
    Case Value Of
      True: Begin
             DBConnection.Connected:=False;
             DBConnection.Connected:=True;
            End;
     False: DBConnection.Connected:=False;
    End;
    End;

    Procedure TDBModule.SetDBPath(Value:String);
    Begin
    FDBPath:=Value;
    End;

    End.

  • sniknik © (15.04.08 14:43) [8]
    > указав "сетевой путь" (\\MyPC\MyApp\MyDB.mdb)
    > запускать "локально" (C:\MyApp\MyDB.mdb)

    > DBModule.DBPath:='\\B0000011\Base\DBase.mdb';
    > // DBModule.DBPath:='D:\test\DBase.mdb';

    не равнозначно, если конечно там не алиас в расшарке, но пока вывод - по сути делается одно, а интерпритация по несуществующему варианту... т.е. "вывод по кофейной гуще".
  • saNat © (15.04.08 14:56) [9]
    > указав "сетевой путь" (\\MyPC\MyApp\MyDB.mdb)
    > запускать "локально" (C:\MyApp\MyDB.mdb)

    В данном случае абстрактный пример. Попробую на конкретном...
    Итак, на 1 машине по адресу "D:\Test\DBase.mdb" лежит БД. В сети она видна как "\\B0000011\Base\DBase.mdb".
    1. Если на первой машине приложение соединяется к БД с прописанным путем "D:\Test\DBase.mdb", то другие клиенты (в сети; подключаются к "\\B0000011\Base\DBase.mdb") соединяются к БД успешно.
    2. Если на первой машине приложение соединяется к БД с прописанным путем "\\B0000011\Base\DBase.mdb", то другие клиенты (в сети; подключаются к "\\B0000011\Base\DBase.mdb") не соединяются с БД. Получаю ошибку "Невозможно использовать "; файл уже используется".
    3. Если сначала к БД подключился клиент (в сети; подключаются к "\\B0000011\Base\DBase.mdb"), а потом присоединяется 1 машина (так же к "\\B0000011\Base\DBase.mdb"), то соединение успешно.

    Т.е. подключаясь с "сети" 1 машина создает файл подключений, который недоступен клиентам? Вот все пока что могу придумать. А как обойти даже не знаю.

    С уваженем, ЕВА
  • saNat © (15.04.08 14:57) [10]

    > 2. Если на первой машине приложение соединяется к БД с прописанным
    > путем "\\B0000011\Base\DBase.mdb", то другие клиенты (в
    > сети; подключаются к "\\B0000011\Base\DBase.mdb") не соединяются
    > с БД. Получаю ошибку "Невозможно использовать "; файл уже
    > используется".


    Поправлюсь: "выдают ошибку"
  • sniknik © (15.04.08 15:16) [11]
    > В данном случае абстрактный пример.
    перенести в потрепаться? абстракциям и флуду там самое место, а не сдесь.

    > Итак, на 1 машине по адресу "D:\Test\DBase.mdb" лежит БД. В сети она видна как "\\B0000011\Base\DBase.mdb".
    еще раз. пусть машина называется B0000011, согласен, но при расшаривании папки Test получить Base без указания его алиасом невозможно. про алиас ты не упоминал... вывод? ты подключаешься к разным базам, а вывод делаешь как будто работаешь с одной. при разных естественно никаких проблем у разных коннектов.

    хотя и права у разных юзеров могут быть разными... может ты подключаешься по сети "гостем" хотя и сам к себе. владелец файла блокировок другой, могут быть разные права. хотя... "это слишком сложно чтобы быть правдой, вот с черепахой дело другое..." © смешарики - край земли.
    первый вариант правдоподобнее.

    > Вот все пока что могу придумать.
    сам смотри в файл блокировок, блокнотом, и проверяй создаются там записи при каждом подключении или нет.
  • saNat © (15.04.08 15:22) [12]

    > еще раз. пусть машина называется B0000011, согласен, но
    > при расшаривании папки Test получить Base без указания его
    > алиасом невозможно. про алиас ты не упоминал... вывод? ты
    > подключаешься к разным базам, а вывод делаешь как будто
    > работаешь с одной. при разных естественно никаких проблем
    > у разных коннектов.

    Да, конечно, используется алиас. Чтобы исключить все возможные недопонимания, уточню: открывая общий доступ к папке "D:\Test\" в поле "Общий ресурс" введено значение "Base". В разрешениях для всех ("Все") дан полный доступ ("Полный доступ").
  • sniknik © (15.04.08 15:33) [13]
    тогда еще вариант. у XP ограничение на 10 коннектов извне по сети, допустим 9 у тебя уже чемто/кемто занято... тогда подключение самого к себе тоже вроде как внешнее занимает последний "слот". дальнейшие ведут к отказам -Ю ошибкам подключения.  

    в этом случае у тебя в event-сах (eventvwr.msc) будет полно ошибок типа TCP - превышен лимит на подключения (точность формулировки не гарантирую)... если найдешь такие, то выход перенести базу на серверную систему, у которой нет подобных ограничений . или "проредить" существующие. (есть еще хакерский вариант, но не будем об этом...)
  • saNat © (16.04.08 10:03) [14]
    sniknik ©, прошу прощения, я все таки обнаружил ситуацию описанную в  [11]. Окончательно запутавшись, решил выделить кусок соединения клиента к БД. Итак.

    1. Проект находится по адресу: "D:\DelphiN\Проекты\КаДР\v. 1.1\Управление доступом"
    2. База данных находится по адресу: "D:\DelphiN\Проекты\КаДР\v. 1.1\Base"
    3. База данных видна в локальной сети: "\\B0000011\Base"
    4. Имя файла базы данных: "DBase.mdb"
    5. К "\\B0000011\Base" открыт полный доступ

    DeskTopUnit - главная форма:

    Unit DeskTopUnit;

    Interface

    Uses
    Classes,Controls,DBModuleUnit,DBPathUnit,Dialogs,Forms,Graphics,Menus,Messages,
    StdCtrls,SysUtils,Variants,Windows;

    Type
    TDeskTop=Class(TForm)
      TestButton                                           :TButton;
      AppMenu                                              :TMainMenu;
       N1                                                  :TMenuItem;
       N2                                                  :TMenuItem;
       N3                                                  :TMenuItem;
       N4                                                  :TMenuItem;
      Procedure TestButtonClick(Sender:TObject);
       procedure N2Click(Sender: TObject);
     Private
     Public
    End;

    Var
    DeskTop                                                :TDeskTop;

    Implementation

    {$R *.dfm}

    Procedure TDeskTop.TestButtonClick(Sender:TObject);
    Begin
    Try
     DBModule.DBConnect:=Not DBModule.DBConnect;
     If DBModule.DBConnect
      Then
        TestButton.Caption:='РАЗОРВАТЬ СОЕДИНЕНИЕ'
      Else
        TestButton.Caption:='НА ЖМИ МЕНЯ';
    Except
     MessageDlg('А ВОТ ТЕБЕ, РОЖА БУРЖУЙСКАЯ, ДУЛЯ ПРОЛЕТАРСКАЯ!',mtError,[mbOK],0);
    End;
    End;

    Procedure TDeskTop.N2Click(Sender: TObject);
    Begin
    DBPath.ShowModal;
    End;

    End.



    DBModule - операции с базой данных:

    Unit DBModuleUnit;

    Interface

    Uses
    ADODB,Classes,DB,DBPathUnit,SysUtils;

    Type
    TDBModule=Class(TDataModule)
      DBConnection                                         :TADOConnection;
      DBQuery                                              :TADOQuery;
      Procedure DBConnectionBeforeConnect(Sender:TObject);
     Private
      Function GetDBConnect:Boolean;
      Procedure SetDBConnect(Value:Boolean);
     Public
      Property DBConnect:Boolean
       Read GetDBConnect
       Write SetDBConnect;
    End;

    Var
    DBModule                                               :TDBModule;

    Implementation

    {$R *.dfm}

    Procedure TDBModule.DBConnectionBeforeConnect(Sender:TObject);
    Var
     Buffer                                                :String;
    Begin
    DBConnection.ConnectionString:='Provider=Microsoft.Jet.OLEDB.4.0;'+
                                   'Data Source='+DBPath.DBPath+';'+
                                   'Persist Security Info=False;'+
                                   'Jet OLEDB:Database Password=0322907';
    End;

    Function TDBModule.GetDBConnect:Boolean;
    Begin
    Result:=DBConnection.Connected;
    End;

    Procedure TDBModule.SetDBConnect(Value:Boolean);
    Begin
    Case Value Of
      True: Begin
             If DBConnection.Connected
              Then
                DBConnection.Close;
             DBConnection.Open;
            End;
     False: DBConnection.Close;
    End;
    End;

    End.



    DBPathUnit - параметры приложения

    Unit DBPathUnit;

    Interface

    Uses
    Classes,Controls,Graphics,Forms,Dialogs,Mask,Messages,
    rxToolEdit,StdCtrls,SysUtils,Variants,Windows;

    Type
    TAppSettings=Record
     DBPath                                                :String[255];
     DayCount                                              :Integer;
    End;
    TDBPath=Class(TForm)
      DBPathHint                                           :TLabel;
      DBPathValue                                          :TFilenameEdit;
      ButtonSave                                           :TButton;
      ButtonClose                                          :TButton;
       procedure FormCreate(Sender: TObject);
       procedure FormActivate(Sender: TObject);
       procedure ButtonSaveClick(Sender: TObject);
       procedure ButtonCloseClick(Sender: TObject);
     Private
      Function GetDBPath:String;
      Procedure SetDBPath(Value:String);
     Public
      Property DBPath:String
       Read GetDBPath
       Write SetDBPath;
    End;

    Var
    DBPath                                                 :TDBPath;

    Implementation

    {$R *.dfm}

    Procedure TDBPath.FormCreate(Sender:TObject);
    Begin
    DBPathValue.Text:='';
    DBPathValue.InitialDir:=ExtractFilePath(ParamStr(0));
    DBPathValue.HistoryList.Clear;
    DBPathValue.FileName:='';
    DBPathValue.DefaultExt:='';
    End;

    Procedure TDBPath.FormActivate(Sender:TObject);
    Begin
    DBPathValue.InitialDir:=ExtractFilePath(ParamStr(0));
    DBPathValue.HistoryList.Clear;
    DBPathValue.DefaultExt:='';
    DBPathValue.FileName:=DBPath;
    End;

    Procedure TDBPath.ButtonSaveClick(Sender:TObject);
    Begin
    DBPath:=DBPathValue.FileName;
    ModalResult:=mrOk;
    End;

    Procedure TDBPath.ButtonCloseClick(Sender:TObject);
    Begin
    ModalResult:=mrCancel;
    End;

    Function TDBPath.GetDBPath:String;
    Var
     FileSettings                                          :File Of TAppSettings;
     AppSettings                                           :TAppSettings;
    Begin
    AssignFile(FileSettings,ExtractFilePath(ParamStr(0))+'\Settings.cfg');
    {$I-}
    ReSet(FileSettings);
    {$I+}
    If IOResult=0
     Then
      Begin
       Read(FileSettings,AppSettings);
       CloseFile(FileSettings);
       Result:=AppSettings.DBPath;
      End
     Else
      Begin
       MessageDlg('Файл конфигурации отсутствует или поврежден.',mtWarning,[mbOk],0);
       Result:='';
      End;
    End;

    Procedure TDBPath.SetDBPath(Value:String);
    Var
     FileSettings                                          :File Of TAppSettings;
     AppSettings                                           :TAppSettings;
    Begin
    AssignFile(FileSettings,ExtractFilePath(ParamStr(0))+'\Settings.cfg');
    {$I-}
    ReSet(FileSettings);
    {$I+}
    If IOResult=0
     Then
      Begin
       Read(FileSettings,AppSettings);
       CloseFile(FileSettings);
      End
     Else
      Begin
       AppSettings.DBPath:='';
       AppSettings.DayCount:=1;
      End;
    AppSettings.DBPath:=Value;
    {$I-}
    ReWrite(FileSettings);
    {$I+}
    If IOResult=0
     Then
      Begin
       Write(FileSettings,AppSettings);
       CloseFile(FileSettings);
      End
     Else
       MessageDlg('Ошибка записи файла конфигурации.',mtError,[mbOk],0);
    End;

    End.



    Проблема:
    1. Если первым подключается сервер (ПК, на котором находится БД), то клиент не подключается
    Файл блокировок:

    B0000011                        Admin                          


    2. Если подключается клиент, а потом сервер, то соединение устанавливается у всех корректно.
    Файл блокировок:

    B0000067                        Admin                           B0000011                        Admin                          



    На результат не влияет задаваемый на сервере путь к базе данных ("сетевой" или "локальный").

    Вот, по-моему, вся информация, имеющаяся на данный момент. Пожалуйста, подскажите как обеспечить корректную работу с БД в многопользовательском режиме (возможно где-то имеется ошибка, которую я не заметил, еще какие-либо рекомендации). Все указанное sniknik'ом проверил.

    С уважением, ЕВА.
  • saNat © (16.04.08 10:11) [15]
    Еще раз перечитал вышенаписанное. Проверил такой момент:
    1. Подключился к БД с сервером
    2. Изменил правила безопасности для файла блокировок DBase.ldb, добавив пользователя "Все" с праввми "Изменить/Чтение и выполнение/Чтение/Запись".
    3. Подключился к БД клиентом.

    Файл блокировок:

    B0000011                        Admin                           B0000067                        Admin                          



    Т.е. можно сделать вывод, как правильно заметил sniknik, проблема в файле блокировок (посыпаю голову пеплом, ибо про то написали почти сутки назад). Как можно ее решить, если он (файл блокировок) каждый раз создается заново?
  • sniknik © (16.04.08 10:46) [16]
    проблема не в файле блокировок, он то как раз честно делает то, что должен, и то что ему разрешили... проблема в правах. ("обратитесь к администратору сети")
    а почему у тебя файл с разными юзерами(методами подключения) создается с разными разрешениями, которые по идее они должны наследоваться от папки, на которую говоришь стоит все... х.з. привлекай админа.
  • saNat © (16.04.08 10:52) [17]

    > проблема не в файле блокировок, он то как раз честно делает
    > то, что должен, и то что ему разрешили... проблема в правах.
    >  

    Да, конечно. Я неверно выразился.

    > а почему у тебя файл с разными юзерами(методами подключения)
    > создается с разными разрешениями, которые по идее они должны
    > наследоваться от папки, на которую говоришь стоит все...
    >  х.з. привлекай админа.

    В разрешениях папки по-умолчанию) прописаны пользователи:
    1. SYSTEM
    2. Администраторы (B0000011\Администраторы)
    3. Пользователи (B0000011\Пользователи)
    4. <Моя учетная запись>
    5. СОЗДАТЕЛЬ-ВЛАДЕЛЕЦ

    Владельцем являются:
    1. Администраторы (B0000011\Администраторы)
    2. <Моя учетная запись>

    Правильным ли решением будет добавить "Все" с правами на, грубо говоря, чтение/запись/изменение?
  • saNat © (16.04.08 11:07) [18]
    Подразумевается - правильным решением, т.к. добавив указанное выше разрешение проблема исчезла.
  • sniknik © (16.04.08 11:15) [19]
    > На результат не влияет задаваемый на сервере путь к базе данных ("сетевой" или "локальный").
    о... а говорил влияет, и различается лиш способом подключения.
    тогда возможно все проще (нет неоднозначности "подключение > другой юзер"). на сервере просто прогу запускают от админа и созданный ей файл получает его владельцем, "гостям" править такой файл в разрешениях не выставлено. с обратной ситуацией, файл во владельцах имеет "гостя", такой правят все кому не лень админ тоже. и вся "загадка".
    но тогда получается ты обманывал когда говорил что
    > расположенная в папке с общим доступом с правами на чтение/запись.
    общих("все") прав там нет.
  • sniknik © (16.04.08 11:17) [20]
    saNat ©   (16.04.08 10:52) [17]
    ну вот, подтверждение ([19]) раньше чем запостил...
  • saNat © (16.04.08 11:24) [21]
    Чаще всего про "Все" вспоминать не приходилось, потому и заблуждался о "полном доступе". Думаю, вопрос решен.
    sniknik ©, большое спасибо за уделенное внимание и помошь (о:

    С уважением, ЕВА.
 
Конференция "Базы" » Многопользовательский доступ к БД [D6, Access]
Есть новые Нет новых   [134433   +22][b:0][p:0.012]