使用 Provider 注解实现动态 SQL

发布于 2023-11-04 18:43:26 字数 5301 浏览 18 评论 0

Mybatis3 中增加了使用注解来配置 Mapper 的新特性,这里主要介绍 @SelectProvider、@UpdateProvider、@InsertProvider 和 @DeleteProvider 的使用方式。

这几个注解声明在 Mapper 对应的 interface 的方法上的,注解用于生成查询用的 sql 语句。如果对应的 Mapper 中已使用 @Param 来注解参数,则在对应的 Prodiver 的方法中无需写参数。

注解中参数:

  • type:参数指定的 Class 类,必须要能够通过无参的构造函数来初始化;
  • method:参数指定的方法,必须是 public 的,返回值必须为 String,可以为 static。

一、@SelectProvider

@ResultMap 注解用于从查询结果集 ResultSet 中取数据然后拼装实体 bean。

public interface UserMapper {
   @SelectProvider(type = SqlProvider.class, method = "selectUser")
   @ResultMap("userMap")
   public User getUser(long userId);
}
public class SqlProvider {
  public String selectUser(long userId){
     SELECT("id, name, email");
      FROM("USER");
      WHERE("ID = #{userId}");

  }
}

上例中定义了一个 Mapper 接口,其中定义了一个 getUser 方法,这个方法根据用户 id 来获取用户信息,并返回相应的 User。而对应的 SQL 语句则写在 SqlProvider 类中。

二、@InsertProvider

public interface UserMapper {
  @InsertProvider(type = SqlProvider.class, method = "addUser")
  @Options(useGeneratedKeys = true, keyProperty = "id")
  int addUser(Tutor tutor);
}
public class SqlProvider {
  public String addUser(User user) {
    return new SQL() {
      {
        INSERT_INTO("USER");
        if (user.getName() != null) {
          VALUES("NAME", "#{name}");
        }
        if (user.getEmail() != null) {
          VALUES("EMAIL", "#{email}");
        }
      }
    }.toString();
  }
}

三、@UpdateProvider

public interface UserMapper {
  @UpdateProvider(type = SqlProvider.class, method = "updateUser")
  int updateUser(User user);
}
public class SqlProvider {
  public String updateUser(User user) {
    return new SQL() {
      {
        UPDATE("USER");
        if (user.getName() != null) {
          SET("NAME = #{name}");
        }
        if (user.getEmail() != null) {
          SET("EMAIL = #{email}");
        }
        WHERE("ID= #{id}");
      }
    }.toString();
  }
}

四、@DeleteProvider

public interface UserMapper {
  @DeleteProvider(type = SqlProvider.class, method = "deleteUser")
  int deleteUser(int id);
}
public class SqlProvider {
  public String deleteUser(int id) {
    return new SQL() {
      {
        DELETE_FROM("USER");
        WHERE("ID= #{id}");
      }
    }.toString();
  }
}

项目实践

在一次项目中,我需要导入一个 excel 文件,该文件每一行有两百多个字段,我需要根据数据库中保存的字段导入规则进行校验,校验成功后,我需要将存在的字段插入数据库中,如果两百多个字段我都在 Mapper 文件使用 <if> 动态标签的话,那不仅费时费力,还极难维护,所以我们就可以通过 @InsertProvider 标签,根据数据库中查询出来的字段规则,动态生成 SQL 语句:

import cn.uni.app.entity.csv.ColumnInfo;
import cn.uni.app.utils.ValidUtil;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;

public class HospMainSql {

  public String addJxkhMain(List<ColumnInfo> list, Map<String, Object> params, String isZy) {
    return new SQL() {
      {
        //isZy=0 则将数据插入 t_card_info_import 中,否则插入 t_card_info_import_zy
        if ("0".equals(isZy)) {
          INSERT_INTO("t_card_info_import");
        } else {
          INSERT_INTO("t_card_info_import_zy");
        }
        //遍历所有字段规则,如果需要导入的数据中包含该字段,则将该字段插入数据库
        for (ColumnInfo info : list) {
          Boolean bool = params.containsKey(info.getColname());
          if (bool) {
            switch (info.getColtype()) {
              //如果是字符串类型
              case "C":
                VALUES(info.getColname(), "'" + params.get(info.getColname()).toString() + "'");
                break;
              //如果是日期类型
              case "D":
                VALUES(info.getColname(), "'" + params.get(info.getColname()).toString() + "'");
                break;
              //如果是数值类型
              case "N":
                if (!StringUtils.isEmpty(params.get(info.getColname()).toString().trim())) {
                  VALUES(info.getColname(), ValidUtil.isNumeric1(params.get(info.getColname()).toString()));
                }
                break;
            }
          }
        }
        /**
         * 下面几个字段与业务无关,在 ts_upload_column_info 中无约束
         */
        VALUES("hospcode", "'" + params.get("hospcode").toString() + "'");
        VALUES("hisid", "'" + params.get("hisid").toString() + "'");
        //调用数据库中编写的,newId() 函数,生成 suid
        VALUES("suid", "newid()");
        //判断是否存在 UploadId
        Boolean tag = params.containsKey("UploadId");
        if (tag) {
          VALUES("UploadId", "'" + params.get("UploadId").toString() + "'");
        }
      }
    }.toString();
  }
}
public class ColumnInfo {
  private Integer colid;
  private String colname;//字段名
  private String coldesc;//字段描述
  private String coltype;//数据类型
  private Integer collen;//数据长度
  private Integer colprec;//数据精度(如果是 decimal)
  private Character notnull;//是否能为空
  private Integer orderid;//排序权重
} 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

0 文章
0 评论
23 人气
更多

推荐作者

qq_E2Iff7

文章 0 评论 0

Archangel

文章 0 评论 0

freedog

文章 0 评论 0

Hunk

文章 0 评论 0

18819270189

文章 0 评论 0

wenkai

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文