كتبت مدونة "Spring+MyBatis+MySQL لإنشاء إطار وصول قاعدة بيانات موزع" قبل وصف كيفية الوصول إلى قواعد بيانات متعددة من خلال SPRING+MYBATIS مصادر البيانات الديناميكية. ومع ذلك ، فإن الحل السابق له بعض القيود (الموصوفة أيضًا في المدونة الأصلية): إنه ينطبق فقط على المواقف التي يكون فيها عدد قواعد البيانات صغيرة وثابتة. لا يوجد شيء يجب فعله حيال الموقف الذي تزداد فيه قاعدة البيانات الديناميكية.
يمكن أن يدعم المخطط المذكور أدناه إضافة قاعدة البيانات الديناميكية وحذفها ، والرقم غير محدود.
إعداد بيئة قاعدة البيانات
فيما يلي MySQL كمثال ، قم بإنشاء 3 قواعد بيانات أولاً محليًا للاختبار. تجدر الإشارة إلى أن هذا الحل لا يحد من عدد قواعد البيانات ، ويدعم نشر قواعد البيانات المختلفة على خوادم مختلفة. كما هو موضح في الشكل ، db_project_001 ، db_project_002 ، db_project_003.
بناء مشروع Microservice الخلفي Java
إنشاء مشروع Maven SPRING BOOT:
التكوين: فئة إدارة تكوين مصدر البيانات.
DataSource: منطق إدارة مصدر البيانات الذي تم تنفيذه من تلقاء نفسه.
DBMGR: يدير علاقة التعيين بين ترميز المشروع و IP لقاعدة البيانات والاسم (يتم تخزين هذا الجزء من البيانات في المشروع الفعلي في ذاكرة التخزين المؤقت Redis ويمكن إضافتها وحذفها ديناميكيًا).
Mapper: واجهة الوصول إلى قاعدة البيانات.
النموذج: رسم الخرائط.
REST: الواجهة المريحة التي تصدرها الخدمات المجهرية إلى الخارج ، وتستخدم هنا للاختبار.
Application.YML: تكوين معلمات JDBC لقاعدة البيانات.
تنفيذ رمز مفصل
1. إضافة تكوين مصدر البيانات
package com.elon.dds.config ؛ import javax.sql.datasource ؛ import org.apache.ibatis.session.sqlsessionfactory ؛ import org.mybatis.spring.sqlsessionfactorybean org.springframework.beans.factory.annotation.qualifier ؛ استيراد org.springframework.boot.autoconfigure.jdbc.datasourceBuilder ؛ استيراد org.springframework.boot.context.properties.configurperties ؛ استيراد org.springframework.context.annotation.bean ؛ استيراد org.springframework.context.annotation.configuration ؛ استيراد com.elon.dds.datasource.dynamicDataSource ؛/*** إدارة تكوين مصدر البيانات. * * Author Elon * version 26 فبراير ، 2018 * / @configuration @mapperscan (basePackages = "com.elon.dds.mapper" ، value = "sqlsessionfactory") فئة عامة dataSourCeConfig { /** * إنشاء مصدر بيانات على أساس معلمات التكوين. استخدام الفئات الفرعية المشتقة. * * return data source */ @bean (name = "datasource") configurationProperties (prefix = "spring.datasource") public datasource getDataSource () {datasourceBuilder builder = datasourceBuilder.create () ؛ builder.type (DynamicDataSource.Class) ؛ إرجاع builder.build () ؛ } /*** إنشاء مصنع جلسة. ** param dataSource Data Source* @Return Session Factory*/ @bean (name = "sqlsessionfactory") sqlsessionfactory getSqlSessionFactory ( @QAalifier ("datasource") datasource datasource) Bean.setDataSource (DataSource) ؛ حاول {return bean.getObject () ؛ } catch (استثناء e) {E.PrintStackTrace () ؛ العودة لاغية. }}} 2. تحديد مصادر البيانات الديناميكية
1) قم أولاً بإضافة فئة هوية قاعدة البيانات لتمييز الوصول إلى قاعدة البيانات المختلفة.
نظرًا لأننا أنشأنا قواعد بيانات منفصلة لمشاريع مختلفة ، فقد استخدمنا ترميز المشروع كفهرس قاعدة البيانات. تدعم الخدمات الدقيقة التزامن متعدد الخيوط واستخدام متغيرات مؤشر الترابط.
حزمة com.elon.dds.datasource ؛/*** فئة إدارة هوية قاعدة البيانات. تستخدم لتمييز قواعد البيانات المختلفة المتصلة بمصادر البيانات. * * Author elon * @Version 2018-02-25 */public class dbidentifier {/** * استخدم ترميزات مشروع مختلفة لتمييز قواعد البيانات */private static threadlocal <string> projectCode = new threadlocal <string> () ؛ السلسلة الثابتة العامة getProjectCode () {return projectCode.get () ؛ ) }}2) يتم اشتقاق DynamicDataSource من مصدر البيانات ، حيث يتم تنفيذ التبديل الديناميكي لاتصالات قاعدة البيانات
استيراد java.lang.reflect.field ؛ استيراد java.sql.connection ؛ استيراد java.sql.sqlexception ؛ import org.apache.logging.log4j.logmanager ؛ import org.apache.logging.log4j.logger ؛ استيراد org.apache.tomcat.jdbocy org.apache.tomcat.jdbc.pool.poolproperties ؛ استيراد com.elon.dds.dbmgr.projectdbmgr ؛/*** تحديد فئات مصدر البيانات الديناميكية المشتقة. مستمدة من مصدر البيانات الأساسي ، وتنفيذ ديناميكيا بنفسه. * * Author Elon * version 2018-02-25 */public class DynamicDataSource يمتد DataSource {private static logger = logmanager.getLogger (DynamicDataSource.Class) ؛ /*** هذه الطريقة هي الاتصال بقواعد بيانات مختلفة عند طلب البيانات من مشاريع مختلفة. */ Override Public Connection getConnection () {String ProjectCode = dBidentIfier.getProjectCode () ؛ // 1. احصل على مصدر بيانات مصدر البيانات DDS = ddSholder.instance (). getDDS (ProjectCode) ؛ // 2. إنشاء if (dds == null) {try {datasource newdds = initdds (projectCode) ؛ ddsholder.instance (). adddds (ProjectCode ، Newdds) ؛ } catch (alfulalArgumentException | alfictAccessException e) {log.error ("init data source fail. العودة لاغية. }} dds = ddsholder.instance (). getDds (projectCode) ؛ حاول {return dds.getConnection () ؛ } catch (sqlexception e) {E.PrintStackTrace () ؛ العودة لاغية. }} /*** انسخ نسخة باستخدام كائن البيانات الحالي كقالب. * * return dds * throws alfictAccessException * throws alficalArgumentException */ private datasource initdds (سلسلة projectCode) يلقي alfortalargumentexception ، inchalcaccessexception {datasource dds = new dataSource () ؛ // 2 الحقل [] pfields = poolproperties.class.getDeclaredFields () ؛ لـ (الحقل f: pfields) {f.setAccessible (true) ؛ قيمة الكائن = f.get (this.getPoolProperties ()) ؛ حاول {f.set (الخاصية ، القيمة) ؛ } catch (استثناء e) {log.info ( يكمل؛ }} dds.setPoolProperties (property) ؛ . String url = string.format (urlformat ، projectDBMGR.Instance (). dds.seturl (url) ؛ إرجاع DDS ؛ }}3) التحكم في إصدار اتصال البيانات من خلال DDStimer (إصدار مصادر بيانات غير مستخدمة تجاوزت الوقت المحدد)
حزمة com.elon.dds.datasource ؛ استيراد org.apache.tomcat.jdbc.pool.datasource ؛/*** إدارة توقيت مصدر البيانات الديناميكي. يتم إغلاق اتصال قاعدة البيانات التي لا يمكن الوصول إليها لفترة طويلة. * * Author Elon * version 25 فبراير ، 2018 * /الفئة العامة ddstimer { /** * فترة زمنية الخمول. سيتم إصدار اتصالات قاعدة البيانات التي لم يتم الوصول إليها لأكثر من هذا الوقت. الافتراضي 10 دقائق. */ خاص ثابت طويل Idleperiodtime = 10 * 60 * 1000 ؛ / *** مصدر البيانات الديناميكي*/ DDS DDS الخاص ؛ / *** آخر وقت الوصول*/ خاص طويل Lastusetime ؛ ddStimer العامة (Datasource dds) {this.dds = dds ؛ this.lastusetime = system.currentTimeMillis () ؛ } / *** تم تحديث أحدث وقت للوصول* / public void refreshtime () {lastusetime = system.currentTimeMillis () ؛ } /*** اكتشف ما إذا كان اتصال البيانات مغلقًا بسبب المهلة. * * return true - توقيت الخروج ؛ false - لم يتم توقيت الخروج*/ public boolean checkandClose () {if (system.currentTimeMillis () - lastusetime> idleperiodtime) {dds.close () ؛ العودة صحيح. } إرجاع خطأ ؛ } بيانات البيانات العامة getDDS () {return dds ؛ }}4) أضف DDSHOLDER لإدارة مصادر البيانات المختلفة وتوفير وظائف إضافة مصدر البيانات والاستعلام
package com.elon.dds.datasource ؛ استيراد java.util.hashmap ؛ استيراد java.util.iterator ؛ استيراد java.util.map ؛ استيراد java.util.map.entry * * Author Elon * version 25 فبراير ، 2018 * /الفئة العامة DdSholder { /** * إدارة قائمة مصدر البيانات الديناميكية. <ترميز المشروع ، مصدر البيانات> */ خريطة خاصة <string ، ddStimer> ddsmap = new hashmap <string ، ddstimer> () ؛ / *** مصادر بيانات غير مستخدمة بشكل دوري من خلال المهام الموقوتة*/ المؤقت الثابت الخاص clearidletask = توقيت جديد () ؛ ثابت {clearidletask.schedule (New ClearidleTimerTask () ، 5000 ، 60 * 1000) ؛ } ؛ Private DdSholder () {} /** الحصول على كائن Singleton* / مثيل DdSholder ثابت عام () {return ddsholderbuilder.instance ؛ } /*** إضافة مصدر بيانات ديناميكي. * * projectCode ProjectCode ترميز * param dds dds */ adddds الفراغ المزامنة العامة (سلسلة projectCode ، ddsource dds) {ddstimer ddst = new ddstimer (dds) ؛ ddsmap.put (ProjectCode ، DDST) ؛ } / *** استعلام مصدر البيانات الديناميكي** PROCESTCODE Project Project Project* @RETURN DDS* / GETSARCED SYNCHRONISTERS PROCART (DDSTIMER DDST = DDSMAP.GET (ProjectCode) ؛ ddst.refreshtime () ؛ إرجاع ddst.getdds () ؛ } إرجاع فارغ ؛ } /*** مصادر بيانات واضحة تم توقيتها بدون أي شخص. */ Public Synchronized void clearidledds () {iterator <intern <string ، ddStimer >> iter = ddsmap.entryset (). iterator () ؛ لـ (؛ iter.hasnext () ؛) {entry <string ، ddStimer> entry = iter.next () ؛ if (enter.getValue (). checkandClose ()) {iter.Remove () ؛ }}} / *** فئة Artifact Singleton* Author Elon* version 26 فبراير ، 2018* / فئة ثابتة خاصة ddsholderbuilder {مثيل ddsholder static الخاص = جديد ddsholder () ؛ }}5) Timer Task يتم استخدام ClearidleTimertask لمسح مصادر البيانات الخاملة بانتظام
Package com.elon.dds.datasource ؛ استيراد java.util.timertask ؛/*** مهام اتصال الخمول. * * author elon * version 26 فبراير 2018 */class clearidletimertask العامة يمتد timertask {Override public void run () {ddsholder.instance (). cleareddleds () ؛ }}3. إدارة علاقة رسم الخرائط لتشفير المشروع مع IP قاعدة البيانات والاسم
حزمة com.elon.dds.dbmgr ؛ استيراد java.util.hashmap ؛ استيراد java.util.map ؛/*** إدارة قاعدة بيانات المشروع. يوفر واجهة للاستعلام اسم قاعدة بيانات و IP استنادًا إلى ترميز المشروع. * Author Elon* version 25 فبراير 2018* /فئة عامة ProjectDBMGR { /*** حفظ علاقة التعيين بين ترميز المشروع واسم البيانات. هنا رمز صعب. في التطوير الفعلي ، يمكن حفظ هذه البيانات العلائقية إلى ذاكرة التخزين المؤقت Redis ؛ * إضافة مشروع جديد أو حذف المشروع لا يتطلب سوى تحديث ذاكرة التخزين المؤقت. في ذلك الوقت ، يجب تعديل واجهة هذه الفئة فقط للحصول على بيانات من ذاكرة التخزين المؤقت. */ خريطة خاصة <string ، string> dbnamemap = new HashMap <string ، string> () ؛ /*** حفظ علاقة التعيين بين ترميز المشروع و IP قاعدة البيانات. */ خريطة خاصة <string ، string> dbipmap = new HashMap <string ، string> () ؛ ProjectDBMGR () {dbnamemap.put ("project_001" ، "db_project_001") ؛ dbnamemap.put ("project_002" ، "db_project_002") ؛ dbnamemap.put ("project_003" ، "db_project_003") ؛ dbipmap.put ("project_001" ، "127.0.0.1") ؛ dbipmap.put ("project_002" ، "127.0.0.1") ؛ dbipmap.put ("project_003" ، "127.0.0.1") ؛ } مثيل projectDBMGR ثابت عام () {return projectDBMgrbuilder.instance ؛ } // في التطوير الفعلي ، يتم تغييره للحصول على السلسلة العامة getDbName (سلسلة projectCode) {if (dbnamemap.containskey (projectCode)) {return dbnamemap.get (projectCode) ؛ } يعود ""؛ } // في التطوير الفعلي ، نغير للحصول على سلسلة عامة getDbip (سلسلة projectCode) {if (dbipmap.containskey (projectCode)) {return dbipmap.get (projectCode) ؛ } يعود ""؛ } projectDBMgrbuilder {projectdbmgr مثيل خاص projectDBMGR = جديد projectDBMGR () ؛ }} 4. تحديد الخريطة للوصول إلى قاعدة البيانات
package com.elon.dds.mapper ؛ import java.util.list ؛ import org.apache.ibatis.annotations.mapper ؛ import org.apache.ibatis.annotations.result ؛ import org.apache.ibatis.annotations.results ؛ import org.apache.annotations.select ؛ تعريف واجهة رسم الخرائط MyBatis. ** author elon* version 26 فبراير ، 2018*/ @mapperpublic interface usermapper {/*** Query جميع بيانات المستخدم* قائمة بيانات المستخدم*/results (value = {result (property = "userId" ، column = "id") ، result (propert @select ("حدد المعرف ، الاسم ، العمر من TBL_USER") قائمة <Sether> getUsers () ؛} 5. تحديد نموذج كائن الاستعلام
Package com.elon.dds.model ؛ user user {private int userD = -1 ؛ اسم السلسلة الخاصة = "" ؛ العمر int الخاص = -1 ؛ Override Public String ToString () {return "name:" + name + "| Age:" + Age ؛ } public int getUserId () {return userId ؛ } public void setUserId (int userId) {this.userId = userId ؛ } السلسلة العامة getName () {return name ؛ } public void setName (اسم السلسلة) {this.name = name ؛ } public int getage () {return Age ؛ } public void setage (int age) {this.age = age ؛ }} 6. تحديد الواجهة المريحة للاستعلام عن بيانات المستخدم
package com.elon.dds.rest ؛ استيراد java.util.list ؛ استيراد org.springframework.beans.factory.annotation. org.springframework.web.bind.annotation.requestparam ؛ استيراد org.springframework.web.bind.annotation.restController واجهة. * * author elon * version 26 فبراير ، 2018 */ @restController @requestMapping (value = "/user") الفئة العامة wsuser {autowired usermapper usermapper ؛ /*** Quep جميع معلومات المستخدم في المشروع** PROJECTCODE PROJECTCODE ترميز* @REGRURN LIST*/REQUESTMAPPE (value = "/v1/user" ، method = requestMethod.get) قائمة عامة <Seter> QueryUser (requestparam (value = "projectCode" ، مطلوب = true) سلسلة projectCode) إعادة usermapper.getusers () ؛ }}يجب تضمين معلمة ProjectCode في كل استعلام.
7. اكتب رمز بدء التشغيل لتطبيق Boot Spring
package com.elon.dds ؛ استيراد org.springframework.boot.springapplication ؛ استيراد org.springframework.boot.autoconfigure.springbootapplication ؛/*** Hello World! * */@springBootApplicationPublic Class App {public static void main (string [] args) {system.out.println ("Hello World!") ؛ springapplication.run (app.class ، args) ؛ }} 8. تكوين مصدر البيانات في Application.yml
يتم استخدام قاعدة البيانات IP واسم قاعدة البيانات مع ٪ s. التبديل ديناميكيا في الاستعلام عن بيانات المستخدم.
الربيع: DataSource: url: jdbc: mysql: // ٪ s: 3306/٪ s؟ useUnicode = true & maracterencoding = utf-8 username: root password: class-class-name: com.mysql.jdbc.driverlogging: configpath: log4j2
خطة الاختبار
1. الاستعلام عن بيانات project_001 والعودة بشكل طبيعي
2. الاستعلام عن بيانات project_002 والعودة بشكل طبيعي
لخص
ما سبق هو رمز التنفيذ للوصول إلى قواعد بيانات متعددة من خلال مصادر البيانات الديناميكية لتكوين التمهيد الربيعي. آمل أن يكون ذلك مفيدًا للجميع. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر على الجميع في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!