概述
官网上对mybatis plus的简介:
mybatis plus是一款mybtais的增强工具,在mybatis的基础上只做增强不做改变,为简化开发,提高效率而生。
正如官方所说,在保证最小代码入侵的前提下,MP(mybatis plus)给mybatis使用者带来了更好的体验。
官网文档:https://baomidou.com/guide/
推荐视频:https://www.bilibili.com/video/BV1yA411t782?p=1
如何去学习?
建议结合视频和官网文档。
最节省时间的方式:直接看文档,按照文档写demo,写完了快速过一遍视频(倍速、快进),毕竟有些技巧文档可能并没有说明。
最全面的学习方式:完整的看一遍视频,看完每小节后,去官方文档查找对应内容,重点看视频没有提到的。
现在着急用:直接点击跳转到本文的 完整测试代码 ,简单看一下代码,应该可以直接复制粘贴使用。
依赖
官网特别提醒,如果引入了mybatis plus的依赖,就不要引入mybatis以及mybatis-spring-starter之类的依赖了,防止发生版本冲突。
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.4.0</version> </dependency>
如果你想要使用自动生成功能,需要导入(模板引擎依赖根据个人需要导入)
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.2</version> </dependency>
注解
加载实体类的注解比较多,大多用于java实体类成员变量与数据库字段之间的映射,相当于传统mybatis
实体类
以User实体类为例,说明注解的作用。
@Data// @TableName(value = "user")public class User { @TableId(type = IdType.AUTO) private Long id; @TableField(value = "name") private String name; private Integer age; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; @Version private Integer version; private StatusEnum status; @TableLogic private Integer deleted; private Integer departmentId;}
@TableName
是实体类名与数据库表名之间的映射。
MP默认是按照类名来映射的,例如类名为User,表为user,那就不需要加这个注解,可以自动映射。
如果类名与表名不一致,就必须用这个注解标注了。
@TableId
加载主键上
@TableId(type = IdType.AUTO) private Long id;
它有几种配置策略,可以按需取用
#数据库自增 AUTO(0), #mybatis plus 设置主键,雪花算法 NONE(1), #开发者,手动复制 INPUT(2), #mybatis分配id,可以使用Long、Integer、String ASSIGN_ID(3), #分配一个uuid,必须是String ASSIGN_UUID(4),
@TableFiled
加在普通成员变量上
如果变量名与字段不一致,可以用value属性标注,可以实现变量和表字段的映射。
而fill可以实现自动填充。
@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
例如项目中,可能每张表都有createTime和updateTime,如果每次插入数据,都手动输入可能有点繁琐。所以可以使用fill属性。
FiledFill.INSERT表示在插入的时候填充。
FiledFill.INSERT_UPDATE表示插入、删除的时候都需要填充。
当然,我们还需要添加一个处理类
@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime", new Date(), metaObject); }}
@TableFiled还有其他的一些属性
String value() default ""; #该字段数据库中没有,不需要映射 boolean exist() default true; String condition() default ""; String update() default ""; FieldStrategy insertStrategy() default FieldStrategy.DEFAULT; FieldStrategy updateStrategy() default FieldStrategy.DEFAULT; FieldStrategy whereStrategy() default FieldStrategy.DEFAULT; #自动填充 FieldFill fill() default FieldFill.DEFAULT; #查询的时候,查询结果忽略该字段 boolean select() default true; boolean keepGlobalFormat() default false; JdbcType jdbcType() default JdbcType.UNDEFINED; Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class; boolean javaType() default false; String numericScale() default "";
@Version
乐观锁的实现方式(取自官网):当要更新一条记录的时候,希望这条记录没有被别人更新:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
mybatis plus中使用乐观锁,只需要添加一个注解@Version
@Version private Integer version;
并配置拦截器
@Configurationpublic class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件 return interceptor; }}
在执行更新操作的时候,会自动在sql后面加上 and version = xx
枚举
可以直接将java枚举类型映射为数据库字段
1、建需要映射的java枚举类
加注解
public enum StatusEnum { WORK(0,"上班"), REST(1,"休息"); StatusEnum(Integer code, String msg){ this.code = code; this.msg = msg; } @EnumValue private Integer code; private String msg;}
2、实体类直接使用
名字也要映射,如果和数据库字段不一致,可以用@TableField指定
private StatusEnum status;
3、配置文件中加上
mybatis-plus: type-enums-package: com.dayrain.nums
逻辑删除
什么时候用到逻辑删除?逻辑删除就是并非真正的删除某个数据,它依然存在数据库中,只是我在取用的时候,把他忽略。
具体的做法就是加一个字段,例如deleted,默认值为1 。
如果用户要删除这条数据,将它置为0。
每一次查询的时候,查询条件加上 and deleted = 1,这条数据表面上就完成了删除,但实际上还在数据库中,所以称为"逻辑删除"。
1、加注解
@TableLogicprivate Integer deleted;
2、配置文件
logic-not-delete-value表示正常状况的值,
logic-delete-value表示逻辑删除后的值,
这些是可以根据实际情况自行调整
mybatis-plus: global-config: db-config: logic-not-delete-value: 1 logic-delete-value: 0
实战:
@Test public void delete() { userMapper.deleteById(1); }
控制台输出
==> Preparing: UPDATE user SET deleted=0 WHERE id=? AND deleted=1==> Parameters: 1(Integer)<== Updates: 0
可以看出,删除实际执行的update,逻辑上的删除
此时执行查询
@Test void testSelect() { List<User> users = userMapper.selectList(null); users.forEach(System.out::println); }
控制台输出
发现查询的时候,会自动带上 deleted=1
JDBC Connection [HikariProxyConnection@1188871851 wrapping com.mysql.cj.jdbc.ConnectionImpl@36e43829] will not be managed by Spring==> Preparing: SELECT id,name,age,create_time,update_time,version,status,deleted FROM user WHERE deleted=1==> Parameters: <== Total: 0
增删改查
查询
@SpringBootTestpublic class UserTest { @Autowired UserMapper userMapper; @Test public void selectTest() { //1、不加条件,查询所有 // userMapper.selectList(null); //2、参数查 // SELECT id,name,age,create_time,update_time,version,status,deleted FROM user WHERE deleted=1 AND (name = ?) // QueryWrapper<User> wrapper = new QueryWrapper(); // wrapper.eq("name","小李"); // List<User> users = userMapper.selectList(wrapper); // users.forEach(System.out::println); //3、多个参数 // SELECT id,name,age,create_time,update_time,version,status,deleted FROM user WHERE deleted=1 AND (name = ? AND age = ?) // QueryWrapper<User> wrapper = new QueryWrapper(); // Map<String, Object>map = new HashMap<>(); // map.put("name", "小李"); // map.put("age", 22); // wrapper.allEq(map); // List<User> users = userMapper.selectList(wrapper); //也可以直接用selectByMap直接传map // users.forEach(System.out::println); //4、比较, // QueryWrapper<User> wrapper = new QueryWrapper(); //gt表示大于,同理 //ge(大于等于),ne(不等于),lt(小于),le(小于等于) // wrapper.gt("age",22); // List<User> users = userMapper.selectList(wrapper); // users.forEach(System.out::println); //5、模糊查询 //复习一下, mysql中 //'%小',表示以'小'结尾,'小%'表示以小开头。'%小%'表示中间有小 // QueryWrapper<User> wrapper = new QueryWrapper(); // wrapper.like("name","小"); '%小%' // wrapper.likeLeft("name","小"); '%小' // wrapper.likeRight("name","小"); '小%' // List<User> users = userMapper.selectList(wrapper); // users.forEach(System.out::println); //6、复合查询 // SELECT id,name,age,create_time,update_time,version,status,deleted FROM user WHERE deleted=1 AND (id IN (select id from user where id < 10)) // QueryWrapper<User> wrapper = new QueryWrapper(); // wrapper.inSql("id", "select id from user where id < 10"); // List<User> users = userMapper.selectList(wrapper); // users.forEach(System.out::println); //7、排序 //desc asc //SELECT id,name,age,create_time,update_time,version,status,deleted FROM user WHERE deleted=1 ORDER BY age DESC // QueryWrapper<User> wrapper = new QueryWrapper(); // wrapper.orderByDesc("age"); // List<User> users = userMapper.selectList(wrapper); // users.forEach(System.out::println); //8、将结果封装成map对象 // QueryWrapper<User> wrapper = new QueryWrapper(); // wrapper.orderByDesc("age"); // List<Map<String, Object>> maps = userMapper.selectMaps(wrapper); // maps.forEach(System.out::println); //9、分页 // Page<User> page = new Page<>(1, 2); // Page<User> result = userMapper.selectPage(page, null); // System.out.println(result); // 结果 // System.out.println(result.getRecords()); /** * ==> Preparing: SELECT COUNT(1) FROM user WHERE deleted = 1 * ==> Parameters: * <== Columns: COUNT(1) * <== Row: 1 * <== Total: 1 * ==> Preparing: SELECT id,name,age,create_time,update_time,version,status,deleted FROM user WHERE deleted=1 LIMIT ? * ==> Parameters: 2(Long) * <== Columns: id, name, age, create_time, update_time, version, status, deleted * <== Row: 1, 小李, 1, 2020-11-03 17:03:18, 2020-11-03 17:31:46, 2, 1, 1 * <== Total: 1 */ //10、连表查询 //自定mapper List<UserDetail> userDetails = userMapper.selectUserDetail(1L); userDetails.forEach(System.out::println); }}
删除
@SpringBootTestpublic class UserTest { @Autowired UserMapper userMapper; @Test public void delete() { //1、根据id删除 // userMapper.deleteById(1); //2、根据id集合删除 // userMapper.deleteBatchIds(Arrays.asList(1,2)); //3、条件删除 QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("age", 14); userMapper.delete(wrapper); }}
更新
@Test void updateUser() { // User user = new User(); // user.setAge(1); // user.setName("小李"); // user.setId(1323545415801319427L); // userMapper.updateById(user); // System.out.println(userMapper.selectById(user.getId())); //条件更新,相当于updateSelective,如果为null,则不更新 //把年龄为25岁的人,名字都改成小明。 User user = new User(); user.setName("小明"); QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("age", 25); userMapper.update(user, queryWrapper); }
添加
@Test void saveUser() { User user = new User(); user.setAge(22); user.setName("小李"); userMapper.insert(user); }
连表查询
MP对mybatis本身的代码没有入侵,如果你喜欢,mybatis依然可以像以前那么用。
当MP提供的内置sql不能满足需求时,比如连表查询等,我们可以自己写sql,实现较为复杂的功能。
注解版
例如现在有员工表、部门表,员工有部门id,需求是查出员工对应的部门名。
做一个简单的连表查询即可,但问题是如何去接收结果?我们这里的做法是定义一个对象来映射结果集,如果字段名和我们的成员变量名不一致,sql中可以采用"别名"的方式。
public interface UserMapper extends BaseMapper<User> { //原生注解 @Select("select user.name name, d.name departmentName from department d , user where user.id = #{id}") List<UserDetail>selectUserDetail(Long id);}
UserDetail类
@Datapublic class UserDetail { private String name; private String departmentName;}
**其实这里的@Select注解就和mybatis没有关系了,是原生mybatis提供的。包括下面的
传统的
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.dayrain.mapper.UserMapper"> <select id="selectAll" resultType="com.dayrain.entity.User"> select * from user; </select></mapper>
为了让Springboot扫描到这个文件,需要在配置文件中加上路径
默认的路径就是 classpath*:/mapper/**/*.
所以
mapper-locations: classpath*:/mapper/**/*.代码自动生成
启动类:
public class Main { public static void main(String[] args) { //创建generator对象 AutoGenerator autoGenerator = new AutoGenerator(); //数据源 DataSourceConfig dataSourceConfig = new DataSourceConfig(); dataSourceConfig.setDbType(DbType.MYSQL); dataSourceConfig.setUrl("jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=UTF-8"); dataSourceConfig.setUsername("root"); dataSourceConfig.setPassword("root"); dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver"); autoGenerator.setDataSource(dataSourceConfig); //全局设置 GlobalConfig globalConfig = new GlobalConfig(); globalConfig.setOutputDir(System.getProperty("user.dir") + "/src/main/java"); globalConfig.setOpen(false); globalConfig.setAuthor("dayrain"); //如果不设置,默认都是以I开头的service globalConfig.setServiceName("%sService"); autoGenerator.setGlobalConfig(globalConfig); //包信息
//路径根据个人需要配置
//该配置运行结果:会在com.dayrain包下生成一个generator文件夹,里面有entity、service等包。 PackageConfig packageConfig = new PackageConfig(); packageConfig.setParent("com.dayrain"); packageConfig.setModuleName("generator"); packageConfig.setController("controller"); packageConfig.setService("service"); packageConfig.setMapper("mapper"); autoGenerator.setPackageInfo(packageConfig); //配置策略 StrategyConfig strategyConfig = new StrategyConfig(); strategyConfig.setEntityLombokModel(true); strategyConfig.setNaming(NamingStrategy.underline_to_camel); strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel); autoGenerator.setStrategy(strategyConfig); autoGenerator.execute(); }}添加自动生成依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.4.0</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.2</version> </dependency>
完整测试代码
目录结构
config
@Configurationpublic class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件 return interceptor; }}entity
用户
@Data// @TableName(value = "user")public class User { @TableId(type = IdType.AUTO) private Long id; @TableField(value = "name") private String name; private Integer age; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; @Version private Integer version; private StatusEnum status; @TableLogic private Integer deleted; private Integer departmentId;}部门
@Datapublic class Department { @TableId(type = IdType.AUTO) private Integer id; private String name;}用户详细信息
@Datapublic class UserDetail { private String name; private String departmentName;}handler
@Componentpublic class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } @Override public void updateFill(MetaObject metaObject) { this.setFieldValByName("updateTime", new Date(), metaObject); }}mapper
public interface UserMapper extends BaseMapper<User> { //原生注解 @Select("select user.name name, d.name departmentName from department d , user where user.id = #{id}") List<UserDetail>selectUserDetail(Long id); List<User>selectAll();}enums
public enum StatusEnum { WORK(0,"上班"), REST(1,"休息"); StatusEnum(Integer code, String msg){ this.code = code; this.msg = msg; } @EnumValue private Integer code; private String msg;}启动类
@SpringBootApplication@MapperScan("com.dayrain.mapper")public class MybatisLearnApplication { public static void main(String[] args) { SpringApplication.run(MybatisLearnApplication.class, args); }}配置文件
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=UTF-8 username: root password: rootmybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl type-enums-package: com.dayrain.nums global-config: db-config: logic-not-delete-value: 1 logic-delete-value: 0 mapper-locations: classpath*:/mapper/**/*.位于 resouces/mapper下
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.dayrain.mapper.UserMapper"> <select id="selectAll" resultType="com.dayrain.entity.User"> select * from user; </select></mapper>sql
DROP TABLE IF EXISTS `user`;CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, `age` int(11) NULL DEFAULT NULL, `create_time` datetime(0) NULL DEFAULT NULL, `update_time` datetime(0) NULL DEFAULT NULL, `version` int(11) NULL DEFAULT 1, `status` tinyint(4) NULL DEFAULT NULL, `deleted` tinyint(4) NULL DEFAULT 1, `department_id` int(11) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 1323545415801319428 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `department`;CREATE TABLE `department` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
如有错误,恳请批评指正!
原文转载:http://www.shaoqun.com/a/488098.html
hts:https://www.ikjzd.com/w/525
moss:https://www.ikjzd.com/w/1653
olive:https://www.ikjzd.com/w/2025
概述官网上对mybatisplus的简介:mybatisplus是一款mybtais的增强工具,在mybatis的基础上只做增强不做改变,为简化开发,提高效率而生。正如官方所说,在保证最小代码入侵的前提下,MP(mybatisplus)给mybatis使用者带来了更好的体验。官网文档:https://baomidou.com/guide/推荐视频:https://www.bilibili.com/
巨鲸:https://www.ikjzd.com/w/1986
hemingway:https://www.ikjzd.com/w/2344
珠海海泉湾有什么好玩的?有什么项目?:http://tour.shaoqun.com/a/41659.html
在珠海旅游可以去哪里?:http://tour.shaoqun.com/a/4087.html
广州番禺有什么又好玩又免费的地方?广州番禺免费景点:http://tour.shaoqun.com/a/3811.html