学习视频

强烈推荐https://www.bilibili.com/video/BV17E411N7KN/?spm_id_from=333.788.videocard.0

入门:https://www.imooc.com/learn/1130

进阶:https://www.imooc.com/learn/1171

动态数据源参考文档:《dynamic-datasource-动态数据源.md》

简介

MyBatis 增强工具

注意:项目中引入 mybatis 或者 mybatis-plus,不能同时引入

参考

官方:MyBatis-Plus (baomidou.com)

示例:https://github.com/baomidou/mybatis-plus-samples

!!!更新日志CHANGELOG.md · baomidou/mybatis-plus - 码云 - 开源中国 (gitee.com)

springboot application.yml 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#mybatis plus 设置
mybatis-plus:
mapper-locations: classpath*:org/jeecg/modules/**/xml/*Mapper.xml
global-config:
# 关闭MP3.0自带的banner
banner: false
db-config:
#主键类型 0:"数据库ID自增",1:"该类型为未设置主键类型", 2:"用户输入ID",3:"全局唯一ID (数字类型唯一ID)", 4:"全局唯一ID UUID",5:"字符串全局唯一ID (idWorker 的字符串表示)";
id-type: ASSIGN_ID
# 默认数据库表下划线命名
table-underline: true
configuration:
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 返回类型为Map,显示null对应的字段
call-setters-on-nulls: true

sql debug 日志输出

1
2
3
logging:
level:
com.baomidou.mybatisplus: DEBUG # mybatis plus 日志输出

注解

TableField

模糊匹配

https://github.com/baomidou/mybatis-plus/blob/3.0/mybatis-plus-annotation/src/main/java/com/baomidou/mybatisplus/annotation/SqlCondition.java

1
2
3
4
// 字段模糊查询
@TableField(condition = SqlCondition.LIKE)
@TableField(condition = SqlCondition.LIKE_LEFT)
@TableField(condition = SqlCondition.LIKE_RIGHT)
1
QueryWrapper<UnitInfo> queryWrapper = new QueryWrapper<>(unitInfo); // unitInfo 为参数对象

CRUD 接口

Service CRUD 接口

save

1
2
3
4
5
6
7
// 插入一条记录(选择字段,策略插入)
// ID字段为空时,会根据ID策略赋值;不为空时,为自定义赋的值
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量),batchSize 批量大小
boolean saveBatch(Collection<T> entityList, int batchSize);

saveOrUpdate

1
2
3
4
5
6
7
8
9
//TableId 数据存在则更新记录,否插入一条记录。注意:必须有主键 ID,否则报错
boolean saveOrUpdate(T entity);
//示例
userService.saveOrUpdate(new User().setName("limei").setAge(16).setId(1429425704274059265L));

// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

remove

1
2
3
4
5
6
7
8
// 根据 entity 条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
boolean update(Wrapper<T> updateWrapper);
// 根据 whereWrapper 条件,更新记录
boolean update(T updateEntity, Wrapper<T> whereWrapper);
// 根据 ID 选择修改
boolean updateById(T entity);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList);
// 根据ID 批量更新
boolean updateBatchById(Collection<T> entityList, int batchSize);

this.lambdaUpdate().set(Event::getStatus, nodeStatus).set(Event::getActStatus, status).eq(Event::getId, event.getId()).update();

this.update(new LambdaUpdateWrapper<Event>().set(Event::getProcInstId, procInstId).eq(Event::getId, event.getId()));

Get

1
2
3
4
5
6
7
8
9
10
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);

Page

1
2
3
4
5
6
7
8
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

Count

1
2
3
4
// 查询总记录数
int count();
// 根据 Wrapper 条件,查询总记录数
int count(Wrapper<T> queryWrapper);

示例

更新数据-lambdaUpdate

根据多个条件更新实体

1
this.waterFacilityService.lambdaUpdate().eq(WaterFacility::getFacilityid, waterFacility.getFacilityid()).eq(WaterFacility::getFacilityname, facilityname_old).update(waterFacility);

根据 ID 更新指定字段

1
2
3
this.formeventService.lambdaUpdate().set(Formevent::getDocmenturl, pdfpath).eq(Formevent::getId, formevent.getId()).update();

this.formeventService.lambdaUpdate().set(SysUser::getOrgCode, null).eq(SysUser::getId, userId).update();

删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//根据 ID 删除
this.formfieldNodeService.removeById(id);

//根据 ID 集合批量删除
List<String> ids = new ArrayList<String>(){{
add("1");
add("2");
}};
this.formfieldNodeService.removeByIds(ids);

//根据非 ID 字段删除
this.formfieldNodeService.remove(new LambdaQueryWrapper<FormfieldNode>().eq(FormfieldNode::getFieldid, fieldid));

//根据字段 Map 信息删除
Map<String, Object> map = new HashMap<>();
map.put("FIELDID", fieldid);
this.formfieldNodeService.removeByMap(map);

查询

根据 ID 查询
1
2
3
getById(id)

actBusinessService.list(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getProcDefId,id));
根据多个条件查询一个
1
2
3
4
WaterFacility byId = waterFacilityService.lambdaQuery().eq(WaterFacility::getFacilityid, facilityid)
.eq(WaterFacility::getFacilityname, facilityname).one();

actBusinessService.getOne(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getTableId,tableId).last("limit 1"));
获取一个
1
actBusinessService.getOne(new LambdaQueryWrapper<ActBusiness>().eq(ActBusiness::getTableId,tableId).last("limit 1"));
模糊查询匹配多个字段
1
2
3
4
userWrapper.and(
wrapper ->
wrapper.like("name", keywords).or().like("address", keywords)
);

Mapper CRUD 接口

说明:

  • 通用 CRUD 封装 BaseMapper接口,为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器
  • 泛型 T 为任意实体对象
  • 参数 Serializable 为任意类型主键 Mybatis-Plus 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键
  • 对象 Wrapper 为 条件构造器
增加
1
2
3
4
5
6
7
8
9
10
11
int insert(T entity);

//插入一条记录
User user = new User();
user.setName("小羊");
user.setAge(3);
user.setEmail("abc@mp.com");
userMapper.insert(user);

// 成功后从对象中获取 ID
user.getId();
删除
1
2
3
4
5
6
7
8
// 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); //wrapper 实体对象封装操作类(可以为 null)
// 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 ID 删除
int deleteById(Serializable id);
// 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
修改

一、根据id更新

1
2
3
4
5
6
7
User user = new User();
user.setUserId(1);
user.setAge(29);

user.updateById();
or
Integer rows = userMapper.updateById(user);

二、条件构造器作为参数进行更新

1
2
3
4
5
6
7
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name","shimin");

User user = new User();
user.setAge(18);

Integer rows = userMapper.update(user, updateWrapper);

三、条件构造器Set方法

假设只更新一个字段在使用updateWrapper 的构造器中也需要构造一个实体对象,这样比较麻烦。可以使用updateWrapper的set方法

1
2
3
4
5
6
7
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("name","shimin").set("age", 35);

Integer rows = userMapper.update(null, updateWrapper);

// 示例
sysUserRoleSpecialMapper.update(null, new LambdaUpdateWrapper<SysUserRoleSpecial>().set(SysUserRoleSpecial::getUserId, userIdPortal).eq(SysUserRoleSpecial::getUserId, userId));

lambda构造器

LambdaUpdateWrapper

1
2
3
4
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getRealName, "shimin").set(User::getAge, 34);

Integer rows = userMapper.update(null, lambdaUpdateWrapper);

LambdaUpdateChainWrapper

1
2
3
4
5
6
7
8
9
10
11
LambdaUpdateChainWrapper<User> lambdaUpdateChainWrapper = new LambdaUpdateChainWrapper<>(userMapper);

boolean update = lambdaUpdateChainWrapper.eq(User::getRealName, "shimin").set(User::getAge, 33).update();


//分步写
lambdaUpdateChainWrapper.eq(User::getRealName, "shimin");
if (user.getAge == 33) {
lambdaUpdateChainWrapper.set(User::getAge, 33);
}
lambdaUpdateChainWrapper.update();
查询
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录。注意:要保证结果集最多只有一个,否则报错
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);
// 根据 entity 条件,查询全部记录
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 查询(根据 columnMap 条件)
List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
// 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 entity 条件,查询全部记录(并翻页)
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

//分页示例
Page<User> page = new Page<>(1, 5); //第 1 页,每页 5 条
page.addOrder(OrderItem.asc("age"));
Page<User> userIPage = mapper.selectPage(page, Wrappers.<User>lambdaQuery().eq(User::getAge, 20).like(User::getName, "Jack"));
log.error("记录 -------------> {}", userIPage.getRecords());
log.error("总条数 -------------> {}", userIPage.getTotal());

// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

条件构造器

https://mp.baomidou.com/guide/wrapper.html#abstractwrapper

  • 以下出现的第一个入参 boolean condition 表示该条件是否加入最后生成的 sql 中,例如:query.like (StringUtils.isNotBlank (name), Entity::getName, name) .eq (age!=null && age >= 0, Entity::getAge, age)
  • 以下代码块内的多个方法均为从上往下补全个别 boolean 类型的入参,默认为 true
  • 以下出现的泛型 Param 均为 Wrapper 的子类实例 (均具有 AbstractWrapper 的所有方法)
  • 以下方法在入参中出现的 R 为泛型,在普通 wrapper 中是 String, 在 LambdaWrapper 中是函数 (例:Entity::getId,Entity 为实体类,getId 为字段 idgetMethod)
  • 以下方法入参中的 R column 均表示数据库字段,当 R 具体类型为 String 时则为数据库字段名 (字段名是数据库关键字的自己用转义符包裹!)! 而不是实体类数据字段名!!!,另当 R 具体类型为 SFunction 时项目 runtime 不支持 eclipse 自家的编译器!!!
  • 以下举例均为使用普通 wrapper, 入参为 MapList 的均以 json 形式表现!
  • 使用中如果入参的 Map 或者 List , 则不会加入最后生成的 sql 中!!!

AbstractWrapper

说明:

QueryWrapper (LambdaQueryWrapper) 和 UpdateWrapper (LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件,entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为

QueryWrapper

说明:

继承自 AbstractWrapper , 自身的内部属性 entity 也用于生成 where 条件
及 LambdaQueryWrapper, 可以通过 new QueryWrapper ().lambda () 方法获取

last - 无视优化规则直接拼接到 sql 的最后

1
.last("limit 0");

select - 设置查询返回字段

1
2
3
4
5
6
select(String... sqlSelect)
select(Predicate<TableFieldInfo> predicate)
select(Class<T> entityClass, Predicate<TableFieldInfo> predicate)

例: select("id", "name", "age") 或 Wrappers.<User>lambdaQuery().select(User::getId)
例: select(i -> i.getProperty().startsWith("test"))

循环构建条件

1
2
3
4
5
queryWrapper.and(wrapper -> {
for(String manageOrgCode: manageOrgCodes){
wrapper.or().likeRight(sys_org_code_name, manageOrgCode);
}
});

UpdateWrapper

说明:

继承自 AbstractWrapper , 自身的内部属性 entity 也用于生成 where 条件
LambdaUpdateWrapper, 可以通过 new UpdateWrapper().lambda() 方法获取!

set

1
2
set(String column, Object val)
set(boolean condition, String column, Object val)
  • SQL SET 字段
  • 例: set("name", "老李头")
  • 例: set("name", "")—> 数据库字段值变为空字符串
  • 例: set("name", null)—> 数据库字段值变为 null

setSql

1
setSql(String sql)
  • 设置 SET 部分 SQL
  • 例: `setSql(“name = ‘老李头’”)

lambda()

  • 获取 LambdaWrapper
    QueryWrapper 中是获取 LambdaQueryWrapper
    UpdateWrapper 中是获取 `LambdaUpdateWrapper

select 返回指定字段

返回指定字段

1
2
3
4
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select("name", "age").like("name", "雨");
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);

排除指定字段

1
2
3
4
5
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.select(User.class, info -> !info.getColumn().equals("manager_id")
&& !info.getColumn().equals("create_time"));
List<User> users = userMapper.selectList(queryWrapper);
users.forEach(System.out::println);

动态指定字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper();

List<SFunction<SysDepart, Object>> columns = new ArrayList<>();
columns.add(SysDepart::getId);
columns.add(SysDepart::getDepartName);
columns.add(SysDepart::getParentId);
columns.add(SysDepart::getOrgCode);
columns.add(SysDepart::getDeptLevel);
columns.add(SysDepart::getOrgType);
if(TableExtendFieldsConfig.tableFieldExist("sys_depart:departLogoType")) {
columns.add(SysDepart::getDepartLogoType);
}

query.select(columns.toArray(new SFunction[]{}));
list = this.list(query);

UpdateWrapper 字段设置null

1
2
3
4
5
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.set(User::getGender(), null); // 设置为null
wrapper.eq(User::getId(), 1);

userService.update(wrapper);

apply

拼接 sql 条件

1
2
3
4
5
6
7
queryWrapper.lambda().apply("date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")--->date_format(dateColumn,'%Y-%m-%d') = '2008-08-08'")  

//SELECT name, belts FROM divisions WHERE FIND_IN_SET('red', belts);
//更多请阅读:https://www.yiibai.com/mysql/find_in_set.html
queryWrapper.lambda().apply("FIND_IN_SET('" + projectCode + "',project_code)");

queryWrapper.lambda().apply(sysUser.getOrgCode() + " like concat(sys_org_code, '%')");

last

  • 无视优化规则直接拼接到 sql 的最后

    注意事项: 只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

  • 例: last("limit 1")

反向模糊查询

1
queryWrapper.lambda().apply(orgCode + " like concat(org_code, '%')")

exists

1
2
3
QueryWrapper<AClass> wrapper = new QueryWrapper<>();
wrapper.exists("SELECT 1 FROM B WHERE A.ID = B.AID");
List<AClass> list = this.mapper.selectList(wrapper);

notExists

1
2
3
QueryWrapper<AClass> wrapper = new QueryWrapper<>();
wrapper.notExists("SELECT 1 FROM B WHERE A.ID = B.AID");
List<AClass> list = this.mapper.selectList(wrapper);

inSql

1
queryWrapper.lambda().inSql(SysPermission::getId, "select permission_id  from sys_depart_permission where depart_id='"+departId+"'");

notInSql

1
querySaWrapper.notInSql(SysAnnouncement::getId, "select annt_id from sys_announcement_send where user_id='"+userId+"'");

排序

1
2
3
4
5
6
queryWrapper.lambda()
.orderByDesc(Event::getMajor)
.orderByDesc(Event::getEmergency)
.orderByDesc(Event::getStarttime);

// order by major desc, emergency desc, starttime desc

复杂的 and or 语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// A and B
.eq("a", "A").eq("b",B);

// A or B
.eq("a", "A").or().eq("b",B);

// A or (B and C)
.eq("a", "A").or(i -> i.eq("b", "B").eq("c", "C"));

// A or (B or C)
.eq("a", "A").or(i -> i.eq("b", "B").or().eq("c", "C"));

// A and (B and C)
.eq("a", "A").and(i -> i.eq("b", "B").eq("c", "C"));

// A and (B or C)
.eq("a", "A").and(i -> i.eq("b", "B").or().eq("c", "C"));
// 示例
queryWrapper.lambda().and(i -> i.in(Event::getProcInstId, procInsIds)
.or()
.eq(Event::getCreateBy, sysUser.getUsername()));

// xxx and (A or (B and C))
queryWrapper.lambda().and(i -> i.in(Event::getProcInstId, procInsIds)
.or(j -> j.eq(Event::getCreateBy, user.getUsername()).ne(Event::getSourcecode, ActConstant.SOURCECODE_FROM_SCM)));

// and 中循环 or
LambdaQueryWrapper<SysDepart> queryWrapper = new LambdaQueryWrapper<SysDepart>();
queryWrapper.and(wrapper -> {
for(String orgCode: orgCodes){
wrapper.or().likeRight(SysDepart::getOrgCode, orgCode);
}
});

分页数据-手动组装

1
2
3
4
Page<Crewinfo> crewinfoPage = new Page<Crewinfo>(pageNo, pageSize);
List<Crewinfo> crewinfoList = new ArrayList<>();
crewinfoPage.setTotal(userPage.getTotal());
crewinfoPage.setRecords(crewinfoList);

空分页数据

1
2
3
4
5
6
7
8
9
Result<IPage<SysUser>> result = new Result<IPage<SysUser>>();

// 没有匹配的数据,返回为空
result.setSuccess(true);
result.setResult(null);
return result;

// 或者
return Result.OK(null); // 推荐-写法简单

批量插入

方案一、批量插入

  1. 数据库连接中增加 &rewriteBatchedStatements=true

  2. service saveBatch

    1
    actZEventTaskTimeoutDealService.saveBatch(list, 1000);

方案二、批量插入数据改造-insertBatchSomeColumn

mysql数据库 mp saveBatch 并不是真正的批量插入。改造如下

  • SpiceSqlInjector.java

    注入InsertBatchSomeColumn

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @Component
    public class SpiceSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
    // 注意:此SQL注入器继承了DefaultSqlInjector(默认注入器),调用了DefaultSqlInjector的getMethodList方法,保留了mybatis-plus的自带方法
    List<AbstractMethod> methodList = super.getMethodList(mapperClass);
    // 注入InsertBatchSomeColumn
    // 在!t.isLogicDelete()表示不要逻辑删除字段,!"update_time".equals(t.getColumn())表示不要字段名为 update_time 的字段
    // methodList.add(new InsertBatchSomeColumn(t -> !t.isLogicDelete() && !"update_time".equals(t.getColumn())));
    methodList.add(new InsertBatchSomeColumn());
    return methodList;
    }
    }
  • TempUsersProcInstIdMapper.java

    新增 insertBatchSomeColumn 批量插入方法

    1
    2
    3
    4
    5
    6
    7
    8
    public interface TempUsersProcInstIdMapper extends BaseMapper<TempUsersProcInstId> {
    /**
    * 批量插入
    * @param entityList 实体列表
    * @return 影响行数
    */
    Integer insertBatchSomeColumn(Collection<TempUsersProcInstId> entityList);
    }
  • 使用

    不需要再去写mapper.xml,直接调用这个方法就可以批量保存了

    1
    tempUsersProcInstIdMapper.insertBatchSomeColumn(tempUsersProcInstIdList);

循环 insert 数据,提示重复数据

解决:循环内先给 id 赋值为 null

1
2
3
4
5
6
7
List<String> names = new ArrayList<String>() {{ add("123");add("456"); }};
Event event = new Event();
for (String name : names) {
event.setId(null); // 必须,否则从第二次插入就开始报错
event.setIntro(name);
eventMapper.insert(event);
}

逻辑删除字段

1
2
@TableLogic(value = "0", delval = "1")
private Integer deleted;

Service updateById 方法默认更新策略为 NOT_NULL

mybatis-plus FieldStrategy 有三种策略:

  • IGNORED:0 忽略
  • NOT_NULL:1 非 NULL,默认策略
  • NOT_EMPTY:2 非空

而默认更新策略是NOT_NULL:非 NULL;即通过接口更新数据时数据为NULL值时将不更新进数据库

SSM

不再引入 MyBatis 以及 MyBatis-Spring

  1. pom.xml

    1
    2
    3
    4
    5
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.2.0</version>
    </dependency>
  2. spring.xml

    替换原来的配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath:mapping/*.xml"/>
    <property name="plugins">
    <array>
    <bean class="com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor"></bean>
    </array>
    </property>
    </bean>

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.bjtcrj.scm.*.persistence.dao" />
    </bean>

问题

XXXServiceImpl 添加了 @DS 切换数据源,更新数据方式采用如下

1
2
3
4
5
6
7
8
this.sysUserPortalService.update(new SysUser().setPassword(passwordEncode).setSalt(salt),
new UpdateWrapper<SysUser>().lambda().eq(SysUser::getUsername, sysUser.getUsername()));

// 或者
this.sysUserPortalService.update(new LambdaUpdateWrapper<SysUser>()
.eq(SysUser::getUsername, username)
.set(SysUser::getPassword, user.getPassword())
.set(SysUser::getSalt, user.getSalt()));

而不要采用如下:

1
2
3
this.sysUserPortalService.lambdaUpdate()
.set(SysUser::getPassword, passwordEncode).set(SysUser::getSalt, salt)
.eq(SysUser::getId, id).update();

登录时sysUserService.getOne(queryWrapper)方法报错

1
是由Mybatis-Plus:3.3.2包中的LambdaQueryWrapper导致,用QueryWrapper替换掉LambdaQueryWrapper后正常,后升级mybatis-plus至3.4.0版本,LambdaQueryWrapper问题得到解决,建议将Mybatis-Plus升级!!!

引入 mybatis-plus 后导致日期类型判断错误Cause: java.lang.IllegalArgumentException: invalid comparison: java.util.Date and java.lang.String

1
2
3
<if test="signin.signtime != null and signin.signtime != ''">
and to_date(to_char(#{signin.signtime},'yyyy-mm-dd'),'yyyy-mm-dd')=to_date(to_char(s.signtime,'yyyy-mm-dd'),'yyyy-mm-dd')
</if>

去掉 != '' 判断

1
2
3
<if test="signin.signtime != null">
and to_date(to_char(#{signin.signtime},'yyyy-mm-dd'),'yyyy-mm-dd')=to_date(to_char(s.signtime,'yyyy-mm-dd'),'yyyy-mm-dd')
</if>

非数据库字段

1
2
@TableField(exist=false)
private String other;