通用mapper如何实现通用

参考:https://blog.****.net/isea533/article/details/78493852

最近的一个项目中,我用到了通用mapper,使用后单表的sql操作都很简单了。那么通用mapper是如何能实现通用的呢,我总结一下我自己的想法。
首先,通用mapper的接口都是使用泛型,就可以保障所有类都能用。
通用mapper如何实现通用
要想让通用mapper实现自己构建sql语句,那么它就首先要知道我们实体类中的所有属性,这点可以通过反射来实现。通过反射机制可以获取类的所有属性信息,然后再拼接成完成的sql语句。然后就可以使用这个sql来进行操作了。

但是如果事先没有放在mapper.xml中,那么这条sql语句是怎么实现的呢?

这里是引用在 MyBatis 中,每一个方法(注解或 XML 方式)经过处理后,最终会构造成 MappedStatement 实例,这个对象包含了方法id(namespace+id)、结果映射、缓存配置、SqlSource 等信息,和 SQL 关系最紧密的是其中的 SqlSource,MyBatis 最终执行的 SQL 时就是通过这个接口的 getBoundSql 方法获取的。
在 MyBatis 中,使用@SelectProvider 这种方式定义的方法,最终会构造成 ProviderSqlSource,ProviderSqlSource 是一种处于中间的 SqlSource,它本身不能作为最终执行时使用的 SqlSource,但是他会根据指定方法返回的 SQL 去构造一个可用于最后执行的 StaticSqlSource,StaticSqlSource的特点就是静态 SQL,支持在 SQL 中使用#{param} 方式的参数,但是不支持 , 等标签。

为了能根据实体类动态生成支持动态 SQL 的方法,通用 Mapper 从这里入手,利用ProviderSqlSource 可以生成正常的 MappedStatement,可以直接利用 MyBatis 各种配置和命名空间的特点(这是通用 Mapper 选择这种方式的主要原因)。在生成 MappedStatement 后,“过河拆桥” 般的利用完就把 ProviderSqlSource 替换掉了,正常情况下,ProviderSqlSource 根本就没有执行的机会。在通用 Mapper 定义的实现方法中,提供了 MappedStatement 作为参数,有了这个参数,我们就可以根据 ms 的 id(规范情况下是 接口名.方法名)得到接口,通过接口的泛型可以获取实体类(entityClass),根据实体和表的关系我们可以拼出 XML 方式的动态 SQL。

上面的两段话就是具体解释了我的想法,动态拼接处SQL的具体过程。