דילוג לתוכן
  • דף הבית
  • קטגוריות
  • פוסטים אחרונים
  • משתמשים
  • חיפוש
  • חוקי הפורום
כיווץ
תחומים

תחומים - פורום חרדי מקצועי

💡 רוצה לזכור קריאת שמע בזמן? לחץ כאן!
  1. דף הבית
  2. תכנות
  3. מניעת race condition ב-DB

מניעת race condition ב-DB

מתוזמן נעוץ נעול הועבר תכנות
42 פוסטים 7 כותבים 1.1k צפיות
  • מהישן לחדש
  • מהחדש לישן
  • הכי הרבה הצבעות
התחברו כדי לפרסם תגובה
נושא זה נמחק. רק משתמשים עם הרשאות מתאימות יוכלו לצפות בו.
  • dovidD מנותק
    dovidD מנותק
    dovid ניהול
    השיב לyossiz ב נערך לאחרונה על ידי
    #5

    @yossiz
    https://stackoverflow.com/a/30000470/1271037

    מנטור אישי למתכנתים (ולא רק) – להתקדם לשלב הבא!

    בכל נושא אפשר ליצור קשר dovid@tchumim.com

    תגובה 1 תגובה אחרונה
    1
    • yossizY מנותק
      yossizY מנותק
      yossiz
      כתב ב נערך לאחרונה על ידי
      #6

      @dovid עוד לא עיינתי בכל המראי מקומות. אבל מישהו הביא לי עכשיו פתרון שאני נהנה מאוד ממנו.
      זה שילוב של פתרון 2 (נעילה ברמת ה-DB) ופתרון 5 (נעילה ברמת הקוד):
      כאשר מושכים את מספר ה-charge הגבוהה ביותר של הארגון מה-DB לנעול רק את השורה ההיא על ידי FOR UPDATE.

      SELECT "chargeNumber" FROM charges WHERE orgId = <orgId> ORDER BY "chargeNumber" DESC LIMIT 1 FOR UPDATE;
      

      מכיון שכל פעם שהקוד הזה רץ הוא מבקש לנעול את השורה ההיא, זה יפעל כמו mutex בקוד. לכן למרות שאין מניעה מצד ה-DB להכניס באמצע הטרנזקציה עוד שורה עם מספר זהה, יש מניעה מצד הקוד.

      📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

      תגובה 1 תגובה אחרונה
      3
      • clickoneC מנותק
        clickoneC מנותק
        clickone
        השיב לyossiz ב נערך לאחרונה על ידי
        #7

        @yossiz לכאורה טריגר הוא הפיתרון הנכון כאן
        אם כי אני כמעט מעולם לא השתמשתי בטריגר (למעט הכרה שלו)
        יש מקרה אחד ויחיד שבו עד היום השתמשתי בטריגר, וגם זה היה מחוסר ברירה ולא מבחירה
        (יכול להיות שאני טועה בזה, אבל אני לא אוהב להשתמש בזה)

        מה מפריע לך בעידכון של שאילתת משנה?

        update orgs set lastCharge=(
        select max(chargeId) from charges where orgId=orges.orgeId
        ) where orgeId=?
        

        אין טסט כמו פרודקשן.

        המייל שלי urivpn@gmail.com

        yossizY תגובה 1 תגובה אחרונה
        4
        • yossizY מנותק
          yossizY מנותק
          yossiz
          השיב לclickone ב נערך לאחרונה על ידי
          #8

          @clickone אמר במניעת race condition ב-DB:

          מה מפריע לך בעידכון של שאילתת משנה?

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

          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

          clickoneC תגובה 1 תגובה אחרונה
          2
          • clickoneC מנותק
            clickoneC מנותק
            clickone
            השיב לyossiz ב נערך לאחרונה על ידי
            #9

            @yossiz
            אני לא מכיר את postgres, אבל אני חושב שזה שווה ערך ל4 והוא עושה את 2 הפקודות ביחד, ולכאורה זה נועל את הDB

            אני מנסה קודם להבין את הצורך
            כמו שכתב @dovid , בד"כ משתמשים במיספור אוטומטי, למה זה לא המצב אצלך?
            אא"כ (שזה מה ששאני מריח) שזה טבלה כמו של חשבוניות / קבלות ואתה צריך לדעת את המספר האחרון שיצא
            ועדיין, לא הבנתי למה אתה שומר את הנתון הזה סטטי בorgs, במקום להביא אותו מחושב באותו הרגע שתצטרך?
            ז"א, במקום למשוך את זה מהטבלה, וללכת ולחזור, אתה פשוט מוסיף את הנתונים בinsert ואז מיד את המס' אתה מכניס עם sub query

            INSERT INTO charge
            (
            docNumber,
            name,
            amount
            )
            VALUES
            (
            (select max(chargeId) from charges where orgId=?) as docNumber,
            "yossiz" as name,
            100 as amount
            )
            

            שים לב שאני כותב את השאילתא ישר לכאן ללא בדיקה אז יכול להיות טעויות

            אין טסט כמו פרודקשן.

            המייל שלי urivpn@gmail.com

            yossizY תגובה 1 תגובה אחרונה
            0
            • yossizY מנותק
              yossizY מנותק
              yossiz
              השיב לclickone ב נערך לאחרונה על ידי yossiz
              #10

              @clickone נראה לי שאנחנו לא משדרים באותו תדר...
              מספר ה-charge שמור בטבלת ה-charges לא עם ה-org.
              כדי לקבל את המספר הבא אני מושך את המספר הגבוהה ביותר של ארגון זה ומוסיף עליו עוד אחד.

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

              ז"א, במקום למשוך את זה מהטבלה, וללכת ולחזור, אתה פשוט מוסיף את הנתונים בinsert ואז מיד את המס' אתה מכניס עם sub query

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

              📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

              clickoneC תגובה 1 תגובה אחרונה
              1
              • clickoneC מנותק
                clickoneC מנותק
                clickone
                השיב לyossiz ב נערך לאחרונה על ידי
                #11

                @yossiz
                ואין לך דרך לדעת מי קשור לאותו ORG?
                אם כן, למה זה ככה? (מוזר לי שאתה מתבסס על הORG אבל אין עמודה שלו בטבלה השנייה)

                כנראה אני אכן מפספס כאן משהו מאד מהותי
                תוכל להסביר יותר מה הקשרים בין הטבלאות?

                אין טסט כמו פרודקשן.

                המייל שלי urivpn@gmail.com

                yossizY תגובה 1 תגובה אחרונה
                0
                • yossizY מנותק
                  yossizY מנותק
                  yossiz
                  השיב לclickone ב נערך לאחרונה על ידי yossiz
                  #12

                  @clickone עזוב טבלאות אחרות, בטעות הזכרתי שיש טבלה של org.
                  יש רק טבלה אחת של charges עם 3 עמודות (שקשורות לנושא שלנו): id, orgId, chargeNumber
                  ה-chargenumber אמור להיות מספר ה-charge לפי הארגון. זה לא יכול להיות autoincrement כי אפשר שתיים עם אותו מספר כאשר הם משוייכים לארגון אחר

                  📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                  clickoneC chagoldC 2 תגובות תגובה אחרונה
                  0
                  • clickoneC מנותק
                    clickoneC מנותק
                    clickone
                    השיב לyossiz ב נערך לאחרונה על ידי
                    #13

                    @yossiz אמר במניעת race condition ב-DB:

                    ה-chargenumber אמור להיות מספר ה-charge של הארגון.

                    שזה תמיד האחרון שנכנסם + 1?
                    או שזה מספר קבוע?
                    כעת אני כן רואה שאתה כותב שיש בטבלה orgid

                    אין טסט כמו פרודקשן.

                    המייל שלי urivpn@gmail.com

                    yossizY תגובה 1 תגובה אחרונה
                    1
                    • yossizY מנותק
                      yossizY מנותק
                      yossiz
                      השיב לclickone ב נערך לאחרונה על ידי yossiz
                      #14

                      @clickone אמר במניעת race condition ב-DB:

                      שזה תמיד האחרון שנכנסם + 1?

                      בדיוק, אבל האחרון של ארגון זה, לא של כל הטבלה

                      📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                      clickoneC תגובה 1 תגובה אחרונה
                      0
                      • clickoneC מנותק
                        clickoneC מנותק
                        clickone
                        השיב לyossiz ב נערך לאחרונה על ידי
                        #15

                        @yossiz
                        אז מצויין, זה מה שכתבתי בדוגמא הזו
                        (תחליף את docNumber ב chargeNumber)

                        INSERT INTO charge
                        (
                        docNumber,
                        name,
                        amount
                        )
                        VALUES
                        (
                        (select max(chargeId) from charges where orgId=?) as docNumber,
                        "yossiz" as name,
                        100 as amount
                        )
                        

                        ואתה התכוונת אליו למעלה, לא?
                        לכאורה בשיטה הזו הוא ינעל את השינויים כי זה נעשה בפעם אחת

                        אין טסט כמו פרודקשן.

                        המייל שלי urivpn@gmail.com

                        תגובה 1 תגובה אחרונה
                        1
                        • clickoneC מנותק
                          clickoneC מנותק
                          clickone
                          כתב ב נערך לאחרונה על ידי clickone
                          #16

                          כאן
                          https://stackoverflow.com/questions/39498675/how-to-create-an-auto-increment-column-that-is-segmented-by-an-other-column
                          לכאורה הוא פתר את זה עם טריגר ולכאורה זה הנכון
                          (זה נראה MSSQL אבל לא התעמקתי)

                          אין טסט כמו פרודקשן.

                          המייל שלי urivpn@gmail.com

                          תגובה 1 תגובה אחרונה
                          1
                          • clickoneC מנותק
                            clickoneC מנותק
                            clickone
                            כתב ב נערך לאחרונה על ידי
                            #17

                            סליחה שאני שם כאן כ"כ הרבה מראי מקומות 😮
                            מאד תמוה בעצם שאין דבר כזה מובנה כי זה דבר די נפוץ מה שאתה מנסה לעשות
                            אבל ראיתי שזה קיים בmysql אבל רק עם המנוע MyISAM
                            https://dba.stackexchange.com/questions/19019/mysql-get-next-unique-value-without-auto-increment/19020#19020
                            הרעיון הוא שאתה מגדיר שדה שהערך שלו יגדל ב1 על סמך שדה אחר בטבלה

                            PRIMARY KEY (SiteID,SiteWorkorderNum)
                            

                            והנה כל הדוגמא משם

                            mysql>     CREATE DATABASE david;
                            Query OK, 1 row affected (0.00 sec)
                            
                            mysql>     USE david
                            Database changed
                            mysql>     CREATE TABLE site_workorder_seq
                                ->     (
                                ->         SiteID int not null,
                                ->         SiteWorkorderNum int not null auto_increment,
                                ->         PRIMARY KEY (SiteID,SiteWorkorderNum)
                                ->     ) ENGINE=MyISAM;
                            Query OK, 0 rows affected (0.01 sec)
                            
                            mysql>     INSERT INTO site_workorder_seq (SiteID) VALUES
                                ->     (1),(1),(2),(3),(3),(3),(3),(4),(4),(4),
                                ->     (5),(5),(4),(2),(2),(2);
                            Query OK, 16 rows affected (0.00 sec)
                            Records: 16  Duplicates: 0  Warnings: 0
                            
                            mysql>     SELECT * FROM site_workorder_seq;
                            +--------+------------------+
                            | SiteID | SiteWorkorderNum |
                            +--------+------------------+
                            |      1 |                1 |
                            |      1 |                2 |
                            |      2 |                1 |
                            |      2 |                2 |
                            |      2 |                3 |
                            |      2 |                4 |
                            |      3 |                1 |
                            |      3 |                2 |
                            |      3 |                3 |
                            |      3 |                4 |
                            |      4 |                1 |
                            |      4 |                2 |
                            |      4 |                3 |
                            |      4 |                4 |
                            |      5 |                1 |
                            |      5 |                2 |
                            +--------+------------------+
                            16 rows in set (0.00 sec)
                            
                            

                            אין טסט כמו פרודקשן.

                            המייל שלי urivpn@gmail.com

                            yossizY תגובה 1 תגובה אחרונה
                            1
                            • yossizY מנותק
                              yossizY מנותק
                              yossiz
                              השיב לclickone ב נערך לאחרונה על ידי
                              #18

                              @clickone מעניין מאוד, זה בדיוק מה שחיפשתי (אבל זה לא קיים ב-postgres).

                              📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                              clickoneC תגובה 1 תגובה אחרונה
                              2
                              • clickoneC מנותק
                                clickoneC מנותק
                                clickone
                                השיב לyossiz ב נערך לאחרונה על ידי
                                #19

                                @yossiz
                                כעת מצאתי משהו דומה על mssql
                                שזה יצירת אינדקס מותאם אישית, שעושה בדיוק את הפעולה הזו
                                https://stackoverflow.com/questions/12152790/sql-server-autoincrement-varying-by-value-of-another-field
                                עכשיו נשאר לבדוק האם יש אפשרות כזו גם בפוסטגרס, אם כי אולי תעדיף כבר להשאר עם הפיתרון הרגיל, שבכל מקרה זה מה שממומש מאחרי הקלעים....

                                אין טסט כמו פרודקשן.

                                המייל שלי urivpn@gmail.com

                                תגובה 1 תגובה אחרונה
                                2
                                • chagoldC מנותק
                                  chagoldC מנותק
                                  chagold
                                  השיב לyossiz ב נערך לאחרונה על ידי
                                  #20

                                  @yossiz אמר במניעת race condition ב-DB:

                                  @clickone עזוב טבלאות אחרות, בטעות הזכרתי שיש טבלה של org.
                                  יש רק טבלה אחת של charges עם 3 עמודות (שקשורות לנושא שלנו): id, orgId, chargeNumber
                                  ה-chargenumber אמור להיות מספר ה-charge לפי הארגון. זה לא יכול להיות autoincrement כי אפשר שתיים עם אותו מספר כאשר הם משוייכים לארגון אחר

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

                                  yossizY תגובה 1 תגובה אחרונה
                                  0
                                  • A מנותק
                                    A מנותק
                                    avr416
                                    כתב ב נערך לאחרונה על ידי avr416
                                    #21

                                    לא הבנתי למה לא נעילה ברמת הקוד?
                                    גם את הנעילה הזאת אתה מקבל בחינם מהקוד..
                                    ולגופו של ענין, הרי אתה לא ניגש לdb מחוץ לקוד, אז אני לא רואה סיבה למה לא להשתמש בזה.
                                    אתה גם יכול לעשות נעילה בקוד פר ארגון, כך שלא יהיו לך הרבה התנגשויות.

                                    אני מממש דבר כזה בחנות אינטרנטית, כשיש צורך להגביל מוצר לפי כמות במלאי, ואני לא רוצה שיווצר מצב דומה למה שתיארת.

                                    תגובה 1 תגובה אחרונה
                                    3
                                    • yossizY מנותק
                                      yossizY מנותק
                                      yossiz
                                      השיב לchagold ב נערך לאחרונה על ידי yossiz
                                      #22

                                      @chagold אבל הקוד הפנימי של ה-DB שמממש את זה לא זמין לנו המשתמשים.

                                      📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                                      chagoldC תגובה 1 תגובה אחרונה
                                      0
                                      • chagoldC מנותק
                                        chagoldC מנותק
                                        chagold
                                        השיב לyossiz ב נערך לאחרונה על ידי
                                        #23

                                        @yossiz https://www.postgresql.org/docs/9.3/sourcerepo.html?

                                        yossizY תגובה 1 תגובה אחרונה
                                        0
                                        • yossizY מנותק
                                          yossizY מנותק
                                          yossiz
                                          השיב לchagold ב נערך לאחרונה על ידי
                                          #24

                                          @chagold אני יודע שקוד המקור של ה-DB זמין, אבל מה אני אעשה עם זה?
                                          אני לא הולך לערוך את הקוד ולקמפל כדי להוסיף אפשרות זו.

                                          📧 יוסי@מייל.קום | 🌎 בלוג | ☕ קפה

                                          תגובה 1 תגובה אחרונה
                                          3

                                          • 1
                                          • 2
                                          • 3
                                          בא תתחבר לדף היומי!
                                          • התחברות

                                          • אין לך חשבון עדיין? הרשמה

                                          • התחברו או הירשמו כדי לחפש.
                                          • פוסט ראשון
                                            פוסט אחרון
                                          0
                                          • דף הבית
                                          • קטגוריות
                                          • פוסטים אחרונים
                                          • משתמשים
                                          • חיפוש
                                          • חוקי הפורום