mybatis-plus的基本使用

mybatis-plus的基本使用

官网地址

https://baomidou.com/guide/quick-start.html

特性了解

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

mybatis入门案例

依赖添加

<!--mybatis-plus依赖-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.3.1</version>
</dependency>

创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String stuId;
    private String stuName;
    private Integer stuSex;
    private String stuAddress;
    private Integer stuAge;
}

定义Mapper接口

//继承BaseMapper即可获取基础的crud方法,<Student>为传入的对象,查询的结果直接封装为对象
public interface StudentMapper extends BaseMapper<Student> {

}

配置扫描Mapper包

//方式1-->创建MybatisPlusConfig的配置类使用@MapperScan注解扫描包路径
@Configuration
@MapperScan("com.lwp.study.dao")
public class MybatisPlusConfig {
    
}

//方式2-->启动类添加@MapperScan注解扫描包路径
@SpringBootApplication(exclude = {
		//禁用Spring Security
		org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class
})
@MapperScan("com.lwp.study.dao")
public class StudyApplication {
	public static void main(String[] args) {
		SpringApplication.run(StudyApplication.class, args);
	}
}

测试使用

@SpringBootTest
class StudyApplicationTests {

	@Autowired
	private StudentMapper studentMapper;

	@Test
	void contextLoads() throws SQLException {
		//Params:queryWrapper – 实体对象封装操作类(可以为 null
		List<Student> students = studentMapper.selectList(null);
		students.forEach(System.out::println);
	}
}

解决驼峰标识解析失败问题

#问题描述:当我们数据库是stuid字段时,实体类定义为stuId驼峰式时,mybatis-plus会从实体解析为stu_id
#		然后去数据库匹配叫stu_id的字段,随后报错,解决方案为关闭驼峰式编码
mybatis-plus:
  configuration:
  # 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名)
  #到经典 Java 属性名 aColumn(驼峰命名) 的类似映射
    map-underscore-to-camel-case: false

日志打印

mybatis-plus:
  configuration:
  	#mybatis自带的控制台日志,可使用log4j,需要添加对应依赖
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

实体类注解

主键生成策略

//配置主键生成紫略
@TableId(type= IdType.ASSIGN_ID)
private String stuId;
/**
 * IdType取值说明:
 	AUTO(0),	//自增
    NONE(1),	//不启用
    INPUT(2),	//自定义输入
    ASSIGN_ID(3),	//雪花算法
    ASSIGN_UUID(4);  //UUID算法
*/

自动填充

实体类定义注解

//value="create_time" 因为关闭了驼峰,所以需要指定数据库字段
//fill= FieldFill.INSERT 插入时触发处理
@TableField(value="create_time",fill= FieldFill.INSERT)
private Date createTime;

//fill= FieldFill.INSERT_UPDATE 插入及更新时处理
@TableField(value="update_time",fill= FieldFill.INSERT_UPDATE)
private Date updateTime;

编写handle处理器

@Component
public class MybatisHandle implements MetaObjectHandler {

    /**
     * 插入元对象字段填充(用于插入时对公共字段的填充)
     * @param metaObject – 元对象
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

    /**
     * 更新元对象字段填充(用于更新时对公共字段的填充)
     * @param metaObject – 元对象
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

测试新增和修改

@Test
public void testInsert(){
    Student stu=new Student();
    stu.setStuName("溪风");
    stu.setStuAge(18);
    //返回受影响的行数
    int resultValue = studentMapper.insert(stu);
    //输出填充Id后的对象
    System.out.println(stu);
}

@Test
public void testUpdate(){
    Student stu=new Student();
    stu.setStuId("1414133065828499457");
    stu.setStuAge(20);
    //返回受影响的行数
    int resultValue = studentMapper.updateById(stu);
    //输出填充Id后的对象
    System.out.println(stu);
}

自动填充时间慢8个小时问题

#修改连接串的serverTimezone指定为Asia/Shanghai解决
url: jdbc:mysql://localhost:3306/lwpstudy?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8

乐观锁

简单理解

乐观锁:在做什么事情的时候都十分乐观,总认为不会出问题,无论做什么都不会去上锁,如果出了问题,再次更新值测试
悲观锁:在做什么事情的时候都十分悲观,总认为会出问题,无论干什么都会先上锁,再去操作

添加字段version

@Version  //乐观锁注解
private Integer version;

配置插件

@Configuration
@MapperScan("com.lwp.study.dao")
@EnableTransactionManagement  //开启事务
public class MybatisPlusConfig {
    /**
     * 乐观锁处理
     * @return
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}

更新测试

单线程成功测试

@Test
public void testUpdate(){
    Student student = studentMapper.selectById("1414125536583036929");
    student.setStuName("魔尊");
    studentMapper.updateById(student);
    //更新的时候会加上乐观锁字段作为where条件判定,然后没问题再进行修改,自动更新version+1
    //UPDATE student SET stuName=?, stuAge=?, version=?, update_time=? WHERE stuId=? AND version=?
}

多线程失败测试

@Test
public void testUpdate(){
    //假设A线程拿到数据时还未更新
    Student student = studentMapper.selectById("1414125536583036929");
    student.setStuName("魔尊");

    //B线程拿到数据并且已更新
    Student student1 = studentMapper.selectById("1414125536583036929");
    student1.setStuName("魔尊1");
    studentMapper.updateById(student1);

    //A线程更新失败,这个时候需要用到自旋锁
    studentMapper.updateById(student);
}
posted @ 2021-07-11 16:45  幸运刘  阅读(171)  评论(0)    收藏  举报