概述
官網上對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 xml檔案中的resultmap,
物體類
以User物體類為例,說明注解的作用,
@Data // @TableName(value = "https://www.cnblogs.com/phdeblog/archive/2020/11/04/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表示插入、洗掉的時候都需要填充,
當然,我們還需要添加一個處理類
@Component public 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;
并配置攔截器
@Configuration public 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、加注解
@TableLogic private 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
增刪改查
查詢
@SpringBootTest public 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); } }
洗掉
@SpringBootTest public 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類
@Data public class UserDetail { private String name; private String departmentName; }
**其實這里的@Select注解就和mybatis沒有關系了,是原生mybatis提供的,包括下面的xml也同樣如此,
xml版
傳統的xml也可以繼續使用,支持動態sql,功能和用法沒有任何改變,

<!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/**/*.xml
所以xml如果是放在類路徑mapper檔案夾下,也可以忽略不寫,
mapper-locations: classpath*:/mapper/**/*.xml
代碼自動生成
啟動類:
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
@Configuration public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 樂觀鎖插件 return interceptor; } }
entity
用戶
@Data // @TableName(value = "https://www.cnblogs.com/phdeblog/archive/2020/11/04/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; }
部門
@Data public class Department { @TableId(type = IdType.AUTO) private Integer id; private String name; }
用戶詳細資訊
@Data public class UserDetail { private String name; private String departmentName; }
handler
@Component public 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: root mybatis-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/**/*.xml
xml
位于 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;
如有錯誤,懇請批評指正!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/202419.html
標籤:其他
上一篇:Java匯出Pdf格式表單
