מבוא לג'וק עם אביב

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

מאמר זה יציג שאילתת אובייקט מונחה של Jooq - Jooq - ודרך פשוטה להגדיר אותה בשיתוף פעולה עם Spring Framework.

לרוב יישומי Java יש איזושהי התמדה של SQL וגישה לשכבה זו בעזרת כלים ברמה גבוהה יותר כמו JPA. ולמרות שזה שימושי, במקרים מסוימים אתה באמת זקוק לכלי עדין וניואנסי יותר כדי להגיע לנתונים שלך או לנצל בפועל את כל מה שיש ל- DB הבסיסי להציע.

Jooq נמנע מדפוסי ORM אופייניים ויוצר קוד המאפשר לנו לבנות שאילתות בטיחותיות ולקבל שליטה מלאה ב- SQL שנוצר באמצעות ממשק API שוטף נקי ועוצמתי.

מאמר זה מתמקד ב- MVC באביב. המאמר שלנו Spring Boot Support for jOOQ מתאר כיצד להשתמש ב- jOOQ ב- Boot Boot.

2. תלות Maven

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

2.1. jOOQ

 org.jooq jooq 3.2.14 

2.2. אביב

ישנן כמה תלות באביב הנדרשת לדוגמא שלנו; עם זאת, כדי להפוך את הדברים לפשוטים, עלינו לכלול במפורש שניים מהם בקובץ POM:

 org.springframework spring-context 5.2.2.RELEASE org.springframework spring-jdbc 5.2.2.RELEASE 

2.3. מאגר מידע

כדי להקל על הדברים לדוגמא שלנו, נשתמש במסד הנתונים המשובץ H2:

 com.h2database h2 1.4.191 

3. יצירת קוד

3.1. מבנה מסד הנתונים

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

כדי להפוך את זה לפשוט, ניצור רק שלוש טבלאות: ה- סֵפֶר לספרים, מְחַבֵּר למחברים, וטבלה אחרת שנקראת מחבר_ספר לייצג את מערכת היחסים בין רבים לסופרים. ה מְחַבֵּר הטבלה כוללת שלוש עמודות: תְעוּדַת זֶהוּת, שם פרטי, ו שם משפחה. ה סֵפֶר הטבלה מכילה רק א כותרת העמודה וה- תְעוּדַת זֶהוּת מפתח ראשי.

שאילתות ה- SQL הבאות, המאוחסנות ב- intro_schema.sql קובץ המשאב, יבוצע כנגד מסד הנתונים שכבר הגדרנו קודם כדי ליצור את הטבלאות הדרושות ולאכלס אותם בנתוני דוגמה:

טפטוף טבלה אם קיים author_book, author, book; צור מחבר טבלה (מזהה INT לא מפתח ראשוני NULL, שם פרטי VARCHAR (50), שם משפחה VARCHAR (50) לא NULL); צור ספר טבלה (מזהה INT לא מפתח ראשוני NULL, כותרת VARCHAR (100) NOT NULL); צור טבלה מחבר_ספר (author_id INT NOT NULL, book_id INT NOT NULL, PRIMARY KEY (author_id, book_id), CONSTRAINT fk_ab_author FOREIGN KEY (author_id) הפניות מחבר (id) בתאריך עדכון CASCADE על מחיקת CASCADE, CONSTREINT (id)); הכנס לערכי מחבר (1, 'קתי', 'סיירה'), (2, 'ברט', 'בייטס'), (3, 'בריאן', 'בשאם'); הכנס לספרי ערכים (1, 'ראש ראש Java'), (2, 'ראש סרוולט ראשוני ו- JSP'), (3, 'מתכנת OCA / OCP Java SE 7'); הכנס למחבר_ספר ערכים (1, 1), (1, 3), (2, 1);

3.2. מאפייני תוסף Maven

נשתמש בשלושה תוספי Maven שונים כדי ליצור את קוד Jooq. הראשון שבהם הוא תוסף Properties Maven.

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

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

ה תכונות קריאה-פרויקט המטרה של תוסף זה צריכה להיות קשורה לשלב מוקדם, כך שניתן להכין את נתוני התצורה לשימוש על ידי תוספים אחרים. במקרה זה, זה קשור ל לְאַתחֵל שלב:

 org.codehaus.mojo property-maven-plugin 1.0.0 אתחול קריאה-פרויקט-מאפיינים src / main / resources / intro_config.properties 

3.3. תוסף SQL Maven

התוסף SQL Maven משמש להפעלת הצהרות SQL ליצירת ואכלוס טבלאות מסדי נתונים. זה יעשה שימוש במאפיינים שהופקו מה- intro_config.properties הקובץ על ידי התוסף Properties Maven ולקחת את הצהרות SQL מה- intro_schema.sql מַשׁאָב.

התוסף SQL Maven מוגדר להלן:

 org.codehaus.mojo sql-maven-plugin 1.5 אתחל לבצע $ {db.driver} $ {db.url} $ {db.username} $ {db.password} src / main / resources / intro_schema.sql com.h2database h2 1.4.191 

שים לב כי יש למקם את התוסף הזה מאוחר יותר מתוסף Properties Maven בקובץ POM מאחר ויעדי הביצוע שלהם קשורים לאותו שלב, ו- Maven יבצע אותם לפי הסדר שבו הם מופיעים.

3.4. תוסף jOOQ Codegen

תוסף Jooq Codegen מייצר קוד Java ממבנה טבלת מסדי נתונים. שֶׁלָה לִיצוֹר המטרה צריכה להיות קשורה ל ליצור מקורות שלב כדי להבטיח את סדר הביצוע הנכון. מטא הנתונים של התוסף נראים כך:

 org.jooq jooq-codegen-maven $ {org.jooq.version} ייצור מקורות מייצר $ {db.driver} $ {db.url} $ {db.username} $ {db.password} com.baeldung.jooq. הקדמה.db src / main / java 

3.5. יצירת קוד

כדי לסיים את תהליך יצירת קוד המקור, עלינו להפעיל את Maven ליצור מקורות שלב. באקליפס אנו יכולים לעשות זאת על ידי לחיצה ימנית על הפרויקט ובחירה רץ כמו –>מקורות ייצור של Maven. לאחר השלמת הפקודה, קבצי מקור המתאימים ל- מְחַבֵּר, סֵפֶר, מחבר_ספר נוצרים טבלאות (ועוד כמה שיעורים תומכים).

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

ה מְחַבֵּר מעמד:

מחלקה ציבורית מחבר מרחיב TableImpl {מחבר סופי ציבורי סטטי AUTHOR = מחבר חדש (); // חברי כיתה אחרים}

ה סֵפֶר מעמד:

ספר בכיתה ציבורית מאריך את TableImpl {גמר סטטי ציבורי ספר ספר = ספר חדש (); // חברי כיתה אחרים}

ה ספר מחברים מעמד:

המחלקה הציבורית מחבר ספר מאריך את TableImpl {ספר הסופי הציבורי הסטטי הציבורי AUTHOR_BOOK = ספר המחבר החדש (); // חברי כיתה אחרים}

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

4. תצורת אביב

4.1. תרגום חריגים מ- jOOQ לאביב

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

בואו נגדיר יישום של ExecuteListener ממשק להמרת חריגים:

מחלקה ציבורית ExceptionTranslator מרחיב DefaultExecuteListener {חריג ריקני ציבורי (ExecuteContext context) {SQLDialect dialect = context.configuration (). dialect (); מתרגם SQLExceptionTranslator = חדש SQLErrorCodeSQLExceptionTranslator (dialect.name ()); context.exception (מתרגם .translate ("גישה למסד נתונים באמצעות Jooq", context.sql (), context.sqlException ())); }}

שיעור זה ישמש בהקשר של יישום האביב.

4.2. הגדרת האביב

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

בוא נתחיל על ידי יישום הערות הכרחיות בכיתה:

  • @תְצוּרָה: הפוך את הכיתה לזיהוי כמיכל שעועית
  • @ComponentScan: קביעת תצורה של הוראות סריקה, כולל ערך אפשרות להכריז על מערך של שמות חבילות לחיפוש רכיבים. במדריך זה, החבילה שיש לחפש היא זו שנוצרה על ידי תוסף Jooq Codegen Maven
  • @EnableTransactionManagement: אפשר עסקאות שתנוהל על ידי אביב
  • @PropertySource: ציין את המיקומים של קבצי המאפיינים שנטענו. הערך במאמר זה מצביע על הקובץ המכיל נתוני תצורה ודיאלקט של מסד הנתונים, וזה במקרה אותו קובץ המוזכר בסעיף קטן 4.1.
@Configuration @ComponentScan ({"com.baeldung.Jooq.introduction.db.public_.tables"}) @EnableTransactionManagement @PropertySource ("classpath: intro_config.properties") מעמד ציבורי PersistenceContext {// הצהרות אחרות}

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

@ סביבת סביבה פרטית אוטומטית; @Bean DataSource ציבורי DataSource () {JdbcDataSource dataSource = חדש JdbcDataSource (); dataSource.setUrl (environment.getRequiredProperty ("db.url")); dataSource.setUser (environment.getRequiredProperty ("db.username")); dataSource.setPassword (environment.getRequiredProperty ("db.password"));
 להחזיר dataSource; }

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

@ TransactionAwareDataSourceProxy פומבית TransactionAwareDataSource () {להחזיר TransactionAwareDataSourceProxy חדש (dataSource ()); } @Bean DataSourceTransactionManager publicManager () {להחזיר DataSourceTransactionManager חדש (dataSource ()); } @Bean ציבורי DataSourceConnectionProvider connectionProvider () {להחזיר DataSourceConnectionProvider חדש (transactionAwareDataSource ()); } @Bean ExceptionTranslator ציבורי exceptionTransformer () {להחזיר ExceptionTranslator חדש (); } @ שעועית ציבורית DefaultDSLContext dsl () {להחזיר DefaultDSLContext חדש (תצורה ()); }

לבסוף, אנו מספקים Jooq תְצוּרָה יישום ולהכריז עליו כשעועית אביב המשמשת את DSLContext מעמד:

@Bean תצורת DefaultConfiguration ציבורית () {DefaultConfiguration JooqConfiguration = תצורת ברירת מחדל חדשה (); jooqConfiguration.set (connectionProvider ()); jooqConfiguration.set (DefaultExecuteListenerProvider חדש (exceptionTransformer ())); מחרוזת sqlDialectName = environment.getRequiredProperty ("jooq.sql.dialect"); ניב SQLDialect = SQLDialect.valueOf (sqlDialectName); jooqConfiguration.set (ניב); החזר jooqConfiguration; }

5. שימוש ב- jOOQ עם אביב

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

נתחיל בהכרזה על חיווט אוטומטי DSLContext אובייקט ומופעים של מחלקות שנוצרו על ידי Jooq לשימוש בכל שיטות הבדיקה:

@ DSLontext הפרטי האוטומטי DSL; מחבר מחבר = מחבר.אוטור; ספר ספרים = Book.BOOK; AuthorBook authorBook = AuthorBook.AUTHOR_BOOK;

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

השלב הראשון הוא הכנסת נתונים לטבלאות:

dsl.insertInto (author) .set (author.ID, 4) .set (author.FIRST_NAME, "Herbert") .set (author.LAST_NAME, "Schildt"). execute (); dsl.insertInto (book) .set (book.ID, 4) .set (book.TITLE, "A Guide of Beginner") .execute (); dsl.insertInto (authorBook) .set (authorBook.AUTHOR_ID, 4). set (authorBook.BOOK_ID, 4). execute ();

א בחר שאילתה לחילוץ נתונים:

תוֹצָאָה תוצאה = dsl. בחר (author.ID, author.LAST_NAME, DSL.count ()). מ- (author) .join (authorBook). on (author.ID.equal (authorBook.AUTHOR_ID)) .join (book). ב- (authorBook.BOOK_ID.equal (book.ID)) .groupBy (author.LAST_NAME) .fetch ();

השאילתה לעיל מייצרת את הפלט הבא:

+ ---- + --------- + ----- + | מזהה | LAST_NAME | ספירה | + ---- + --------- + ----- + | 1 | סיירה | 2 | | 2 | בייטס | 1 | | 4 | שילט | 1 | + ---- + --------- + ----- +

התוצאה מאושרת על ידי לִטעוֹן ממשק API:

assertEquals (3, result.size ()); assertEquals ("סיירה", result.getValue (0, מחבר. LAST_NAME)); assertEquals (Integer.valueOf (2), result.getValue (0, DSL.count ())); assertEquals ("Schildt", result.getValue (2, מחבר. LAST_NAME)); assertEquals (Integer.valueOf (1), result.getValue (2, DSL.count ()));

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

@Test (צפוי = DataAccessException.class) חלל ציבורי givenInvalidData_whenInserting_thenFail () {dsl.insertInto (authorBook). Set (authorBook.AUTHOR_ID, 4). Set (authorBook.BOOK_ID, 5). Execute (); }

5.2. עדכון נתונים

עכשיו בואו ונעדכן את הנתונים הקיימים:

dsl.update (author) .set (author.LAST_NAME, "Baeldung") .where (author.ID.equal (3)) .execute (); dsl.update (book) .set (book.TITLE, "בניית ה- API של REST שלך עם אביב") .where (book.ID.equal (3)) .execute (); dsl.insertInto (authorBook) .set (authorBook.AUTHOR_ID, 3). set (authorBook.BOOK_ID, 3) .execute ();

קבל את הנתונים הדרושים:

תוֹצָאָה תוצאה = dsl. בחר (author.ID, author.LAST_NAME, book.TITLE). מ- (author) .join (authorBook). on (author.ID.equal (authorBook.AUTHOR_ID)). להצטרף (book). on ( authorBook.BOOK_ID.equal (book.ID)). Where (author.ID.equal (3)) .fetch ();

הפלט צריך להיות:

+ ---- + --------- + ---------------------------------- + | מזהה | LAST_NAME | TITLE | + ---- + --------- + ---------------------------------- + | 3 | Baeldung | בניית ה- REST API שלך עם Spring | + ---- + --------- + ---------------------------------- +

הבדיקה הבאה תאמת שג'וק עבד כצפוי:

assertEquals (1, result.size ()); assertEquals (Integer.valueOf (3), result.getValue (0, author.ID)); assertEquals ("Baeldung", result.getValue (0, מחבר. LAST_NAME)); assertEquals ("בניית ה- REST API שלך עם אביב", result.getValue (0, book.TITLE));

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

@Test (צפוי = DataAccessException.class) חלל ציבורי givenInvalidData_whenUpdating_thenFail () {dsl.update (authorBook). Set (authorBook.AUTHOR_ID, 4). Set (authorBook.BOOK_ID, 5) .execute (); }

5.3. מחיקת נתונים

השיטה הבאה מוחקת כמה נתונים:

dsl.delete (מחבר). Where (author.ID.lt (3)). ביצוע ();

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

תוֹצָאָה תוצאה = dsl. בחר (author.ID, author.FIRST_NAME, author.LAST_NAME). מ- (author) .fetch ();

פלט השאילתה:

+ ---- + ---------- + --------- + | מזהה | FIRST_NAME | LAST_NAME | + ---- + ---------- + --------- + | 3 | בריאן | בשאם | + ---- + ---------- + --------- +

הבדיקה הבאה מאמתת את המחיקה:

assertEquals (1, result.size ()); assertEquals ("בריאן", result.getValue (0, מחבר.FIRST_NAME)); assertEquals ("בשאם", result.getValue (0, מחבר. LAST_NAME));

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

@Test (צפוי = DataAccessException.class) חלל ציבורי givenInvalidData_whenDeleting_thenFail () {dsl.delete (book) .where (book.ID.equal (1)) .execute (); }

6. מסקנה

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

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


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