扩展通用接口selectAll 方法
首先定义接口:
@RegisterMapper
public interface SelectAllMapper {
/**
* 查询全部结果
*
* @return
*/
@SelectProvider(type = MySelectProvider.class, method = "dynamicSQL")//method = "dynamicSQL"是固定值
List 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
//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 {
@UpdateProvider(type=MyBatchUpdateProvider.class, method="dynamicSQL")
void batchUpdate(List list);
}
MyBatchUpdateProvider类:
public class MyBatchUpdateProvider extends MapperTemplate {
public MyBatchUpdateProvider(Class> mapperClass, MapperHelper mapperHelper) {
super(mapperClass, mapperHelper);
}
/*
UPDATE tabple_emp
emp_name=#{record.empName},
emp_age=#{record.empAge},
emp_salary=#{record.empSalary},
where emp_id=#{record.empId}
*/
public String batchUpdate(MappedStatement statement) {
//1.创建StringBuilder用于拼接SQL语句的各个组成部分
StringBuilder builder = new StringBuilder();
//2.拼接foreach标签
builder.append("");
//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("");
//6.获取所有字段信息
Set 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(" ");
//10.使用前面缓存的主键名、主键值拼接where子句
builder.append("where ").append(idColumn).append("=").append(idHolder);
builder.append(" ");
//11.将拼接好的字符串返回
return builder.toString();
}
}
如果使用批量更新的时候抛异常,需要在连接数据库语句后面加上:allowMultiQueries=true
Example 用法:
通用 Mapper 中的 Example 方法有两大类定义,一个参数和两个参数的,例如下面两个:
List 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 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 countries = mapper.selectByExample(example);
排序
Example example = new Example(Country.class);
example.orderBy("id").desc().orderBy("countryname").orderBy("countrycode").asc();
List countries = mapper.selectByExample(example);
去重
CountryExample example = new CountryExample();
//设置 distinct
example.setDistinct(true);
example.createCriteria().andCountrynameLike("A%");
example.or().andIdGreaterThan(100);
List countries = mapper.selectByExample(example);
设置查询列
Example example = new Example(Country.class);
example.selectProperties("id", "countryname");
List 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 countries = mapper.selectByExample(example);
Weekend
使用 Example 时,需要自己输入属性名,例如 "countryname",假设输入错误,或者数据库有变化,这里很可能就会出错,因此基于 Java 8 的方法引用是一种更安全的用法,如果你使用 Java 8,你可以试试 Weekend。
Weekend weekend = new Weekend<>(User.class);
//关键字查询部分
String keyword = pageReq.getKeyword();
WeekendCriteria 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 users = userMapper.selectByExample(weekend);
执行的sql为:
WHERE (
user_name = ?
OR police_no = ?
OR real_name = ?
)
AND (department_id = ?)