【2020-03-21】springboot mybatis-plus 基本使用

文章目录

      • 创建数据库
      • mybatis-plus 快速启动
      • 配置日志
      • CRUD 扩展
          • **insert**
          • **update**
          • 自动填充
        • 乐观锁、悲观锁
          • 分页查询
          • 删除操作
        • 性能分析插件
        • 条件构造器
        • 代码自动生成器

创建数据库

  1. 创建数据库和表
CREATE TABLE user
(
	id BIGINT(20) NOT NULL COMMENT '主键ID',
	name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
	age INT(11) NULL DEFAULT NULL COMMENT '年龄',
	email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY (id)
);

  1. 插入数据
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');

mybatis-plus 快速启动

  1. 导入依赖
        
            mysql
            mysql-connector-java
        
        
            com.baomidou
            mybatis-plus-boot-starter
            3.0.5
        
        
            org.projectlombok
            lombok
            true
        

说明,使用 mybatis-plus 可以省略大量的代码,尽量不要同时导入 mybatis 和 mybatis-plus

  1. 连接数据库 和 mybatis 相同
spring:
  datasource:
    username: root
    password: mima
    url: jdbc:mysql://192.168.2.136:3306/mybatis-plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver
  1. ==传统方式 pojo-dao (连接mybatis,配置mapper.xml文件)-service-controller ==
  2. 使用mybatis-plus之后
    • pojo
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
    • mapper 接口
    @Repository // 代表持久层
    public interface UserMapper extends BaseMapper<User> {
    }
    
    • 注意点 我们需要在主启动类上去扫描我们的mapper包小的所有接口 @MapperScan("com.ybs.mybatisplus.mapper")
    • 测试类中测试
    @Autowired
        private UserMapper userMapper;
    
        @Test
        void contextLoads() {
            // 参数是一个Wrapper条件构造器
            //查询心全部用户
            List<User> users = userMapper.selectList(null);
            users.forEach(System.out::println);
        }
    
    • 结果
    User(id=1, name=Jone, age=18, [email protected])
    User(id=2, name=Jack, age=20, [email protected])
    User(id=3, name=Tom, age=28, [email protected])
    User(id=4, name=Sandy, age=21, [email protected])
    User(id=5, name=Billie, age=24, [email protected])
    

问题
1、sql mybatis-plus 生成
2、方法 mybatis-plus 生成

配置日志

我们所有的sql都是不可见,我们希望知道是怎么执行的,配置日志

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

结果

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4a8a0099] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1157484092 wrapping com.mysql.cj.jdbc.ConnectionImpl@712c5463] will not be managed by Spring
==>  Preparing: SELECT id,name,age,email FROM user 
==> Parameters: 
<==    Columns: id, name, age, email
<==        Row: 1, Jone, 18, [email protected]
<==        Row: 2, Jack, 20, [email protected]
<==        Row: 3, Tom, 28, [email protected]
<==        Row: 4, Sandy, 21, [email protected]
<==        Row: 5, Billie, 24, [email protected]
<==      Total: 5

CRUD 扩展

insert
 @Test
    public void testInsert(){
        User user = new User();
        user.setName("Paulson 的测试");
        user.setAge(44);
        user.setEmail("[email protected]");

        int result = userMapper.insert(user); // 自动生成ID
        System.out.println(user);
        System.out.println(result);
    }

结果

User(id=1241297892581425154, name=Paulson 的测试, age=44, [email protected])

数据库中插入的id的默认值是全局的默认id

  • 主键生成策略
    • ID_WORKER 默认全局唯一ID
    • AUTO 主键自增
      • 需要配置主键自增(数据库配置主键自增,增加注解@TableId(type = IdType.AUTO))
    • NONE 未设置
    • INPUT 手动输入 自己配置ID
    • UUID 全局唯一id
    • ID_WORKER_STR ID_WORKER的字符串表示法

分布式系统唯一ID生成(uuid, 自增id, 雪花算法, redis)
雪花算法: snowflake ,结果是一个Long类型的ID。核心思想:毫秒数,机器id,毫秒内的流水号,0

update
 @Test
    public void testUpdate(){
        User user = new User();
        // 通过条件自动拼接动态sql
        user.setId(6L);
        user.setAge(55);
        user.setName("Paulson 的更新");
        userMapper.updateById(user);
    }

所有的sql都是自动动态配置的

自动填充

创建时间、修改时间 自动完成这些操作,不希望手动更新
阿里巴巴开发手册:所有数据库表:gmt_create, gmt_modified. 几乎所有的表都要配置,而且需要自动化实现

方式一、数据库级别(工作中不允许修改数据库)
1、在表中新增字段 create_time, update_time,修改默认值 CURRENT_TIMESAMP
2、再次测试插入方法。先同步实体类

private Date createTime;private Date updateTime;

方式二、代码级别
1、删除数据的默认值
2、实体类时间字段属性增加主键

 @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

3、编写处理器来处理这个注解


@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    /**
     * 插入时的填充策略
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill....");
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }

    /**
     * 更新时的填充策略
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill....");
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}

4、测试插入、测试更新。观察时间变化

乐观锁、悲观锁

原子引用

乐观锁:顾名思义,十分乐观,认为不会出现问题,无论干什么都不去上锁! 如果出现了问题,再次更新值测试。version, new version。
悲观锁:顾名思义,十分悲观,总是认为会出现问题,无论干什么都上上锁,再去操作!

乐观锁机制

乐观锁实现方式:
- 取出记录时,获取当前的version
- 更新时,带上version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version 不对,就更新失败

--- A
update user set name = 'ybs', version = version +1 where id =2 and version = 1 

--- B 线程抢先完成,这个时候version=2,会导致A修改失败
update user set name = 'ybs', version = version +1 where id =2 and version = 1 

测试一下MP的乐观锁插件
1、给数据库中增加version字段
2、给实体类加对应的字段

@Version // 乐观锁private Integer version;

3、注册组件

@MapperScan("com.ybs.mybatisplus.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {
    // 注册乐观锁插件

    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

4、测试乐观锁
```java
    // 测试乐观锁,成功
    @Test
    public void testOptimisticLocker(){
        // 1、查询用户信息
        User user = userMapper.selectById(1L);
        // 2、修改用户信息
        user.setName("ybs");
        user.setEmail("[email protected]");
        // 3、执行更新操作
        userMapper.updateById(user);
    }

    // 测试乐观锁,失败,多线程
    @Test
    public void testOptimisticLocker2(){
        // 线程1
        User user = userMapper.selectById(1L);
        user.setName("ybs111");
        user.setEmail("[email protected]");

        // 线程2 模拟另一个线程进行插队操作
        User user2 = userMapper.selectById(1L);
        user2.setName("ybs222");
        user2.setEmail("[email protected]");
        userMapper.updateById(user2);

        // 自旋锁多次尝试操作。多线程下一定要加锁
        // 3、执行更新操作
        userMapper.updateById(user);  // 如果没有乐观锁,就会覆盖插队线程的值
    }
##### **查询**

```java
 
// 测试查询
    @Test
    public void testSelectById(){
        User user = userMapper.selectById(1L);
        System.out.println(user);

        List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
        users.forEach(System.out::println);
    }

    // 条件查询  使用Map操作
    @Test
    public void testSelectByBatchIds(){
        HashMap map = new HashMap<>();
        // 自定义查询条件
        map.put("name", "Paulson 的测试");
        map.put("age", 43);
        List users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
分页查询

1、原始的limit 进行分页
2、使用第三方插件 pageHelper
3、mybatis 也内置了分页插件

如何使用
1、 配置拦截器组件


@Bean
    public PaginationInterceptor paginationInterceptor(){
        return new PaginationInterceptor();
    }

2、直接使用Page对象

// 测试分页插件
    @Test
    public void testPage(){
        // 参数一:当前页
        // 参数二:页面大小
        Page<User> page = new Page<>(2, 5);
        userMapper.selectPage(page, null);

        page.getRecords().forEach(System.out::println);
        System.out.println(page.getTotal());
    }
删除操作
  • 基本的删除操作
   // 测试删除
    @Test
    public void testDeleteById(){
        userMapper.deleteById(2L);
        userMapper.deleteBatchIds(Arrays.asList(2, 3));
    }

    @Test
    public void testDeleteMap(){
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "Paulson 的测试");
        userMapper.deleteByMap(map);
    }
  • 逻辑删除(更新操作)

物理删除: 从数据库中直接移除
逻辑删除:在数据库中没有被删除。通过一个变量让他失效。 deleted=0 =》 deleted=1

管理员可以查看删除的记录! 防止数据的丢失,类似于回收站

1、数据增加deleted
2、实体类中增加属性

@TableLogic
    private Integer deleted;

3、配置


@Bean public LogicSqlInjector logicSqlInjector(){ return new LogicSqlInjector(); }
# 逻辑删除
  global-config:
    db-config:
      logic-delete-value: 1
      logic-not-delete-value: 0
  • 逻辑删除走的是更新操作,并不是删除操作
  • 逻辑删除后 查询后会自动过滤

性能分析插件

平时开发中,会遇到一些慢sql druid
mp 提供性能分析插件,如果超过设置的时间就会停止运行

1、导入插件

@Bean
    @Profile({"dev","test"}) //设置 dev test 环境开启
    public PerformanceInterceptor performanceInterceptor(){
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(100); //设置SQL执行的最大时间,如果超过了则不实行
        performanceInterceptor.setFormat(true);  // 是否格式化
        return performanceInterceptor;
    }

2、修改配置 配置环境为dev或test

spring:
  profiles:
    active: dev
  • 测试
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
- 结果 (只要超过了设置的时间就会抛出异常)
 Time:20 ms - ID:com.ybs.mybatisplus.mapper.UserMapper.selectList
Execute SQL:
    SELECT
        id,
        name,
        age,
        email,
        version,
        deleted,
        create_time,
        update_time 
    FROM
        user 
    WHERE
        deleted=0
  • 使用性能分析插件,可以提高效率

条件构造器

Wrapper 十分重要
写一些复杂的sql可以使用它来替代
1、// 查询 name 不为空,邮箱不为空,年龄大于22

 @Test
    public void testWrapper1(){
        // 查询 name 不为空,邮箱不为空,年龄大于22
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age", 12);
        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }
2、查询一个数据  selectOne  出现多个结果使用 selectList
```java
 @Test
    void test2(){
        // 查询 name 为 Sandy
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "Sandy");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }

3、年龄在20-30之间

 void test3(){
        // 年龄在20-30之间
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age", 20, 30);
        Integer count = userMapper.selectCount(wrapper);// 查询结果数目
        System.out.println(count);
    }

4、 模糊查询:name 不包含 E 的, email t开头

 @Test
    void test4(){
        // 模糊查询:name 不包含 E 的, email t开头
        QueryWrapper wrapper = new QueryWrapper<>();
        // 左和右  t%
        wrapper.notLike("name", "P")
                .likeRight("email", "t");
        List> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }

5、内查询 IN

 @Test
    void test5(){
        // 内查询 IN
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // id 在子查询中查出来
        wrapper.inSql("id", "select id from user where id < 3");
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);


    }

代码自动生成器


public class YbsCode {

    public static void main(String[] args) {

        AutoGenerator mpg = new AutoGenerator();
        // 配置策略
        // 1、全局配置
        GlobalConfig gc = new GlobalConfig();
        String project_path = System.getProperty("user.dir");
        gc.setOutputDir(project_path + "/src/main/java");
        gc.setAuthor("YBS");
        gc.setOpen(false);
        gc.setFileOverride(false);
        gc.setServiceName("%sService"); // 去service的I
        gc.setIdType(IdType.ID_WORKER);
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        // 2、设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("");
        dsc.setDriverName("");
        dsc.setUsername("");
        dsc.setPassword("");
        dsc.setDbType(DbType.MYSQL);

        // 2、包的配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("blog");
        pc.setParent("com.ybs");
        pc.setEntity("entity");
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // 4、测试配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("user");
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);
        strategy.setLogicDeleteFieldName("deleted");

        // 自动填充
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);

        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);


        // 乐观锁
        strategy.setVersionFieldName("version");
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);
        mpg.setStrategy(strategy);
        mpg.execute(); // 执行

        //
    }
}

你可能感兴趣的:(Spring)