Après avoir travaillé dur pendant plusieurs nuits pour déboguer le programme, rédiger plusieurs blogs et finalement établir le mécanisme d'extension pour la configuration de MyBatis. Bien que le mécanisme d'extension soit important, il n'est du moins pas si inspirant s'il n'y a pas de fonction d'extension vraiment pratique. Ce blog vous donnera quelques exemples d'extensions.
La raison de cette étude du code source est la compatibilité entre les bases de données Oracle et MySQL. Par exemple, en utilisant des lignes doubles verticales comme connecteurs dans Oracle et en utilisant la fonction Concat dans MySQL; Par exemple, utiliser la fonction Decode dans Oracle, tout en utilisant un cas standard uniquement dans MySQL; Par exemple, supprimer la table du formulaire où le champ1 dans (Sélectionner le champ Field1 Form où Field2 =?) Peut être exécuté, mais les exceptions seront lancées dans MySQL, etc.
Commençons par résoudre ces problèmes de compatibilité. Tout d'abord, vous devez ajouter des configurations liées à l'identité de la base de données à la configuration:
<! - Créer un objet de configuration par vous-même -> <bean id = "mybaticonfig" /> <bean id = "sqlSessionFactory" p: dataSource-ref = "dataSource"> <! - Inject MyBatis Configuration Object -> <propriété name = "Configuration" Ref = "MyBaSConfig" /> <! - scanne automatique name = "Mappenlocations"> <Rarray> <Value> CLASSPATH *: ** / *. SqlMapper.xml </value> </Ray> </ Property> <! - Database Product Identification Configuration -> <propriété Name = "DatabaseIdProvider"> <Eban> <Propriété Name = "Properties"> <Propris> <! - Cela signifie que si la description du produit DATABase contient la clé MySQL est utilisé comme DatabaseID en configuration. Les mots clés de l'implémentation native de MyBatis sont sensibles à la casse. Je n'ai pas testé Oracle et DB2 -> <prop key = "mysql"> mysql </prop> <prop key = "oracle"> oracle </prop> <prop key = "h2"> h2 </prop> <prop> key = "db2"> db2 </ prop> </props> </ propriété> </Eban>
1. Problème du connecteur
1. Écrivez la classe d'implémentation de la fonction de configuration SQL
classe publique ConcatsQlConfigFonction étend AbstractSqlConfigFonction {// Le niveau de commande par défaut est défini dans la classe parentale abstraite @OverRidePublic String getName () {return "Concat";} @ OverRidepublic String eval (String DatabaseId, String [] Args) {If (Args.Length <2) {Throw.ThrowException ("la fonction Concat nécessite à Two Lengend <2) {Throw.ThrowException (" la fonction Concat nécessite à TwoFenth arguments. ");} if (" mysql ".equalSignoreCase (databaseid)) {return" concat ("+ tool.string.join (args,", ") +") ";} else {return tool.string.join (args," || ");}}}2. Inscrivez-vous dans le bloc de code statique de la classe Schemahandlers, ou appelez la méthode Schemahandlers dans la classe d'initialisation de démarrage.
static {// registre instructionHandlerRegister ("cache-ref", new cacheRefstatementHandler ()); registre ("cache", new cachestatementhandler ()); registre ("paramètre", new ResultMapStationdler ()); registre (sql ", new SqlstatementHandler ()); registre ("SELECT | INSERT | Update | Delete", new CrudstatementHandler ()); // Enregistrer le ScripThandlerRegister ("Trim", New TrimScriptHandler (); ForeachScriptHandler ()); registre ("if | when", new ifScripThandler ()); registre ("choisir", new ChooseScripThandler ()); // registre ("quand", new ifScriptHandler ()); registre ("sinon" DbstatementHandler (), new dbscriptHandler ()); // registre sqlconfigFunctionRegReg (new DecodesqlConfigFonction ()); registre (new concatQlconfigFonction ()); // registre sqlconfigfunctionEn plus de l'enregistrement de ConcatsQlConfigFonction, le code ci-dessus a également d'autres codes d'enregistrement, qui sont donnés ici et seront omis ci-dessous.
3. Modifiez la configuration SQLMapper
<select id="selectString" resultType="string">select PARAM_NAME, $concat{PARAM_CODE, PARAM_NAME} AS CODE_NAME from BF_PARAM_ENUM_DEF<if test="null != paramName and '' != paramName">where PARAM_NAME LIKE $CONCAT{'%', #{paramName, jdbcType=VARCHAR}, '%'} </ if> </lect>4. Classe d'interface d'écriture
@RepositoryPublic Interface iExampledao {public String SelectString (@param ("paramname") String paramname);}5. Écrivez des classes de test
@Runwith (springjunit4classrunner.class) @contextconfiguration (locations = {"classpath: printemps / applicationContext.xml"}) @ composantpublic class exampledaotest {@resourceprivate iexampledao dao; @TestPublic Void TestSelectString () {string a a = dao.selectString ("show"); assert.assertequals ("show zone", a);}}6. Exécutez comme suit dans MySQL et H2 respectivement (ajustez le niveau de journal MyBatis pour tracer)
(1) MySQL
20161108 00:12:55,235 [main]-[DEBUG] ==> Preparing: select PARAM_NAME, CONCAT(PARAM_CODE,PARAM_NAME) AS CODE_NAME from BF_PARAM_ENUM_DEF where PARAM_NAME LIKE CONCAT('%',?,'%') 20161108 00:12:55,269 [main]-[DEBUG] ==> Parameters: Display (String) 20161108 00: 12: 55,287 [Main] - [Trace] <== Colonnes: param_name, code_name20161108 00: 12: 55,287 [Main] - [trace] <== Row: Area Zone, display_area Affichage Area20161108 00: 12: 55,289 [Main] - [Debug](2) H2
20161108 00: 23: 08,348 [Main] - [Debug] ==> Préparation: sélectionnez param_name, param_code || param_name as code_name from bf_param_enum_def où param_name like '%' ||? || '%' 20161108 00: 23: 08,364 [Main] - [Debug] == 00: 23: 08,411 [Main] - [Trace] <== Colonnes: param_name, code_name20161108 00: 23: 08,411 [Main] - [trace] <== Row: Affichage Zone, affichage Affichage Area20161108 00: 23: 08,411 [Main] - [Debug] <== Total:
Comme vous pouvez le voir, le problème de compatibilité des connecteurs a été résolu.
De plus, nous avons également constaté que l'écriture est plus gênante lors de l'utilisation de mots clés comme des mots clés, alors donnons-lui un nouvel ensemble de fonctions de configuration SQL:
classe publique likeqlconfigfunctionfactory implémente isqlconfigfunctionfactory {@OverRidePublic Collection <SQLConfigFonction> GetSQlConfigFonctions () {return arrays.aslist (getleftlikesqlconfigFunction (), getRightlikesqlConfigFigFunction (),) getLikesqlConfigFunction ());} private isqlconfigfunction getleftlikesqlconfigFunction () {return new AbstractLikesQlConfigFunction () {@ OverRidepublic String getName () {return "like";} @ overdepublic evalue (String arg) {return "like" $ concat {'%', "+ arg +"} ";}};} private isqlconfigfunction getRightlikesqlconfigFunction () {return new AbstractLikesqlConfigFunction () {@ overderepublic string getName () {return" rLy ";} @ overrideprotected strig ev (string arg) {return" rLy "; $ concat {"+ arg +", '%'} ";}};} private isqlconfigfunction getLikesqlConfigFonction () {return new AbstractLikesqlConfigFunction () {@ Overdepepublic string getName () {return" like ";} @ overdeprotected String evv. $ concat {'%', "+ arg +", '%'} ";}};} classe abstraite privée abstractLikesqlconfigFonction étend abstractsqlconfigfonction {@OverridePublic String ev (String databaseId, string [] args) {la fonction nécessite une seule et 1) {throw.ThrowException (" la fonction comme une et une seule et 1) {throw.ThrowException ("La fonction comme un et une et 1) {throw.ThrowException (" La fonction comme une et une et 1) {throw.ThrowException ("La fonction comme une et une et 1) {Throw argument. ");} return eval (args [0]);} protégée de chaîne abstraite (String arg);}}Ici, un ensemble de fonctions de configuration SQL est défini, avec une similitude gauche, une similitude droite et une correspondance de similitude moyenne, et les fonctions de configuration SQL peuvent également être imbriquées. Par conséquent, le fichier de configuration de SqlMapper est simplifié à:
<select id = "selectString" resultType = "String"> sélectionner param_name, $ concat {param_code, param_name} comme code_name from bf_param_enum_def <if test = "null! = paramname et ''! = paramname"> où param_name $ like {# {paramname, jdbctype = varchar}Les résultats de l'exécution sont exactement les mêmes.
Si vous le trouvez toujours gênant, car param_name et paramname sont des correspondances de type chameau, vous pouvez même ajouter une fonction de champ et modifier la configuration à
où $ fieldlike {# {param_name, jdbcType = varchar}}S'il est combiné avec le dictionnaire de données, la configuration JDBCTYPE peut également être générée automatiquement:
où $ fieldlike {# {param_name}}Dans ce cas, s'il y a plusieurs paramètres, il n'y aura pas d'ambiguïté (ou une fonction de configuration nouvellement définie $ likes {} sera utilisé pour éliminer l'ambiguïté), de sorte que plusieurs conditions peuvent être simplifiées à:
où $ aime {# {param_name, param_name2, param_name3}}Bien sûr, il y a des simplifications plus creusables qui ne sont plus seulement dans le cadre de la compatibilité, donc nous n'irons pas plus loin ici.
2. Décoder la fonction / cas ... quand
La fonction de décodage dans Oracle est très pratique, et la syntaxe est la suivante:
Decode (condition, valeur 1, valeur de retour 1, valeur 2, valeur de retour 2, ... valeur n, valeur de retour n [, valeur par défaut])
Écriture standard des équivalents:
Condition de cas Lorsque la valeur 1 puis renvoie la valeur 1 où la valeur 2 puis renvoie la valeur 2 ... quand la valeur n puis renvoyer la valeur n [else par défaut] fin
Implémentez maintenant une fonction de configuration de décodage $:
classe publique DecodesqlConfigFonction étend AbstractSQLConfigFunction {@OverRidePublic String getName () {return "Decode";} @ OverRidepublic String EVAL (String DatabaseId, String [] Args) {if (args.Length <3) {thord.throwException ("La fonction Decode nécessite au moins trois Arguments. ");} if (" h2 ".equalSignoreCase (databaseID)) {// Lorsque vous testez, utilisez H2 au lieu d'Oracle, et modifiez-le sur Oraclereturn dans le programme officiel" Decode ("+ Tool.String.join (args,", ") +") ";} else {Stringbuffer sb = new Stringbuffer (); sb.append (" Cased " ") .append (args [0]); int i = 2, l = args.length; for (; i <l; i = i + 2) {sb.append (" when ") .append (args [i-1]). sb.append ("else") .append (args [l-1]);} sb.append ("end"); return sb.toString ();}}}Utilisez ensuite SchemAhandlers pour enregistrer et modifier la configuration dans SQLMapper:
<select id = "selectString" resultType = "string"> sélectionner param_name, $ decode {# {paramname}, '1', 'a', '2', 'b', 'c'} as decode_test from bf_param_enum_def <if test = "null! = paramname et ''! = paramname"> quand param_name $ like! jdbcType = varchar}} </ if> </lect>Les tests sont les suivants:
(1) dans H2 (remplacer Oracle par H2)
20161108 06: 53: 29,747 [Main] - [debug] ==> Préparation: sélectionner param_name, decode (?, '1', 'a', '2', 'b', 'c') as decode_test from bf_param_enum_def où param_name comme '%' | || '%'
(2) dans MySQL
20161108 06: 50: 55,998 [Main] - [Debug] ==> Préparation: sélectionnez param_name, cas? Quand '1' alors 'a' quand '2' alors 'b' else 'c' se termine comme decode_test de bf_param_enum_def où param_name comme '%' ||? || '%'
Ce qui précède est une introduction détaillée à l'extension et à l'application de la configuration SQLMapper dans MyBatis présentée par l'éditeur (1). J'espère que cela vous sera utile. Si vous avez des questions, veuillez me laisser un message et l'éditeur vous répondra à temps. Merci beaucoup pour votre soutien au site Web Wulin.com!