Mybatis如何实现@Select等注解动态组合SQL语句_第1页
Mybatis如何实现@Select等注解动态组合SQL语句_第2页
Mybatis如何实现@Select等注解动态组合SQL语句_第3页
Mybatis如何实现@Select等注解动态组合SQL语句_第4页
Mybatis如何实现@Select等注解动态组合SQL语句_第5页
已阅读5页,还剩6页未读, 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第Mybatis如何实现@Select等注解动态组合SQL语句@ApiModelProperty(value="是否启用",example="0",position=2)

privateBooleanenabled;

*删除标示:0-未删除,1-已删除

@ApiModelProperty(value="删除标示",example="0",position=3)

privateBooleandeleted;

*当前页码

@ApiModelProperty(value="当前页码",example="1",position=4)

@Invisible

privatelongpi;

*当前页面大小

@ApiModelProperty(value="当前页面大小",example="10",position=5)

@Invisible

privatelongps;

}

最后需要对上述中的SimpleSelectLangDriver实现类中将被该注解声明过的字段排除操作,代码如下:

for(Fieldfield:parameterType.getDeclaredFields()){

//排除被Invisble修饰的变量

if(!field.isAnnotationPresent(Invisible.class)){

Stringtmp="iftest=\"_field!=null\"AND_column=#{_field}/if

sb.append(tmp.replaceAll("_field",field.getName()).replaceAll("_column",

CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,field.getName())));

}

如上所示,只是对SimpleSelectLangDriver类增加了if(!field.isAnnotationPresent(Invisible.class))这样的判断,已过滤多余的变量。

需要注意的是在使用Select的时候,传入的参数前无需加入@Param注解,否则会导致Mybatis找不到参数而抛出异常,如需加入就需要绑定对象属性(如在语句中就需要使用)。

2、自定义Selectin注解

在使用Mybatis注解的时候,发现其对SelectIn格式的查询支持不是很友好,在字符串中输入十分繁琐,可以通过将自定义的标签转成格式;下面便通过我们自己实现的LanguageDriver来实现SQL的动态解析:

DAO接口层中代码如下:

@Select("SELECT*FROMadmin_roleWHEREidIN(#{roleIdList})")

@Lang(SimpleSelectInLangDriver.class)

ListRoleDOselectRolesByRoleId(ListIntegerroleIdList);

LanguageDriver实现类如下:

packagemon;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importorg.apache.ibatis.mapping.SqlSource;

importorg.apache.ibatis.scripting.LanguageDriver;

importorg.apache.ibatis.scripting.xmltags.XMLLanguageDriver;

importorg.apache.ibatis.session.Configuration;

*@authorAllen

*@date2025/3/9

*自定义Selectin注解,用于动态生成Selectin语句

publicclassSimpleSelectInLangDriverextendsXMLLanguageDriverimplementsLanguageDriver{

*Pattern静态申明

privatefinalPatterninPattern=Ppile("\\(#\\{(\\w+)\\}\\)");

*实现自定义Selectin注解

*@paramconfiguration配置参数

*@paramscript入参

*@paramparameterType参数类型

*@return转换后的SqlSource

@Override

publicSqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,ClassparameterType){

Matchermatcher=inPattern.matcher(script);

if(matcher.find()){

script=matcher.replaceAll("foreachcollection=\"$1\"item=\"_item\"open=\"(\""

+"separator=\",\"close=\")\"#{_item}/foreach

script="script"+script+"/script

returnsuper.createSqlSource(configuration,script,parameterType);

}

通过自己实现LanguageDriver,在服务器启动的时候,就会将我们自定义的标签解析为动态SQL语句,其等同于:

@Select("SELECT*"+

"FROMadmin_role"+

"WHEREidIN"+

"foreachitem='item'index='index'collection='list'open='('separator=','close=')'"+

"#{item}"+

"/foreach")

ListRoleDOselectRolesByRoleId(ListIntegerroleIdList);

通过实现LanguageDriver,剥离了冗长的动态拼接SQL语句,简化了SelectIn的注解代码。

需要注意的是在使用SelectIn的时候,则与上述相反需务必在传入的参数前加@Param注解,否则会导致Mybatis找不到参数而抛出异常。

3、自定义Update的注解

在扩展update注解时,数据库每张表的字段和实体类的字段必须遵循一个约定(数据库中采用下划线命名法,实体类中采用驼峰命名法)。

当我们update的时候,会根据每个字段的映射关系,写出如下代码:

/**

*更新

*@paramroleDO角色信息

*@return影响行数

@Update("updateadmin_rolesetrole_name=#{roleDO.roleName},"

+"enabled=#{roleDO.enabled},deleted=#{roleDO.deleted},modifierId=#{roleDO.modifierId},"

+"modifier=#{roleDO.modifier},last_modified=#{roleDO.lastModified}whereid=#{roleDO.id}")

intupdate(@Param(value="roleDO")RoleDOroleDO);

上述的代码我们可以将实体类中的驼峰式代码转换为下划线式命名方式,这样就可以将这种映射规律自动化,但此代码存在一定的问题,就是当你在更新部分字段时其余所有字段原来的值必须传入,否则可能会将原有数据更新为null或空,亦或在更新时先查询原数据后将变更的数据进行操作,这样不仅增加了数据库查询操作且会造成代码冗余,而经过实现LanguageDriver后,注解代码如下:

/**

*更新

*@paramroleParam角色信息

@Update("updateadmin_role(#{roleDO})whereid=#{id}")

@Lang(SimpleUpdateLangDriver.class)

voidupdate(RoleParamroleParam);

相对于原始的代码量有很大的减少,尤其是对于一个类中字段越多,改善也就越明显。实现方式为:

packagemon;

importjava.lang.reflect.Field;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importorg.apache.ibatis.mapping.SqlSource;

importorg.apache.ibatis.scripting.LanguageDriver;

importorg.apache.ibatis.scripting.xmltags.XMLLanguageDriver;

importorg.apache.ibatis.session.Configuration;

importmon.base.CaseFormat;

*@authorAllen

*@date2025/3/9

*自定义Update注解,用于动态生成Update语句

publicclassSimpleUpdateLangDriverextendsXMLLanguageDriverimplementsLanguageDriver{

*Pattern静态申明

privatefinalPatterninPattern=Ppile("\\(#\\{(\\w+)\\}\\)");

*实现自定义Update注解

*@paramconfiguration配置参数

*@paramscript入参

*@paramparameterType参数类型

*@return转换后的SqlSource

@Override

publicSqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,ClassparameterType){

Matchermatcher=inPattern.matcher(script);

if(matcher.find()){

StringBuildersb=newStringBuilder();

sb.append("set

for(Fieldfield:parameterType.getDeclaredFields()){

//排除被Invisble修饰的变量

if(!field.isAnnotationPresent(Invisible.class)){

Stringtmp="iftest=\"_field!=null\"_column=#{_field},/if

sb.append(tmp.replaceAll("_field",field.getName()).replaceAll("_column",

CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,field.getName())));

sb.deleteCharAt(sb.lastIndexOf(","));

sb.append("/set

script=matcher.replaceAll(sb.toString());

script="script"+script+"/script

returnsuper.createSqlSource(configuration,script,parameterType);

}

注意此处在传入的参数前无需加入@Param注解。

4、自定义Insert的注解同理

我们可以抽象化Insert操作,简化后的Insert注解为:

/**

*插入

*@paramroleParam角色信息

@Insert("insertintoadmin_role(#{roleDO})")

@Lang(SimpleInsertLangDriver.class)

voidinsert(RoleParamroleParam);

SimpleInsertLanguageDriver实现类代码如下:

packagemon;

importjava.lang.reflect.Field;

importjava.util.regex.Matcher;

importjava.util.regex.Pattern;

importorg.apache.ibatis.mapping.SqlSource;

importorg.apache.ibatis.scripting.LanguageDriver;

importorg.apache.ibatis.scripting.xmltags.XMLLanguageDriver;

importorg.apache.ibatis.session.Configuration;

importmon.base.CaseFormat;

*@authorAllen

*@date2025/3/9

*自定义Insert注解,用于动态生成Insert语句

publicclassSimpleInsertLangDriverextendsXMLLanguageDriverimplementsLanguageDriver{

*Pattern静态申明

privatefinalPatterninPattern=Ppile("\\(#\\{(\\w+)\\}\\)");

*实现自定义Insert注解

*@paramconfiguration配置参数

*@paramscript入参

*@paramparameterType参数类型

*@return转换后的SqlSource

@Override

publicSqlSourcecreateSqlSource(Configurationconfiguration,Stringscript,ClassparameterType){

Matchermatcher=inPattern.matcher(script);

if(matcher.find()){

StringBuildersb=newStringBuilder();

StringBuildertmp=newStringBuilder();

sb.append("(");

for(Fieldfield:parameterType.getDeclaredFields()){

if(!field.isAnnotationPresent(Invisible.class)){

sb.append(

CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE,field.getName())

+",");

tmp.append("#{"+field.getName()+"},");

sb.deleteCharAt(sb.lastIndexOf(","));

tmp.deleteCharAt(tmp.lastIndexOf(","));

sb.append(")values("

+tmp.toString()+")");

script=matcher.replaceAll(sb.toString());

script="script"+script+"/script

returnsuper.createSqlSource(configuration,script,parameterType);

}

至此我们完成了基本的@Select、@Update、@Insert自定义注解,简单化繁杂的拼接SQL语句的尴尬,但以上代码在SimpleSelectLangDriver中还有一定的局限性,比如对于一些字段我们需要使用like来进行查询,这时就需要对上述自定义Seleect注解进行完善以实现各种业务的场景。

四、注意事项遇到的一些坑

务必确保数据库中列名和实体类中字段能一一对应。在使用自定义SQL解析器的时候,只能传入一个参数,即相应的对象参数即可;传入多个参数会导致解析器中获得到的class对象改变,使得sql解析异常。Update的实现能满足大部分的业务,但有些业务场景可以会遇到根据查询条件来更新查询参数的情况,比如UpdateuserSETuesr_name=王雷WHEREuser_name=小王在这样的场景中请不要使用自定义的SQL解析器。请使用Mybatis3.3以上版本。3.2以下版本会存在一些Bug,在本例中使用的为mybatis-spring-boot-starter1.3.1,其Mybatis为3.4.5。

五、总结

通过实现LanguageDriver,我们可以很方便的自定义自己的注解。在遵循一些约定的情况下(数据库下划线命名,实体驼峰命名),我们可以大幅度的减少SQL的编写量,并且可以完全的屏蔽掉麻烦的XML编写方式,再也不用再编写复杂的拼接动态SQL的烦恼,简化工作,提高开发效率。

//

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论