1.不用写mapper.xml映射文件,让接口继承自basemapper即可。
数据库中表的字段必须和user类中的字段一摸一样,数据库中的表必须叫user
只能进行简单的crud操作。
package com.atguigu.rj1192.springboot630.mapper;
import com.atguigu.rj1192.springboot630.pojo.User;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
//只需要继承自basemapper接口,就可以实现该方法
//数据库中有一个user表,对应我们的user类
//@Mapper
public interface UserMapper extends BaseMapper <User>{
}
2.当实体类和表名不一致时,可以在实体类指定表名
package com.atguigu.rj1192.springboot630.pojo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@ToString
@TableName("users")//当实体类和表名不一致的时候,用@tablename来指定表名
public class User {
@TableField(exist = false)
public String tons;//类中有,但是表中没有的属性
public int id;
public String username;
public String password;
}
2.service层
userservice接口要继承自IService<User>
package com.atguigu.rj1192.springboot630.service.impl;
import com.atguigu.rj1192.springboot630.pojo.User;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.stereotype.Service;
import java.util.Collection;
@Service
public interface UserService extends IService<User> {
}
Userserviceimpl实现类要继承自ServiceImpl<UserMapper,User>
第一个参数代表要使用哪个mappper映射文件
第二个参数代表要操作的数据类型
package com.atguigu.rj1192.springboot630.service;
import com.atguigu.rj1192.springboot630.mapper.UserMapper;
import com.atguigu.rj1192.springboot630.pojo.User;
import com.atguigu.rj1192.springboot630.service.impl.UserService;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
//第一个参数代表要使用哪个mappper映射文件
//第二个参数代表要操作的数据类型
public class UserServiceimpl extends ServiceImpl<UserMapper,User> implements UserService{
}
controller层调用的时候
@RequestMapping("/")
public ModelAndView index() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
// 将要查询出来的user类型的数据,转换成wrapper类型。
QueryWrapper<User> wrapper = new QueryWrapper<>();
Collection<User> users=userService.list(wrapper);
mav.addObject("users", users);
return mav;
}
3.mybatisplus主键自增
IdType.INPUT IdType.None 不自增 ,需要用户设置id,一般用input
IdType.ASSIGN_UUID varchar类型 IdType.ASSIGN_ID bigint类型 雪花算法生成随机id
插入新数据时不用管id,会自增的。
其他的主键自增方法还有:
1》mysql自增,缺点是如果做了分库分表,需要查询最大的id后,+1才能插入新数据,比较耗时间
2》uuid 缺点是无法排序,每次都生成唯一且随机的
3》redis集群 原子操作
@Data
public class User {
// IdType.INPUT IdType.None 不自增 ,需要用户设置id,一般用input
// IdType.ASSIGN_UUID varchar类型 IdType.ASSIGN_ID bigint类型 雪花算法生成随机id
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
// 添加和修改时都有值
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
4.mybatisplus修改时间和添加时间自动填充
(1)数据库表中添加自动填充字段
在User表中添加datetime类型的新的字段 create_time、update_time
(2)实体上添加注解
FieldFill.INSERT 在插入新数据时执行对应的方法(第三步定义)
FieldFill.INSERT_UPDATE 在插入和更新数据时执行对应的方法(第三步定义)
@Data
public class User {
// IdType.INPUT IdType.None 不自增 ,需要用户设置id,一般用input
// IdType.ASSIGN_UUID varchar类型 IdType.ASSIGN_ID bigint类型 雪花算法生成随机id
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
// 添加和修改时都有值
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
(3)编写实际的填充类和填充方法
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);
//使用mp执行添加操作,会执行
@Override
public void insertFill(MetaObject metaObject) {//MetaObject 原数据对象 数据库名 表名等信息
LOGGER.info("开始添加填充 ....");
//注意:这里的字段名是类中的名称,不是数据库中的字段!!!!
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
// 使用mp执行更新操作,会执行
@Override
public void updateFill(MetaObject metaObject) {
LOGGER.info("开始更新填充 ....");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
(4)在修改和插入时就会自动填充修改时间和插入时间。
@Test
void updateuser() {
User user = new User();
// 不需要去设置id值,mp会帮我们自动生成id值
user.setAge(555);
user.setId(102l);
// 返回结果是影响的行数
System.out.println("修改影响的行数:" + userMapper.updateById(user));
}
5.mybatisplus设置乐观锁
mike工资是五千 管理员a 要将工资修改为8000 管理员b要将工资减少两千
a和b同时修改,同时拿到修改前的5000
a修改工资为8000,提交事务。
a提交事务后,b修改工资5000-2000=3000,b将工资修改为3000
mike的工资变成了3000,而不是6000,就造成了丢失更新问题
乐观锁和悲观锁可以解决丢失更新问题
乐观锁:设置一个版本号,管理员在修改数据前,需要先获得版本号
管理员a和b同时获得1版本,a修改完了提交,数据变成2版本,b修改完了提交,发现数据已经变成2版本了,则b管理员提交失败。
悲观锁:不允许两个管理员同时修改一条数据,必须等一个修改完一个才能修改
1》数据库中添加version字段 bigint类型
2》实体类中添加version字段,并添加@Version注解
并通过@TableField(fill = FieldFill.INSERT)设置添加新记录时给verison默认值1
@Data
public class User {
// IdType.INPUT IdType.None 不自增 ,需要用户设置id,一般用input
// IdType.ASSIGN_UUID varchar类型 IdType.ASSIGN_ID bigint类型 雪花算法生成随机id
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String name;
private Integer age;
private String email;
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
// 添加和修改时都有值
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
}
设置添加新记录时给verison默认值1
this.setFieldValByName("version", 1, metaObject);
(上面添加新纪录时间自动填充的步骤一样)
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MyMetaObjectHandler.class);
//使用mp执行添加操作,会执行
@Override
public void insertFill(MetaObject metaObject) {//MetaObject 原数据对象 数据库名 表名等信息
LOGGER.info("开始添加填充 ....");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("version", 1, metaObject);
}
// 使用mp执行更新操作,会执行
@Override
public void updateFill(MetaObject metaObject) {
LOGGER.info("开始更新填充 ....");
this.setFieldValByName("updateTime", new Date(), metaObject);
}
3》配置乐观锁插件
在mybatisplus设置类中 设置乐观锁插件
(在这个类中配置@mapperscan注解,这个注解尽量不写在启动类上,而是写在mp配置类中。)
@MapperScan("com.example.mp1229.mapper")
@Configuration
public class MPconfig {
// 乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
4》需要先查询出来,再修改 在修改之后,会发现该数据的verision增加了1
//测试乐观锁
@Test
void testOptimisticLocker() {
User user = userMapper.selectById(102l);
// 不需要去设置id值,mp会帮我们自动生成id值
user.setAge(10);
// 返回结果是影响的行数
System.out.println("修改影响的行数:" + userMapper.updateById(user));
}
模拟取出数据后,数据库中version实际数据比取出的值大,即已被其它线程修改并更新了version
//测试乐观锁
@Test
void testOptimisticLocker() {
User user = userMapper.selectById(102l);
// 不需要去设置id值,mp会帮我们自动生成id值
user.setAge(10);
// 模拟取出数据后,数据库中version实际数据比取出的值大,即已被其它线程修改并更新了version
user.setVersion(user.getVersion()-1);
// 返回结果是影响的行数
System.out.println("修改影响的行数:" + userMapper.updateById(user));
}
6.逻辑删除(mp3.3.0版本后)
逻辑删除:假删除,将对应数据中代表是否被删除字段状态修改为“被删除状态”,之后在数据库中仍旧能看到此条数据记录
1)数据库中添加 deleted字段
2)mybatisplus实体类中添加deleted字段,并设置默认值 0 (未删除) 和上面一样。
user类
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
MyMetaObjectHandler类
//使用mp执行添加操作,会执行
@Override
public void insertFill(MetaObject metaObject) {//MetaObject 原数据对象 数据库名 表名等信息
LOGGER.info("开始添加填充 ....");
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
this.setFieldValByName("version", 1, metaObject);
// 添加新数据时,逻辑已删除值设置为0,未删除
this.setFieldValByName("deleted",0,metaObject);
}
3)application.yaml配置逻辑删除字段,删除和未删除对应的 逻辑值
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名( 3.3.0 版本后,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
4)使用deletebyid 删除即可
@Test
void logcaldel(){
int result=userMapper.deleteById(1608419885151080450l);
System.out.println("逻辑删除结果"+result);
}
5)查询所有 会自动携带查询deleted为0的数据 @Test void findall() { System.out.println(userMapper.selectList(null)); }
7.逻辑删除(mp3.0.5版本)
1.引入逻辑删除插件
//项目的总配置类
@MapperScan("com.atguigu.eduservice.mapper")
@Configuration
public class EduConfig {
// 逻辑删除插件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
2.逻辑删除属性上加@login注解
@TableLogic
private Boolean isDeleted;
8.分页插件
1》在配置类中加入分页插件
//项目的总配置类
@MapperScan("com.atguigu.eduservice.mapper")
@Configuration
public class EduConfig {
// mybatis分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2.使用时实现page对象
Page<EduTeacher> pageTeacher = new Page<>(current, limit);
eduTeacherService.page(pageTeacher, null);//底层会把分页的所有数据封装到pageTeacher对象中
List<EduTeacher> records = pageTeacher.getRecords();
long size = pageTeacher.getSize();
9.代码生成器
3.0.5mp
1.添加依赖
<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
2.在test类中新建类,点击运行即可
package com.hxut.zh.gaoxiaofix;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.jupiter.api.Test;
/**
* @author
* @since 2018/12/13
*/
public class CodeGenerator {
@Test
public void run() {
// 1、创建代码生成器
AutoGenerator mpg = new AutoGenerator();
// 2、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
// 生成的地址,最好写绝对路径
gc.setOutputDir("E:\\java\\GaoXiaoFix" + "/src/main/java");
gc.setAuthor("zh");
gc.setOpen(false); //生成后是否打开资源管理器,生成代码后是否打开文件夹
gc.setFileOverride(false); //重新生成时文件是否覆盖
//UserServie
gc.setServiceName("%sService"); //去掉Service接口的首字母I
gc.setIdType(IdType.ID_WORKER_STR); //主键策略 疑问:是主键自动补全的类型吗?
gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
gc.setSwagger2(true);//开启Swagger2模式
mpg.setGlobalConfig(gc);
// 3、数据源配置
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/gaoxiaofix?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("mysql");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
// 4、包配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("gaoxiaofix"); //模块名
//包 com.atguigu.eduservice
pc.setParent("com.hxut.zh");
//包 com.atguigu.eduservice.controller
pc.setController("controller");
pc.setEntity("entity");
pc.setService("service");
pc.setMapper("mapper");
mpg.setPackageInfo(pc);
// 5、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("device_info","fix_history","fix_info");//表名称,根据哪个表生成代码
strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
strategy.setRestControllerStyle(true); //restful api风格控制器
strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
mpg.setStrategy(strategy);
// 6、执行
mpg.execute();
}
}