1. Préface
Lorsque vous utilisez Java pour développer un logiciel d'application d'entreprise, Spring + MyBatis + MySQL est souvent utilisé pour créer un cadre de base de données. Si le volume de données est important, une bibliothèque MySQL stocke l'efficacité d'accès aux données très faible et utilise souvent la méthode de gestion du stockage de sous-réparties. Cet article décrit comment construire une architecture d'accès multi-données via Spring + MyBatis et utiliser le multi-threading pour améliorer l'efficacité d'accès à la base de données.
Il convient de noter que cette méthode ne convient qu'aux situations où le nombre de bases de données et de noms est fixe, et pas particulièrement importante. En réponse à la situation où le nombre de bases de données n'est pas corrigé, j'écrirai un autre plan de traitement plus tard.
2. Plan global
3. Préparation de l'environnement de développement
3.1 Télécharger Spring, MyBatis, MySQL Composants.
3.2 Eclipse: IDE de développement Java. Les forfaits pot suivants sont introduits:
La structure du code est la suivante:
4. Créer un cluster de base de données
Créez 11 bases de données dans MySQL (test1 / 2/3/4/5/6/7/8/9/10/11) pour créer un tableau simple:
Insérez 50 millions de données dans le tableau TBL_DEMO dans Test1 et 5 millions de données dans le tableau TBL_DEMO dans les 10 autres bases de données (en utilisant des fonctions).
Insérez 50 millions de données dans le tableau TBL_DEMO dans Test1 et 5 millions de données dans le tableau TBL_DEMO dans les 10 autres bases de données (en utilisant des fonctions).
5. Créer une interface de mappage de base de données MyBatis
/ ** * Interface de mappage MyBatis * * * @author elon * @version 1.0, 23 octobre 2015 * / interface publique idemo {public void insertdemo (démo demodao); Liste publique <Integer> selectGroup ();} / ** * * MyBatis Mapping Service Interface * * @author elon * @version 1.0, 23 octobre 2015 * / interface publique idemoservice {public void insertdemo (démo de Demodao); Public List <Integer> selectGroup ();} / ** * * MyBatis Mapping Service Implementation * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique DemoserviceImplt implémente idemoService {private idemo idea = null; public void SetIDEMO (Idemo Idea) {this.idemo = idea; } @Override public void insertdemo (démo demodao) {ideamo.insertdemo (démo); } @Override public list <Integer> selectGroup () {return idea.selectGroup (); }}6. Créer une gestion de l'identité de base de données et des sources de données dynamiques
/ ** * * Enregistrez l'ID de base de données. Chaque thread est stocké par un objet indépendant * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique dbindetificier {private static threadlocal <string> dbkey = new ThreadLocal <string> (); public static void setDBKey (Final String dbKeyPara) {dbkey.set (dbkeypara); } public static static getDBKey () {return dbkey.get (); }} / ** * Source de données dynamique. Différentes bases de données peuvent être connectées en fonction de différents index de données * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique DynamicDataSource étend AbstractroutingDataSource {@Override Object DeviterCurrentlookupKey () {return dbindentifier.getDbkey (); }}7. Créer un objet d'accès à la base de données
/ ** * * Objet d'accès à la base de données. Utilisé pour insérer des données. * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique Demodao {private int a; chaîne privée b; INT PRIVÉ C; public int geta () {return a; } public void seta (int a) {this.a = a; } public String getB () {return b; } public void setB (String b) {this.b = b; } public int getc () {return c; } public void setc (int c) {this.c = c; }} / ** * Définition du résultat du mappage * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique Démoresult implémente Serializable {/ ** * Commentaire pour <code> SerialVersionUid </code> <br> * * / private static final SerialVersionuid = -413001138792531448l; somme longue privée; public long getSUM () {return sum; } public void setsum (long sum) {this.sum = sum; } @Override public String toString () {return String.Valueof (sum); }}8. Créer des tâches d'accès à la base de données
/ ** * Définition de la tâche d'accès à la base de données. Emballez chaque demande à l'accès à la base de données dans un objet de tâche, placez-le dans la gestion des tâches, puis attendez que l'exécution de la tâche termine et récupére le résultat d'exécution. * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique DBTask implémente Runnable {// L'identité de la base de données de l'opération, utilisée pour spécifier la base de données accessible. Conformément à la définition de la source de données dynamique des données dans le fichier de configuration de ressort. String final privé dbkey; // MyBatis Database Access Object Private Final Object DBAccessObject; // Nom de la méthode d'accès à la base de données MySBatis, utilisé pour refléter l'appel Private Final String Methodname; // Stockez la valeur des paramètres variables objet final privé [] ParaArray; // Stockez le type de paramètre variable @SuppressWarnings ("RawTypes") Private Final Class [] ParaclassArray; // Résultat de l'opération de la base de données. L'opération de requête renvoie le résultat de la requête; Les opérations d'insertion, de suppression et de modification renvoient null. Opérateresult d'objet privé; // Informations d'exception lancées par l'exception de l'exception privée de la base de données de l'opération; // Identifiez si la tâche a été exécutée à la finition booléenne privée; / ** * Constructeur * @param dbkey database id * @param dbaccessObject Database Access Object * @param Methodnname Database Access Method Name * @param ParaArray Paramet List * / public dbtask (final string dbkey, this.dbKey = dbkey; this.dbaccessObject = dbAccessObject; this.MethodName = Methodname; this.paraArray = paraArray; finition = false; exception = null; parAclassArray = new Class [ParaArray.Length]; pour (int index = 0; index <paraArray.length; ++ index) {paraClassArray [index] = paraArray [index] .getClass (); } operaresult = null; } / ** * Fonction d'exécution de la tâche * * / @Override public void run () {try {dbindetificier.setdbkey (dbkey); Méthode méthode = dbaccessObject.getClass (). GetMethod (méthodename, paraClassArray); // L'opération de requête renvoie le résultat de la requête; Les opérations d'insertion, de suppression et de modification renvoient null operaSult = Method.invoke (dbaccessObject, paraArray); } catch (exception e) {exception = e; e.printStackTrace (); } finir = true; } / ** * * Renvoie le résultat de l'opération. L'opération de requête renvoie les résultats de la requête; Insert, supprimer et modifier les opérations Retour Null * * @return Operation Result * / public objet getRetValue () {return operaSult; } / ** * Throw Operab Operation Operation Exception * * @return Exception * / Public Exception getException () {return exception; } / ** * * Renvoie si la tâche a été exécutée * * @return tag * / public boolean isFinish () {return finition; }}9. Créez un gestionnaire de tâches de base de données
/ ** * Gestion des tâches d'accès à la base de données. Mettez la tâche d'accès à la base de données dans le pool de threads à exécuter. * * * @author elon * @version 1.0, 23 octobre 2015 * / classe publique dbtaskmgr {classe statique privée dbtaskmgrinstance {public static final dbtaskmgr instance = new dbtaskmgr (); } public static dbtaskmgr instance () {return dbtaskmgrinstance.instance; } Pool privé ThreadPoolExecutor; public dbtaskmgr () {pool = new ThreadPoolExecutor (10, 50, 60, timeunit.seconds, new ArrayBlockingQueue <Runnable> (10000), new ThreadPoolExecutor.CalleRrunSpolicy ()); } public void excute (tâche de runnable) {pool.execute (tâche); }}10. Créer un fichier de configuration MyBatis
10.1 mybatis.xml
<? xml version = "1.0" encoding = "utf-8"?> <! doctype Configuration public "- // mybatis.org//dtd config 3.0 // en" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <mappers> Resource = "CFG / Demomapper.xml" /> </mappers> </fonfi configuration>
10.2 Demomapper.xml
<? xml version = "1.0" Encoding = "UTF-8"?> <! Doctype Mappeur public "- // mybatis.org//dtd Mappeur 3.0 // en" "http://mybatis.org/dtd/mybatis.idemo"> <insertpacepace = "com.elon.idem" id = "insertdemo" ParameterType = "com.elon.demodao"> insérer dans tbl_demo (a, b, c) valeurs (# {a}, # {b}, # {c}); </ insert> <resultmap id = "démoresult" type = "com.elon.demoresult"> <id propriété = "sum" colonnel = "sumcolum" /> </sultMap> <select id = "selectGroup" resultMap = "Demoresult"> SELECT SUM (a) comme sumcolum à partir du groupe tbl_demo par C; </lect> </ mapper>11. Créer un fichier de configuration de ressort
11.1 printemps.xml
<? xml version = "1.0" encoding = "utf-8"?> <beans xmlns = "http://www.springframework.org/schema/beans" xmlns: xsi = "http://www.w3.org/2001/xmlschema-instance" XSI: ScheMalocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-Beans-3.0.xsd"> <bean id = "datasource_1"> <propriété name = "Driverclassname" Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.70.69.69: 3306 / test1"> </ propriété> <propriété name = "userName" user123 "> </ / propriété name =" mot de passe "value =" user123 "> < name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_2"> <propriété name = "Driverclname" Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.70.69.69: 3306 / test2"> </ propriété> <propriété name = "username" user123 "> </ propriété> <propriété name =" mot de passe "value =" user123 "> < name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_3"> <propriété name = "Driverclname" value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.70.69.69: 3306 / test3"> </ propriété> <propriété name = "userName" user123 "> </ propriété> <propriété name =" mot de passe "value =" user123 "> name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_4"> <propriété name = "Driverclname" Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.70.69.69: 3306 / test4"> </ propriété> <propriété name = "userName" user123 "> </ / propriété name =" mot de passe "value =" user123 "> name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_5"> <propriété name = "Driverclname" value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.70.69.69: 3306 / test5"> </ propriété> <propriété name = "userName" user123 "> </ propriété> <propriété name =" mot de passe "value =" user123 "> < name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_6"> <propriété name = "Drivercname" Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.70.69.69: 3306 / test6"> </ propriété> <propriété name = "userName" user123 "> </ propriété> <propriété name =" mot de passe "value =" user123 "> name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </ bean> <bean id = "datasource_7"> <propriété name = "Driverclname" Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.61.67.246: 3306 / test7"> </ propriété> <propriété name = "userName" value = "user123"> </ propriété> <propriété name = "mot de passe" value = "user123"> </parepreway name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.61.67.246: 3306 / test8"> </ propriété> <propriété name = "userName" value = "user123"> </ propriété> <propriété name = "mot de passe" value = "user123"> </ / propriété> <propriété name = "mot de passe" Value = "user123"> </ / propriété> <propriété Name = "Password" Value = "user123 "> name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_9"> <propriété name = "Drivercly" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://10.61.67.246:3306/test9"></property> <property name="username" value="user123"></property> <property name="password" value="user123"></property> <property name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_10"> <propriété name = "Drivercname" Value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.61.67.246: 3306 / test10"> </ propriété> <propriété name = "username" value = "user123"> </ propriété> <propriété name = "mot de passe" value = "user123"> </parepreway name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource_11"> <propriété name = "Drivercly" value = "com.mysql.jdbc.driver"> </ propriété> <propriété name = "url" value = "jdbc: mysql: //10.61.67.246: 3306 / test11"> </ propriété> <propriété name = "userName" value = "user123"> </ propriété> <propriété name = "mot de passe" value = "user123"> </ / propriété> <propriété name = "mot de passe" Value = "user123"> </prewet> <propriété Name = "Password" Value = "user123 "> name = "maxactive" value = "100"> </ propriété> <propriété name = "maxidle" value = "30"> </ propriété> <propriété name = "maxwait" value = "500"> </ propriété> <propriété name = "defaultAutoMmit" value = "true"> </ propriété> </pan> <bean id = "datasource"> <propriété nom = "TargetDataSources"> <maph = <maph key = "test1" value-ref = "dataSource_1" /> <entrée key = "test2" value-ref = "dataSource_2" /> <entrée key = "test3" value-ref = "dataSource_3" /> <entry key = "test4" value-ref = "dataSource_4" /> <entry key = "test5" value-ref = "dataSource_5" / entrée! key = "test6" value-ref = "dataSource_6" /> <entrée key = "test7" value-ref = "dataSource_7" /> <entrée key = "test8" value-ref = "dataSource_8" /> <entry key = "test9" value-ref = "dataSource_9" /> <entrée = "test10" key = "test11" value-ref = "dataSource_11" /> </ map> </ propriété> </ bean> <bean id = "sqlSessionFactory"> <propriété name = "configLocation" value = "propertypath: cfg / mybatis.xml"> </ propriété> <propriété named = "datasource" ref = "datasource" /> </ beeb> <a-beeb = "idem" reflemy name = "MAPERINTERFACE" Value = "com.elon.idemo"> </ propriété> <propriété name = "SqlSessionFactory" ref = "SQLSessionFactory"> </ Property> </ bean> <bean id = "idemoService"> <propriété name = "idemo" Ref = "idemo"> </parem
12. Code de test
classe publique testmain {/ ** * Code de test * * * @param args * / public static void main (String [] args) {@SuppressWarnings ("Resource") ApplicationContext context = new classPathxmlApplicationContext ("CFG / Spring.xml"); Idemoservice Service1 = (idemoService) context.getBean ("idemoservice"); // Créer un objet de tâche dbtask task1 = new dbtask ("test1", service1, "selectGroup"); Dbtask task2 = new dbtask ("test2", service1, "selectGroup"); DBTASK Task3 = new DBTask ("test3", service1, "selectGroup"); Dbtask task4 = new dbtask ("test4", service1, "selectGroup"); Dbtask task5 = new DBTask ("test5", service1, "selectGroup"); Dbtask task6 = new dbtask ("test6", service1, "selectGroup"); Dbtask task7 = new DBTask ("test7", service1, "selectGroup"); DBTASK Task8 = new DBTask ("test8", service1, "selectGroup"); Dbtask task9 = new dbtask ("test9", service1, "selectGroup"); Dbtask task10 = new dbtask ("test10", service1, "selectGroup"); Dbtask task11 = new dbtask ("test11", service1, "selectGroup"); Demodao Demo = new Demodao (); Demo.seta (10000000); Demo.setB ("12121212"); Demo.setc (100); Dbtask taskInsert = new DBTask ("test2", service1, "insertdemo", démo); SimpledateFormat Format = new SimpledateFormat ("Yyyy-mm-dd hh: mm: ss"); System.out.println ("Démarrer les données d'insertion:" + format.format (new Date ())); Dbtaskmgr.instance (). Excuse (taskInsert); while (true) {if (! taskInsert.isfinish ()) {try {thread.sleep (1000); } catch (InterruptedException e) {e.printStackTrace (); }} else {Break; }} System.out.println ("Insérer des données end:" + format.format (new Date ())); System.out.println ("Démarrer le requête du tableau de données de 50 millions:" + format.format (new Date ())); Dbtaskmgr.instance (). Excuse (tâche1); while (true) {if (! task1.isfinish ()) {try {thread.sleep (1000); } catch (InterruptedException e) {e.printStackTrace (); }} else {Break; }} System.out.println (tâche1.getRetValue ()); System.out.println ("Query 50 millions Table de données End:" + Format.Format (new Date ())); List <dbtask> taskList = new ArrayList <dbtask> (); taskList.add (tâche2); taskList.add (tâche3); taskList.add (tâche4); taskList.add (tâche5); taskList.add (tâche6); taskList.add (tâche7); taskList.add (tâche8); taskList.add (tâche9); taskList.add (tâche10); taskList.add (tâche11); System.out.println ("Démarrer la requête 10 5 millions de tableaux de données:" + format.format (new Date ())); for (dbtask task: taskList) {dbtaskmgr.instance (). excuse (tâche); } while (true) {int succès = 0; for (dbtask task: tasklist) {if (! task.isfinish ()) {try {thread.sleep (1000); } catch (InterruptedException e) {e.printStackTrace (); }} else {++ réussite; }} if (succès == 10) {break; }} pour (tâche dbtask: taskList) {System.out.println (tâche.getReTValue ()) ;; } System.out.println ("10 5 millions de données de données La requête de la requête:" + format.format (new Date ())); }}13. Résultats des tests
Il faut 45S pour interroger directement une base de données de 50 millions de données.
Il faut 22 pour interroger 10 bases de données avec 5 millions de données de manière synchrone.
Étant donné que 10 bases de données sont placées sur deux serveurs, un serveur dispose de 5 bases de données. Si 10 données sont déployées sur 10 serveurs séparément, l'efficacité sera encore plus élevée.
Résumer
Ce qui précède est l'introduction de l'éditeur à Spring + MyBatis + MySQL pour créer un cadre d'accès à base de données distribué. J'espère que ce sera utile à tout le monde. Si vous avez des questions, veuillez me laisser un message et l'éditeur répondra à tout le monde à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!