谷粒学院-第一天笔记

第一天内容

一、Mybatis-plus的使用

1. 创建数据库

正常创建流程,字符编码使用utf8mb4,排序规则依然使用general-cl。

# 创建数据库表
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)
);
# 插入数据
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');

2. 创建SpringBoot项目,添加依赖

<!--mybatis-plus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>
<!--mysql运行时依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<!--lombok用来简化实体类-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

3. 添加mysql的相关配置

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/数据库名?serverTimezone=GMT%2B8
spring.datasource.username=用户名
spring.datasource.password=密码

4. 创建entity文件夹,并创建User实体

package com.example.demo.entity;

import lombok.Data;

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

5. 创建mapper文件夹,并创建UserMapper接口

# 继承了BaseMapper接口,从而实现CRUD的功能,另外要注意加入注解
package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.springframework.stereotype.Repository;

@Repository
public interface UserMapper extends BaseMapper<User> {

}

6. 在测试类中注入UserMapper对象,并简单查询一下是否成功

@Autowired
private UserMapper userMapper;

@Test
void contextLoads() {
    List<User> users = userMapper.selectList(null);
    users.forEach(System.out::println);
}

7. 添加在控制台输出sql日志的配置

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

二、添加记录

1. 操作步骤

package com.example.demo;

import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class CRUDTest {
    @Autowired
    private UserMapper userMapper;

    @Test
    public void testInsert(){
        User user = new User();
        user.setName("小A");
        user.setAge(22);
        user.setEmail("ss");
        int result = userMapper.insert(user);
        System.out.println("影响的行数:" + result);
        System.out.println("用户的ID:" + user.getId());
    }
}

此时插入的id值为:1459034582838120449,显然不是加1.因此牵扯到mybatis中主键生成策略。
策略1: 按照id的范围来分表,比如1-9999存储在表1,10000-19999存储在表2,以此类推。这样做的缺点为如果每个表中的数据量少,则数据表多。
策略2: hash策略。id%n的数为存放的表。这样在扩充表时,需要重新排布数据。
雪花算法-分布式ID生成器: 能够保证不同表的主键的不重复性,以及相同表中主键的有序性。

2. MP的主键生成策略

# 默认的主键生成策略,使用了雪花算法
@TableId(type = IdType.ASSIGN_ID)
private String id;
# 自增策略
@TableId(type = IdType.AUTO)
private String id;

全局配置主键生成策略

mybatis-plus.global-config.db-config.id-type=auto

三、 更新记录

1. 操作

@Test
public void updateUser(){
    User user = new User();
    user.setName("my baby");
    user.setId(7L); // 因为是long类型的数据
    int result = userMapper.updateById(user);
    System.out.println(result);
}

阿里巴巴的代码规范要求每个表中都要有id、create_time、update_time,修改表结构。这样就需要在改变记录时更新时间。可以使用手动改变记录的时间值,然后更新到表中。也可以使用==自动填充功能
==。

2. 自动填充功能·

a. 在字段上面添加自动填充注解
@TableField(fill = FieldFill.INSERT)
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
b. 实现元对象处理器接口(一定要加@Component注解)
package com.example.demo.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        System.out.println("insertFill====");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);

    }

    @Override
    public void updateFill(MetaObject metaObject) {
        System.out.println("updateFill=====");
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

四、乐观锁(模拟修改冲突并配置乐观锁)

1. 模拟修改冲突

一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元。
此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了。
现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1多万。

2. 创建产品表,并添加记录

CREATE TABLE product(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称',
price INT(11) DEFAULT 0 COMMENT '价格',
version INT(11) DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id));
INSERT INTO product (id, NAME, price) VALUES (1, '外星人笔记本', 100);

3. 创建实体类

package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;

@Data
public class Product {
    private Long id;
    private String name;
    private Integer price;
    private Integer version;
}

4. 创建ProductMapper

package com.example.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.Product;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductMapper extends BaseMapper<Product> {
}

5. 模拟冲突

@Autowired
private ProductMapper productMapper;

@Test
public void testConcurrentUpdate() {
    //1、 小李获取数据
    Product p1 = productMapper.selectById(1L);
    System.out.println("小李取出的价格" + p1.getPrice());

    // 2、 小王获取数据
    Product p2 = productMapper.selectById(1L);
    System.out.println("小王取出的价格" + p2.getPrice());

    // 3、小李加了50元存入数据库
    p1.setPrice(p1.getPrice() + 50);
    productMapper.updateById(p1);

    // 4、小王减了30元存入数据库
    p2.setPrice(p2.getPrice() - 30);
    int i = productMapper.updateById(p2);
    if (i==0) {
        System.out.println("小王更新失败");
        //发起重试
        p2 = productMapper.selectById(1L);
        p2.setPrice(p2.getPrice() - 30);
        productMapper.updateById(p2);
    }

    //5、其他人看到的结果.最后的结果
    Product p3 = productMapper.selectById(1L);
    System.out.println("" + "最后的结果" + p3.getPrice());
}

输出结果为70.

6. 乐观锁

首先在version字段上加@Version注解

@Version
private Integer version;

第二步 创建乐观锁配置文件

package com.example.demo.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

//做事务处理
@EnableTransactionManagement
//配置类
@Configuration
public class MybatisPlusConfig {
    @Bean
    //乐观锁插件
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

之后再执行测试文件,则更新为120.

五、 查询记录

1. 基本的查询功能

@Test
public void selectBatch(){
    //根据id的数组进行查询
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);
}

@Test
public void selectByMap(){
    // 将查询条件组合为一个map进行查询
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","Jone");
    map.put("age",18);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);
}

2. 分页查询

首先配置分页插件,在MybatisPlusConfig中添加下列代码

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

测试

@Test
public void testSelectPage(){
    Page<User> page = new Page<>(1, 5);
    Page<User> pageParam = userMapper.selectPage(page, null);
    List<User> records = pageParam.getRecords();
    records.forEach(System.out::println);
    System.out.println(pageParam.getPages());//总页数
    System.out.println(pageParam.getTotal());//总记录数
    System.out.println(pageParam.getCurrent());//当前页码号
    System.out.println(pageParam.getSize());//每页记录数
    System.out.println(pageParam.hasNext());//是否有下一页
    System.out.println(pageParam.hasPrevious());//是否有上一页
}

3. 返回指定的列,使用Page<Map<String,Object>>

@Test
public void testSelectMapPage(){
    QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
    queryWrapper.select("id","name");
    Page<Map<String,Object>> page = new Page<>(1, 5);
    Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, queryWrapper);
    List<Map<String, Object>> records = pageParam.getRecords();
    records.forEach(System.out::println);
}

结果为:
在这里插入图片描述

六、 删除记录

1. 简单删除

// 根据id删除
@Test
public void testDeleteById() {
    int i = userMapper.deleteById(5L);
    System.out.println("删除了"+i+"行");
}

// 根据id的集合删除
@Test
public void testDeleteBatchIds() {
    int i = userMapper.deleteBatchIds(Arrays.asList(10,7,8));
    System.out.println("删除了"+i+"行");
}

// 根据map删除
@Test
public void testDeleteByMap(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","helen");
    map.put("age","18");
    int i = userMapper.deleteByMap(map);
    System.out.println("删除了"+i+"行");
}
2. 逻辑删除

即表面上删除了,但记录还保存在数据库中。
首先在数据库中加一个deleted字段

ALTER TABLE `user` ADD COLUMN `deleted` boolean DEFAULT false

第二步 修改实体类

@TableLogic
private Integer deleted;

第三步 application.properties 加入以下配置,此为默认值,如果你的默认值和mp默认的一样,该配置可无

# 配置逻辑删除插件
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0

第四步 测试
删除一条记录之后数据库还存在,deleted字段变为了1。
再进行查询的时候就已经查不到了。

七、数据库的分库分表问题

1. 将一个数据库根据业务逻辑划分为多个数据库可以减轻访问压力,但是也带来了其他的问题。

  1. join操作的问题。
  2. 事务问题。
  3. 成本问题。

2. 主从分离

在这里插入图片描述

3. 数据库分表

垂直拆分、水平拆分

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值