מדריך פשוט לאיחוד חיבורים בג'אווה

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

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

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

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

2. מדוע איגום חיבורים?

השאלה כמובן רטורית.

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

  1. פתיחת חיבור למסד הנתונים באמצעות מנהל ההתקן של מסד הנתונים
  2. פתיחת שקע TCP לקריאת / כתיבת נתונים
  3. קריאת / כתיבת נתונים דרך השקע
  4. סוגרים את הקשר
  5. סוגרים את השקע

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

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

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

3. מסגרות איגום חיבורי JDBC

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

מאחד דידקטי, שמטרתו של מאמר זה, זה לא.

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

3.1. Apache Commons DBCP

נתחיל במעגל מהיר זה עם רכיב ה- DBCP של אפאצ'י קומונס, חיבור מאפיינים מלא המאגר מסגרת JDBC:

מחלקה ציבורית DBCPDataSource {פרטי סטטי BasicDataSource ds = BasicDataSource חדש (); סטטי {ds.setUrl ("jdbc: h2: mem: test"); ds.setUsername ("משתמש"); ds.setPassword ("סיסמה"); ds.setMinIdle (5); ds.setMaxIdle (10); ds.setMaxOpenPreparedStatements (100); } חיבור סטטי ציבורי getConnection () זורק SQLException {החזר ds.getConnection (); } DBCPDataSource פרטי () {}}

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

כך תוכל להשיג חיבור מאוחד עם ה- DBCPDataSource מעמד:

חיבור con = DBCPDataSource.getConnection ();

3.2. HikariCP

הלאה, בואו נסתכל על HikariCP, מסגרת איגום חיבורי JDBC ברק שנוצרה על ידי ברט וולדרידג '(לפרטים המלאים כיצד להגדיר ולהפיק את המרב מ- HikariCP, אנא עיינו במאמר זה):

מחלקה ציבורית HikariCPDataSource {פרטי סטטי HikariConfig config = HikariConfig חדש (); פרטי HikariDataSource סטטיים פרטיים; סטטי {config.setJdbcUrl ("jdbc: h2: mem: test"); config.setUsername ("משתמש"); config.setPassword ("סיסמה"); config.addDataSourceProperty ("cachePrepStmts", "true"); config.addDataSourceProperty ("prepStmtCacheSize", "250"); config.addDataSourceProperty ("prepStmtCacheSqlLimit", "2048"); ds = HikariDataSource חדש (config); } חיבור סטטי ציבורי getConnection () זורק SQLException {החזר ds.getConnection (); } HikariCPDataSource פרטי () {}}

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

חיבור con = HikariCPDataSource.getConnection ();

3.3. C3PO

האחרון בסקירה זו הוא C3PO, מסגרת חיבור JDBC4 חזקה ואיחוד הצהרות שפותח על ידי סטיב וולדמן:

מחלקה ציבורית C3poDataSource {private static ComboPooledDataSource cpds = new ComboPooledDataSource (); סטטי {נסה {cpds.setDriverClass ("org.h2.Driver"); cpds.setJdbcUrl ("jdbc: h2: mem: test"); cpds.setUser ("משתמש"); cpds.setPassword ("סיסמה"); } לתפוס (PropertyVetoException e) {// לטפל בחריג}} חיבור סטטי ציבורי getConnection () זורק SQLException {return cpds.getConnection (); } C3poDataSource פרטי () {}}

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

חיבור con = C3poDataSource.getConnection ();

4. יישום פשוט

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

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

ממשק ציבורי ConnectionPool {Connection getConnection (); שחרור בוליאני Connection (חיבור חיבור); מחרוזת getUrl (); מחרוזת getUser (); מחרוזת getPassword (); }

ה ConnectionPool ממשק מגדיר את ה- API הציבורי של מאגר חיבורים בסיסי.

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

מחלקה ציבורית BasicConnectionPool מיישמת ConnectionPool {url מחרוזת פרטי; משתמש מחרוזת פרטי; סיסמת מחרוזת פרטית; חיבור פרטי פרטי Pool; רשימה פרטית usedConnections = ArrayList חדש (); פרטית סטטית int INITIAL_POOL_SIZE = 10; BasicConnectionPool ליצור סטטי ציבורי (כתובת URL למחרוזת, משתמש מחרוזת, סיסמת מחרוזת) זורק SQLException {רשימה מאגר = ArrayList חדש (INITIAL_POOL_SIZE); עבור (int i = 0; i <INITIAL_POOL_SIZE; i ++) {pool.add (createConnection (url, user, password)); } להחזיר BasicConnectionPool חדש (url, משתמש, סיסמה, מאגר); } // קונסטרוקטורים סטנדרטיים @ Override חיבור ציבורי getConnection () {חיבור חיבור = connectionPool .remove (connectionPool.size () - 1); usedConnections.add (חיבור); חיבור חזרה; } @Override public boolean releaseConnection (חיבור חיבור) {connectionPool.add (חיבור); להחזיר usedConnections.remove (חיבור); } חיבור סטטי פרטי createConnection (כתובת מחרוזת, משתמש מחרוזת, סיסמת מחרוזת) זורק SQLException {החזר DriverManager.getConnection (url, משתמש, סיסמה); } public int getSize () {return connectionPool.size () + usedConnections.size (); } // גטרים סטנדרטיים}

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

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

אפשר ליצור חיבורי JDBC עם ה- DriverManager בכיתה ועם יישומי מקורות נתונים.

מכיוון שעדיף לשמור על יצירת מסד נתונים של קשרים אגנוסטיים, השתמשנו בשירותים הראשונים לִיצוֹר() שיטת מפעל סטטית.

במקרה זה מיקמנו את השיטה בתוך ה- BasicConnectionPool, כי זה היישום היחיד של הממשק.

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

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

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

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

5. שימוש ב- BasicConnectionPool מעמד

כצפוי, באמצעות שלנו BasicConnectionPool הכיתה היא פשוטה.

בואו ניצור מבחן יחידה פשוט ונקבל חיבור H2 בזיכרון משולב:

@ מבחן ציבורי whenCalledgetConnection_thenCorrect () {ConnectionPool connectionPool = BasicConnectionPool .create ("jdbc: h2: mem: test", "user", "password"); assertTrue (connectionPool.getConnection (). isValid (1)); }

6. שיפורים נוספים ושיקום מחדש

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

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

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

@Override חיבור ציבורי getConnection () זורק SQLException {if (connectionPool.isEmpty ()) {if (usedConnections.size () <MAX_POOL_SIZE) {connectionPool.add (createConnection (url, user, password)); } אחר {זרוק RuntimeException חדש ("הגעת לגודל הבריכה המרבי, אין חיבורים זמינים!"); }} חיבור חיבור = connectionPool .remove (connectionPool.size () - 1); if (! connection.isValid (MAX_TIMEOUT)) {connection = createConnection (url, user, password); } usedConnections.add (חיבור); חיבור חזרה; } 

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

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

כיבוי חלל ציבורי () זורק את SQLException {usedConnections.forEach (זה :: releaseConnection); עבור (חיבור c: connectionPool) {c.close (); } connectionPool.clear (); }

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

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

7. מסקנה

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

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

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

כרגיל, כל דגימות הקוד המוצגות במאמר זה זמינות ב- GitHub.