1.配置
连接配置
# MySQL5 驱动不同 com.mysql.jdbc.Driver
# MySQL8 驱动不同 com.mysql.cj.jdbc.Driver 需要增加时区的配置 severTimezone=GMT%2B8
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/数据库名字?
useUnicode=true&characterEncoding=utf8&useSSL=false&severTimezone=GMT%2B8
username: root
password: root
配置日志 可以打印执行的SQL语句
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
导入的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库连接的-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</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>
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 代码构造生成器的-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.1</version>
</dependency>
<!-- 模板-->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.swagger/swagger-annotations -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
<!--
资源插件 告诉maven把 src/main/java目录中的 指定扩展名的文件 拷贝到 target/classes目录中。
-->
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes>
<!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<!-- filtering 选项 false 不启用过滤器, *.property 已经起到过
滤的作用了 -->
<filtering>false</filtering>
</resource>
</resources>
2.CRUD
@Autowired
private UserMapper userMapper;
//新增
@Test
public void testInsert() {
User user = new User().setName("三水").setAge(22).setEmail("4556445646");
int insert = userMapper.insert(user);
System.out.println("insert = " + insert);
}
//测试通过id删除单个
@Test
public void testDeleteById(){
int i = userMapper.deleteById(2L);
System.out.println("i = " + i);
}
//通过id批量删除
@Test
public void testDeleteBatchIds(){
int i = userMapper.deleteBatchIds(Arrays.asList(4L,3L,5L));
System.out.println("i = " + i);
}
//测试通过map删除
@Test
public void testDelete(){
HashMap<String, Object> map = new HashMap<>();
map.put("name","江东");
map.put("age",22);
int i = userMapper.deleteByMap(map);
System.out.println("i = " + i);
}
//通过ID更新
@Test
public void testUpdateById(){
User user = new User();
user.setId(1495601226191011846L);
user.setName("哈哈哈阿斯蒂芬");
int i = userMapper.updateById(user);
System.out.println("i = " + i);
}
逻辑删除
物理删除:从数据库中直接移除
逻辑删除:在数据库中没有被移除
1.数据库中添加字段
is_deleted
添加默认值是 0 表示没有被删除,1是被删除
添加配置
# global-config:
# db-config:
# logic-delete-field: deleted
# logic-delete-value: 1
# logic-not-delete-value: 0
2.实体类中添加
@TableLogic //添加注解
@TableField("is_deleted") // 阿里规范不要is
private Integer deleted;
3.MP组件
3.1 分布式ID
MP默认给我们使用的就是分布式ID
使用
注意:
1.字段上需要添加一个注解 : @TableId(type = IdType.AUTO)
2.数据库中id要设置自增长
值 | 描述 |
---|---|
AUTO | 数据库ID自增 |
NONE | 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | insert前自行set主键值 |
ASSIGN_ID | 分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默认实现类为DefaultIdentifierGenerator 雪花算法) |
ASSIGN_UUID | 分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator 的方法nextUUID (默认default方法) |
ID_WORKER | 分布式全局唯一ID 长整型类型(please use ASSIGN_ID ) |
UUID | 32位UUID字符串(please use ASSIGN_UUID ) |
ID_WORKER_STR | 分布式全局唯一ID 字符串类型(please use ASSIGN_ID ) |
3.2 自动填充
阿里规范中,每一张表至少都需要有三个字段,id,createTime,updateTime
-
在数据库中添加create_time 和 update_time字段
-
在实体类中添加createTime 和updateTime
-
在属性上添加注解
@TableField(value = "create_time", fill = FieldFill.INSERT) private Date createTime; // java.util @TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) // 在新增的,默认修改时间为新增时间 private Date updateTime;
-
新建一个handler
@Slf4j @Component // 一定不要忘记把处理器加入到IOC容器中 只有在Spring容器中,才能使用Spring提供的功能 public class MyMetaObjectHandler implements MetaObjectHandler { //插入时的填充策略 @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill....."); // 每一次新增的时候会自动的执行 fieldName = 实体类字段 //setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } //更新时的填充策略 @Override public void updateFill(MetaObject metaObject) { log.info("start update fill....."); this.setFieldValByName("updateTime", new Date(), metaObject); } }
3.3乐观锁
乐观锁:顾名思义十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新测试值
悲观锁:顾名思义十分悲观,它总是认为总是会出现问题,无论干什么都会上锁,再去操作!
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前 version
- 更新时,带上这个 version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果 version 不对,就更新失败
3.3.1在数据库中加入version字段
并且设置默认值是1
3.3.2.在实体类的字段上加上@Version
注解
@Version //乐观锁@Version注解
private Integer version;
说明:
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下
newVersion = oldVersion + 1
newVersion
会回写到entity
中- 仅支持
updateById(id)
与update(entity, wrapper)
方法 - 在
update(entity, wrapper)
方法下,wrapper
不能复用!!!
3.3.3.注册组件
// Spring Boot 方式
@Configuration
@MapperScan("按需修改")
public class MybatisPlusConfig {
/**
* 旧版
*/
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
/**
* 新版
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
多线程一定要加乐观锁!!!
测试
//测试乐观锁成功
@Test
public void TestOptimisticLocker1(){
//1.查询用户表信息
User user = userMapper.selectById(1L);
//2.修改用户信息
user.setName("陈超").setEmail("132465789@qq.com");
//3.执行更新操作
userMapper.updateById(user);
}
//测试乐观锁失败
@Test
public void TestOptimisticLocker2(){
//线程1
User user = userMapper.selectById(1L);
user.setName("陈超111").setEmail("132465789@qq.com");
//模拟另外一个线程执行了插队操作
User user1 = userMapper.selectById(1L);
user.setName("陈超222").setEmail("132465789@qq.com");
userMapper.updateById(user1);
userMapper.updateById(user);//如果没有乐观锁就会覆盖插队线程的值!
}
3.4分页插件
配置拦截器插件
@Configuration
@MapperScan("com.jsd.mybatisplusdemo02.mapper")
public class MapperConfig {
// 最新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 分页
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
mybatisPlusInterceptor.addInnerInterceptor(paginationInnerInterceptor);
//乐观锁
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
return mybatisPlusInterceptor;
}
}
//测试分页查询
@Test
public void testPage() {
//参数1: 当前页
//参数2: 页面大小
Page<User> page = new Page<>(1, 3);
Page<User> userPage = userMapper.selectPage(page, null);
userPage.getRecords().forEach(System.out::println);
//总记录数
long total = page.getTotal();
System.out.println("total = " + total);
List<User> records = userPage.getRecords();
System.out.println("records = " + records);
List<User> records1 = page.getRecords();
System.out.println("records1 = " + records1);
long total1 = userPage.getTotal();
System.out.println("total1 = " + total1);
}
4.条件构造器
说明:
QueryWrapper(LambdaQueryWrapper) 和 UpdateWrapper(LambdaUpdateWrapper) 的父类
用于生成 sql 的 where 条件, entity 属性也用于生成 sql 的 where 条件
注意: entity 生成的 where 条件与 使用各个 api 生成的 where 条件没有任何关联行为
@Test
public void testQueryWrapper(){
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.like("name","江");//模糊查询
wrapper.eq("age",22); //age = 22 的
List<User> users = userMapper.selectList(wrapper);
users.forEach(System.out::println);
}