使用下面的SQL创建数据库与添加数据
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) ); DELETE FROM user; 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'); 复制代码
添加MyBatis-Plus、mysql连接驱动、lombok的依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.0.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> 复制代码
application.yml
spring: datasource: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/mp username: root password: 1234 复制代码
@SpringBootApplication @MapperScan("com.jikedaquan.study.mp.mapper") public class MpApplication { public static void main(String[] args) { SpringApplication.run(MpApplication.class, args); } } 复制代码
@Data public class User { private Long id; private String name; private Integer age; private String email; } 复制代码
UserMapper接口继承MyBatis-Plus提供的BaseMapper接口即可拥有CRUD的方法,泛型中填写操作的实体类,这里为User
public interface UserMapper extends BaseMapper<User> { } 复制代码
@RunWith(SpringRunner.class) @SpringBootTest public class MpApplicationTests { @Autowired private UserMapper userMapper; @Test public void contextLoads() { List<User> userList = userMapper.selectList(null);//条件为null时查询所有数据 userList.forEach(System.out::println); } } 复制代码
配置日志到控制台输出
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 复制代码
MyBatis-Plus提供了多种主键生成策略以应对不同的场景
策略 | 说明 |
---|---|
AUTO | 数据库ID自增 |
NONE | 该类型为未设置主键类型 |
INPUT | 用户输入ID,该类型可以通过自己注册自动填充插件进行填充 |
ID_WORKER | 全局唯一ID (idWorker) |
UUID | 全局唯一ID (UUID) |
ID_WORKER_STR | 字符串全局唯一ID (idWorker 的字符串表示) |
在实体类的主键字段上添加注解(自增时注意配合数据库设置)
@Data public class User { @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; private String email; } 复制代码
application.yml
mybatis-plus: global-config: db-config: id-type: id_worker 复制代码
在常用业务中有些属性需要配置一些默认值,MyBatis-Plus提供了实现此功能的插件。在这里修改user表添加 create_time
字段和 update_time
字段,在User类中添加对应属性。
提供了4种自动填充策略: DEFAULT ,默认不处理。 INSERT ,插入填充字段。 UPDATE ,更新填充字段。 INSERT_UPDATE ,插入和更新填充字段。
@Data public class User { private Long id; private String name; private Integer age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; } 复制代码
实现 MetaObjectHandler 接口,实现 insertFill 和 updateFill 方法,此处的 create_time
和 update_time
字段需要插入时填充值, 只有 update_time
字段在修改时需要填充,所以策略如下。
//需要将自定义填充控制器注册为组件 @Component public class MyMetaObjectHandler implements MetaObjectHandler { private static final Logger LOGGER= LoggerFactory.getLogger(MyMetaObjectHandler.class); //insert操作时要填充的字段 @Override public void insertFill(MetaObject metaObject) { LOGGER.info("start insert fill ..."); //根据属性名字设置要填充的值 this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } //update操作时要填充的字段 @Override public void updateFill(MetaObject metaObject) { LOGGER.info("start insert fill ..."); this.setFieldValByName("updateTime",new Date(),metaObject); } } 复制代码
@RunWith(SpringRunner.class) @SpringBootTest public class CRUDTest { @Autowired private UserMapper userMapper; @Test public void testInsert(){ User user = new User(); user.setName("jack11"); user.setAge(20); user.setEmail("4849111@qq.com"); int result= userMapper.insert(user); System.out.println(result); System.out.println(user); } } 复制代码
@Test public void testUpdate(){ User user = new User(); user.setId(2L); user.setName("Jackie"); int result = userMapper.updateById(user); System.out.println(result); } 复制代码
一次插入数据后, create_time
和 update_time
都被填充了设置的时间,做update操作后只有 update_time
的进行了填充修改。
乐观锁的核心原理就是提交版本必须等于记录当前版本才能执行更新
意图:
乐观锁实现方式:
@Version private Integer version; 复制代码
@Configuration public class MyBatisPlusConfig { @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor(){ return new OptimisticLockerInterceptor(); } } 复制代码
@Test public void testOptimisticLocker1() { User user = userMapper.selectById(1128212430124097543L); user.setName("修改后"); int result = userMapper.updateById(user); if (result == 1) { System.out.println("修改成功"); } else { System.out.println("修改失败"); } } @Test public void testOptimisticLocker2() { User user = userMapper.selectById(1128212430124097543L); user.setName("修改后"); user.setVersion(user.getVersion()-1);//测试旧版本 int result = userMapper.updateById(user); if (result == 1) { System.out.println("修改成功"); } else { System.out.println("修改失败"); } } 复制代码
启用分页插件和启用乐观锁插件都是通过注册一个Bean完成
@Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } 复制代码
@Test public void testSelectPage(){ //构建分页条件第二页每页显示3条 Page<User> page=new Page<>(2,3); //使用分页条件查询,不使用其他条件 userMapper.selectPage(page, null); //获取分页后查询出的记录 List<User> records = page.getRecords(); records.forEach(System.out::println); System.out.println("是否有下一页:"+page.hasNext()); System.out.println("是否有上一页:"+page.hasPrevious()); System.out.println("总记录数:"+page.getTotal()); } 复制代码
有些数据希望不再展示,但在物理上仍然存在,这时可以使用逻辑删除。逻辑删除就是在表中添加一个逻辑字段(在上面基础上添加字段 deleted
),删除的实质操作就是操作这个逻辑值,在查询、修改时根据此逻辑值进行近一步操作。
@Bean public LogicSqlInjector logicSqlInjector(){ return new LogicSqlInjector(); } 复制代码
mybatis-plus: global-config: db-config: logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) 复制代码
@TableLogic private Integer deleted; 复制代码
@Test public void testLogicDelete(){ int result=userMapper.deleteById(1L); System.out.println(result); } 复制代码
观察日志可以看到生成的sql是update语句
在开发和测试时观察sql执行耗时
spring: profiles: active: dev 复制代码
@Bean @Profile({"dev","test"}) //设置 dev test 环境开启 public PerformanceInterceptor performanceInterceptor(){ return new PerformanceInterceptor(); } 复制代码
@Test public void testSelectById() { User user = userMapper.selectById(1L); System.out.println(user); } @Test public void testSelectBatchIds() { List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); users.forEach(System.out::println); } @Test public void testSelectByMap() { Map<String, Object> param = new HashMap<>(); param.put("name", "jack"); param.put("age", 18); List<User> users = userMapper.selectByMap(param); users.forEach(System.out::println); } @Test public void testSelectMap(){ Page<User> page = new Page<>(2, 3); IPage<Map<String, Object>> mapIPage = userMapper.selectMapsPage(page, null); } @Test public void testDeleteById(){ int result = userMapper.deleteById(1L); System.out.println(result); } @Test public void testDeleteBatchIds(){ int result = userMapper.deleteBatchIds(Arrays.asList(2L,3L,4L)); System.out.println(result); } 复制代码
欢迎热爱技术的小伙伴和我交流