MyBatisPlus概述
无侵入
:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小
:启动即会自动注入基本
CURD
,性能基本无损耗,直接面向对象操作,
BaseMapper
强大的
CRUD
操作
:内置通用
Mapper
、通用
Service
,仅仅通过少量配置即可实现单表大部分
CRUD
操作,更有强大的条件构造器,满足各类使用需求
,
以后简单的
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
操作智能分析阻断,也可自定义拦截规则,预防误
操作
MyBatisPlus可以节省我们大量工作时间,所有的CRUD代码它都可以自动化完成
创建一个SpringBoot项目
创建数据库 mybatis_plus
创建user表
DROP TABLE IF EXISTS user;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' );
导入依赖
<!-- 数据库驱动 --><dependency><groupId> mysql </groupId><artifactId> mysql-connector-java </artifactId></dependency><!-- lombok --><dependency><groupId> org.projectlombok </groupId><artifactId> lombok </artifactId></dependency><!-- mybatis-plus --><!-- mybatis-plus 是自己开发,并非官方的! --><dependency><groupId> com.baomidou </groupId><artifactId> mybatis-plus-boot-starter </artifactId><version> 3.0.5 </version></dependency>
连接数据库!这一步和 mybatis 相同!
# mysql 5 驱动不同 com.mysql.jdbc.Driver# mysql 8 驱动不同 com.mysql.cj.jdbc.Driver 、需要增加时区的配置serverTimezone=GMT%2B8spring.datasource.username = rootspring.datasource.password = adminspring.datasource.url = jdbc : mysql : //localhost : 3306/mybatis_plus?useSSL = false&useUnicode = true&characterEncoding = utf-8&serverTimezone = GMT%2B8spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
使用mybatis,需要配置mapper.xml文件手写sql语句
使用了
mybatis-plus
之后
pojo
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
mapper接口
package com.wu.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.wu.pojo.User; import org.springframework.stereotype.Repository; // 在对应的Mapper上面继承基本的类 BaseMapper @Repository // 代表持久层 public interface UserMapper extends BaseMapper<User> { // 所有的CRUD操作都已经编写完成了 // 你不需要像以前的配置一大堆文件了! }
注意点,我们需要在主启动类上去扫描我们的mapper包下的所有接口
@MapperScan("com.wu.mapper")
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
//查询全部
// 参数是一个mapper ,条件构造器 ,不用可以为null
List<User> userList = userMapper.selectList(null);
userList.forEach(System.out::println);
}
配置日志
# 配置日志mybatis-plus.configuration.log-impl = org.apache.ibatis.logging.stdout.StdOutImpl
CRUD扩展
Insert 插入
// 测试插入
@Test
public void testInsert(){
User user = new User();
user.setName("Java如此简单");
user.setAge(3);
user.setEmail("22233@qq.com");
int result = userMapper.insert(user); // 帮我们自动生成id
System.out.println(result); // 受影响的行数
System.out.println(user); // 发现,id会自动回填
}
主键生成策略默认 ID_WORKER 全局唯一 id
主键自增(雪花算法 ,UUID)
我们需要配置主键自增:1 、实体类字段上@TableId(Type=IdType.AUTO)2 、数据库字段一定要是自增!3 、再次测试插入即可!
更新操作
// 测试更新
@Test public void testUpdate(){
User user = new User(); // 通过条件自动拼接动态sql
user.setId(6L);
user.setName("关注公众号:狂神说");
user.setAge(18); // 注意:updateById 但是参数是一个 对象!
int i = userMapper.updateById(user);
System.out.println(i); }
乐观锁
乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
乐观锁: 1 、先查询,获得版本号 version = 1-- Aupdate user set name = "kuangshen" , version = version + 1where id = 2 and version = 1-- B 线程抢先完成,这个时候 version = 2 ,会导致 A 修改失败!update user set name = "kuangshen" , version = version + 1where id = 2 and version = 1
1、给数据库中增加version字段!
2、我们实体类加对应的字段
@Version // 乐观锁 Version 注解private Integer version ;
3、注册组件
// 扫描我们的 mapper 文件夹 @MapperScan("com.kuang.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4
、测试一下!
// 测试乐观锁成功!@Testpublic void testOptimisticLocker (){// 1 、查询用户信息User user = userMapper . selectById ( 1L );// 2 、修改用户信息user . setName ( "不想玩了" );user . setEmail ( "2361577441@qq.com" );// 3 、执行更新操作userMapper . updateById ( user );}
// 测试乐观锁失败!多线程下@Testpublic void testOptimisticLocker2 (){// 线程 1User user = userMapper . selectById ( 1L );user . setName ( "111111" );user . setEmail ( "23465@qq.com" );// 模拟另外一个线程执行了插队操作User user2 = userMapper . selectById ( 1L );user2 . setName ( "222222" );user2 . setEmail ( "110@qq.com" );userMapper . updateById ( user2 );// 自旋锁来多次尝试提交!userMapper . updateById ( user ); // 如果没有乐观锁就会覆盖插队线程的值!}
查询操作
// 测试查询@Testpublic void testSelectById (){User user = userMapper . selectById ( 1L );System . out . println ( user );}// 测试批量查询!@Testpublic void testSelectByBatchId (){List < User > users = userMapper . selectBatchIds ( Arrays . asList ( 1 , 2 , 3 ));users . forEach ( System . out :: println );}// 按条件查询之一使用 map 操作@Testpublic void testSelectByBatchIds (){HashMap < String , Object > map = new HashMap <> ();// 自定义要查询map . put ( "name" , " Java如此简单" );map . put ( "age" , 3 );List < User > users = userMapper . selectByMap ( map );users . forEach ( System . out :: println );}
分页查询
1
、原始的
limit
进行分页
2
、
pageHelper
第三方插件
3
、
MP
其实也内置了分页插件!
1 、配置拦截器组件即可// 分页插件@Beanpublic PaginationInterceptor paginationInterceptor () {return new PaginationInterceptor ();}
2、直接使用Page对象即可!
// 测试分页查询@Testpublic void testPage (){// 参数一:当前页// 参数二:页面大小// 使用了分页插件之后,所有的分页操作也变得简单的!Page < User > page = new Page <> ( 2 , 5 );userMapper . selectPage ( page , null );page . getRecords (). forEach ( System . out :: println );System . out . println ( page . getTotal ());}
删除操作
1
、根据
id
删除记录
// 测试删除@Testpublic void testDeleteById (){userMapper . deleteById ( 1240620674645544965L );}// 通过 id 批量删除@Testpublic void testDeleteBatchId (){userMapper . deleteBatchIds ( Arrays . asList ( 1240620674645544961L , 1240620674645544962L ));}// 通过 map 删除@Testpublic void testDeleteMap (){HashMap < String , Object > map = new HashMap <> ();map . put ( "name" , " 狂神说 Java" );userMapper . deleteByMap ( map );
逻辑删除:
物理删除 :从数据库中直接移除逻辑删除 :再数据库中没有被移除,而是通过一个变量来让他失效 deleted=0=> deleted = 1
1、在数据表中增加一个 deleted 字段
2、实体类中增加属性
@TableLogic //逻辑删除
private Integer deleted ;
3、配置!
// 逻辑删除组件!@Beanpublic ISqlInjector sqlInjector () {return new LogicSqlInjector ();}
# 配置逻辑删除mybatis-plus.global-config.db-config.logic-delete-value = 1mybatis-plus.global-config.db-config.logic-not-delete-value = 0
//测试删除 @Test public void testdeleteById() { userMapper.deleteById(5l); } //批量ID删除 @Test public void testDeleteBatchId() { userMapper.deleteBatchIds(Arrays.asList(1493186264636956673l, 1493188750437318658l)); } //map删除 @Test public void testDmap() { HashMap<String, Object> map = new HashMap<>(); map.put("name", "天基王"); userMapper.deleteByMap(map); }
删除后再次查询会自动过滤逻辑删除的字段防止数据丢失
测试!
@SpringBootTest
public class WrapperTest {
@Autowired
UserMapper userMapper;
@Autowired
UserService userService;
@Test
void test() {
//查询name不为空的用户,并且邮箱不为空的用户,年龄小于20000
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.isNotNull("name") //名字不为空
.isNotNull("email") //邮箱不为空
.ge("age", 2000); //age大于等于2000
userMapper.selectList(wrapper)
.forEach(System.out::println); //和map 相似
}
@Test
void test1() {
//查询名字 凯莎
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "凯莎");
User user = userMapper.selectOne(wrapper); //查询一个数据 .selectOne
System.out.println(user);
}
@Test
void test2() {
//查询 22到30
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.between("age", 22, 30); //20到30区间
Long count = userMapper.selectCount(wrapper);//查询结果数
System.out.println(count);
}
@Test
void test3() {
//模糊查询
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper
.notLike("name", "e")// 不包含e的名字
.likeRight("email", "t"); //左和右(t%)在%左边 t开头的
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
@Test
void test4() {
//内嵌查询
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);
}
@Test
void test5() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//通过id降序 排序
wrapper.orderByDesc("id");
List<User> list = userMapper.selectList(wrapper);
list.forEach(System.out::println);
}
}