一、MyBatis Generator
? ? ? ? 為 MyBastis 框架設計的代碼生成工具,簡化持久層編碼工作。根據數據庫表自動生成 Java 實體類、Mapper 接口、SQL 的 xml 文件。讓開發者專注于業務邏輯。
1、引入插件
? ? ? ? MyBatis?官網搜索 MyBatis Generator 插件:Running MyBatis Generator With Maven – MyBatis Generator Corehttps://mybatis.org/generator/running/runningWithMaven.html
<plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.6</version><executions><execution><id>Generate MyBatis Artifacts</id><phase>deploy</phase><goals><goal>generate</goal></goals></execution></executions><configuration><!--generator配置文件所在位置--><configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile><!-- 允許覆蓋生成的文件;xml不會覆蓋, 采用追加的方式--><overwrite>true</overwrite><verbose>true</verbose><!--將當前pom的依賴項添加到生成器的類路徑中--><includeCompileDependencies>true</includeCompileDependencies></configuration><!--該插件的依賴,在 <dependencies> 中引入的它識別不到--><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version></dependency></dependencies></plugin>
2、修改 generatorConfig.xml 文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration><!-- 一個數據庫一個context --><context id="MysqlTables" targetRuntime="MyBatis3Simple"><!--禁用自動生成的注釋--><commentGenerator><property name="suppressDate" value="true"/><property name="suppressAllComments" value="true" /></commentGenerator><!--數據庫連接信息--><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://127.0.0.1:3306/book_test?serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true"userId="root"password="root"></jdbcConnection><!-- 生成實體類, 配置路徑 --><javaModelGenerator targetPackage="com.edu.generator.model" targetProject="src/main/java" ><property name="enableSubPackages" value="false"/><property name="trimStrings" value="true"/></javaModelGenerator><!-- 生成mapxml文件 --><sqlMapGenerator targetPackage="generatorMapper" targetProject="src/main/resources" ><property name="enableSubPackages" value="false" /></sqlMapGenerator><!-- 生成mapxml對應client,也就是接口dao --><javaClientGenerator targetPackage="com.edu.generator.mapper" targetProject="src/main/java" type="XMLMAPPER" ><property name="enableSubPackages" value="false" /></javaClientGenerator><!-- table可以有多個,tableName表示要匹配的數據庫表 --><table tableName="user_info" domainObjectName="UserInfo" enableSelectByExample="true"enableDeleteByExample="true" enableDeleteByPrimaryKey="true" enableCountByExample="true"enableUpdateByExample="true"><!-- 類的屬性是否用數據庫中的真實字段名做為屬性名, 不指定這個屬性會自動轉換 _ 為駝峰命名規則 --><property name="useActualColumnNames" value="false" /><!-- 數據庫表主鍵 --><generatedKey column="id" sqlStatement="Mysql" identity="true" /></table><table tableName="book_info" domainObjectName="BookInfo" enableSelectByExample="true"enableDeleteByExample="true" enableDeleteByPrimaryKey="true" enableCountByExample="true"enableUpdateByExample="true"><!-- 類的屬性是否用數據庫中的真實字段名做為屬性名, 不指定這個屬性會自動轉換 _ 為駝峰命名規則 --><property name="useActualColumnNames" value="false" /><!-- 數據庫表主鍵 --><generatedKey column="id" sqlStatement="Mysql" identity="true" /></table></context>
</generatorConfiguration>
- targetRuntime="MyBatis3Simple":"MyBatis3Simple" 生成的 SQL 的 xml 語句比較簡單;"MyBatis3" 比較復雜。
- targetPackage="com.edu.generator.model":生成在哪個包。
- tableName="user_info":數據庫對應的表名。
- domainObjectName="BookInfo":對應的實體類名。
- <generatedKey column="id":主鍵名。
- <property name="useActualColumnNames" value="false" />:屬性名自動轉換成駝峰命名規則。
? ? ? ? 只生成實體類的版本:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration><!-- 一個數據庫一個context --><context id="MysqlTables" targetRuntime="MyBatis3Simple"><!-- 禁用自動生成的注釋 --><commentGenerator><property name="suppressDate" value="true"/><property name="suppressAllComments" value="true" /></commentGenerator><!-- 數據庫連接信息 --><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://127.0.0.1:3306/mybatis_test?serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true"userId="root"password="123456"></jdbcConnection><!-- 生成實體類配置 --><javaModelGenerator targetPackage="com.edu.mybatis.plus.model" targetProject="src/main/java" ><property name="enableSubPackages" value="false"/><property name="trimStrings" value="true"/></javaModelGenerator><!-- 移除SQL映射文件生成器(不生成Mapper XML) --><!-- 移除Java客戶端生成器(不生成Mapper接口) --><!-- 表配置 --><table tableName="user_info" domainObjectName="UserInfo"><property name="useActualColumnNames" value="false" /><generatedKey column="id" sqlStatement="Mysql" identity="true" /></table></context>
</generatorConfiguration>
3、生成代碼
? ? ? ? 在 maven 中運行插件,自動生成代碼:
? ? ? ? 生成的文件:
? ? ? ? 實體類把 getter、setter 都生成了,為了好看,可以調整為 @Data:
? ? ? ? Mapper 接口、xml 文件生成了一些基礎的數據庫操作。(不建議用,mxl 文件代碼太亂了,看著很復雜)
? ? ? ? 該插件的使用,需要配置很多東西,比如數據庫連接的信息,但是這些信息已經在 spring boot 的配置文件中配置過了,因此該插件還不夠方便。對于 mapper、xml 的編寫,Mybatis-plus 框架才是我們學習的重點。用用 MyBatis Generator 的實體類自動生成即可。
二、MyBatis-plus
? ? ? ? MyBatis-plus 在 MyBatis 的基礎上擴展功能,跟 MyBatis 不沖突。直接在 Spring Boot 項目的POM 文件中引入依賴即可。
? ? ? ? 官方文檔:
快速開始 | MyBatis-Plushttps://baomidou.com/getting-started/
1、快速上手
創建一個 Spring Boot 項目:
引入依賴:spring boot3 對應的版本
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.12</version>
</dependency>
配置數據庫連接信息(.yml)。
在啟動類中加入?@MapperScan,指定要掃描的 Mapper 文件路徑。或者每個 mapper 類加上 @Mapper,二選其一。
創建要操作的表對應的實體類。
編寫 Mapper 接口類:
2、簡單 CRUD 單元測試
(1)查
@Testpublic void testSelectAll() {System.out.println(("----- 查詢所有 ------"));List<UserInfo> userList = userInfoMapper.selectList(null);userList.forEach(System.out::println);}@Testvoid testSelectById(){System.out.println(("----- 按 主鍵 查詢 ------"));UserInfo userInfo = userInfoMapper.selectById(2);System.out.println(userInfo);}@Testvoid testSelectByIds(){System.out.println(("----- 按 主鍵 集合查詢 ------"));List<UserInfo> userInfos = userInfoMapper.selectByIds(List.of(1,2));userInfos.forEach(System.out::println);}
(2)增
@Testvoid testInsert(){System.out.println(("----- 插入一條數據 ------"));UserInfo userInfo = new UserInfo();userInfo.setUserName("Jay");userInfo.setPassword("Chou");int insert = userInfoMapper.insert(userInfo);System.out.println("影響行數:"+ insert);}
id 生成了隨機數:
想自增需要使用 @TableId 設置:
id 會從最大值 2 開始自增:
如果想修改最大值:表上右鍵 >> 設計表 >> 選項 修改
(3)改
@Testvoid testUpdate(){System.out.println(("----- 按 主鍵 更新一條數據 ------"));UserInfo userInfo = new UserInfo();userInfo.setId(2);userInfo.setUserName("lisi");userInfo.setDeleteFlag(1);userInfoMapper.updateById(userInfo);}
(4)刪
@Testvoid testDelete(){System.out.println(("----- 按 主鍵 刪除一條數據 ------"));userInfoMapper.deleteById(-2019921918);}
3、命名映射注解
? ? ? ? MyBatis-plus 如何將類名、屬性名與數據庫表、主鍵字段、普通字段對應:
- 根據實體類名推斷表名。(@TableName)
- 默認 id 屬性是主鍵。(@TableId)
- 駝峰規則的屬性名對應的蛇形命名,就是表字段。(@TableField)
- 如果 java 命名不符合自動對應的的規則,可以用注解進行綁定。
4、打印日志
? ? ? ? 把 mybatis 改成 mybatis-plus 即可:
mybatis-plus:configuration: # 配置打印 MyBatis ?志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5、自動生成代碼(了解)
參考:代碼生成器 | MyBatis-Plus
引入依賴:generator + 模板引擎
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.12</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>
自動生成代碼:
?public void test() {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/book_test?characterEncoding=utf8" +"&useSSL=false&allowPublicKeyRetrieval=true","root", "123456").globalConfig(builder -> builder.outputDir(Paths.get(System.getProperty("user.dir")) + "/src/main/java")).packageConfig(builder -> builder.parent("com.edu.mybatis.plus.generator").entity("entity").mapper("mapper").service("service").xml("mapper.xml")).strategyConfig(builder -> builder.entityBuilder().enableLombok()).templateEngine(new FreemarkerTemplateEngine()).execute();}?
6、復雜 CRUD 操作
(1)什么是條件構造器
? ? ? ? 條件構造器(Wrapper 類)允許鏈式構造條件(用 . 的方式直接引用條件構造方法),避免編寫復雜 SQL,同時減少?SQL 注入風險。
- AbstractWrapper:抽象類,提供 Wrapper 類共有的方法和屬性。
- QueryWrapper:構造查詢條件。
- UpdateWrapper:構造更新條件,可以不用構造實體類設置 set。
- LambdaQueryWrapper:基于 Lambda 表達式構造查詢條件。
- LambdaUpdateWrapper:基于 Lambda 表達式構造更新條件。
????????AbstractWrapper 實現了 Compare 接口,包含了各種條件構造器,比如大于、等于、模糊查詢等,這些操作是四種 Wrapper 共有的:(更多詳情參考官方文檔)
? ? ? ? (Lambda)QueryWrapper 和 (Lambda)UpdateWrapper 的不同之處就是紅框的部分。綠框是構造函數,其余方法都是差不多一樣的。
(2)QueryWrapper
? ? ? ? 增刪改查都能用?QueryWrapper 實現。
查詢:
SELECT id,user_name,password FROM user_info WHERE delete_flag = 0 AND user_name
LIKE "%min%"
@Testvoid testQueryWrapper(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.select("id", "user_name", "password").eq("delete_flag", 0).like("user_name", "min");List<UserInfo> userList = userInfoMapper.selectList(queryWrapper);userList.forEach(System.out::println);}
更新:需要構造實體類,設置修改值。
UPDATE user_info SET delete_flag=1 WHERE id < 3
@Testvoid testQueryWrapper2(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();UserInfo userInfo = new UserInfo();userInfo.setDeleteFlag(1);queryWrapper.lt("id", 3);userInfoMapper.update(userInfo, queryWrapper);}
刪:
DELETE FROM user_info WHERE user_name = Jay2
@Testvoid testQueryWrapper3(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.eq("user_name", "Jay2");userInfoMapper.delete(queryWrapper);}
(3)UpdateWrapper
更新:不用構造實體類,直接 set。
UPDATE user_info SET delete_flag=0 WHERE id IN (1,2)
@Testvoid testUpdateWrapper(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.set("delete_flag", 0).in("id", List.of(1,2));userInfoMapper.update(updateWrapper);}
直接 set sql 語句更新:
UPDATE user_info SET delete_flag=delete_flag+1 WHERE id IN (1,2)
@Testvoid testUpdateWrapper2(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.setSql("delete_flag = delete_flag + 1").in("id", List.of(1,2));userInfoMapper.update(updateWrapper);}
(4)LambdaQueryWrapper
? ? ? ? 字段名容易寫錯,Lambda 的版本就是用 實體類名::get屬性名來替代字段名字符串。
? ? ? ? 可以直接 new Lambda 版本,或者 new 普通版本再使用?lambda 方法轉為?Lambda 版本。
SQL:
SELECT id,user_name,password FROM user_info WHERE delete_flag = 0 AND user_name
LIKE "%min%"
@Testvoid testLambdaQueryWrapper(){
// LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<>();QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().select(UserInfo::getId, UserInfo::getUserName, UserInfo::getPassword).eq(UserInfo::getDeleteFlag, 0).like(UserInfo::getUserName, "min");List<UserInfo> userList = userInfoMapper.selectList(queryWrapper);userList.forEach(System.out::println);}
(5)LambdaUpdateWrapper
SQL:
UPDATE user_info SET delete_flag=0 WHERE id IN (1,2)
@Testvoid testLambdaUpdateWrapper(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.lambda().set(UserInfo::getDeleteFlag, 1).in(UserInfo::getId, List.of(1,2));userInfoMapper.update(updateWrapper);}
setIncrBy:遞增
setDecrBy:遞減
示例:
UPDATE user_info SET delete_flag = delete_flag + 1
@Testvoid testLambdaUpdateWrapper(){UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<>();updateWrapper.lambda().set(UserInfo::getDeleteFlag, 1).in(UserInfo::getId, List.of(1,2));userInfoMapper.update(updateWrapper);}
(6)自定義 SQL
? ? ? ? MyBatis-plus 框架提供的操作不能滿足所有的需求,我們可以利用 Wrapper 構造條件,在 Mapper 自定義 SQL。
- 條件構造器傳參:參數名 ew 或者重命名?@Param(Constants.WRAPPER)。
- 構造器使用:${ew.customSqlSegment} 引用。
SQL:
select id,username,password FROM user_info WHERE user_name = "admin"
注解方式:
@Select("SELECT id, user_name, password FROM user_info ${ew.customSqlSegment}")UserInfo selectByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
XML 方式:
<select id="selectByCustom2" resultType="com.edu.mybatis.plus.model.UserInfo">SELECT id, user_name, password FROM user_info ${ew.customSqlSegment}</select>
測試代碼:
@Testvoid testSelectByCustom(){QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();queryWrapper.lambda().eq(UserInfo::getUserName, "admin");userInfoMapper.selectByCustom(queryWrapper);}