אורקל ודוט נט – המציאות מוזרה מכל דמיון

21 בספטמבר 2008

תגובה אחת

שלום לכולם,

במאמר הזה אני אדבר על החיבור המוזר של אורקל ודוט נט, מנקודת המבט של מפתחים המשתמשים System.Data.OracleClient.

קדם דבר

לפני שנתחיל לדבר, ניישר קו על מה זה אורקל. אורקל הוא מסד נתונים אימתני. אורקל הוא מפלצת אימתנית של מסד נתונים שמסוגלת לעשות פחות או יותר הכל.

מה זה אורקל ביחס לסיקוול סרבר(Sql server)?  פחות או יותר אותו דבר. יש הבדלים, אבל בוא נגיד שהם יותר למומחי מסדי-נתונים שזה העבודה שלהם ולא למפתחים. לעומת זאת יש הבדלים שחשובים לנו: באורקל עובדים עם PL/SQL ובסיקוול עובדים עם T-SQL, הממשק הנפוץ של סיקוול סרבר הוא ה-Enterprise Manager שהוא כלי גרפי והממשק הנפוץ של אורקל הוא חלון דוס מתוחכם (הרקע בלבן והטקסט בשחור ולא כמו בדוס שזה להפך), אההה וכן – מיקרוסופט לא פיתחה את אורקל. (המאמר אינו עוסק בהבדלים בין אורקל וסיקוול סרבר ואין לקחת את פיסקה זו אפילו כעל קצה המזלג)

מיקרוסופט היא חברה מאוד מונופולית. בכל תחום אפשרי היא מקשה על המתחרים שלה ובכך הורגת אותם באכזריות (מהלך שאני תומך בו מאוד). אז למה מיקרוסופט לא עשתה אותו דבר לפיתוח דוט נט עם אורקל? היה מאוד פשוט לבוא ולהגיד “כן, טוב, אי-אפשר לפתח עם אורקל בדוט-נט”. אבל אורקל הוא מסד נתונים מאוד מבוסס ומיקרוסופט ידעו ויודעים שכל ניסיון להתעלם מאורקל רק יוביל שיתעלמו מדוט נט. אז הם התייחסו אליו, וברצינות.

המאמר הזה מיועד בעיקרו לאלו שעובדים עם אורקל ונתקלו בבעיות נפוצות.

חלק א': Data Providers (או: אופס', בנינו למתחרים מוצר יותר טוב)

כיום עם הדוט-נט Framework נשלח Namespace בשם System.Data, והוא בין השאר מכיל את ה-Data Providers של דוט נט. ה-Data Providers הללו מאפשרים לנו להתקשר למסדי הנתונים. דוט נט פריימוורק נשלח עם שלושה Data Providers כברירת מחדל: סיקוול סרבר (SqlDataProvider), אורקל (OracleDataProvider) ואחד לכל השאר (OleDbProvider).

שימו לב מה מיקרוסופט עשו, הם שמו את אורקל באותה רמת חשיבות ותכנון מראש של סיקוול סרבר. זה כמעט שקול לזה שמיקרוסופט יביאו את ווינדוס לונגהורן עם פיירפוקס מותקן בתוכו. תראו את גודל האמירה הזאת: אנחנו תואמים למוצר של חברה יריבה.

משהו מאוד מעניין לשים לב עליו הוא בדיקות מהירות (BenchMarking) שבוצעו על שלושת ה-Native Data Providers. חיפשתי במשך כמה שעות מאמר שקראתי לפני כשנתיים ב-Dotnetjunkies.com המראה Preformance testing של שלושת ה-DataProviders ומראה כיצד בכל הסיטואציות שנבדקו לאורקל Data Provider יש ביצועים מהירים יותר. חשוב להדגיש, מיקרוסופט בנו את ה-Data Provider של המתחרים ככה שבשילוב עם מסד הנתונים אורקל – הוא יותר מהיר מה-Data Provider של סיקוול סרבר בשילוב עם סיקוול. (חשוב להדגיש שחיפשתי את המאמר, לא מצאתי, שלחתי אי-מייל למנהלי האתר ואם וכאשר הם יחזרו אליי עם קישור אני אשים אותו כאן. אגב אתם מוזמנים לחפש בדיקות מהירות של ADO.net ל-Data Providers השונים ולהוסיף בתגובות למאמר)

חלק ב: עבודה עם קידודים (או: “מה קורה שמנסים לכתוב עברית במסד נתונים מערב-אירופאי”)

אורקל (בדומה לסיקוול סרבר) עובד עם קידודים שונים לשפות שונות. באורקל הקידודים הללו נקראים CharcterSets. ישנם שלושה CharcterSets נפוצים: utf-8 (יוניקוד), IW8ISO8859P8 (עברית ואנגלית), WE8ISO8859P1 (אנגלית). דוט נט בתוך הפריימוורק עצמו, בתוך ה-CLR, עובד עם יוניקוד.

אם האורקל שלנו פועל על קידוד יוניקוד – הרווחנו. אין שום צורך לבצע התאמות.

אם האורקל שלנו פועל על קידוד עברית ואנגלית – הרווחנו. הפריימוורק יודעת לטפל בזה.

אם האורקל שלנו פועל על קידוד אנגלית (והקידוד ASCII המקומי – עברית) ובכל זאת אנחנו מכניסים לתוכו או קוראים ממנו גם מידע בעברית – נדפקנו קשות. כל פעם שנכניס מידע למסד הנתונים נצטרך לדאוג שהוא יעבור לקידוד המתאים, וכל פעם שנקרא מידע ממסד הנתונים נצטרך לדאוג שהוא יעבור לקידוד שאנחנו יכולים לקרוא. אם לא נקודד את המידע לפני ששולחים אותו לאורקל – יופיעו סימני שאלה במסד במקום התווים בעברית. אם לא נקודד את המידע שאנו מחזירים מאורקל – נקבל בחזרה רק סימני שאלה (למרות שהעברית במסד הנתונים עצמו מופיעה בסדר).

נציג פונקציה בדוט נט שמטרתה היא להמיר מחרוזת מקידוד מקומי מסויים לקידוד מקומי אחר:

  public string encodingConvert(string from_encoding,string to_encoding,string src)
  {
   Encoding fromEncoding = Encoding.GetEncoding(from_encoding);
   Encoding toEncoding = Encoding.GetEncoding(to_encoding);
   return toEncoding.GetString(fromEncoding.GetBytes(src));
  }

הפונקציה תקבל מחרוזת טקסטואלית ותמיר אותו מקידוד המקור לקידוד היעד. מצאתי שבזמן עבודה עם CharcterSet אנגלית (WE8ISO8859P1) באפליקציות שתומכות בעברית צריך להשתמש בשתי הפונקציות הבאות:

  public string encodeheb(string src)
  {
   return encodingConvert("windows-1255","ISO-8859-1",src);
  }

  public string decodeheb(string src)
  {
   return encodingConvert("ISO-8859-1","windows-1255",src);
  }

הפונקציה הראשונה, encodeheb, תקבל מחרוזת עברית מתוך העבודה הפנימית בדוט-נט (למשל מתוך טופס של המשתמש) ותקודד אותו ככה שהעברית תשמר נכון במסד. הפונקציה השנייה,decodeheb, תקבל מחרוזת ממסד הנתונים ותדאג לקודד אותו כך שדוט-נט יוכל לעבוד איתו (להציג אותו למשתמש למשל או לבצע מניפולציות על המחרוזת הזו).

ברגע שניישם את הפונקציות הללו בקוד שלנו, נצטרך להתחיל ליצור פונקציות שיודעות לתרגם את הפקדים הרלוונטים. למשל בעת החזרת נתונים מאורקל נצטרך לדאוג לבצע decodeheb על כל DataCell בכל DataRow בכל DataTable בכל DataSet וגם לבנות מעטפת לפונקציות של OracleDataReader. בעת שליחת נתונים לאורקל דרך שאילתות נצטרך לדאוג כי הן יעברו במקום מרכזי שבו יהיה ניתן קדם שליחתם לאורקל לדאוג שהם יעברו לקידוד שאורקל יכול לעבוד איתו באמצעות פונקציה encodeheb (עקרונית, לעבור על OracleParameter.Value ולדאוג להעביר אותו לקידוד המתאים).

שאלה נפוצה היא אם משחקים כאלו ב-Encoding לא פוגעים בביצועים או מקשים בצורה בלתי-סבירה על תהליך כתיבת הקוד – התשובה היא לא. בכל אפליקציה רצינית שראיתי תמיד יש פונקציות שמטפלות בכל הקשור ל-DAL בצורה פרטנית לטיפוסי הנתונים. לא חסרות דרכים לשלב כאלו פונקציות בצורה שתהיה שקופה ברוב תהליך כתיבת הקוד. אפשר למשל לשלב את זה ב-DAL שלנו, אפשר לרשת מפקדי ה-Data השונים ולהוסיף להם את הפונקציות שאחריות לשינויי הקידודים ב-Delegates הרלוונטים, ועוד אלף ואחת אפשרויות.

עוד שאלה נפוצה על שינויי קידוד היא מה קורה אם (למשל) עבדנו בפיתוח באורקל בקידוד אנגלית אבל שרת האורקל ריצה שלנו פועל על קידוד יוניקודעברית-אנגלית. מאוד פשוט, ניתן לשמור קונפיגיורציה אפלקטיבית שאומרת האם בכלל יש לבצע את שינויי הקידודים האלו או לא. כמובן שהתרחיש היותר הגיוני הוא שבגירסה 1.0 של האפליקציה היינו חייבים לעבוד עם קידוד אנגלית, ולפני גירסה 2.0 עברנו ל-CharcterSet של יוניקודעברית-אנגלית. גם כן, היות וכל הקריאות לשינויי הקידודים הם Centerlized באפליקציה שלנו אפשר דרך עריכה של הקוד (או כתיבה נכונה של והסתמכות על קונפיגיורציה אפלקטיבית) לדאוג שלא יתבצעו שינויי הקידוד.

שוב, כל הסיפור הזה תקף אך ורק אם אתה עובדים עם מסד אורקל שמאיזהשהי סיבה ה-Charcter Set שלו הוא אנגלית בלבד (WE8ISO8859P1).

 

חלק ג': ORA-01036: illegal variable name/number  (או: “הודעת שגיאה ג'נארית שלא אומרת כלום!“)

למי מכם שצברו ניסיון בעבודה עם System.Data.OracleClient הבינו עד עכשיו קטע מאוד מעניין: מיקרוסופט לא היו כזה סגורים על כל הקטע של Bind Variables (המקביל של אורקל ל-SqlParameter של סיקוול) ובחלק מהמקומות פשוט לא דאגו להודעות שגיאה נורמליות.

ההודעת שגיאה אשר כתובה למעלה היא הודעת שגיאה של אורקל. אורקל זורק את השגיאה הזאת כאשר דוט נט מצהירה בצורה בלתי-זהירה על Bind Variables. מה זה “בלתי-זהירה”? מה צריך לבדוק? מה צריך לתקן?

מצחיק מאוד שכל הנושא הזה לא מתועד בשום מקום, אין שום מאמר מקיף אליו בשום-מקום באינטרנט ולמעשה כרגע אני די משוכנע שאני היחידי שעושה טעויות כאלו, אבל ניחא 🙂

הנה האפשרויות שאני נתקלתי בהן:

1. השם של ה-Bind Variable גדול מ-31 תווים.

2. אי-הוספת “:” בהצהרה על שם ה-Bind Variable (בדומה לשטרודל של סיקוול סרבר).

3. אם הצהרנו על Bind Variable ולא השתמנו בו.

4. סינטקס קלול ליד שם הפרמטר – למשל, לשים רווח לפניאחרי שם פרמטר או שם פרמטר עם רווחים.

5. לא הוספנו ל-OracleCommand מאפיין CommandType.

6. הצהרה על סוג פרמטר לא נכון ביחס לעבודה איתו בשאילתות או PL/SQL (הצהרה על מחרוזת ולהשוות למספר, להעביר LONG במקום NUMBER בתוך פונקציה וכיו”ב).

השגיאה הזאת מאוד מפורסמת בעיקר כי יש אנשים שביזבזו שעות על גבי שעות לנסות למצוא פסיק או שורה שכחלק מהרגלי כתיבת קוד הם תמיד שמים ומאוד קשה לשים לב שהם לא שם או שיש שם פסיק יותר מדי.

 

חלק ד': ORA-00100 error: maximum open cusors (או: “הפקודות שסירבו למות”)

שגיאה מאוד פשוטה שנגרמת מכך שלכל שרת אורקל יש מספר מקסימלי של Cursors שהוא רשאי לפתוח בזמן נתון. אם עברנו את הגבול הזה – כנראה מאוד שעשינו משהו לא נכון. (או שיש לנו מעל 100+ פניות למסד הנתונים פר שנייה ביחס לערך ההתחלתי של המקסימום Open cursors).

אופציה ראשונה היא שבטעות הכנסו את האפליקציה שלנו ללולאה אין-סופית והיא מפגיזה את השרת בשאילתות בלי לתת לו הזדמנות להחזיר נתונים (למשל בלולאה אין-סופית שבראש מסך מסויים תתבצע שאילתא א-סינכרונית וישר אחר-כך תתבצע הפנייה למסך אחר). אם זה המצב – לולאות אין-סופיות זה דבר רע – תתקנו את זה.

אופציה שנייה, לא עשיתם Dispose ל-OracleCommand שלכם. בכדי להחזיר רשומות דרך PL/SQL בדוט נט צריך לעבוד עם מה שנקרא Ref Cursors.  מה שקורה הוא שנשלחות תוצאות שאילתא מאורקל בטיפוס הנתונים הפנימי שאורקל עובד איתו. הטיפוס נתונים הזה צריך בסוף להיסגר אחרת הוא נחשב פתוח (עמוק, אני יודע). יש גבול לכמה תוצאות שאילתות פתוחות אפשר להחזיק בו-זמנית בשרת אורקל. אם שלחנו Ref Cursors מ-PL/SQL לדוט נט באמצעות OracleCommand חובה עלינו לבצע Dispose ל-OracleCommand ברגע שהיא כבר לא בשימוש. אסור לחכות ל-GC שיעשה את זה.

אופציה שלישית, לא עשיתם שום דבר רע. האפליקציה שלכם גדלה והגיע למצב שצריך לדאוג ל-Oracle Scalability. דברו עם ה-DBA שלכם, אבל בעקרון מספיק לשנות את max_open_cursors בקובץ ההגדרות של השרת אורקל. מניסיון מכאיב עם DBA, אל תעלו את המקסימום לפי 5 בלי להגיד ל-DBA 🙂

 

חלק ה': פריסת לקוח אורקל (או: “איזה מזל שצריך לעשות את זה רק פעם אחת!”)

בשעה טובה הגעתם לזמן לפרוס שרת אפליקציה שמתקשר לשרת אורקל. היות ובניגוד לאקסס וסיקוול סרבר, Windows Server לא בא עם הכלים המתאימים להתחבר לאורקל. צריך תשתית מתאימה על המכונה בכדי ששרת האפליקציה שלנו (web server) יוכל להתקשר לשרת האורקל.

האפשרות הראשונה היא להתקין על המכונה הזאת Oracle Client שזאת חבילת תוכנות שאפשר להוריד מהאתר של אורקל. לקנפג את ה-TNS_NAMES והכל מוכן. למיטב ידיעתי לכל גירסה של אורקל שאינו 10/11 אין שום אפשרות אחרת.

אם עובדים עם אורקל 10/11 יש מה שנקרא Oracle Instant Client. מדובר על קבוצה מאוד קטנה של DLLים שמאפשרים התחברות למסד אורקל. כמה התהליך של התקנת Instant Client:

1. הורדת Oracle 10g/11 Instant Client מאתר ההורדות של אורקל.

2. העתקת כל ה-DLLים שבספרייה הראשית של ה-ZIP שהורדתם לספריית System32. כמובן שבמקום להעתיק ל-System32 ניתן להוסיף איזה תיקייה בצד ולהוסיף אותה ל-Path של חלונות, אבל במצב הזה כבר מומלץ להצטייד באיש IT הידודותי הקרוב למקום מגוריכם.

3. העתקת TNS_NAMES.ora ו-Sqlnet.ora לספריה כלשהי במכונה. (לא לשכוח קנפג את TNS_NAMES).

4. להוסיף Enviorment variable על המכונה בשם TNS_ADMIN שיכוון למיקום של הקובץ.

5. לתת למשתמשי ה-IIS הרלוונטים גישת Read & Read and execute & List content על הספרייה שבו שמנו את ה-TNS_NAMES.ora. ייתכן וגם יהיה צורך לתת למשתמשי ה-IIS הרלוונטים הרשאה לקרוא את ה-DLLים שפרסנו בסעיף 2 (משתנה לפי גירסת מערכת ההפעלה של חלונות ועדכוני האבטחה).

 

לסיכום

השתדלתי במאמר זה להעביר חלק מהידע שהצטבר אצלי בעבודה על השילוב המוזר של אורקל ודוט נט. מקווה שעזרתי לכם וחסכמתי כמה שעות של דיבוג.

 

ברכות,

ג'סטין-יוסף אנג'ל

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

תגובה אחת

  1. חגי 26 בפברואר 2009 ב 19:44

    שלום רב
    אשמח לדעת תשובה אך אני מתגבר על בעית העברית
    הבעיה היא העברית בדטבס בסדר גמור אך בפרונט בסמני שאלה שמתי לב לבעיה מתוך האדמין מה שאני כביכול לשנות זה מסתדר העברית אך בדטבס מוצג לי בגבריש ובאתר ובאדמין בעברית הנתונים הנשלפים מי הדטבס מוצגים באתר כביכול בסימני שאלה ובדטבס הם תקנים

    אשמח לדעת תשובה
    0508630449

    הגב