JDBC עם גרובי

1. הקדמה

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

JDBC, אמנם ברמה נמוכה יחסית, הוא היסוד של מרבית ה- ORM וספריות גישה אחרות ברמה גבוהה ב- JVM. ואנחנו יכולים להשתמש ב- JDBC ישירות בגרובי, כמובן; עם זאת, יש לו ממש API מסורבל.

למרבה המזל עבורנו, הספרייה הסטנדרטית של Groovy בונה על JDBC כדי להציג ממשק נקי, פשוט אך חזק. אז נבדוק את מודול גרובי SQL.

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

2. התקנת JDBC ו- Groovy

עלינו לכלול את ה- קִצבִּי-מודול SQL בין התלות שלנו:

 org.codehaus.groovy groovy 2.4.13 org.codehaus.groovy groovy-sql 2.4.13 

אין צורך לרשום זאת במפורש אם אנו משתמשים ב- groovy-all:

 org.codehaus.groovy גרובי הכל 2.4.13 

אנו יכולים למצוא את הגרסה האחרונה של גרובי, גרובי-מ"ר ו גרובי-הכל במרכז מייבן.

3. חיבור למסד הנתונים

הדבר הראשון שעלינו לעשות על מנת לעבוד עם מסד הנתונים הוא התחברות אליו.

בואו נציג את groovy.sql.Sql בכיתה, בה נשתמש לכל הפעולות במסד הנתונים עם מודול ה- Groovy SQL.

מופע של מ"ר מייצג מסד נתונים עליו אנו רוצים לפעול.

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

3.1. ציון פרמטרי חיבור

במהלך מאמר זה, אנו נשתמש במסד נתונים של HSQL, שהוא DB יחסי קל המשמש בעיקר בבדיקות.

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

מפה dbConnParams = [url: 'jdbc: hsqldb: mem: testDB', משתמש: 'sa', סיסמה: '', מנהל ההתקן: 'org.hsqldb.jdbc.JDBCDriver']

כאן בחרנו לציין את אלה המשתמשים ב- מַפָּה, אם כי זו לא הבחירה היחידה האפשרית.

לאחר מכן נוכל להשיג חיבור מה- מ"ר מעמד:

def sql = Sql.newInstance (dbConnParams)

נראה כיצד להשתמש בו בחלקים הבאים.

כשתסיים, עלינו תמיד לשחרר משאבים קשורים:

sql.close ()

3.2. באמצעות א מקור מידע

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

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

גרובי מ"ר מחלקה מקבלת מקורות נתונים בסדר גמור:

def sql = Sql.newInstance (מקור נתונים)

3.3. ניהול משאבים אוטומטי

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

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

Sql.withInstance (dbConnParams) {Sql sql -> haveFunWith (sql)}

4. הוצאת הצהרות נגד מסד הנתונים

עכשיו נוכל להמשיך לדברים המעניינים.

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

sql.execute "צור טבלה PROJECT (מספר שלם מזהה לא null, שם varchar (50), url varchar (100))"

בתיאוריה זה עובד גם בהצהרות DDL / DML וגם בשאילתות; עם זאת, הטופס הפשוט לעיל אינו מציע דרך להחזיר תוצאות שאילתות. נעזוב שאילתות להמשך.

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

4.1. הכנסת נתונים

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

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

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

אז נניח שיש לנו טבלה עם מפתח ראשי לתוספת אוטומטית (זהות בעגה HSQLDB):

sql.execute "צור טבלה PROJECT (ID IDENTITY, NAME VARCHAR (50), URL VARCHAR (100))"

בואו נכניס שורה בטבלה ונשמור את התוצאה במשתנה:

def ids = sql.execute הוסף "" "הכנס לפרויקט (שם, URL) ערכים ('tutorials', 'github.com/eugenp/tutorials')" ""

executeInsert מתנהג בדיוק כמו לבצע, אבל מה זה מחזיר?

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

זה נשמע מסובך, אבל במקרה שלנו, שהוא ללא ספק הנפוץ ביותר, יש שורה אחת וערך שנוצר יחיד:

assertEquals (0, ids [0] [0])

הכנסה שלאחר מכן תחזיר ערך שנוצר של 1:

ids = sql.executeInsert "" "INSERT INTO PROJECT (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring')" "" assertEquals (1, ids [0] [ 0])

4.2. עדכון ומחיקת נתונים

באופן דומה קיימת שיטה ייעודית לשינוי ומחיקת נתונים: executeUpdate.

שוב, זה שונה מ לבצע רק בערך ההחזר שלו ונראה רק את צורתו הפשוטה ביותר.

ערך ההחזר, במקרה זה, הוא מספר שלם, מספר השורות המושפעות:

def count = sql.executeUpdate ("UPDATE PROJECT SET URL = '//' + URL") assertEquals (2, count)

5. שאילתת מסד הנתונים

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

התמודדות עם ה- JDBC ResultSet השיעור הוא לא בדיוק כיף. למזלנו, גרובי מציעה הפשטה יפה על כל זה.

5.1. איטרציה על תוצאות שאילתות

בעוד שלולאות הן בסגנון כה ישן ... כולנו נסגרים בימינו.

וגרובי כאן כדי להתאים לטעמנו:

sql.eachRow ("SELECT * FROM PROJECT") {GroovyResultSet rs -> haveFunWith (rs)}

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

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

5.2. גישה לערכי תוצאות

בנוסף לכל ResultSet שיטות, GroovyResultSet מציע כמה כלי עזר נוחים.

בעיקר, הוא חושף מאפיינים בשם התואמים לשמות עמודות:

sql.eachRow ("SELECT * FROM PROJECT") {rs -> assertNotNull (rs.name) assertNotNull (rs.URL)}

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

GroovyResultSet מציע גם גישה לעמודות באמצעות אינדקס מבוסס אפס:

sql.eachRow ("SELECT * FROM PROJECT") {rs -> assertNotNull (rs [0]) assertNotNull (rs [1]) assertNotNull (rs [2])}

5.3. דִפּוּף

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

כל שורה ולשיטות קשורות יש עומסי יתר שמקבלים קיזוז ומספר מקסימאלי של שורות שהוחזרו:

def offset = 1 def maxResults = 1 def שורות = sql.rows ('SELECT * FROM PROJECT ORDER BY NAME', offset, maxResults) assertEquals (1, rows.size ()) assertEquals ('REST with Spring', שורות [0 ].שֵׁם)

הנה ה שורות השיטה מחזירה רשימה של שורות במקום לחזור עליהן כמו כל שורה.

6. שאילתות והצהרות פרמטראטיות

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

אם אתה חושב על שרשור מחרוזות, עצור עכשיו והלך לקרוא על הזרקת SQL!

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

בואו ונציג את אותם עומסי יתר העוסקים בפרמטרים בשאילתות SQL והצהרות.

6.1. מיתרים עם מצייני מקום

בסגנון דומה ל- JDBC רגיל, אנו יכולים להשתמש בפרמטרים מיקוםיים:

sql.execute ('INSERT INTO PROJECT (NAME, URL) VALUES (?,?)', 'tutorials', 'github.com/eugenp/tutorials')

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

sql.execute ('INSERT INTO PROJECT (NAME, URL) VALUES (: name,: url)', [name: 'REST with Spring', url: 'github.com/eugenp/REST-With-Spring'])

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

6.2. מחרוזות גרוביות

אנחנו יכולים גם לבחור בסגנון Groovier באמצעות GStrings עם מצייני מיקום.

כל השיטות שראינו אינן מחליפות את מקומי המקום במיתוג GS בדרך הרגילה; במקום זאת, הם מכניסים אותם כפרמטרים של JDBC, ומבטיחים שתחביר SQL יישמר כהלכה, ללא צורך לצטט או להימלט מכל דבר ובכך ללא סיכון להזרקה.

זה בסדר גמור, בטוח וגרובי:

def name = 'REST with Spring' def url = 'github.com/eugenp/REST-With-Spring' sql.execute "INSERT INTO PROJECT (NAME, URL) VALUES ($ {name}, $ {url})"

7. עסקאות וקשרים

עד כה דילגנו על חשש חשוב מאוד: עסקאות.

למעשה, לא דיברנו בכלל על איך גרובי מ"ר גם מנהל קשרים.

7.1. חיבורים קצרי חיים

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

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

עוֹד, אם אנו רוצים להוציא מספר הצהרות DML ושאילתות כפעולה אטומית אחת, אנחנו צריכים עסקה.

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

7.2. עסקאות עם חיבור במטמון

Groovy SQL אינו מאפשר לנו ליצור או לגשת לעסקאות באופן מפורש.

במקום זאת, אנו משתמשים ב- עם תנועה שיטה עם סגירה:

sql.withTransaction {sql.execute "" "INSERT INTO PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" "" sql.execute "" "INSERT INTO PROJECT (NAME, URL ערכים ('לנוח עם אביב', 'github.com/eugenp/REST-With-Spring') "" "}

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

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

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

sql.withTransaction {sql.execute "" "INSERT INTO PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" "" sql.commit () sql.execute "" "INSERT INTO PROJECT (NAME, URL) VALUES ('REST with Spring', 'github.com/eugenp/REST-With-Spring') "" "sql.rollback ()}

7.3. חיבורים במטמון ללא עסקה

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

sql.cacheConnection {sql.execute "" "INSERT IN PROJECT (NAME, URL) VALUES ('tutorials', 'github.com/eugenp/tutorials')" "" throw new Exception ('This does not roll back')}

8. מסקנות וקריאה נוספת

במאמר זה בדקנו את מודול ה- Groovy SQL וכיצד הוא משפר ומפשט את JDBC באמצעות סגירות ומחרוזות גרובי.

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

לא דיברנו על כל תכונה אחת של גרובי SQL; לדוגמא, השארנו את עיבוד האצווה, נהלי האחסון, המטא נתונים ודברים אחרים.

למידע נוסף, עיין בתיעוד גרובי.

ניתן למצוא את היישום של כל הדוגמאות וקטעי הקוד בפרויקט GitHub - זהו פרויקט של Maven, כך שיהיה קל לייבא ולהפעיל אותו כמות שהוא.


$config[zx-auto] not found$config[zx-overlay] not found