使用说明

项目引入

具体版本请查看

maven

<dependency>
  <groupId>com.github.wpyuan</groupId>
  <artifactId>mybatis-crud</artifactId>
  <version>${latest.version}</version>
</dependency>

gradle

implementation 'com.github.wpyuan:mybatis-crud:版本号'

使用设置

实体类(以下称entity)创建

可以先用Mybatis-Generator生成表对应entity类,在做下面的修改,需保证字段不缺类型一致

主键字段添加@com.github.mybatis.crud.annotation.Id注解、类上添加@com.github.mybatis.crud.annotation.Table注解,举例如下:

mysql数据库的employee表,对应的entity

@Table(name = "employee")
public class Employee {
    @Id
    private Long id;

    ...

}

oracle数据库的employee表,对应的entity

@Table("employee")
public class EmployeeOra {
    /**
     * @mbg.generated Fri Dec 25 11:16:58 CST 2020
     */
    @Id(sequence = "EMPLOYEE_ID_S")
    private Long id;
    
    ...
}

需要注意的是:需在@com.github.mybatis.crud.annotation.Table填入name值指定表名,oracle数据库需在@com.github.mybatis.crud.annotation.Id填入sequence值指定序列

mapper创建

组件已封装多个通用mapper,可选择继承使用,比如com.github.mybatis.crud.mapper.DefaultMapper包含默认CRUD实现,如下例子:

public interface EmployeeMapper extends DefaultMapper<Employee>, BatchInsertMapper<Employee> {
}

其中com.github.mybatis.crud.mapper.BatchInsertMapper是批量插入实现,可选择继承,然后配置此mapper扫描路径(这个不做赘述)

开始使用

创建表对应entitymapper后,以插入删除修改查询介绍

插入

insert

全字段插入

int insert(E entity);

insertSelective

有值的字段插入

int insertSelective(E entity);

删除

根据主键删除记录

int deleteByPrimaryKey(E entity);

根据条件删除记录

int delete(Condition<E> condition);

其中Condition<E> condition包含有

方法 说明
andBetween, between, orBetween betweenand … 的实现
diy 自定义语句实现
andEq, andEq, eq, eq, orEq, orEq 等于=的实现
andGt, andGt, gt, gt, orGt, orGt 大于>的实现
andGtEq, andGtEq, gtEq, gtEq, orGtEq, orGtEq 大于等于>=的实现
andIn, andIn, in, in, orIn, orIn in的实现
andNotNull, notNull, orNotNull is not null的实现
andNull, isNull, orNull is null的实现
andLt, andLt, lt, lt, orLt, orLt 小于<的实现
andLtEq, andLtEq, ltEq, ltEq, orLtEq, orLtEq 小于等于<=的实现
andLeftLike, andLeftLike, andLike, andLike, andLikeDiy, andRightLike, andRightLike, like, like, likeDiy, lLike, lLike, orLeftLike, orLeftLike, orLike, orLike, orLikeDiy, orLLike, orLLike, orRightLike, orRightLike, orRLike, orRLike, rLike, rLike like的实现
andNotBetween, notBetween, orNotBetween not betweenand … 的实现
andNotEq, andNotEq, nEq, nEq, orNotEq, orNotEq 不等于!=的实现
andNotIn, andNotIn, notIn, notIn, orNotIn, orNotIn not in 的实现
andLeftNotLike, andLeftNotLike, andNotLike, andNotLike, andNotLikeDiy, andRightNotLike, andRightNotLike, lNotLike, lNotLike, notLike, notLike, notLikeDiy, orLeftNotLike, orLeftNotLike, orLNotLike, orLNotLike, orNotLike, orNotLike, orNotLikeDiy, orRightNotLike, orRightNotLike, orRNotLike, orRNotLike, rNotLike, rNotLike not like 的实现

删除employeeName like '%1/%/2'、删除id=1的记录举例,更多用法会在后续ConditionLikeEscapeHandler小节讲述:

Employee employee = new Employee();
int updates = mapper.delete(new Condition<Employee>(employee).lLike("employeeName", "1/%/2"));

employee.setId(1L);
updates = mapper.delete(new Condition<Employee>(employee).eq("id")); 

修改

主要方法如下:

    /**
     * 根据主键更新覆盖
     *
     * @param entity 实体类
     * @return 影响条数
     */
    int updateByPrimaryKey(E entity);

    /**
     * 根据主键更新覆盖有值列
     *
     * @param entity 实体类
     * @return 影响条数
     */
    int updateByPrimaryKeySelective(E entity);

    /**
     * 根据主键更新覆盖指定列
     *
     * @param entity 实体类
     * @param fields 指定列
     * @return 影响条数
     */
    int updateField(@Param("entity") E entity, @Param("fields") String... fields);

    /**
     * 根据条件更新覆盖指定列
     *
     * @param update 条件
     * @return 影响条数
     */
    int update(Update<E> update);

这里说明int update(Update<E> update);方法的使用:

以指定id条件为例子,这里条件可任意,具体使用更多用法在后续Condition小节介绍

查询

主要方法如下:


    /**
     * 根据主键查询
     *
     * @param entity 实体类
     * @return 查询结果
     */
    E selectByPrimaryKey(E entity);

    /**
     * 根据条件查询列表
     *
     * @param condition 条件
     * @return 查询结果
     */
    List<E> list(Condition<E> condition);

    /**
     * 根据条件查询一个结果
     *
     * @param condition 条件
     * @return 查询结果
     */
    E detail(Condition<E> condition);

    /**
     * 根据条件复杂查询出结果
     *
     * @param leftJoin 查询条件
     * @return 查询结果
     */
    List<Map<String, Object>> select(LeftJoin<E> leftJoin);

    /**
     * 根据条件复杂查询出结果并转换格式
     *
     * @param resultTypeClass 返回结果类型class
     * @param leftJoin        查询条件
     * @return 查询结果
     */
    <R> List<R> select(Class<R> resultTypeClass, LeftJoin<E> leftJoin);
    

这里讲下两个select方法的区别:

两个都提供了左外连接的实现,目前出于可维护性考虑,不考虑继续推出多外联表方法实现,建议写入xml文件,增加可读性

这里讲下两个select方法的使用:

Employee employee = new Employee();
UserInfo userInfo = UserInfo.builder().build();

List<Map<String, Object>> data = mapper.select(new LeftJoin<Employee>(Employee.class)
    .field(As.of(UserInfo.class, "userId", "userId"))
    .field(UserInfo.class, "userName")
    on(On.of(Employee.class, "id"), On.of(UserInfo.class, "employeeId"))
);

其中涉及LeftJoin左外连接、As别名设置,即查询列返回的列别名,具体含义在后续LeftJoinAsOn小节说明

Employee employee = new Employee();
employee.setId(1L);
List<EmployeeVO> employeeVOS = mapper.select(EmployeeVO.class,
    new LeftJoin<Employee>(Employee.class)
    .field(As.of(UserInfo.class, "userId", "userId"))
    .field(UserInfo.class, "userName")
    .on(On.of(Employee.class, "id"), On.of(UserInfo.class, "employeeId"), OnCondition.builder(employee).build().eq("id"))
    .where(WhereCondition.builder(employee).build().eq("id"))
);

其中where指定where条件,涉及OnConditionWhereCondition均在后续小节说明

其他类说明

LikeEscapeHandler

like 转义处理器,处理like语句条件值中的%,_通配符为文本处理,若不加处理器则作为原通配符处理

可选择性启用,启用方式:

@Configuration
public class PluginInterceptor {

    @Bean
    public DefaultMybatisInterceptor defaultMybatisPlugin() {
        DefaultMybatisInterceptor defaultMybatisInterceptor = new DefaultMybatisInterceptor();
        defaultMybatisInterceptor.setPluginHandlers(new LikeEscapeHandler());
        return defaultMybatisInterceptor;
    }
}


@Configuration
public class MyBatisConfig {

   
    @Autowired
    private DefaultMybatisInterceptor defaultMybatisInterceptor;

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setPlugins(defaultMybatisInterceptor);
        
        ...
        
        SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBean.getObject();
        
        ...
        
        return sqlSessionFactory;
    }
}

Condition

单表条件构造器,构造方法和功能方法如下

构造方法

构造器 说明
Condition(Class eClass) 使用 new Condition(Employee.class)创建条件构造器,其中Employee更换为条件对应的表的entity
Condition(Condition source) 复制Condition方法,不是同一引用
Condition(E entity) entity初始化条件构造器

也可以用builder创建条件构造器,如:


/**
 * 有条件值的entity,构造Condition如下
 */
Employee employee = new Employee();
employee.setId(1L);
Condition.<Employee>builder(employee).build()

/**
 * 无条件值的entity,构造Condition如下
 */
Condition.<Employee>builder(Employee.class).build()

功能方法

连接符方法

支持groupandor连接符,其中:

语句方法
方法 说明
andBetween, between, orBetween betweenand … 的实现
diy 自定义语句实现
andEq, andEq, eq, eq, orEq, orEq 等于=的实现
andGt, andGt, gt, gt, orGt, orGt 大于>的实现
andGtEq, andGtEq, gtEq, gtEq, orGtEq, orGtEq 大于等于>=的实现
andIn, andIn, in, in, orIn, orIn in的实现
andNotNull, notNull, orNotNull is not null的实现
andNull, isNull, orNull is null的实现
andLt, andLt, lt, lt, orLt, orLt 小于<的实现
andLtEq, andLtEq, ltEq, ltEq, orLtEq, orLtEq 小于等于<=的实现
andLeftLike, andLeftLike, andLike, andLike, andLikeDiy, andRightLike, andRightLike, like, like, likeDiy, lLike, lLike, orLeftLike, orLeftLike, orLike, orLike, orLikeDiy, orLLike, orLLike, orRightLike, orRightLike, orRLike, orRLike, rLike, rLike like的实现
andNotBetween, notBetween, orNotBetween not betweenand … 的实现
andNotEq, andNotEq, nEq, nEq, orNotEq, orNotEq 不等于!=的实现
andNotIn, andNotIn, notIn, notIn, orNotIn, orNotIn not in 的实现
andLeftNotLike, andLeftNotLike, andNotLike, andNotLike, andNotLikeDiy, andRightNotLike, andRightNotLike, lNotLike, lNotLike, notLike, notLike, notLikeDiy, orLeftNotLike, orLeftNotLike, orLNotLike, orLNotLike, orNotLike, orNotLike, orNotLikeDiy, orRightNotLike, orRightNotLike, orRNotLike, orRNotLike, rNotLike, rNotLike not like 的实现

其中andBetweenbetween类似没有前缀and等效,是为了方便书写和简洁,这里默认了and前缀连接符

具体使用

根据如上构造方法、连接符和语句方法,可写出高度灵活复杂的条件,举例如下:

Condition<Employee> condition = new Condition<Employee>(Employee.class)
        .and(
                c -> c.group(
                        c1 -> c1.diy(null, null, "1", "=", 1, null)
                                .and(
                                        c2 -> c2.diy(null, null, "1", "=", 1, null)
                                                .diy(null, "or", "1", "=", 1, null)
                                )
                )
                .or(
                        c3 -> c3.group(
                                c4 -> c4.diy(null, null, "1", "=", 1, null)
                                        .diy(null, "or", "1", "=", 1, null)
                        ).diy(null, "and", "1", "=", 0, null)
                )
        );

即实现语句:

and( ( 1 = 1 and ( 1 = 1 or 1 = 1 ) ) or ( ( 1 = 1 or 1 = 1 ) and 1 = 0 ) )

其中的diy为自定义语句,可替换上述语句方法小点表格中任意方法

为了可读性和易维护性,不建议复杂的语句用组件写,建议写在xml文件,这里只是功能展示

更多Condition方法尽请期待…

OnCondition

外连接On条件构造器,与Condition单表条件构造器不同,专注与构造外连接时,on后面的连接条件,即是涉及两表的条件构造器

构造方法

含有Condition单表条件构造器所有构造方法外,还有

构造器 说明
OnCondition(Class<?> eClass, Class<?> eClass2) 使用new OnCondition(Employee.class, UserInfo.class)即初始化出EmployeeUserInfo对应两表的条件构造器
OnCondition(Object entity, Object entity2) 使用new OnCondition(employee, userInfo)即初始化出employeeuserInfo对应两表的条件构造器

也可以用builder创建条件构造器,与Condition单表条件构造器用法一样不做赘述

功能方法

连接符方法

Condition单表条件构造器一样不做赘述

语句方法

含有Condition单表条件构造器所有语句方法外,还有

方法 说明
andEq, eq, orEq 两表等于=的实现
andNotEq, nEq, orNotEq 两表不等于!=的实现
diy 两表自定义语句实现
andGt, gt, orGt 两表大于>的实现
andGtEq, gtEq, orGtEq 两表大于等于>=的实现
andLt, lt, orLt 两表小于<的实现
andLtEq, ltEq, orLtEq 两表小于等于<=的实现

具体使用

根据如上方法,可写出两表联表查询,举例如下:

Employee employee = new Employee();
employee.setId(1L);
List<Map<String, Object>> data = mapper.select(new LeftJoin<Employee>(Employee.class)
        .field(UserInfoOra.class,"userName", "userId")
        .on(On.of(Employee.class, "id"), On.of(UserInfo.class, "employeeId"),
                OnCondition.<UserInfo>builder(UserInfo.class).build().eq("isEnable", false),
        ).where(WhereCondition.builder(employee).build().eq("id"))
);

即实现语句:

select e.*, u.user_id, u.user_name
from employee e
left join user_info u on u.employee_id = e.id and u.is_enable = 0
where e.id = 1

其中LeftJoinOn下文单独小节说明

更多OnCondition方法尽请期待…

WhereCondition

外连接Where条件构造器,也是涉及两表的条件构造器,与OnCondition不同的是,WhereCondition专注于where的条件,其余全部和OnCondition雷同,这里不作赘述

As

别名标注,用法如下:

new LeftJoin<Employee>(Employee.class)
        .field(As.of(UserInfo.class, "userId", "createdUserId"))

即,查询UserInfo对应表的user_id字段返回createdUserId别名,As需配合LeftJoin等外连接类使用

On

连接条件标注,用法如下:

new LeftJoin<Employee>(Employee.class)
        .on(On.of(Employee.class, "id"), On.of(UserInfo.class, "employeeId"))

即,查询Employee对应表左外连UserInfo对应表记录,连接条件是Employeeid字段等于UserInfoemployeeId字段

LeftJoin

左外连接构造器

构造方法

构造器 说明
LeftJoin(Class eClass) 即使用new LeftJoin(Employee.class)创建左外连接构造器
LeftJoin(E entity) 即使用new LeftJoin(employee)创建左外连接构造器

目前两种方法推荐使用第一种创建

功能方法

限定符和类型 方法 说明
LeftJoin field(As… fieldAs) 查询两表的字段别名设置
LeftJoin field(Class<?> eClass, String… field) 指定查询字段,默认全查主表字段,这里供外连接表查询字段设置
LeftJoin on(On onLeft, On onRight, OnCondition… onCondition) 外连接on条件,onLeftonRight指定连接关系,OnCondition其他连接条件,on上面的条件 不支持( )符号
LeftJoin where(WhereCondition… whereConditions) where条件, 不支持( )符号

如下举例:

new LeftJoin<Employee>(Employee.class)
        .field(UserInfoOra.class,"userName", "userId")
        .on(On.of(Employee.class, "id"), On.of(UserInfo.class, "employeeId"),
                OnCondition.<UserInfo>builder(UserInfo.class).build().eq("isEnable", false),
        ).where(WhereCondition.builder(employee).build().eq("id"))

扩展

本插件经过一系列封装,具有高度的扩展性,利于应对各种场景,即可在sql各种阶段加入自定义逻辑,以下仅供参考,更多场景自行判断使用。

可支持扩展的几种类型

目前仅支持前置处理,后置处理等,敬请期待后续更新。

具体操作

下面分别给上述几种类型举例,如何在指定类型加入自定义逻辑处理器

删除前置处理

自定义删除前置处理器,需实现DeleteMybatisInterceptorHandler接口,例子:

public class DelAllHandler implements DeleteMybatisInterceptorHandler {
    @Override
    public void before(Invocation invocation) {
        //do something
    }
}

上述例子是删除全部数据前置处理器,这个用于拦截些错误语句或sql注入导致的全表删除数据的异常操作,可在before前置方法中加入处理逻辑。

注意:com.github.mybatis.crud.handler.DeleteMybatisInterceptorHandler

插入前置处理

自定义删除前置处理器,需实现InsertMybatisInterceptorHandler接口,例子:

public class WhInsertHandler implements InsertMybatisInterceptorHandler {
    @Override
    public void before(Invocation invocation) {
        //do something
    }
}

上述例子是插入数据wh字段填入前置处理器,这个用于插入记录前,填充与业务无关的、便于审计运维的whowhenwh字段,可在before前置方法中加入处理逻辑。

注意:com.github.mybatis.crud.handler.InsertMybatisInterceptorHandler

查询前置处理

自定义查询前置处理器,需实现SelectMybatisInterceptorHandler接口,例子:

public class TenantHandler implements SelectMybatisInterceptorHandler {
    @Override
    public void before(Invocation invocation) {
        //do something
    }
}

上述例子是租户查询前置处理器,这个用于查询前,追加租户id条件做数据屏蔽使用,可在before前置方法中加入处理逻辑。

注意:com.github.mybatis.crud.handler.SelectMybatisInterceptorHandler

更新前置处理

自定义更新前置处理器,需实现UpdateMybatisInterceptorHandler接口,例子:

public class VersionHandler implements UpdateMybatisInterceptorHandler {
    @Override
    public void before(Invocation invocation) {
        //do something
    }
}

上述例子是更新版本号前置处理器,这个用于更新前,校对记录版本号、升版本号处理,可在before前置方法中加入处理逻辑。

注意:com.github.mybatis.crud.handler.UpdateMybatisInterceptorHandler

prepare前置处理

自定义prepare前置处理器,需实现PrepareMybatisInterceptorHandler接口,例子:

public class ConnHandler implements PrepareMybatisInterceptorHandler {
    @Override
    public void before(Invocation invocation) {
        //do something
    }
}

上述例子是连接prepare前置处理器,这个用于对连接Connection做处理操作,可在before前置方法中加入处理逻辑。

注意:com.github.mybatis.crud.handler.PrepareMybatisInterceptorHandler