MyBatis-Plus
MP 快速入门
- 建立基于 SpringBoot 的 Maven 工程,并引入相关依赖,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
- 为 SpringBoot 工程添加 application.yml 配置文件
server:
port: 8080
servlet:
context-path: /ls
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: 'jdbc:mysql://localhost:3306/mybatis?useSSL=false&serverTimezone=Asia/Shanghai'
- 编写 SpringBoot 的启动器,同时使用注解扫描 Mapper 接口
@SpringBootApplication
@MapperScan(basePackages = {"com.ls.lsmp0720.mapper"})
public class Lsmp0720Application {
public static void main(String[] args) {
SpringApplication.run(Lsmp0720Application.class, args);
}
}
- 编写 POJO 实体 Bean
@Data
@ToString
@NoArgsConstructor
@TableName(value = "user") // 对应的表名
public class User {
@TableId(type = IdType.AUTO) // 指定主键,主键的值的生成策略
private Integer userId;
private String userName;
private String roleCode;
private String userPass;
@TableField(condition = SqlCondition.LIKE) // 用于条件判断时 判断形式
private String cname;
private String isLogin;
@TableField(value = "telphone")
private String telephone;
private String address;
private String nation;
private String email;
private String userImg;
private String gender; // 1 2
@TableField(exist = false)// 在进行表的相关操作时去掉该字段(表中不存在),否则会报错
private String sex; // 性别描述 女 男
}
排除非表字段还可使用: transiant static 但推荐@TableField(exist = false)
- 定义 Mapper 接口并继承 MP 的 BaseMapper 接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
- 编写测试类
- baseMapper的一些测试:
@Test // 改
void contextLoadsUpdate() {
User user = new User();
user.setUserId(712);
user.setAddress("济南长清");
user.setRoleCode("plain");
user.setTelephone("18012344321");
userMapper.updateById(user);
}
@Test // 查
void contextLoadsByMap() {
Map<String,Object> map = new HashMap<>();
map.put("role_code","plain");
map.put("address","济南浪曦");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
@Test // 增
void contextLoadsInsert() {
User newUser = new User();
newUser.setUserName("jacky");
newUser.setUserPass("123456");
newUser.setCname("杰克王");
userMapper.insert(newUser);
}
条件构造器
MP 框架提供了强大的条件构造器,使用条件构造器可以用来组装更加复杂的查询 SQL。条件构造器通过 Wrapper 类(抽象类) 来实现,Wrapper 中提供了大量的条件组合
- like eq lt
@Test
void contextLoadsWrapper001() {
// 条件构造器 是 复杂操作的基础. Wrapper类是抽象类
QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
// 查询cname中有小 且 性别是1 id<705
userQueryWrapper.like("cname","小")
.eq("gender",1)
.lt("user_id",705);
List<User> users = userMapper.selectList(userQueryWrapper);
for (User user : users) {
System.out.println(user);
}
}
- like: 两边模糊 likeRight: 右模糊 likeLeft: 左模糊
- between isNotNull
@Test
void contextLoadsWrapper002() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// id 在7005-712之间,email不是null的
queryWrapper.between("user_id",705,712)
.isNotNull("email");
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
-
or() orderByDesc
- 条件1.or().条件2
@Test
void contextLoadsWrapper003() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 查询 地址 是 济南长清 或者 角色为管理员并且性别是1的 最后按照id降序排序
queryWrapper.eq("address","济南长清")
.or()
.eq("role_code","manager").eq("gender",1)
.orderByDesc("user_id");
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
- 应用mysql函数(自定义代码块)
@Test
void contextLoadsWrapper004() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 应用mysql函数
// 查询 用户名长度是5个的 并且 性别是1
//queryWrapper.apply("char_length(user_name)={0} and gender = {1}",5,1);
queryWrapper.apply("char_length(user_name)={0}",5).eq("gender",1);
// 占位符从0开始计算
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
- {0} {1} 为占位符
- inSql 子查询
@Test
void contextLoadsWrapper005() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// inSql 子查询 用到in语句里
// 查询 是管理员 并且user_id在地址为济南浪曦的id集合当中
queryWrapper.eq("role_code","manager")
.inSql("user_id","select user_id from user where address = '济南浪曦'");
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
- and 将某些条件作为整体
- 查询角色是plain的 并且 (要么是乌克兰 要么邮箱是空的)
@Test
void contextLoadsWrapper006() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("role_code","plain")
.and(wr -> wr.eq("nation","乌克兰").or().isNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
void contextLoadsWrapper007() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 查询角色是plain 并且 (要么是乌克兰 要么邮箱是空的)
queryWrapper.eq("role_code","plain")
.nested(wr -> wr.eq("nation","乌克兰").or().isNull("email"));
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
- 指定查询或排除字段
- select(String… columns) 指定要查的列,适用于要查询出来的列较少的情况下
@Test
void contextLoadsWrapperA() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 指定要查询出来的列,适用于要查询出来的列较少的情况下
queryWrapper.like("cname","小")
.select("user_id","user_name","user_pass","cname");
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
- select(Class,Predicated predicate) 指定排除一些列,适用于 较少列不需要查询的情况下
@Test
void contextLoadsWrapperB() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
// 指定排除一些列,适用于 较少列不需要查询的情况下
queryWrapper.like("cname","小")
.select(User.class,info -> !"user_img".equals(info.getColumn()) && !"gender".equals(info.getColumn()));
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
@Test
void contextLoads072201() {
// 当 cname 的值非空时 才进行条件查询
String cname = "小";
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like(StringUtils.hasLength(cname),"cname",cname);
List<User> users = userMapper.selectList(queryWrapper);
for (User user : users) {
System.out.println(user);
}
}
Wrapper 构造方法
QueryWrapper 条件构造器提供了有参的构造方法,可以将一个 POJO 对象作为参数传递给构造方法,用于创 建 QueryWrapper 对象。使用这种方式创建的条件对象,会将 POJO 对象中不为 null 的属性值作为 where 条件, 组成查询 sql
- 默认使用“等值”判断
-
要在实体 Bean 上使用注解@TableField 来修饰,@TableField 的属性 condition 默认就是采用等值连 接的方式,更改 condition 的属性值就可以更改连接方式
@Test
void contextLoads072202() {
User user = new User();
user.setRoleCode("plain");
user.setNation("中国");
user.setCname("小");// 在javabean中设置为模糊
// 使用javabean创建条件构造器,默认对javabean中非空的属性 进行等值的拼接
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
queryWrapper.orderByDesc("user_id");
List<User> users = userMapper.selectList(queryWrapper);
for (User u : users) {
System.out.println(u);
}
}
map
- allEq 将map里的键值对进行等值条件拼接
@Test
void contextLoads072203() {
// allEq 将map里的键值对进行等值条件拼接
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Map<String,Object> map = new HashMap<>();
map.put("role_code","plain");
map.put("nation","中国");
queryWrapper.allEq(map);
List<User> users = userMapper.selectList(queryWrapper);
for (User u : users) {
System.out.println(u);
}
}
- userMapper.selectMaps(queryWrapper) 查询少量列 组装为map 适合查询少量的列
@Test
void contextLoads072204() {
// 查询少量列 组装为map 适合查询少量的列
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("user_name","l")
.eq("gender",1)
.select("user_name","gender");
List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);
for (Map<String, Object> map : maps) {
System.out.println(map);
}
}
- selectCount()
@Test
void contextLoads072205() {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.like("user_name","l")
.eq("gender",1);
Long count = userMapper.selectCount(queryWrapper);
System.out.println("名字里有l且性别是1的人数: " + count);
}
lambda 条件构造器
优点: 通过javabean的成员变量 替代 表的列名
- Lambda 条件构造器提供了三种创建方式:
- LambdaQueryWrapper wrapper1 = new LambdaQueryWrapper<>();
- LambdaQueryWrapper wrapper2 = new QueryWrapper().lambda();
- LambdaQueryWrapper wrapper3 = Wrappers.lambdaQuery();
@Test
void contextLoads072206() {
// lambda 条件构造器 优点: 通过javabean的成员变量 替代 表的列名
LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
// 查询昵称里有小字的 id降序排序
lambdaQueryWrapper.like(User::getCname,"小")
.orderByDesc(User::getUserId);
List<User> users = userMapper.selectList(lambdaQueryWrapper);
users.forEach(System.out::println);
}
自定义sql
-
注解版
- 必须写@Param(“ew”) ${ew.customSqlSegment}用来拼接wrapper中的语句
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select user_name,user_pass,email from user ${ew.customSqlSegment} ")
List<User> selectMy01(@Param("ew") Wrapper<User> wrapper);// 查询用户名,密码和邮箱
List<User> selectMy02(@Param("ew") Wrapper<User> wrapper);// 查询用户名,密码和电话
}
<mapper namespace="com.ls.lsmp0720.mapper.UserMapper">
<select id="selectMy02" resultType="com.ls.lsmp0720.bean.User">
select user_name,user_pass,telphone as telephone from user ${ew.customSqlSegment}
</select>
<!-- 自定义sql语句字段和列名的注解配置会失效,需要自己写别名才能封装到bean中 -->
</mapper>
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
lazy-loading-enabled: true
aggressive-lazy-loading: false # 默认开
# map-underscore-to-camel-case: true 默认
mapper-locations: 'classpath*:/mapper/**/*.xml'
classpath*:/mapper/**/*.xml 为默认值,若在此,可不配
- test
@Test
void contextLoads072207() {
User user = new User();
user.setRoleCode("plain");
user.setCname("小");
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
//List<User> users = userMapper.selectMy01(wrapper);
List<User> users = userMapper.selectMy02(wrapper);
users.forEach(System.out::println);
}
MP分页插件
- 配置类中加入插件
@Configuration
public class MyConfig {
//MybatisPlusInterceptor 核心插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
}
- 测试
@Test
void contextLoads072208() {
// IPage<T> 和 实现类 Page<T> 是分页模型 约等于 之前的PageBean<T>
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("user_id");
// 分页查询 泛型是User 是否封装总记录数
Page<User> page = new Page<>(1,4,true);
page = userMapper.selectPage(page,wrapper);
// userMapper.selectMapPage() 需要入参page的泛型为Map,适用于查询列数不多
// Page<Map<String,Object>>
System.out.println("总记录数 = "+page.getTotal());
System.out.println("每页条数 = "+page.getSize());
System.out.println("总页数 = "+page.getPages());
List<User> users = page.getRecords();// 获取查询结果
users.forEach(System.out::println);
}
-
自定义 sql 分页
在进行分页操作时,可能查询的数据并不是来源于一张表,可能会是多表的联合查询。这种情况 selectPage 方 法与 selectMapsPage 方法就不再适用。此时就可以使用自定义 sql 的分页查询,定义方法时第一个参数必须是 page 对象,第二个参数为 Wrapper 对象。
-
UserMapper接口
Page<User> selectMyPage01(Page<User> page, @Param("ew") Wrapper<User> wrapper);
- UserMapper.xml
<select id="selectMyPage01" resultType="com.ls.lsmp0720.bean.User">
select user_name,user_pass,telphone as telephone,address,email from user ${ew.customSqlSegment}
</select>
- test
@Test
void contextLoads072209() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.orderByDesc("user_id");
Page<User> page = new Page<>(1,4,true);
page = userMapper.selectMyPage01(page, wrapper);
System.out.println("总记录数 = "+page.getTotal());
System.out.println("每页条数 = "+page.getSize());
System.out.println("总页数 = "+page.getPages());
List<User> users = page.getRecords();
users.forEach(System.out::println);
}
更新
@Test
void contextLoads072210Update() {
//1.按id更新,更新javabean的非空成员变量对应的字段
/*User user = new User();
user.setUserId(713);
user.setTelephone("19900001111");
user.setAddress("天津");
userMapper.updateById(user);*/
//2.按UpdateWrapper更新
/*UpdateWrapper<User> wrapper = new UpdateWrapper<>();
User user = new User();// 更新条件
user.setEmail("jiji@qq.com");
wrapper.eq("cname","吉吉国王");// 筛选条件
userMapper.update(user,wrapper);*/
//3.按UpdateWrapper更新
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
User user = new User();
user.setIsLogin("0");// 更新条件
wrapper.eq("cname","吉吉国王") // 其他的like lt isNull等条件的方法都可以使用
.set("gender",1);// 更新条件
userMapper.update(user,wrapper);
}
删除
@Test
void contextLoads072210Delete() {
// 1. 按照id删除
//userMapper.deleteById(716);
/* User user = new User();
user.setUserId(715);
userMapper.deleteById(user);*/
// 2. 按照Wrapper删除
/*QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("user_name","2").eq("user_pass","2");
userMapper.delete(wrapper);*/
//3. 按照多个id删除
/*List<Integer> list = new ArrayList<>();
list.add(718);
list.add(719);
userMapper.deleteBatchIds(list);*/
//4. 按照map删除
Map<String,Object> map = new HashMap<>();
map.put("user_name","a");
map.put("user_pass","a");
userMapper.deleteByMap(map);
}
ActiveRecord 模式
让javabean具备基本的增删改查操作,必须有对应的Mapper接口 继承BaseMapper
- 让模型类继承 Model 抽象类
public class User extends Model<User> {
- 测试
@Test
void contextLoads072211() {
// 通用service里有单表的操作方法,方法名系列 跟 mapper里的方法名系列 有区别
User user = new User();
user.setUserName("xionger");
user.setUserPass("123");
user.setCname("熊二");
userService.save(user);
}
@Test
void contextLoads072210AR() {
// 让javabean具备基本的增删改查操作,必须有对应的Mapper接口 继承BaseMapper
User user = new User();
user.setUserId(712);
user.setIsLogin("0");
user.setAddress("上海");
user.updateById();
}
主键策略
局部主键策略 (推荐)
- type = IdType.AUTO 采用数据库中的主键自增
- type = IdType.INPUT 采用用户的输入
- type = IdType.ASSIGN_ID 如果用户未输入,则采用mp的算法生成主键值,可以是整数,也可以是字符串
- type = IdType.ASSIGN_UUID 如果用户未输入,则采用mp的算法生成主键值,是字符串
全局主键策略
mybatis-plus:
global-config:
db-config:
id-type: xxx
mp配置
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
lazy-loading-enabled: true # 这个跟下面搭配使用
aggressive-lazy-loading: false # 默认开
# map-underscore-to-camel-case: true 默认
mapper-locations: 'classpath*:/mapper/**/*.xml'
global-config:
db-config:
logic-delete-value: 1
logic-not-delete-value: 0
# type-aliases-package: com.ls.lsmp0720.bean 不推荐
通用Service
- 定义 Service 接口继承 MP 框架提供的 IService 接口。
- 定义 Service 接口的实现类,继承 ServiceImpl 类,再实现自定义 Service 接口。
public interface UserService extends IService<User> {
}
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
}
@Test
void contextLoads072211() {
// 通用service里有单表的操作方法,方法名系列 跟 mapper里的方法名系列 有区别
User user = new User();
user.setUserName("xionger");
user.setUserPass("123");
user.setCname("熊二");
userService.save(user); // 更新
}
MyBatis Plus 进阶
逻辑删除
在执行 deleteById 操作时,不再是 delete 操作,而是转变为 update 操作,并 且自动的增加了逻辑删除字段的判断。将 deleted 字段更新为指定值
-
yml配置
-
在实体 bean 中使用@TableLogic 注解修饰逻辑删 除字段
@Data
@ToString
@NoArgsConstructor
@TableName("employee")
public class Employee {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
private Long manageId;
private String createTime;
@Version
private Integer version;// 乐观锁字段
@TableLogic()
@TableField(select = false)// 不再查询该字段
private Integer deleted; // 逻辑删除字段 0: 未删除 1: 已删除
}
- test
@Test
void contextLoads072212() {
// 逻辑删除字段
// employeeDao.deleteById(1312931436365443079L);
// 当进行查询或更新时,mp自动排除 已经逻辑删除的记录
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.le("age",200);
List<Employee> employees = employeeDao.selectList(wrapper);
employees.forEach(System.out::println);
}
- 自定义sql中 关于逻辑字段的查询 既不自动将逻辑删除字段纳入条件,也不排除查询逻辑删除字段
@Mapper
public interface EmployeeDao extends BaseMapper<Employee> {
@Select("select id,name,age,email,manage_id,create_time,version from employee ${ew.customSqlSegment}") // 手动排除查询逻辑删除字段
List<Employee> selectMy01(@Param("ew")Wrapper<Employee> wrapper);
}
@Test
void contextLoads072213() {
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.le("age",200)
.eq("deleted",0);// 手动选择
List<Employee> employees = employeeDao.selectMy01(wrapper);
employees.forEach(System.out::println);
}
自动填充
填充原理是直接给 entity 的属性设置值,setFieldValByName 方法是 MetaObjectHandler 的默认方法,调用此方法就可以为实体对象的属性完成赋值操作.
@TableField(fill = FieldFill.INSERT)
private String createTime;
- 使用属性 fill 来指定填充的类型。并在 Spring 容器中,增加一个元数据类型处理器 MetaObjet
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
boolean has = metaObject.hasSetter("createTime");// 表中有这个字段
if (has){
Object createTime = metaObject.getValue("createTime");
if (createTime == null){// 还没有被赋值过
// insert 插入时,自动填充的属性 createTime
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String value = sdf.format(new Date());
setFieldValByName("createTime",value,metaObject);
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
}
}
- 测试
@Test
void contextLoads072214() {
// 自动填充
Employee e = new Employee();
e.setName("大朱静");
e.setAge(98);
employeeDao.insert(e);
}
乐观锁插件
乐观锁的意图,当要更新表的一条记录的时候,希望这条记录没有被别人更新,是为了防止更新冲突的问题。乐观锁的实现方式,其中一种最为常见的就是版本号的机制。取出一条记录时,会获得这条记录当前的版本号,如果在 更新时版本号没有发生变化,说明这条记录没有被别人更新,如果版本号已经发生变化了,则不再更新这条记录。
执行过程为:取出记录时,获取当前版本 version;更新时,带上这个版本 version;版本正确则更新成功,错 误则更新失败。
乐观锁功能实现:
- 配置 OptimisticLockerInterceptor 乐观锁插件类
@Configuration
public class MyConfig {
//MybatisPlusInterceptor 核心插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());// 乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 分页
return mybatisPlusInterceptor;
}
}
- 使用注解@Version 修饰实体
@Version
private Integer version;// 乐观锁字段
- 测试
@Test
void contextLoads072215() {
// 乐观锁字段
Employee e1 = new Employee();
e1.setId(1312931436365443081L);
e1.setEmail("da1@qq.com");
e1.setVersion(1);
employeeDao.updateById(e1);
System.out.println("-------------------");
System.out.println(e1);// 更新后的字段回填 更新后版本号在原来的基础上加一
Employee e2 = new Employee();
e2.setId(1312931436365443081L);
e2.setEmail("dadada@126.com");
e2.setVersion(1);// 修改失败
employeeDao.updateById(e2);
}
- 同一个程序中同一个wrapper不能复用,因为会将连个版本都加上
@Test
void contextLoads072216() {
// 同一个wrapper不能复用
Employee e1 = new Employee();
e1.setEmail("e4@qq.com");
e1.setVersion(4);
UpdateWrapper<Employee> wrapper = new UpdateWrapper<>();
wrapper.eq("id",1312931436365443081L);// 筛选
employeeDao.update(e1,wrapper);
System.out.println("========================");
Employee e2 = new Employee();
e2.setEmail("suibian@qq.com");
e2.setVersion(5);
employeeDao.update(e2,wrapper);
}