מדריך ל- Apache Commons DbUtils

1. סקירה כללית

Apache Commons DbUtils היא ספרייה קטנה שהופכת את העבודה עם JDBC להרבה יותר קלה.

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

2. התקנה

2.1. תלות Maven

ראשית, עלינו להוסיף את commons-dbutils ו h2 תלות שלנו pom.xml:

 commons-dbutils commons-dbutils 1.6 com.h2database h2 1.4.196 

תוכל למצוא את הגרסה האחרונה של commons-dbutils ו- h2 ב- Maven Central.

2.2. מסד נתונים לבדיקה

עם התלות שלנו במקום, בואו ליצור סקריפט ליצירת הטבלאות והרשומות בהם נשתמש:

צור עובד בטבלה (id int לא מפתח ראשוני NULL אוטומטי הכניסה, שם פרטי varchar (255), שם משפחה varchar (255), כפל משכורת, תאריך שכירה,); צור דוא"ל טבלה (id int לא מפתח ראשוני NULL auto_increment, עובדid int, כתובת varchar (255)); הכנס לעובד (שם פרטי, שם משפחה, משכורת, תאריך שכירה) VALUES ('John', 'Doe', 10000.10, to_date ('01 -01-2001 ',' dd-mm-yyyy ')); // ... הכנס לדוא"ל (עובד, כתובת) ערכים (1, '[דוא"ל מוגן]'); // ...

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

מחלקה ציבורית DbUtilsUnitTest {חיבור חיבור פרטי; @ לפני התקנת הריק הציבורי DB () זורק חריג {Class.forName ("org.h2.Driver"); מחרוזת db = "jdbc: h2: mem:; INIT = סקריפט מ- 'classpath: /employees.sql'"; חיבור = DriverManager.getConnection (db); } @ לאחר חלל ציבורי closeBD () {DbUtils.closeQuietly (חיבור); } // ...}

2.3. POJOs

לבסוף נצטרך שתי שיעורים פשוטים:

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

3. הקדמה

ספריית DbUtils מספקת ה QueryRunner הכיתה כנקודת הכניסה הראשית לרוב הפונקציונליות הזמינה.

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

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

כמובן שהספרייה כבר מספקת כמה יישומים המטפלים בתמורות הנפוצות ביותר, כגון רשימות, מפות ו- JavaBeans.

4. שאילתת נתונים

כעת, כשאנו יודעים את היסודות, אנו מוכנים לשאול את מסד הנתונים שלנו.

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

@Test הציבור בטל givenResultHandler_whenExecutingQuery_thenExpectedList () זורק SQLException {MapListHandler beanListHandler = MapListHandler חדש (); רץ QueryRunner = QueryRunner חדש (); רשימה list = runner.query (חיבור, "בחר * מעובד", beanListHandler); assertEquals (list.size (), 5); assertEquals (list.get (0) .get ("firstname"), "John"); assertEquals (list.get (4) .get ("שם פרטי"), "נוצרי"); }

לאחר מכן, הנה דוגמה לשימוש ב- BeanListHandler להפוך את התוצאות ל עוֹבֵד מקרים:

@ מבחן הריק פומבי givenResultHandler_whenExecutingQuery_thenEmployeeList () זורק SQLException {BeanListHandler beanListHandler = BeanListHandler חדש (שכיר עובד); רץ QueryRunner = QueryRunner חדש (); רשימת רשימת עובדים = runner.query (חיבור, "בחר * מעובד", beanListHandler); assertEquals (employeeList.size (), 5); assertEquals (employeeList.get (0) .getFirstName (), "John"); assertEquals (employeeList.get (4) .getFirstName (), "נוצרי"); }

עבור שאילתות שמחזירות ערך יחיד, אנו יכולים להשתמש ב- ScalarHandler:

@Test הציבור בטל givenResultHandler_whenExecutingQuery_thenExpectedScalar () זורק SQLException {ScalarHandler scalarHandler = ScalarHandler חדש (); רץ QueryRunner = QueryRunner חדש (); שאילתת מחרוזת = "בחר מספר (*) מעובד"; ספירה ארוכה = runner.query (חיבור, שאילתה, scalarHandler); assertEquals (ספירה, 5); }

ללמוד את כל ה ResultSerHandler יישומים, אתה יכול להתייחס ל ResultSetHandler תיעוד.

4.1. מטפלים בהתאמה אישית

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

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

בואו נראה איך הגישה השנייה נראית. ראשית, בואו נוסיף שדה נוסף שלנו עוֹבֵד מעמד:

מעמד ציבורי שכיר {דוא"ל עם רשימה פרטית; // ...}

עכשיו, בואו ניצור מחלקה שמרחיבה את ה- BeanListHandler הקלד וקבע את רשימת הדוא"ל לכל עובד:

מעמד ציבורי EmployeeHandler מרחיב את BeanListHandler {חיבור חיבור פרטי; עובד עובד ציבורי (Connection con) {סופר (שכיר עובד); this.connection = con; } @Override ידית רשימה ציבורית (ResultSet rs) זורקת SQLException {רשימת עובדים = super.handle (rs); רץ QueryRunner = QueryRunner חדש (); מטפל BeanListHandler = BeanListHandler חדש (Email.class); שאילתת מחרוזת = "בחר * מאימייל איפה עובדid =?"; עבור (עובד שכיר: עובדים) {רשימת מיילים = runner.query (חיבור, שאילתה, מטפל, עובד.גטייד ()); employee.setEmails (מיילים); } להחזיר עובדים; }}

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

לבסוף, בואו לבדוק את הקוד שלנו כדי לראות אם הכל עובד כצפוי:

@Test הציבור בטל givenResultHandler_whenExecutingQuery_thenEmailsSetted () זורק SQLException {EmployeeHandler employeeHandler = EmployeeHandler חדש (חיבור); רץ QueryRunner = QueryRunner חדש (); רשימת עובדים = runner.query (חיבור, "בחר * מהעובד", עובד הנדלר); assertEquals (workers.get (0) .getEmails (). size (), 2); assertEquals (workers.get (2) .getEmails (). size (), 3); }

4.2. מעבדי שורות בהתאמה אישית

בדוגמאות שלנו, שמות העמודות של עוֹבֵד הטבלה תואמים את שמות השדות של שלנו עוֹבֵד class (ההתאמה אינה רגישה לאותיות רישיות). עם זאת, זה לא תמיד המקרה - למשל כאשר שמות עמודות משתמשים בקו תחתון כדי להפריד בין מילים מורכבות.

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

בואו נראה איך זה נראה. ראשית, בואו ניצור טבלה נוספת ונכניס לתוכה כמה רשומות:

צור טבלה עובד_לגיטימיות (id int לא מפתח ראשוני NULL מפתח_עלייה אוטומטית, שם פרטי varchar (255), שם משפחה varchar (255), שכר כפול, תאריך שכירת תאריך); INSERT INTO worker_legacy (first_name, last_name, משכורת, שכר_תאריך) VALUES ('John', 'Doe', 10000.10, to_date ('01 -01-2001 ',' dd-mm-yyyy ')); // ...

עכשיו, בואו לשנות את שלנו עובד עובד מעמד:

מעמד ציבורי EmployeeHandler מרחיב את BeanListHandler {// ... EmployeeHandler הציבורי (Connection con) {super (Employee.class, BasicRowProcessor חדש (BeanProcessor חדש (getColumnsToFieldsMap ()))); // ...} מפה סטטית ציבורית getColumnsToFieldsMap () {Map columnToFieldsMap = HashMap חדש (); columnToFieldsMap.put ("FIRST_NAME", "firstName"); columnToFieldsMap.put ("LAST_NAME", "lastname"); columnToFieldsMap.put ("HIRED_DATE", "hiredate"); להחזיר עמודות ToFieldsMap; } // ...}

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

לבסוף, בואו נבדוק שהכל בסדר:

@Test הציבור בטל givenResultHandler_whenExecutingQuery_thenAllPropertiesSetted () זורק SQLException {EmployeeHandler עובדHandler = עובד עובד חדש (חיבור); רץ QueryRunner = QueryRunner חדש (); שאילתת מחרוזת = "בחר * FROM עובד_אגות"; רשימת עובדים = runner.query (חיבור, שאילתה, עובד מטפל); assertEquals ((int) workers.get (0) .getId (), 1); assertEquals (workers.get (0) .getFirstName (), "John"); }

5. הכנסת רשומות

ה QueryRunner class מספק שתי גישות ליצירת רשומות במסד נתונים.

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

@ מבחן ציבורי בטל כאשר הכנס_הכניסה () זורק SQLException {רץ QueryRunner = QueryRunner חדש (); מחרוזת insertSQL = "הכנס לעובד (שם פרטי, שם משפחה, משכורת, תאריך שכירה)" + "ערכים (?,?,?,?)"; int numRowsInserted = runner.update (חיבור, insertSQL, "Leia", "קיין", 60000.60, תאריך חדש ()); assertEquals (numRowsInserted, 1); }

השנייה היא להשתמש ב- לְהַכנִיס() שיטה שבנוסף להצהרת SQL ולפרמטרים להחלפה, יש צורך ב- ResultSetHandler כדי לשנות את המפתחות שנוצרו אוטומטית. ערך ההחזר יהיה מה שהמטפל מחזיר:

@Test הציבור בטל givenHandler_whenInserting_thenExpectedId () זורק SQLException {ScalarHandler scalarHandler = ScalarHandler חדש (); רץ QueryRunner = QueryRunner חדש (); מחרוזת insertSQL = "הכנס לעובד (שם פרטי, שם משפחה, משכורת, תאריך שכירה)" + "ערכים (?,?,?,?)"; int newId = runner.insert (חיבור, insertSQL, scalarHandler, "ג'ני", "Medici", 60000.60, תאריך חדש ()); assertEquals (newId, 6); }

6. עדכון ומחיקה

ה עדכון() שיטת ה- QueryRunner ניתן להשתמש בכיתה גם לשינוי ומחיקת רשומות ממסד הנתונים שלנו.

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

@ מבט פומבי בטל givenSalary_whenUpdating_thenUpdated () זורק SQLException {משכורת כפולה = 35000; רץ QueryRunner = QueryRunner חדש (); מחרוזת updateSQL = "עדכן עובד משכורת קבועה = משכורת * 1.1 איפה משכורת <=?"; int numRowsUpdated = runner.update (חיבור, updateSQL, משכורת); assertEquals (numRowsUpdated, 3); }

והנה עוד למחיקת עובד עם המזהה הנתון:

@ מבחן ציבורי בטל כאשרDeletingRecord_thenDeleted () זורק SQLException {רץ QueryRunner = QueryRunner חדש (); מחרוזת deleteSQL = "מחק מעובד איפה id =?"; int numRowsDeleted = runner.update (חיבור, deleteSQL, 3); assertEquals (numRowsDeleted, 1); }

7. פעולות אסינכרוניות

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

הנה דוגמה להשגת כל העובדים במסד הנתונים, בהמתנה של עד 10 שניות לקבלת התוצאות:

@Test הציבור בטל givenAsyncRunner_whenExecutingQuery_thenExpectedList () זורק חריג {רץ AsyncQueryRunner = AsyncQueryRunner חדש (Executors.newCachedThreadPool ()); EmployeeHandler עובדHandler = עובד עובד חדש (חיבור); שאילתת מחרוזת = "בחר * מעובד"; עתיד עתיד = runner.query (חיבור, שאילתה, עובד עובד); רשימת רשימת עובדים = future.get (10, TimeUnit.SECONDS); assertEquals (employeeList.size (), 5); }

8. מסקנה

במדריך זה חקרנו את התכונות הבולטות ביותר בספריית Apache Commons DbUtils.

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

וכמו תמיד, ניתן למצוא את קוד המקור השלם למאמר זה ב- Github.


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