PDA

View Full Version : سوال: ثبت همزمان یک رکورد در دو دیتابیس مختلف



esagraphic
سه شنبه 01 اردیبهشت 1394, 16:59 عصر
سلام به همه
من یک برنامه دارم که روی دو سیستم نصب میشه یک سیستم به یک شهر است و یم سیستم دگه به شهر دگری الان میخواهم هر ریکوردی که هر سیستم ثبت میکنن یک کاپی هم روی دیتابیس که روی وب سرور است mysql ذخیره بشه به این معنی وقتی یک ریکورد ثبت میکنه یکی داخل خود سیستم که دیتابیس داره و از نوع express است که همراه برنامه اتچ شده ذخیره بشه و یک کاپی اش به روی ویب سرور که شخص بعدی بتونه دیتا ها را کنترول کنه به خاطری یک نمونه روی سیستم ذخیره بشه چون زمانی که انترنت قطع میشه بتونه ریکورد ها را روی سیستم خود ذخیره کنه و مشکل هم دقیقا همینجاست چیکار باید کنم چه پیشنهادی دارین که زمانی که انترنت قطع میشه روی سیستم ذخیره کنه در صورتی که انترنت وصل شد باقی مانده دیتا های که روی سیستم است را آپلود کنه روی ویب سرور منتظر نظرات همه شما هستم

Javad_raouf
چهارشنبه 02 اردیبهشت 1394, 09:53 صبح
سلام
بهترین کار نمی دونم چیه ولی کاری که خودم توی همچین موقعیتی انجام دادم:
1. توی هر جدول از دیتابیس Local باید یک فیلد Flag مانند داشته باشی مثلا به نام Sync که از نوع بیت. که Nullable نیست و مقدار پیش فرض داره یعنی وی قسمت Default Value می نویسی 0
2. توی تمامی جداولت توی کلاینت علاوه بر فیلد LocalID که کلید اصلی جدول است و می تونه Identity باشه یک فیلد دیگه به نام ServerID می زاری که Nullabe باشه.
3. توی تمامی جداولت توی سرور فیلد ServerID کلید اصلی است ولی فیلد LocalID نباید Nullabe باشد
4.توی تمامی جداولت چه در سرور و چه در کلاینت فیلدی باید باشد از نوع DateTime به نام LastChange که یک سری مشخصه هایی داره:
الف- Nullable نیست
ب- توی دیتابیس سرور و کلاینت مقدار پیش فرض داره یعنی توی قسمت Default Value این رو می نویسی : (GetDate()) بدین معنی که هر زمان هر جدول اضافه شد توی این فیلد تاریخ و زمان افزوده شدن مشخص می شه
ج- توی سرور این فیلد نباید دستی ویرایش یا ثبت بشه ولی توی کلاینت به صورت دستی ثبت یا ویرایش میشه
5- به ازای هر جدولت فقط در سرور یک تریگر داری که که هنگام ویرایش هر رکورد از جدول مقدار LastChange رو به روز می کنه
اینم کدی که باید توی تریگر هر جدول از دیتابیس سرورت بنویسی:
Create TRIGGER [dbo].[Tr_ExampleLastChange] ON [dbo].[tblExample]
AFTER INSERT,UPDATE--,DELETE
AS
BEGIN
SET NOCOUNT ON;
Update tblExample Set
LastChange = GetDate()
Where
ServerID In (Select ServerID From Inserted Where LastChange is NULL OR DATEDIFF(SECOND,ISNULL(LastChange,GetDate()),GetDa te()) > 5)
SET NOCOUNT OFF;
END
یا شایدم این بهینه تر باشه نمی دونم:
Create TRIGGER [dbo].[Tr_ExampleLastChange] ON [dbo].[tblExample]
AFTER INSERT,UPDATE--,DELETE
AS
BEGIN
SET NOCOUNT ON;
Update tblExample Set
LastChange = GetDate()
From Inserted
Where
Inserted.ServerID = tblExample.ServerID AND (Inserted.LastChange is NULL OR DATEDIFF(SECOND,ISNULL(Inserted.LastChange,GetDate ()),GetDate()) > 5)
SET NOCOUNT OFF;
END
فرقی نمی کنه کدوم باشه جفتش یک کار انجام میشه حالا اساتید بگن کدوم سریع تره
نکته: فیلدی مثل Flag که گفتم فقط توی جدول Local لازم داریم می شه الکی توی جدول Server هم اضافه کرد فقط برای اینکه جداول یک شکل باشند و مدیریت ارتباطاتشون راحت تر باشه
ادامه دارد....

Javad_raouf
چهارشنبه 02 اردیبهشت 1394, 10:48 صبح
وقتی کارایی که گفتم رو بدون نقص انجام داده دیگه بقیش راحته
شما خیلی راحت با استفاده از دستورات معمولی برنامت رو برای Local می نویسی و توی برنامت به هر روشی که دلت خواست جداولت رو پر می کنی فقط چند نکته رو هنگام کار کردن با جداول برنامه Local در نظر بگیر:
1. توی Insert به هیچ عنوان فیلد
Sync رو مقدار نمیدی یعنی همیشه باید بعد از Insert فیلد
Sync همون مقدار پیشفرض یعنی 0 رو داشته باشه
2. توی Update هات همیشه باید فیلد
Sync رو برابر با 0 قرار بدی یعنی هر دستور Update که می نویسی بعد از Update TableName Set اولین چیزی که می نویسی باید این باشه
Sync = 0 و بعدش هر مقدار دهی دیگه که دوست داری رو می نویسی
3.

حالا قسمت مهمش اینه توی برنامت که روی Local اجراست یک تابع داری به نام Synchronize که دو تا کار اصلی انجام میده اول ارسال تغییرات کلاینت جاری، دوم دریافت تغییرات سرور
کد تابع Synchronize بستگی به نحوه ارتباطت با سرور داره یعنی هم می تونی به صورت وب سرویس با سرور در ارتباط باشی هم مستقیم به دیتابیس سرور دسترسی داشته باشی
من کار به کدت یا نحوه ارتباطت ندارم فقط الگوریتم مد نظرم رو نوشتاری میگم بهت
اول قسمت Send تابع Synchronize (یعنی همون ارسال تغییراتی که توی کلاینت صورت گرفته):
خیلی سادست، توی تمامی جداولت هر رکوردی که فیلد Sync برابر با 0 داشت یعنی هنوز به سرور ارسال نشده و باید ارسال شود
نکته حائز اهمیت در ارسال اینه که ارسال به سرور فقط به معنی Insert نیست بلکه ممکنه این رکورد در سرور باشه و چون در کلاینت ویرایش شده مقدار فیلد Sync شده 0
منظورم اینه که ما باید یک جور بفهمیم برای به روز کردن این رکورد در سرور باید از Insert استفاده کنیم یا از Update؟؟؟
برای این منظور فیلد ServerID موجود در کلاینت به کارمون میاد یعنی اگر این فیلد Null باشه یعنی این رکورد کلا در سرور نیست ولی اگر این فیلد مقدار داشته باشه باید دنبال همین مقدار توی سرور باشیم و همون رکورد رو آپدیت کنیم
نکته مهم اینه که پس از Sync کردن رکورد هایی که ServerID شون توی کلاینت Null هست باید فیلد ServerIDشون از روی سرور ست بشه
پس از ارسال موفق به سرور فیلد Sync رکورد مورد نظر در کلاینت رو برابر 1 قرار میدیم
حالا قسمت Receive تابع Synchronize:
ببین همیشه پس از پایان عملیات Receive تاریخ و ساعت جاری رو باید یک جا ذخیره کنی تا بعدا بفهمی که اطلاعات موجود از سرور رو تا چه زمانی دریافت کردی و فقط تغییرات بعد از اون زمان رو دریافت کنی.
1. ابتدای عملیات Receive اون DateTime ی که نمی دونم توی رجیستری ذخیره کردی یا توی دیتابیس یا هر جای دیگه رو لود می کنی اسمش رو میزاریم مثلا LastSync و اگر وجود نداشت(یعنی اولین باره Synchronize می کنی) مقدارشو با DateTime.MinValue پر می کنی
دیگه بقیش سادست توی تمامی جداول موجود در سرور هر رکوردی که مقدار فیلد LastChange بزرگتر از LastSync داشت معلوم میشه توی کلاینت یا نیست و یا آپدیت شده و توی کلاینت نسخه قدیمیش هست
مثلا یک رکوردی در جدول tblExample موجود در سرور پیدا کردیم که LastChangeش بزرگتر از LastSync بود حالا اول سرچ می کنیم توی جدول tblExample موجود در کلاینت که آیا رکوردی با ServerID برابر با رکورد پیدا شده در سرور هست یا نه
اگر پیدا کردیم از دستور Update برای به روز کردن استفاده می کنیم و اگر پیدا نکردیم یک رکورد جدید Insert می کنیم
نکته مهم اینجاست که توی این Insert و آپدیت فیلد Sync موجود در کلاینت باید مقدار 1 بگیرد

Javad_raouf
چهارشنبه 02 اردیبهشت 1394, 11:00 صبح
یک سری مشکلات ممکنه پیش بیاد مثلا:
یک رکورد با یک ServerID مشخص توی دو تا کلاینت ویرایش بشه (توی برنامه هایی که جداول به هم ربط دارن این یعنی فاجعه) اگر برات مهمه اینا رو می تونی مدیریت کنی مثلا یک فیلد دیگه به جدولات اضافه کنی که ClientID باشه نه مثل ServerId که کلید بود بلکه ClientID مقدار تکراری می پذیره یعنی هر کلاینتت یک ID منحصر به فرد داره و هر رکوردی در دیتابیس اضافه می کنه با Id خودش اضافه می کنه
وقتی این کار رو کردی مثلا می تونی جلوش رو بگیری که یک کلاینت رکورد یک کلاینت دیگه رو ویرایش کنه:متفکر:
یا راه هایی که بتونه ویرایش بکنه و مشکلی پیش نیاد که نیاز به این داره که من دقیقا بدونم برنامت چیه

در کل الگوریتمی که من گفتم کار می کنه پایداریش هم تقریبا 100 درصده به شرطی که نسبت به برنامه خودت یک سری محدودیت ها رو مدیریت کنی
ولی::::::::
این همه توضیح دادم چون می خواستم کارت راه بیفته و خودمم از همین روش استفاده می کنم ولی به نظرم این کار اصولی نیست
منظورم اینه که قطعا راه های اصولی تر و بهتری خود SQL Server در اختیارمون قرار میده که ما نیازی نیست اصلا خودمون رو درگیر کنیم:لبخند:
امیدوارم تونسته باشم کمکی بکنم

alibilgats
چهارشنبه 02 اردیبهشت 1394, 11:38 صبح
سلام
اتفاقا من هم توی پروژه آخریم دقیقا همین مورد رو پیاده سازی کردم!
الگوریتمش هم تقریبا مثل توضیحاتی بود که دوست عزیزمون دادن. یعنی استفاده از تریگر. البته من هم از flag استفاده کردم و هم از جدول تغییرات. یعنی هر رکوردی که توی سرور حذف بشه و یا آپدیت بشه توی یه جدول تغییرات کدش رو ثبت میکنم و برای همگام سازی اطلاعات کلاینت به اون جدول مراجعه میکنم.
در کل کار طاقت فرساییه! کنترل زیادی باید انجام بدی تا صحت اطلاعات حفظ بشه!

esagraphic
چهارشنبه 02 اردیبهشت 1394, 16:38 عصر
یک سری مشکلات ممکنه پیش بیاد مثلا:
یک رکورد با یک ServerID مشخص توی دو تا کلاینت ویرایش بشه (توی برنامه هایی که جداول به هم ربط دارن این یعنی فاجعه) اگر برات مهمه اینا رو می تونی مدیریت کنی مثلا یک فیلد دیگه به جدولات اضافه کنی که ClientID باشه نه مثل ServerId که کلید بود بلکه ClientID مقدار تکراری می پذیره یعنی هر کلاینتت یک ID منحصر به فرد داره و هر رکوردی در دیتابیس اضافه می کنه با Id خودش اضافه می کنه
وقتی این کار رو کردی مثلا می تونی جلوش رو بگیری که یک کلاینت رکورد یک کلاینت دیگه رو ویرایش کنه:متفکر:
یا راه هایی که بتونه ویرایش بکنه و مشکلی پیش نیاد که نیاز به این داره که من دقیقا بدونم برنامت چیه

در کل الگوریتمی که من گفتم کار می کنه پایداریش هم تقریبا 100 درصده به شرطی که نسبت به برنامه خودت یک سری محدودیت ها رو مدیریت کنی
ولی::::::::
این همه توضیح دادم چون می خواستم کارت راه بیفته و خودمم از همین روش استفاده می کنم ولی به نظرم این کار اصولی نیست
منظورم اینه که قطعا راه های اصولی تر و بهتری خود SQL Server در اختیارمون قرار میده که ما نیازی نیست اصلا خودمون رو درگیر کنیم:لبخند:
امیدوارم تونسته باشم کمکی بکنم



دوست عزیز تشکر بابت اینک وقتت را در اختیارم گذاشتی و رهنمائی کردی این نکته آخری که نوشتی ولی::::::: جالب بود
برنامه که من دارم کار خیلی سختی نمیکنه تنها ده ریکورد را میگره ذخیره میکنه هر کلاینت دقیقا به موقعیت های مختلفی نصب است ده ریکورد ذخیره میکنه و یک کاپی هم باید روی سرور ویب سرور که MySQL یا SQL فرقی نمیکنه ذخیره کنه یک برنامه دگه به مدیریت میدیم که تنها اونم ویرایش اینها نمیکنه تنها گزارش میگیره و چاپ میکنه خواست من دقیقاً اینه که من نمیخواهم از Sqlserver استفاده کنم نصبش برای مشتری کمی سخته و نگهداریش براش کمی سخته میخوام از sql express که کنار برنامه دیتابیس اتچ است استفاده کنم سوال پیش میاد چرا مستقیم تو دیتابیس که روی سرور است من ذخیره نمیکنم به این دلیل امکان داره یک کلاینت برای چند دقیقه یا ساعتی انترنتش قطع باشه پس بتونه روی لوکال ذخیره کنه زمانی که انترنت وصل شد باقی مانده اطلاعاتی که در زمان قطی انترنت ذخیره کرده را روی ویب سرور آپلود کنه ممنون میشم بازم رهنمائی کنید

alibilgats
چهارشنبه 02 اردیبهشت 1394, 16:58 عصر
خب دوست عزیز اگر حجم اطلاعات شما انقد پایینه به نظر من بهتره خودتو درگیر SQL حتی از نوع express نکنی!
از access استفاده کن تا نیازی به نصب هم نداشته باشی

esagraphic
چهارشنبه 02 اردیبهشت 1394, 17:10 عصر
خب دوست عزیز اگر حجم اطلاعات شما انقد پایینه به نظر من بهتره خودتو درگیر SQL حتی از نوع express نکنی!
از access استفاده کن تا نیازی به نصب هم نداشته باشی
اطلاعات من زیاد است ولی تعداد هر دفعه ریکورد کمه اطلاعات زیاد درج میشه بالای ملیون اما من میخوام یک کاپی بره روی ویب سرور

malizergani
چهارشنبه 02 اردیبهشت 1394, 18:02 عصر
سلام دوست عزیز

فکر نمی کنم لازم به بانک دوم باشه!

بانک اولتون رو مگه طبق استاندارد درست نکردید؟

این کارتون سرعت روند کار رو برای شما در فرایند کار کند می کنه. رفته رفته سیستم شما با هنگ مواجه میشه.

اگر بخواهید از نسخه پشتیبان داشته باشید با دستور Backup Database [NameDatabase] To Disk =N'AddressFile'

موفق و پیروز باشید

esagraphic
چهارشنبه 02 اردیبهشت 1394, 20:37 عصر
سلام دوست عزیز

فکر نمی کنم لازم به بانک دوم باشه!

بانک اولتون رو مگه طبق استاندارد درست نکردید؟

این کارتون سرعت روند کار رو برای شما در فرایند کار کند می کنه. رفته رفته سیستم شما با هنگ مواجه میشه.

اگر بخواهید از نسخه پشتیبان داشته باشید با دستور Backup Database [NameDatabase] To Disk =N'AddressFile'

موفق و پیروز باشید

سلام دوست عزیز به خاطری از دو دیتابیس کار میگیرم که نرم افزار تو یک شهر نصب است و دیتابیس دومی تو یه شهر دگه است زمانی که کلاینت ها ریکورد ها را ذخیره میکنن یک کاپی به لوکال ویکی به ویب سرور منتقل بشه

Javad_raouf
شنبه 05 اردیبهشت 1394, 13:26 عصر
دوست عزیز تشکر بابت اینک وقتت را در اختیارم گذاشتی و رهنمائی کردی این نکته آخری که نوشتی ولی::::::: جالب بود
برنامه که من دارم کار خیلی سختی نمیکنه تنها ده ریکورد را میگره ذخیره میکنه هر کلاینت دقیقا به موقعیت های مختلفی نصب است ده ریکورد ذخیره میکنه و یک کاپی هم باید روی سرور ویب سرور که MySQL یا SQL فرقی نمیکنه ذخیره کنه یک برنامه دگه به مدیریت میدیم که تنها اونم ویرایش اینها نمیکنه تنها گزارش میگیره و چاپ میکنه خواست من دقیقاً اینه که من نمیخواهم از Sqlserver استفاده کنم نصبش برای مشتری کمی سخته و نگهداریش براش کمی سخته میخوام از sql express که کنار برنامه دیتابیس اتچ است استفاده کنم سوال پیش میاد چرا مستقیم تو دیتابیس که روی سرور است من ذخیره نمیکنم به این دلیل امکان داره یک کلاینت برای چند دقیقه یا ساعتی انترنتش قطع باشه پس بتونه روی لوکال ذخیره کنه زمانی که انترنت وصل شد باقی مانده اطلاعاتی که در زمان قطی انترنت ذخیره کرده را روی ویب سرور آپلود کنه ممنون میشم بازم رهنمائی کنید
اینا که گفتید منافاتی با چیزی که من براتون نوشتم نداره
به نظر من از همون روش که گفتم استفاده کنید