一、导入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
二、配置文件。写pojo
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/market?useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
三、mapper层接口继承 BaseMapper
@Mapper
@Repository //表示这是dao(持久层)层,只有需要用到mybatis(数据库)时才用到
public interface UserMapper extends BaseMapper<User> {
//所有的CRUD操作都已经编写完成了,你不需要像以前的配置一大堆文件了!
}
四、使用
@Autowired
private UserMapper userMapper;
//继承了BaseMapper,所有的方法都来自己父类
//我们也可以编写自己的扩展方法!
@Test
void contextLoads() {
// User user =userMapper.selectById(5);
// System.out.println(user);
//参数是一个wrapper ,条件构造器,这里我们先不用nuLL/查询全部用户
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
--------------------------------------------------------------------------------------
正式开始
数据库表结构
实体类的注解
public class User {
//对应数据库中的主键(uuid、自增id、雪花算法、redis、 zookeeper ! )
@TableId(type = IdType.NONE)
private Integer id;
private String name;
private Integer password;
//时间类型LocalDateTime要与MyDateObjectHandler类中对应
//自动填写插入操作FieldFill.INSERT
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
//自动填写更新操作时间
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@Version //乐观锁的注解
private Integer version;
@TableLogic //逻辑删除注解
private Integer deleted;
}
==================================================
一。简单增删改查使用
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
private UserMapper userMapper;
//继承了BaseMapper,所有的方法都来自己父类
//我们也可以编写自己的扩展方法!
@Test
void contextLoads() {
User user =userMapper.selectById(3);
System.out.println(user);
// 参数是一个wrapper ,条件构造器,这里我们先不用nuLL,查询全部用户
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
//add
@Test
public void TestAdd(){
User user=new User();
user.setId(7);
user.setName("rtul");
user.setPassword(123125);
int insert=userMapper.insert(user);
System.out.println(insert);
System.out.println(user);
}
//update
@Test
public void TestUpdate(){
// User user=new User();
// user.setId(5);
// user.setName("小乔乔");
// user.setPassword(12121);
// int user1=userMapper.updateById(user);
// System.out.println(userMapper.selectById(5));
}
//测试查询
@Test
public void TestQuery() {
User user = userMapper.selectById(3);
System.out.println(user);
}
//查询多个id
@Test
public void TestQuery2(){
//类型是Collection --所以用集合Arrays.asList
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
System.out.println(users);
}
//条件查询之一通过map
@Test
public void TestQuery3(){
HashMap<String,Object> map = new HashMap<>();
// map.put("name","www");
map.put("password","12121");
userMapper.selectByMap(map);
System.out.println();
}
//按id删除
@Test
public void TestDelete(){
userMapper.deleteById(1);
//查询多个id
//类型是Collection --所以用集合Arrays.asList
userMapper.deleteBatchIds(Arrays.asList(1,2,3));
//条件查询之一通过map
HashMap<String,Object> map = new HashMap<>();
// map.put("name","www");
map.put("password","12121");
userMapper.deleteByMap(map);
}
二。关于时间的创建时间和更新时间
建一个headler包,MyDateObjectHandler类
@Component //把处理器组件加到IOC容器中
public class MyDateObjectHandler implements MetaObjectHandler {
//插入时填充策略
@Override
public void insertFill(MetaObject metaObject) {
// this.setFieldValByName("createTime",new Date(),metaObject);
// this.setFieldValByName("updateTime",new Date(),metaObject);
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
this.strictInsertFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
//this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐使用)
// 或者
// this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
//this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
//更新时填充策略
@Override
public void updateFill(MetaObject metaObject) {
//this.setFieldValByName("updateTime",new Date(),metaObject);
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
// this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
// 或者
//this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
// 或者
//this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 该方法有bug)
}
}
三。乐观锁,分页插件和防止恶意全表更新删除的配置
@EnableTransactionManagement //自动管理事务
@Configuration //配置类
public class MyBatisPlusConfig {
// @Bean
//旧版
// //注册乐观锁
// public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor(){
// return new OptimisticLockerInnerInterceptor();
// }
//分页组件配置
// 旧版
// @Bean
// public PaginationInterceptor paginationInterceptor(){
// return new PaginationInterceptor();
// }
// 逻辑删除旧版需要的配置,新版不需要
// @Bean
// public ISqlInjector sqlInjector() {
// return new LogicSqlInjector();
// }
//新版
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
//注册乐观锁
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//分页插件配置
//默认DbType.数据库类型
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
//配置全表更新与删除插件,针对 update 和 delete 语句 作用: 阻止恶意的全表更新删除
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}
测试
//测试乐观锁成功
@Test
public void TestOptimisticLocker(){
//1.查询用户信息
User user=userMapper.selectById(4);
//2.插入用户信息
user.setName("白起1");
user.setPassword(22322);
//3.执行更新操作
userMapper.updateById(user);
}
//测试乐观锁失败
@Test
public void TestOptimisticLocker2(){
User user=userMapper.selectById(1);
user.setName("白起1");
user.setPassword(22322);
//模拟插队
User user2=userMapper.selectById(1);
user.setName("白起2");
user.setPassword(22322);
userMapper.updateById(user2);
//可以自旋锁来多次尝试提交!
userMapper.updateById(user);//如果没有乐观锁就会覆盖插队线程的值!
}
//分页查询三种方式-1、使用limit。2、第三方插件。3、MyBatisPlus内置分页
//分页查新。需要配置拦截组件
//MybatisPlus3.5的在Mybatis方法里面直接加 interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL))
@Test
public void TestPageQuery(){
//参数一是页码,二是数量
Page<User> Page = new Page<>(1,3);
//wrapper暂时不用
userMapper.selectPage(Page,null);
//getRecords获得记录
Page.getRecords().forEach(System.out::println);
Page.getPages(); //一共多少页
Page.getTotal();//一共多少条数据
Page.getCurrent(); //当前第几页
Page.getRecords();//获取分页后的数据
}
//防止全表更新删除
@Test
public void testDeleteUpdate() {
LambdaUpdateWrapper<User> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(User::getId, 1);
User user = new User();
user.setId(5);
user.setName("custom_name");
//我没写这个方法,不知道wrapper是什么
// userMapper.saveOrUpdate(user, wrapper);
}
逻辑删除
逻辑删除旧版需要的配置类,新版不需要。
要在application.properties中配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
## 日志,StdOutImpl系统自带日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 逻辑删除配置
# 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
mybatis-plus.global-config.db-config.logic-delete-field=flag
# 逻辑已删除值(默认为 1)
mybatis-plus.global-config.db-config.logic-delete-value=1
# 逻辑未删除值(默认为 0)
mybatis-plus.global-config.db-config.logic-not-delete-value=0
# 配置端口
# server.port=8000
# 开发模式
# spring.profiles.active=dev
测试
//逻辑删除。物理删除是直接从数据库中删除。逻辑删除是在数据库中没有删除,而是通过变量来使他失效
//管理员可以查看删除记录,以防数据丢失,类似于回收站
//在配置文件中配置了之后删除不会删除数据库中的数据
// UPDATE user SET deleted=1 WHERE id=? AND deleted=0实际执行的是update
@Test
public void TestLogicDelete() {
//按id删除
userMapper.deleteById(1);
}
------------------------------------------------------------------------------------------
wrapper条件构造器用法
极其好用
测试
@SpringBootTest
public class wrapperTest {
@Autowired
private UserMapper userMapper;
//wrapper是条件构造器,多重条件查询
@Test
public void TestPageQuery(){
//wrapper是条件构造器,多重条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
//年龄大于20,年龄,更新时间非空
//非空
wrapper.isNotNull("age");
wrapper.isNotNull("update_time");
//大于
wrapper.ge("age",20);
System.out.println(userMapper.selectList(wrapper));
}
// 查询一个
@Test
public void TestPageQuery2(){
//wrapper是条件构造器,多重条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
//名字==诸葛
wrapper.eq("name","诸葛");
//selectOne只能查一个存在的
User user=userMapper.selectOne(wrapper);
System.out.println(user);
}
// 查询一个
@Test
public void TestPageQuery3(){
//wrapper是条件构造器,多重条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
//年龄18到30之间的
wrapper.between("age",18,30);
Long count = userMapper.selectCount(wrapper);
System.out.println(count);
// List<User> users = userMapper.selectList(wrapper);
// users.forEach(System.out::println);
}
// Map查询
@Test
public void TestPageQuery4(){
//wrapper是条件构造器,多重条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
//不包含
// wrapper.notLike("name","w");
//包含
wrapper.like("name","w");
//右开头,比如 w%
wrapper.likeRight("name","l");
List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
maps.forEach(System.out::println);
}
}
自学自狂神,有位大哥总结的更好:https://blog.csdn.net/greenhandp/article/details/124008224?spm=1001.2014.3001.5506