6

Mybatis通用Mapper的实现

 2 years ago
source link: https://laboo.top/2019/05/26/mybatis/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Mybatis通用Mapper的实现

Posted on

2019-05-26 Edited on 2021-12-15 In 技术分享

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

传统Mybatis开发使用XML的方式编写SQL脚本进行数据库操作,
Mybatis允许使用动态SQL但是即使如此, 依然存在许多重复性工作, 因为每个基本表的增删改查语句模式其实都是相同的

Mybatis也可以使用Dao接口上以注解的形式编写SQL, 但是也是一样, 必须重复编写, 非常不方便

其实Mybatis已经考虑到了这点, 为我们提供了自定义通用Mapper的实现机制

https://github.com/GitHub-Laziji/commons-mybatis

实现方法分为两步

声明引用的方法

在Dao接口的方法上以注解的形式声明, 使用哪个类的哪个方法, 如下

public interface DODao<T extends DO> extends Dao<T> {

@SelectProvider(type = SqlProvider.class, method = "selectById")
T selectById(Long id);

@InsertProvider(type = SqlProvider.class, method = "insert")
@Options(useGeneratedKeys = true, keyColumn = "id")
int insert(T bean);

@UpdateProvider(type = SqlProvider.class, method = "update")
int update(T bean);

@DeleteProvider(type = SqlProvider.class, method = "delete")
int delete(Long id);
}

在实现方法中可以接收Dao接口中传来的参数, 最后返回一个SQL字符串, 这个SQL可以是动态的, 例如可以使用id=#{id}这样的语法

T selectById(Long id)实现如下

public String selectById(ProviderContext context) {
Class clazz = getEntityClass(context);
assert clazz != null;
return new SQL()
.SELECT(getColumns(clazz))
.FROM(getTableName(clazz))
.WHERE("`id`=#{id}")
.toString();
}

我们可以通过context获取Dao的泛型类, 也就是实体类

private Class getEntityClass(ProviderContext context) {
for (Type type : context.getMapperType().getGenericInterfaces()) {
ResolvableType resolvableType = ResolvableType.forType(type);
if (resolvableType.getRawClass() == Dao.class
|| resolvableType.getRawClass() == DODao.class
|| resolvableType.getRawClass() == VODao.class) {
return resolvableType.getGeneric(0).getRawClass();
}
}
return null;
}

通过反射我们可以拿到对应的字段名, 类名, 字段名获取如下, Ignore 是自定义注解, 用于忽略一些字段

private String[] getVariables(Class clazz, String[] prefixes) {
List<String> variables = new ArrayList<>();
for (Method method : clazz.getMethods()) {
Ignore annotation = method.getAnnotation(Ignore.class);
if (annotation != null) {
continue;
}
String name = method.getName();
for (String prefix : prefixes) {
int length = prefix.length();
if (name.length() > length && name.startsWith(prefix)
&& name.charAt(length) >= 'A' && name.charAt(length) <= 'Z') {
String variableName = (char) (name.charAt(length) - 'A' + 'a') + name.substring(length + 1);
variables.add(variableName);
break;
}
}

}
return variables.toArray(new String[]{});
}

private String[] getReadVariables(Class clazz) {
return getVariables(clazz, new String[]{"is", "get"});
}

使用通用Mapper无需编写任何SQL 只需创建空Dao 继承通用的Dao<T>即可


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK