通用mapper扩展通用接口和Example 用法

扩展通用接口selectAll 方法
首先定义接口:

@RegisterMapper
public interface SelectAllMapper<T> {

    /**
     * 查询全部结果
     *
     * @return
     */
    @SelectProvider(type = MySelectProvider.class, method = "dynamicSQL")//method = "dynamicSQL"是固定值
    List<T> selectAll();
}

其中 MySelectProvider 是你要实现的一个类,该类需要继承 MapperTemplate。
@RegisterMapper 注解可以避免 mappers 参数配置,通用 Mapper 检测到该接口被继承时,会自动注册。

public class MySelectProvider extends MapperTemplate {

    public BaseSelectProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }
 
    /**
     * 查询全部结果
     *
     * @param ms
     * @return
     */
    public String selectAll(MappedStatement ms) {
        final Class<?> entityClass = getEntityClass(ms);
        //修改返回值类型为实体类型
        setResultType(ms, entityClass);
        StringBuilder sql = new StringBuilder();
        sql.append(SqlHelper.selectAllColumns(entityClass));
        sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
        sql.append(SqlHelper.orderByDefault(entityClass));
        return sql.toString();
    }
}

其中 selectAll 方法名要和接口中定义的方法名一致。其次就是该方法的参数为 MappedStatement 类型。
在 selectAll 方法中,首先是获取了当前接口的实体类型:
final Class<?> entityClass = getEntityClass(ms);
因为接口返回值类型为 List<T>,MyBatis 会认为返回值类型为 List<Object>,这和我们想要的实体类型不一样,所以下一行代码就是设置返回值类型:
setResultType(ms, entityClass);
注意,只有返回 T 或者 List 时需要设置,返回 int 类型时不需要设置。
接下来就是纯粹的拼接 XML 形式的 SQL 了。

//select col1,col2...
sql.append(SqlHelper.selectAllColumns(entityClass));
//from tablename - 支持动态表名
sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass)));
//order by xxx
sql.append(SqlHelper.orderByDefault(entityClass));

这是其中最简单的一个方法实现。当你想要实现某种方法时,可以从已有的例子中找一个最接近的方法,在此基础上进行修改。

自定义批量更新接口

接口:

public interface MyBatchUpdateMapper<T> {
	
	@UpdateProvider(type=MyBatchUpdateProvider.class, method="dynamicSQL")
	void batchUpdate(List<T> list);

}

MyBatchUpdateProvider类:

public class MyBatchUpdateProvider extends MapperTemplate {

	public MyBatchUpdateProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
		super(mapperClass, mapperHelper);
	}
	
	/*
		<foreach collection="list" item="record" separator=";" >
			UPDATE tabple_emp
			<set>
				emp_name=#{record.empName},
				emp_age=#{record.empAge},
				emp_salary=#{record.empSalary},
			</set>
			where emp_id=#{record.empId}
		</foreach>
	 */
	public String batchUpdate(MappedStatement statement) {
		
		//1.创建StringBuilder用于拼接SQL语句的各个组成部分
		StringBuilder builder = new StringBuilder();
		
		//2.拼接foreach标签
		builder.append("<foreach collection=\"list\" item=\"record\" separator=\";\" >");
		
		//3.获取实体类对应的Class对象
		Class<?> entityClass = super.getEntityClass(statement);
		
		//4.获取实体类在数据库中对应的表名
		String tableName = super.tableName(entityClass);
		
		//5.生成update子句
		String updateClause = SqlHelper.updateTable(entityClass, tableName);
		
		builder.append(updateClause);
		
		builder.append("<set>");
		
		//6.获取所有字段信息
		Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);
		
		String idColumn = null;
		String idHolder = null;
		
		for (EntityColumn entityColumn : columns) {
			
			boolean isPrimaryKey = entityColumn.isId();
			
			//7.判断当前字段是否为主键
			if(isPrimaryKey) {
				
				//8.缓存主键的字段名和字段值
				idColumn = entityColumn.getColumn();
				
				//※返回格式如:#{record.age,jdbcType=NUMERIC,typeHandler=MyTypeHandler}
				idHolder = entityColumn.getColumnHolder("record");
				
			}else {
				
				//9.使用非主键字段拼接SET子句
				String column = entityColumn.getColumn();
				String columnHolder = entityColumn.getColumnHolder("record");
				
				builder.append(column).append("=").append(columnHolder).append(",");
				
			}
			
		}
		
		builder.append("</set>");
		
		//10.使用前面缓存的主键名、主键值拼接where子句
		builder.append("where ").append(idColumn).append("=").append(idHolder);
		
		builder.append("</foreach>");
		
		//11.将拼接好的字符串返回
		return builder.toString();
	}

}

如果使用批量更新的时候抛异常,需要在连接数据库语句后面加上:allowMultiQueries=true

Example 用法:
通用 Mapper 中的 Example 方法有两大类定义,一个参数和两个参数的,例如下面两个:

List<T> selectByExample(Object example);
int updateByExampleSelective(@Param("record") T record, @Param("example") Object example);

所有 Example 方法中的 example 类型都是 Object 类型,这是因为通用 Mapper 支持所有符合 Example 结构的参数,例如通过 MBG 生成的 CountryExample、UserExample 类。还有通用 Mapper 中提供的通用 Example,以及支持 Java8 方法引用的 Weekend 类型。
用法如下:

CountryExample example = new CountryExample();
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
example.setDistinct(true);
int count = mapper.deleteByExample(example);

生成的 CountryExample 中包含了和字段相关的多种方法,根据自己的需要设置相应的条件即可。
通用 Example

这是由通用 Mapper 提供的一个类,这个类和 MBG 生成的相比,需要自己设置属性名。这个类还额外提供了更多的方法。
示例:

Example example = new Example(Country.class);
example.setForUpdate(true);
example.createCriteria().andGreaterThan("id", 100).andLessThan("id",151);
example.or().andLessThan("id", 41);
List<Country> countries = mapper.selectByExample(example);

动态 SQL
示例:

Example example = new Example(Country.class);
Example.Criteria criteria = example.createCriteria();
if(query.getCountryname() != null){
    criteria.andLike("countryname", query.getCountryname() + "%");
}
if(query.getId() != null){
    criteria.andGreaterThan("id", query.getId());
}
List<Country> countries = mapper.selectByExample(example);

排序

Example example = new Example(Country.class);
example.orderBy("id").desc().orderBy("countryname").orderBy("countrycode").asc();
List<Country> countries = mapper.selectByExample(example);

去重

CountryExample example = new CountryExample();
//设置 distinct
example.setDistinct(true);
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
List<Country> countries = mapper.selectByExample(example);

设置查询列

Example example = new Example(Country.class);
example.selectProperties("id", "countryname");
List<Country> countries = mapper.selectByExample(example);

除了这里提到的方法外,还有很多其他的方法,可以查看 Example 源码进行了解。
Example.builder 方式

Example example = Example.builder(Country.class)
        .select("countryname")
        .where(Sqls.custom().andGreaterThan("id", 100))
        .orderByAsc("countrycode")
        .forUpdate()
        .build();
List<Country> countries = mapper.selectByExample(example);

 Weekend

使用 Example 时,需要自己输入属性名,例如 "countryname",假设输入错误,或者数据库有变化,这里很可能就会出错,因此基于 Java 8 的方法引用是一种更安全的用法,如果你使用 Java 8,你可以试试 Weekend。

     Weekend<User> weekend = new Weekend<>(User.class);
        //关键字查询部分
        String keyword = pageReq.getKeyword();
        WeekendCriteria<User, Object> keywordCriteria = weekend.weekendCriteria();
        if (StringUtils.isNotEmpty(keyword)) {
            keywordCriteria.orLike(User::getUserName, keyword).orLike(User::getPoliceNo, keyword).orLike(User::getRealName, keyword);
        //此处不需要再用下面这一句了,不然上面这个条件组合会重复一次
            //weekend.and(keywordCriteria)
        }
        //部门查询部分
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("departmentId", departmentId);
        weekend.and(criteria);

        PageHelper.startPage(pageReq.getPageIndex(), pageReq.getPageSize());
        List<User> users = userMapper.selectByExample(weekend);


执行的sql为:

WHERE (
  user_name = ? 
  OR police_no = ? 
  OR real_name = ?
) 
AND (department_id = ?)

 

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值