日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Mybatis-Plus 详解

發布時間:2024/5/14 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mybatis-Plus 详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. Mybatis-Plus概念

1.1 Mybatis-Plus介紹

官?: https://mybatis.plus/ https://mp.baomidou.com/ Mybatis-Plus 介紹 MyBatis-Plus (簡稱 MP )是?個 MyBatis 的增強?具,在 MyBatis 的基礎上只做增強不做改變,-為簡化開發、提?效率??。

愿景 我們的愿景是成為 MyBatis 最好的搭檔,就像 魂?羅 中的 1P 2P ,基友搭配,效率翻倍。

1.2 特性

  • ?侵?:只做增強不做改變,引?它不會對現有?程產?影響,如絲般順滑
  • 損耗?:啟動即會?動注?基本 CURD,性能基本?損耗,直接?向對象操作
  • 強?的 CRUD 操作:內置通? Mapper、通? Service,僅僅通過少量配置即可實現單表?部分CRUD 操作,更有強?的條件構造器,滿?各類使?需求
  • ?持 Lambda 形式調?:通過 Lambda 表達式,?便的編寫各類查詢條件,?需再擔?字段寫錯
  • ?持主鍵?動?成:?持多達 4 種主鍵策略(內含分布式唯? ID ?成器 - Sequence),可?由配置,完美解決主鍵問題
  • ?持 ActiveRecord 模式:?持 ActiveRecord 形式調?,實體類只需繼承 Model 類即可進?強?的 CRUD 操作
  • ?持?定義全局通?操作:?持全局通??法注?( Write once, use anywhere
  • 內置代碼?成器:采?代碼或者 Maven 插件可快速?成 Mapper Model Service Controller 層代碼,?持模板引擎,更有超多?定義配置等您來使?
  • 內置分?插件:基于 MyBatis 物理分?,開發者?需關?具體操作,配置好插件之后,寫分?等同于普通 List 查詢
  • 分?插件?持多種數據庫:?持 MySQLMariaDBOracleDB2H2HSQLSQLitePostgreSQLServer 等多種數據庫
  • 內置性能分析插件:可輸出 Sql 語句以及其執?時間,建議開發測試時啟?該功能,能快速揪出慢查詢
  • 內置全局攔截插件:提供全表 delete update 操作智能分析阻斷,也可?定義攔截規則,預防誤操作

1.3 架構

1.4 作者

Mybatis-Plus 是由 baomidou (苞??)組織開發并且開源的,?前該組織?概有 30 ?左右。 碼云地址: https://gitee.com/organizations/baomidou

2. Mybatis-Plus快速??

2.1 安裝

全新的 MyBatis-Plus 3.0 版本基于 JDK8 ,提供了 lambda 形式的調?,所以安裝集成 MP3.0 要求 如下:
  • JDK 8+
  • Maven or Gradle
Release Spring Boot Maven <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.0</version> </dependency> Spring MVC Maven: <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.4.0</version> </dependency> 對于 Mybatis 整合 MP 有常常有三種?法,分別是 Mybatis+MP Spring+Mybatis+MP Spring Boot+Mybatis+MP

2.2 創建數據庫以及表

創建 User 表,其表結構如下:

-- 創建測試表 DROP TABLE IF EXISTS tb_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) ); -- 插?測試數據 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');

2.3 創建?程

?導?依賴:

<dependencies><!-- mybatis-plus插件依賴 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.1.1</version></dependency><!--Mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!--連接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.11</version></dependency><!--簡化bean代碼的?具包--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.4</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.6.4</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build>

2.4 Mybatis + MP

下?演示,通過純 Mybatis Mybatis-Plus 整合。 創建? Module <?xml version="1.0" encoding="UTF-8" ?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>lagou-mybatis-plus</artifactId><groupId>com.lagou.mp</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>lagou-mybatis-plus-simple</artifactId> </project> log4j.properties log4j.rootLogger=DEBUG,A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n Mybatis 實現查詢 User 第?步,編寫 mybatis-config.xml ?件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><properties resource="jdbc.properties"></properties><!--environments: 運?環境--><environments default="development"><environment id="development"><!--當前的事務事務管理器是JDBC--><transactionManager type="JDBC"></transactionManager><!--數據源信息 POOLED:使?mybatis的連接池--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!--引?映射配置?件--><mappers><mapper resource="mapper/UserMapper.xml"></mapper></mappers> </configuration> 第?步,編寫 User 實體對象:(這?使? lombok 進?了進化 bean 操作) @Data // getter setter @toString @NoArgsConstructor @AllArgsConstructor public class User {private Long id;private String name;private Integer age;private String email; } 第三步,編寫 UserMapper 接?: public interface UserMapper {List<User> findAll(); } 第四步,編寫 UserMapper.xml ?件: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.lagou.mapper.UserMapper"><!-- 查詢所有 --><select id="findAll" resultType="com.lagou.pojo.User">select * from user</select> </mapper> 第五步,編寫 TestMybatis 測試?例: public class MPTest {@Testpublic void test1() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> all = mapper.findAll();for (User user : all) {System.out.println(user);}} } 測試結果: User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com) 注:如果實體類名稱和表名稱不?致,可以在實體類上添加注解 @TableName(" 指定數據庫表名 ") Mybatis+MP 實現查詢 User 第?步,將 UserMapper 繼承 BaseMapper ,將擁有了 BaseMapper 中的所有?法: import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.lagou.pojo.User; public interface UserMapper extends BaseMapper<User> { } 第?步,使? MP 中的 MybatisSqlSessionFactoryBuilder 進程構建: @Test public void test2() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml");//這?使?的是MP中的MybatisSqlSessionFactoryBuilderSqlSessionFactory sqlSessionFactory = new MybatisSqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 可以調?BaseMapper中定義的?法List<User> all = mapper.selectList(null);for (User user : all) {System.out.println(user);} } 測試: User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com) 注:如果實體類名稱和表名稱不?致,可以在實體類上添加注解 @TableName(" 指定數據庫表名 ") 簡單說明:
  • 由于使?了 MybatisSqlSessionFactoryBuilder進?了構建,繼承的BaseMapper中的?法就載?到了SqlSession中,所以就可以直接使?相關的?法;
  • 如圖

2.5 Spring + Mybatis + MP

引?了 Spring 框架,數據源、構建等?作就交給了 Spring 管理。 創建? Module <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>lagou-mybatis-plus</artifactId><groupId>com.lagou.mp</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>lagou-mybatis-plus-spring</artifactId><properties><spring.version>5.1.6.RELEASE</spring.version></properties><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency></dependencies> 實現查詢 User 第?步,編寫 jdbc.properties jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/mp?serverTimezone=GMT%2B8&useSSL=false jdbc.username=root jdbc.password=root 第?步,編寫 applicationContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--引?properties--><context:property-placeholder location="classpath:jdbc.properties"/><!--dataSource--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><!--這?使?MP提供的sqlSessionFactory,完成spring與mp的整合--><bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" ><property name="dataSource" ref="dataSource"/></bean><!--掃描mapper接?,使?的依然是mybatis原?的掃描器--><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.lagou.mapper"/></bean> </beans> 第三步,編寫 User 對象以及 UserMapper 接?: @Data @NoArgsConstructor @AllArgsConstructor public class User {private Long id;private String name;private Integer age;private String email; } public interface UserMapper extends BaseMapper<User> {List<User> findAll(); } 第四步,編寫測試?例: @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:applicationContext.xml") public class TestSpringMP {@Autowiredprivate UserMapper userMapper;@Testpublic void test2() throws IOException {List<User> users = this.userMapper.selectList(null);for (User user : users) {System.out.println(user);}}

2.6 SpringBoot + Mybatis + MP

使? SpringBoot 將進?步的簡化 MP 的整合,需要注意的是,由于使? SpringBoot 需要繼承 parent ,所以需要重新創建?程,并不是創建?Module 創建?程

導?依賴 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--簡化代碼的?具包--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--mybatis-plus的springboot?持--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.1</version></dependency><!--mysql驅動--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> log4j.properties log4j.rootLogger=DEBUG,A1 log4j.appender.A1=org.apache.log4j.ConsoleAppender log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout.ConversionPattern=[%t] [%c]-[%p] %m%n

編寫application.properties

spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mp? useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=tr ue&useSSL=false spring.datasource.username=root spring.datasource.password=root

編寫pojo

@Data @NoArgsConstructor @AllArgsConstructor public class User {private Long id;private String name;private Integer age;private String email; } 編寫 mapper public interface UserMapper extends BaseMapper<User> { } 編寫啟動類 package com.lagou.mp; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; @MapperScan("com.lagou.mp.mapper") //設置mapper接?的掃描包 @SpringBootApplication public class MyApplication {public static void main(String[] args) {SpringApplication.run(MyApplication.class, args);} }

編寫測試?例

package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelect() {List<User> userList = userMapper.selectList(null);for (User user : userList) {System.out.println(user);}} } 測試: User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com)

3. 通?CRUD

通過前?的學習,我們了解到通過繼承 BaseMapper 就可以獲取到各種各樣的單表操作,接下來我們將詳細講解這些操作。

3.1 插?操作

?法定義 /*** 插??條記錄** @param entity 實體對象.*/int insert(T entity); 測試?例 @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testInsert(){User user = new User();user.setAge(18);user.setEmail("test@lagou.cn");user.setName("?慕");//返回的result是受影響的?數,并不是?增后的idint result = userMapper.insert(user);System.out.println(result);System.out.println(user.getId());} } 測試 1 1318744682116739074 可以看到,數據已經寫?到了數據庫,但是, id 的值不正確,我們期望的是數據庫?增?,實際是 MP ? 成了 id 的值寫?到了數據庫。 如何設置 id 的?成策略呢? MP ?持的 id 策略: package com.baomidou.mybatisplus.annotation; import lombok.Getter; /** * ?成ID類型枚舉類 * * @author hubin * @since 2015-11-10 */ @Getter public enum IdType {/*** 數據庫ID?增*/AUTO(0),/*** 該類型為未設置主鍵類型*/NONE(1),/*** ?戶輸?ID* <p>該類型可以通過??注冊?動填充插件進?填充</p>*/INPUT(2),/* 以下3種類型、只有當插?對象ID 為空,才?動填充。 *//*** 全局唯?ID (idWorker)*/ID_WORKER(3),/*** 全局唯?ID (UUID)*/UUID(4),/*** 字符串全局唯?ID (idWorker 的字符串表示)*/ID_WORKER_STR(5);private final int key;IdType(int key) {this.key = key;} }

修改 User 對象: package com.lagou.mp.pojo; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor @TableName("tb_user") public class User {@TableId(type = IdType.AUTO) //指定id類型為?增?private Long id;private String userName;private String password;private String name;private Integer age;private String email; } 數據插?成功:

@TableField MP 中通過 @TableField 注解可以指定字段的?些屬性,常常解決的問題有 2 個: 1 、對象中的屬性名和字段名不?致的問題(?駝峰) 2 、對象中的屬性字段在表中不存在的問題 使?:

?其他?法,如?字段不加?查詢字段:

?效果:

3.2 更新操作

MP 中,更新操作有 2 種,?種是根據 id 更新,另?種是根據條件更新。 根據 id 更新 ?法定義: /*** 根據 ID 修改** @param entity 實體對象*/int updateById(@Param(Constants.ENTITY) T entity); 測試: @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testUpdateById() {User user = new User();user.setId(6L); //主鍵user.setAge(21); //更新的字段//根據id更新,更新不為null的字段this.userMapper.updateById(user);} } 結果:

根據條件更新 ?法定義: /*** 根據 whereEntity 條件,更新記錄** @param entity 實體對象 (set 條件值,可以為 null)* @param updateWrapper 實體對象封裝操作類(可以為 null,??的 entity ?于?成 where 語句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import net.minidev.json.writer.UpdaterMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testUpdate() {User user = new User();user.setAge(22); //更新的字段//更新的條件QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("id", 6);//執?更新操作int result = this.userMapper.update(user, wrapper);System.out.println("result = " + result);} } 或者,通過 UpdateWrapper 進?更新: @Testpublic void testUpdate() {//更新的條件以及字段UpdateWrapper<User> wrapper = new UpdateWrapper<>();wrapper.eq("id", 6).set("age", 23);//執?更新操作int result = this.userMapper.update(null, wrapper);System.out.println("result = " + result);} 測試結果: [main] [com.lagou.mp.mapper.UserMapper.update]-[DEBUG] == > Preparing: UPDATE tb_user SET age = ? WHERE id = ? [main] [com.lagou.mp.mapper.UserMapper.update]-[DEBUG] == > Parameters: 23 (Integer), 6 (Integer) [main] [com.lagou.mp.mapper.UserMapper.update]-[DEBUG] < == Updates: 1 均可達到更新的效果。 關于 wrapper 更多的?法后?會詳細講解。

3.3 刪除操作

deleteById ?法定義: /** * 根據 ID 刪除 * * @param id 主鍵ID */ int deleteById(Serializable id); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteById() {//執?刪除操作int result = this.userMapper.deleteById(6L);System.out.println("result = " + result);} }

結果:

[main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] == > Preparing: DELETE FROM tb_user WHERE id = ? [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] == > Parameters: 6 (Long) [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] < == Updates: 1 數據被刪除。 deleteByMap ?法定義: /*** 根據 columnMap 條件,刪除記錄** @param columnMap 表字段 map 對象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.HashMap; import java.util.Map; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteByMap() {Map<String, Object> columnMap = new HashMap<>();columnMap.put("age",21);columnMap.put("name","?慕");//將columnMap中的元素設置為刪除的條件,多個之間為and關系int result = this.userMapper.deleteByMap(columnMap);System.out.println("result = " + result);} }

結果:

[main] [com.lagou.mp.mapper.UserMapper.deleteByMap]-[DEBUG] == > Preparing: DELETE FROM tb_user WHERE name = ? AND age = ? [main] [com.lagou.mp.mapper.UserMapper.deleteByMap]-[DEBUG] == > Parameters: ? (String), 21 (Integer) [main] [com.lagou.mp.mapper.UserMapper.deleteByMap]-[DEBUG] < == Updates: 0 delete ?法定義: /** * 根據 entity 條件,刪除記錄 * * @param wrapper 實體對象封裝操作類(可以為 null) */ int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; 結果: 3.3.4、deleteBatchIds ?法定義: import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.HashMap; import java.util.Map; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteByMap() {User user = new User();user.setAge(20);user.setName("?慕");//將實體對象進?包裝,包裝為操作條件QueryWrapper<User> wrapper = new QueryWrapper<>(user);int result = this.userMapper.delete(wrapper);System.out.println("result = " + result);} }

結果:

[main] [com.lagou.mp.mapper.UserMapper.delete]-[DEBUG] == > Preparing: DELETE FROM tb_user WHERE name = ? AND age = ? [main] [com.lagou.mp.mapper.UserMapper.delete]-[DEBUG] == > Parameters: ?慕 (String), 20 (Integer) [main] [com.lagou.mp.mapper.UserMapper.delete]-[DEBUG] < == Updates: 0

3.3.4deleteBatchIds

?法定義: /*** 刪除(根據ID 批量刪除)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testDeleteByMap() {//根據id集合批量刪除int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));System.out.println("result = " + result);} } 結果: [main] [com.lagou.mp.mapper.UserMapper.deleteBatchIds]-[DEBUG] == > Preparing: DELETE FROM tb_user WHERE id IN ( ? , ? , ? ) [main] [com.lagou.mp.mapper.UserMapper.deleteBatchIds]-[DEBUG] == > Parameters: 1 (Long), 10 (Long), 20 (Long) [main] [com.lagou.mp.mapper.UserMapper.deleteBatchIds]-[DEBUG] < == Updates: 1

3.4 查詢操作

MP 提供了多種查詢操作,包括根據 id 查詢、批量查詢、查詢單條數據、查詢列表、分?查詢等操作。

3.4.1selectById

?法定義: /*** 根據 ID 查詢** @param id 主鍵ID*/T selectById(Serializable id); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectById() {//根據id查詢數據User user = this.userMapper.selectById(2L);System.out.println("result = " + user);} } 結果: result = User (id = 2 , name = Jack, age = 20 , email = test2@baomidou.com)

3.4.2selectBatchIds

?法定義: /** * 查詢(根據ID 批量查詢) * * @param idList 主鍵ID列表(不能為 null 以及 empty) */ List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectBatchIds() {//根據id集合批量查詢List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 10L));for (User user : users) {System.out.println(user);}} } 結果: User (id = 2 , name = Jack, age = 20 , email = test2@baomidou.com) User (id = 3 , name = Tom, age = 28 , email = test3@baomidou.com)

3.4.3selectOne

?法定義: /** * 根據 entity 條件,查詢?條記錄 * * @param queryWrapper 實體對象封裝操作類(可以為 null) */ T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectOne() {QueryWrapper<User> wrapper = new QueryWrapper<User>();wrapper.eq("name", "jack");//根據條件查詢?條數據,如果結果超過?條會報錯User user = this.userMapper.selectOne(wrapper);System.out.println(user);} } 結果: User (id = 2 , name = Jack, age = 20 , email = test2@baomidou.com)

3.4.4selectCount

?法定義: /** * 根據 Wrapper 條件,查詢總記錄數 * * @param queryWrapper 實體對象封裝操作類(可以為 null) */ Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectCount() {QueryWrapper<User> wrapper = new QueryWrapper<User>();wrapper.gt("age", 23); //年齡?于23歲//根據條件查詢數據條數Integer count = this.userMapper.selectCount(wrapper);System.out.println("count = " + count);} } 結果: count = 2

3.4.5selectList

?法定義: /** * 根據 entity 條件,查詢全部記錄 * * @param queryWrapper 實體對象封裝操作類(可以為 null) */ List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectList() {QueryWrapper<User> wrapper = new QueryWrapper<User>();wrapper.gt("age", 23); //年齡?于23歲//根據條件查詢數據List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println("user = " + user);}} } 結果: user = User (id = 3 , name = Tom, age = 28 , email = test3@baomidou.com) user = User (id = 5 , name = Billie, age = 24 , email = test5@baomidou.com)

3.4.6selectPage

?法定義: /** * 根據 entity 條件,查詢全部記錄(并翻?) * * @param page 分?查詢條件(可以為 RowBounds.DEFAULT) * @param queryWrapper 實體對象封裝操作類(可以為 null) */ IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); 配置分?插件: package com.lagou.mp; import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @MapperScan("com.lagou.mp.mapper") //設置mapper接?的掃描包 public class MybatisPlusConfig {/*** 分?插件*/@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor();} } 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectPage() {QueryWrapper<User> wrapper = new QueryWrapper<User>();wrapper.gt("age", 20); //年齡?于20歲Page<User> page = new Page<>(1,1);//根據條件查詢數據IPage<User> iPage = this.userMapper.selectPage(page, wrapper);System.out.println("數據總條數:" + iPage.getTotal());System.out.println("總?數:" + iPage.getPages());List<User> users = iPage.getRecords();for (User user : users) {System.out.println("user = " + user);}} }

結果:

數據總條數: 4 總?數: 4 user = User (id = 3 , name = Tom, age = 28 , email = test3@baomidou.com)

3.5 SQL注?的原理

前?我們已經知道, MP 在啟動后會將 BaseMapper 中的?系列的?法注冊到 meppedStatements 中, 那么究竟是如何注?的呢?流程?是怎么樣的?下?我們將?起來分析下。 MP 中, ISqlInjector 負責 SQL 的注??作,它是?個接?, AbstractSqlInjector 是它的實現類,實現關系如下:

AbstractSqlInjector 中,主要是由 inspectInject() ?法進?注?的,如下: @Override public void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {Class<?> modelClass = extractModelClass(mapperClass);if (modelClass != null) {String className = mapperClass.toString();Set<String> mapperRegistryCache = GlobalConfigUtils.getMapperRegistryCache(builderAssistant.getConfiguration());if (!mapperRegistryCache.contains(className)) {List<AbstractMethod> methodList = this.getMethodList();if (CollectionUtils.isNotEmpty(methodList)) {TableInfo tableInfo = TableInfoHelper.initTableInfo(builderAssistant, modelClass);// 循環注??定義?法methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo));} else {logger.debug(mapperClass.toString() + ", No effective injection method was found.");}mapperRegistryCache.add(className);}} } 在實現?法中, methodList.forEach(m -> m.inject(builderAssistant, mapperClass, modelClass, tableInfo)); 是關鍵,循環遍歷?法,進?注?。 最終調?抽象?法 injectMappedStatement 進?真正的注?: /*** 注??定義 MappedStatement** @param mapperClass mapper 接?* @param modelClass mapper 泛型* @param tableInfo 數據庫表反射信息* @return MappedStatement*/public abstract MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo); 查看該?法的實現:

SelectById 為例查看: public class SelectById extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<? > modelClass, TableInfo tableInfo) {SqlMethod sqlMethod = SqlMethod.LOGIC_SELECT_BY_ID;SqlSource sqlSource = new RawSqlSource(configuration, String.format(sqlMethod.getSql(),sqlSelectColumns(tableInfo, false),tableInfo.getTableName(), tableInfo.getKeyColumn(), tableInfo.getKeyProperty(),tableInfo.getLogicDeleteSql(true, false)), Object.class);return this.addSelectMappedStatement(mapperClass, sqlMethod.getMethod(), sqlSource, modelClass, tableInfo);} } 可以看到,?成了 SqlSource 對象,再將 SQL 通過 addSelectMappedStatement ?法添加到meppedStatements中。

4. 配置

MP 中有?量的配置,其中有?部分是 Mybatis 原?的配置,另?部分是 MP 的配置,詳情: https://m ybatis.plus/config/ 下?我們對常?的配置做講解。

4.1、基本配置

4.1.1configLocation

MyBatis 配置?件位置,如果有單獨的 MyBatis 配置,請將其路徑配置到 configLocation 中。 MyBatis Configuration 的具體內容請參考 MyBatis 官??檔 Spring Boot mybatis-plus.config-location = classpath:mybatis-config.xml

Spring MVC

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" ><property name="configLocation" value="classpath:mybatis-config.xml"/> </bean>

4.1.2mapperLocations

MyBatis Mapper 所對應的 XML ?件位置,如果您在 Mapper 中有?定義?法( XML 中有?定義實現),需要進?該配置,告訴 Mapper 所對應的 XML ?件位置。 Spring Boot mybatis-plus.mapper-locations = classpath*:mybatis/*.xml Spring MVC <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" ><property name="mapperLocations" value="classpath*:mybatis/*.xml"/> </bean> Maven 多模塊項?的掃描路徑需以 classpath*: 開頭 (即加載多個 jar 包下的 XML ?件) 測試: UserMapper.xml <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.lagou.mp.mapper.UserMapper"><select id="findById" resultType="com.lagou.mp.pojo.User">select * from tb_user where id = #{id}</select> </mapper> package com.lagou.mp.mapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.mapper.BaseMapper; public interface UserMapper extends BaseMapper<User> {User findById(Long id); } 測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSelectPage() {User user = this.userMapper.findById(2L);System.out.println(user);} } 運?結果:

4.1.3typeAliasesPackage ?

MyBaits 別名包掃描路徑,通過該屬性可以給包中的類注冊別名,注冊后在 Mapper 對應的 XML ?件中可以直接使?類名,?不?使?全限定的類名(即 XML 中調?的時候不?包含包名)。 Spring Boot mybatis-plus.type-aliases-package = com.lagou.mp.pojo Spring MVC <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" ><property name="typeAliasesPackage" value="com.baomidou.mybatisplus.samples.quickstart.entity"/> </bean>

4.2、進階配置

本部分( Configuration )的配置?都為 MyBatis 原??持的配置,這意味著您可以通過 MyBatis XML配置?件的形式進?配置。

4.2.1mapUnderscoreToCamelCase

  • 類型: boolean
  • 默認值: true
是否開啟?動駝峰命名規則( camel case )映射,即從經典數據庫列名 A_COLUMN (下劃線命名) 到經典 Java 屬性名 aColumn (駝峰命名) 的類似映射。 注意: 此屬性在 MyBatis 中原默認值為 false ,在 MyBatis-Plus 中,此屬性也將?于?成最終的 SQL 的select body 如果您的數據庫命名符合規則?需使? @TableField 注解指定數據庫字段名 示例( SpringBoot ): ? #關閉?動駝峰映射,該參數不能和mybatis-plus.config-location同時存在 mybatis-plus.configuration.map-underscore-to-camel-case=false

4.2.2cacheEnabled

  • 類型: boolean
  • 默認值: true
全局地開啟或關閉配置?件中的所有映射器已經配置的任何緩存,默認為 true 示例: mybatis-plus.configuration.cache-enabled=false

4.3DB 策略配置

4.3.1idType

  • 類型: com.baomidou.mybatisplus.annotation.IdType
  • 默認值: ID_WORKER
全局默認主鍵類型,設置后,即可省略實體對象中的 @TableId(type = IdType.AUTO) 配置。 示例: SpringBoot mybatis-plus.global-config.db-config.id-type=auto SpringMVC <!--這?使?MP提供的sqlSessionFactory,完成了Spring與MP的整合--><bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" ><property name="dataSource" ref="dataSource"/><property name="globalConfig"><bean class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><property name="idType" value="AUTO"/></bean></property></bean></property></bean>

4.3.2tablePrefix

  • 類型: String
  • 默認值: null
表名前綴,全局配置后可省略 @TableName() 配置。 SpringBoot mybatis-plus.global-config.db-config.table-prefix=tb_ SpringMVC <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean" ><property name="dataSource" ref="dataSource"/><property name="globalConfig"><bean class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><property name="idType" value="AUTO"/><property name="tablePrefix" value="tb_"/></bean></property></bean></property></bean>

5. 條件構造器

MP 中, Wrapper 接?的實現類關系如下:

可以看到, AbstractWrapper AbstractChainWrapper 是重點實現,接下來我們重點學習 AbstractWrapper 以及其?類。 說明 : QueryWrapper(LambdaQueryWrapper) UpdateWrapper(LambdaUpdateWrapper) 的?類 ?于?成 sql where 條件 , entity 屬性也?于?成 sql where 條件 注意 : entity ?成的 where 條件與 使?各個 api ?成的 where 條件 沒有任何關聯?為 官??檔地址: https://mybatis.plus/guide/wrapper.html

5.1allEq

5.1.1、說明

allEq(Map<R, V> params) allEq(Map<R, V> params, boolean null2IsNull) allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
  • 全部eq(或個別isNull)
個別參數說明 : params : key 為數據庫字段名 , value 為字段值 null2IsNull : true 則在 map value null 時調? isNull ?法 , false 時則忽 value null 1: allEq({id:1,name:" ?王 ",age:null}) ---> id = 1 and name = ' ?王 ' and age is null 2: allEq({id:1,name:" ?王 ",age:null}, false) ---> id = 1 and name = ' ?王 ' allEq(BiPredicate<R, V> filter, Map<R, V> params) allEq(BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) allEq(boolean condition, BiPredicate<R, V> filter, Map<R, V> params, boolean null2IsNull) 個別參數說明 : filter : 過濾函數 , 是否允許字段傳??對條件中 params null2IsNull : 同上 1: allEq((k,v) -> k.indexOf("a") > 0, {id:1,name:" ?王 ",age:null}) --- > name = ' ?王 ' and age is null 2: allEq((k,v) -> k.indexOf("a") > 0, {id:1,name:" ?王 ",age:null}, false) ---> name = ' ?王 '

5.1.2、測試?例

package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.HashMap; import java.util.List; import java.util.Map;@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testWrapper() {QueryWrapper<User> wrapper = new QueryWrapper<>();//設置條件Map<String,Object> params = new HashMap<>();params.put("name", "jack");params.put("age", "20"); // wrapper.allEq(params);//SELECT * FROM tb_user WHERE password IS NULL AND name = ? AND age = ? // wrapper.allEq(params,false); //SELECT * FROM tb_user WHERE name = ? AND age = ? // wrapper.allEq((k, v) -> (k.equals("name") || k.equals("age")) ,params);//SELECT * FROM tb_user WHERE name = ? AND age = ?List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println(user);}} }

5.2、基本?較操作

  • eq
    • 等于 =
  • ne
    • 不等于 <>
  • gt
    • ?于 >
  • ge
    • ?于等于 >=
  • lt
    • ?于 <
  • le
    • ?于等于 <=
  • between
    • BETWEEN 1 AND 2
  • notBetween
    • NOT BETWEEN 1 AND 2
  • in
    • 字段 IN (value.get(0), value.get(1), ...)
  • notIn
    • 字段 NOT IN (v0, v1, ...)
測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;QueryWrapper<User> wrapper = new QueryWrapper<>();//SELECT id,name,age,email FROM tb_user WHERE password = ? AND age >= ? AND name IN (?,?,?)wrapper.eq("email", "test2@baomidou.com").ge("age", 20).in("name", "jack", "jone", "tom");List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println(user);}} }

5.3、模糊查詢

  • like
    • LIKE '%值%'
    • 例: like("name", "") ---> name like '%%'
  • notLike
    • NOT LIKE '%%'
    • : notLike("name", "") ---> name not like '%%'
  • likeLeft
    • LIKE '%'
    • : likeLeft("name", "") ---> name like '%'
  • likeRight
    • LIKE '%'
    • : likeRight("name", "") ---> name like '%'
測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testWrapper() {QueryWrapper<User> wrapper = new QueryWrapper<>();//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name LIKE ?//Parameters: %?%(String)wrapper.like("name", "?");List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println(user);}} }

5.4、排序

  • orderBy
    • 排序:ORDER BY 字段, ...
    • : orderBy(true, true, "id", "name") ---> order by id ASC,name ASC
  • orderByAsc
    • 排序:ORDER BY 字段, ... ASC
    • : orderByAsc("id", "name") ---> order by id ASC,name ASC
  • orderByDesc
    • 排序:ORDER BY 字段, ... DESC
    • : orderByDesc("id", "name") ---> order by id DESC,name DESC
測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testWrapper() {QueryWrapper<User> wrapper = new QueryWrapper<>();//SELECT id,user_name,password,name,age,email FROM tb_user ORDER BY age DESCwrapper.orderByDesc("age");List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println(user);}} }

5.5、邏輯查詢

  • or
    • 拼接 OR
    • 主動調? or 表示緊接著下?個?法不是? and 連接!(不調? or 則默認為使? and 連接)
  • and
    • AND 嵌套
    • : and(i -> i.eq("name", "李?").ne("status", "活著")) ---> and (name = '?' and status <> '活著')
測試?例: package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testWrapper() {QueryWrapper<User> wrapper = new QueryWrapper<>();//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name= ? OR age = ?wrapper.eq("name","jack").or().eq("age", 24);List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println(user);}} }

5.6select

MP 查詢中,默認查詢所有的字段,如果有需要也可以通過 select ?法進?指定字段。 package com.lagou.mp; import com.lagou.mp.mapper.UserMapper; import com.lagou.mp.pojo.User; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testWrapper() {QueryWrapper<User> wrapper = new QueryWrapper<>();//SELECT id,name,age FROM tb_user WHERE name = ? OR age = ?wrapper.eq("name", "jack").or().eq("age", 24).select("id", "name", "age");List<User> users = this.userMapper.selectList(wrapper);for (User user : users) {System.out.println(user);}} }

6. ActiveRecord

ActiveRecord (簡稱 AR )?直?受動態語?( PHP Ruby 等)的喜愛,? Java 作為準靜態語?,對于 ActiveRecord 往往只能感嘆其優雅,所以我們也在 AR 道路上進?了?定的探索,希望?家能夠喜歡。? 什么是 ActiveRecord ActiveRecord 也屬于 ORM (對象關系映射)層,由 Rails 最早提出,遵循標準的 ORM 模型:表映射到記錄,記錄映射到對象,字段映射到對象屬性。配合遵循的命名和配置慣例,能夠很?程度的快速實現模型的操作,?且簡潔易懂。 ActiveRecord 的主要思想是:
  • 每?個數據庫表對應創建?個類,類的每?個對象實例對應于數據庫中表的??記錄;通常 表的每個字段在類中都有相應的Field
  • ActiveRecord同時負責把??持久化,在ActiveRecord中封裝了對數據庫的訪問,即 CURD;
  • ActiveRecord是?種領域模型(Domain Model),封裝了部分業務邏輯;

6.1、開啟AR之旅

MP 中,開啟 AR ?常簡單,只需要將實體對象繼承 Model 即可。 package com.lagou.mp.pojo; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor public class User extends Model<User> {private Long id;private String userName;private String password;private String name;private Integer age;private String email; }

6.2、根據主鍵查詢

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testAR() {User user = new User();user.setId(2L);User user2 = user.selectById();System.out.println(user2);} }

6.3、新增數據

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testARInsert() {User user = new User();user.setName("應顛");user.setAge(30);user.setEmail("yingdian@lagou.cn");boolean insert = user.insert();System.out.println(insert);} } [main] [com.lagou.mp.mapper.UserMapper.insert]-[DEBUG] == > Preparing: INSERT INTO tb_user ( name, age, email ) VALUES ( ?, ?, ?, ?, ? ) [main] [com.lagou.mp.mapper.UserMapper.insert]-[DEBUG] == > Parameters: 應癲 (String), 30 (Integer), liubei@lagou.cn(String) [main] [com.lagou.mp.mapper.UserMapper.insert]-[DEBUG] < == Updates: 1

6.4、更新操作

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testAR() {User user = new User();user.setId(8L);user.setAge(35);boolean update = user.updateById();System.out.println(update);} } 結果: [main] [com.lagou.mp.mapper.UserMapper.updateById]-[DEBUG] == > Preparing: UPDATE tb_user SET age = ? WHERE id = ? [main] [com.lagou.mp.mapper.UserMapper.updateById]-[DEBUG] == > Parameters: 35 (Integer), 8 (Long) [main] [com.lagou.mp.mapper.UserMapper.updateById]-[DEBUG] < == Updates: 1

6.5、刪除操作

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testAR() {User user = new User();user.setId(7L);boolean delete = user.deleteById();System.out.println(delete);} }

結果:

[main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] == > Preparing: DELETE FROM tb_user WHERE id = ? [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] == > Parameters: 7 (Long) [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] < == Updates: 1

6.6、根據條件查詢

@RunWith(SpringRunner.class) @SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testARFindById() {User user = new User();QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();userQueryWrapper.le("age","20");List<User> users = user.selectList(userQueryWrapper);for (User user1 : users) {System.out.println(user1);}} } 結果: User (id = 1 , name = Jone, age = 18 , email = test1@baomidou.com) User (id = 2 , name = Jack, age = 20 , email = test2@baomidou.com) User (id = 7 , name = ?慕 , age = 18 , email = test@lagou.cn)

7. 插件

7.1mybatis的插件機制

MyBatis 允許你在已映射語句執?過程中的某?點進?攔截調?。默認情況下, MyBatis 允許使?插件 來攔截的?法調?包括: 1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) 2. ParameterHandler (getParameterObject, setParameters) 3. ResultSetHandler (handleResultSets, handleOutputParameters) 4. StatementHandler (prepare, parameterize, batch, update, query) 我們看到了可以攔截 Executor 接?的部分?法,?如 update query commit rollback 等?法,還有其他接?的?些?法等。 總體概括為: 1. 攔截執?器的?法 2. 攔截參數的處理 3. 攔截結果集的處理 4. 攔截 Sql 語法構建的處理 攔截器示例: package com.lagou.mp.plugins; import org.apache.ibatis.executor.Executor; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.plugin.*; import java.util.Properties; @Intercepts({@Signature(type= Executor.class,method = "update",args = {MappedStatement.class,Object.class})}) public class MyInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {//攔截?法,具體業務邏輯編寫的位置return invocation.proceed();}@Overridepublic Object plugin(Object target) {//創建target對象的代理對象,?的是將當前攔截器加?到該對象中return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {//屬性設置} }

注?到Spring容器:

/*** ?定義攔截器*/@Beanpublic MyInterceptor myInterceptor(){return new MyInterceptor();}

或者通過xml配置,mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><plugins><plugin interceptor="com.lagou.mp.plugins.MyInterceptor"></plugin></plugins> </configuration>

7.2、執?分析插件

MP 中提供了對 SQL 執?的分析的插件,可?作阻斷全表更新、刪除的操作,注意:該插件僅適?于開發環境,不適?于?產環境。 SpringBoot 配置: @Bean public SqlExplainInterceptor sqlExplainInterceptor(){SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();List<ISqlParser> sqlParserList = new ArrayList<>();// 攻擊 SQL 阻斷解析器、加?解析鏈sqlParserList.add(new BlockAttackSqlParser());sqlExplainInterceptor.setSqlParserList(sqlParserList);return sqlExplainInterceptor; } 測試: @Test public void testUpdate(){User user = new User();user.setAge(20);int result = this.userMapper.update(user, null);System.out.println("result = " + result); } 結果: Caused by: com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: Prohibition of table update operation at com.baomidou.mybatisplus.core.toolkit.ExceptionUtils.mpe(ExceptionUtils.java:4 9) at com.baomidou.mybatisplus.core.toolkit.Assert.isTrue(Assert.java:38) at com.baomidou.mybatisplus.core.toolkit.Assert.notNull(Assert.java:72) at com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser.processUpdate( BlockAttackSqlParser.java:45) at com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.processParser(Abstract JsqlParser.java:92) at com.baomidou.mybatisplus.core.parser.AbstractJsqlParser.parser(AbstractJsqlPar ser.java:67) at com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler.sqlParser (AbstractSqlParserHandler.java:76) at com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor.intercept(Sql ExplainInterceptor.java:63) at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) at com.sun.proxy. $Proxy70 .update(Unknown Source) at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession. java:197) ... 41 more 可以看到,當執?全表更新時,會拋出異常,這樣有效防?了?些誤操作。

7.3、性能分析插件

性能分析攔截器,?于輸出每條 SQL 語句及其執?時間,可以設置最?執?時間,超過時間會拋出異常。 該插件只?于開發環境,不建議?產環境使?。 配置: javaconfig ?式 @Bean public PerformanceInterceptor performanceInterceptor(){PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();performanceInterceptor.setMaxTime(100);performanceInterceptor.setFormat(true);return performanceInterceptor; } xml ?式 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><plugins><!-- SQL 執?性能分析,開發環境使?,線上不推薦。 maxTime 指的是 sql 最?執?時 ? --><plugin interceptor="com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor "><property name="maxTime" value="100" /><!--SQL是否格式化 默認false--><property name="format" value="true" /></plugin></plugins> </configuration> 執?結果: Time 11 ms - ID com.lagou.mp.mapper.UserMapper.selectById Execute SQL SELECT id, user_name, password, name, age, email FROM tb_user WHERE id = 7 可以看到,執?時間為 11ms 。如果將 maxTime 設置為 1 ,那么,該操作會拋出異常。

7.4、樂觀鎖插件

7.4.1、主要適?場景

意圖: 當要更新?條記錄的時候,希望這條記錄沒有被別?更新 樂觀鎖實現?式:
  • 取出記錄時,獲取當前version
  • 更新時,帶上這個version
  • 執?更新時, set version = newVersion where version = oldVersion
  • 如果version不對,就更新失敗

7.4.2、插件配置

spring xml: <bean class="com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor" /> spring boot: @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() {return new OptimisticLockerInterceptor(); }

7.4.3、注解實體字段

需要為實體字段添加 @Version 注解。 第?步,為表添加 version 字段,并且設置初始值為 1 ALTER TABLE `tb_user` ADD COLUMN `version` int(10) NULL AFTER `email`; UPDATE `tb_user` SET `version`='1';

第?步,為User實體對象添加version字段,并且添加@Version注解:

@Version private Integer version;

7.4.4、測試

測試?例: @Test public void testUpdate(){User user = new User();user.setAge(30);user.setId(2L);user.setVersion(1); //獲取到version為1int result = this.userMapper.updateById(user);System.out.println("result = " + result); } 執??志: main] [com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser]- [DEBUG] Original SQL: UPDATE tb_user SET age = ?, version = ? WHERE id = ? AND version = ? [main] [com.baomidou.mybatisplus.extension.parsers.BlockAttackSqlParser]- [DEBUG] parser sql: UPDATE tb_user SET age = ?, version = ? WHERE id = ? AND version = ? [main] [org.springframework.jdbc.datasource.DataSourceUtils]-[DEBUG] Fetching JDBC Connection from DataSource [main] [org.mybatis.spring.transaction.SpringManagedTransaction]-[DEBUG] JDBC Connection [HikariProxyConnection@540206885 wrapping com.mysql.jdbc.JDBC4Connection@27e0f2f5] will not be managed by Spring [main] [com.lagou.mp.mapper.UserMapper.updateById]-[DEBUG] == > Preparing: UPDATE tb_user SET age = ?, version = ? WHERE id = ? AND version = ? [main] [com.lagou.mp.mapper.UserMapper.updateById]-[DEBUG] == > Parameters: 30 (Integer), 2 (Integer), 2 (Long), 1 (Integer) [main] [com.lagou.mp.mapper.UserMapper.updateById]-[DEBUG] < == Updates: 1 [main] [org.mybatis.spring.SqlSessionUtils]-[DEBUG] Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@30135202] result = 1 可以看到,更新的條件中有 version 條件,并且更新的 version 2 如果再次執?,更新則不成功。這樣就避免了多?同時更新時導致數據的不?致。

7.4.5、特別說明

  • ?持的數據類型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整數類型下 newVersion = oldVersion + 1
  • newVersion 會回寫到 entity
  • 僅?持 updateById(id) update(entity, wrapper) ?法
  • update(entity, wrapper) ?法下, wrapper 不能復?!!!

8. Sql 注?器

我們已經知道,在 MP 中,通過 AbstractSqlInjector BaseMapper 中的?法注?到了 Mybatis 容器,這樣這些?法才可以正常執?。 那么,如果我們需要擴充 BaseMapper 中的?法,?該如何實現呢? 下?我們以擴展 findAll ?法為例進?學習。

8.1、編寫MyBaseMapper

package com.lagou.mp.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import java.util.List; public interface MyBaseMapper<T> extends BaseMapper<T> {List<T> findAll(); } 其他的 Mapper 都可以繼承該 Mapper ,這樣實現了統?的擴展。 如: package com.lagou.mp.mapper; import com.lagou.mp.pojo.User; public interface UserMapper extends MyBaseMapper<User> {User findById(Long id); }

8.2、編寫MySqlInjector

如果直接繼承 AbstractSqlInjector 的話,原有的 BaseMapper 中的?法將失效,所以我們選擇繼承 DefaultSqlInjector 進?擴展。 package com.lagou.mp.sqlInjector; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector; import java.util.List; public class MySqlInjector extends DefaultSqlInjector {@Overridepublic List<AbstractMethod> getMethodList() {List<AbstractMethod> methodList = super.getMethodList();methodList.add(new FindAll());// 再擴充?定義的?法list.add(new FindAll());return methodList;} }

8.3、編寫FindAll

package com.lagou.mp.sqlInjector; import com.baomidou.mybatisplus.core.enums.SqlMethod; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.baomidou.mybatisplus.core.metadata.TableInfo; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; public class FindAll extends AbstractMethod {@Overridepublic MappedStatement injectMappedStatement(Class<?> mapperClass, Class<? > modelClass, TableInfo tableInfo) {String sqlMethod = "findAll";String sql = "select * from " + tableInfo.getTableName();SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);} }

8.4、注冊到Spring容器

/** * ?定義SQL注?器 */ @Bean public MySqlInjector mySqlInjector(){return new MySqlInjector(); }

8.5、測試

@Test public void testFindAll(){List<User> users = this.userMapper.findAll();for (User user : users) {System.out.println(user);} } 輸出的 SQL [main] [com.lagou.mp.mapper.UserMapper.findAll]-[DEBUG] == > Preparing: select * from tb_user [main] [com.lagou.mp.mapper.UserMapper.findAll]-[DEBUG] == > Parameters: [main] [com.lagou.mp.mapper.UserMapper.findAll]-[DEBUG] < == Total: 10 ?此,我們實現了全局擴展 SQL 注?器。

9. ?動填充功能

有些時候我們可能會有這樣的需求,插?或者更新數據時,希望有些字段可以?動填充數據,?如密碼、version 等。在 MP 中提供了這樣的功能,可以實現?動填充。

9.1、添加@TableField注解

@TableField(fill = FieldFill.INSERT) //插?數據時進?填充 private String version; email 添加?動填充功能,在新增數據時有效。 FieldFill 提供了多種模式選擇: public enum FieldFill { 9.2、編寫MyMetaObjectHandler 9.3、測試/*** 默認不處理*/DEFAULT,/*** 插?時填充字段*/INSERT,/*** 更新時填充字段*/UPDATE,/*** 插?和更新時填充字段*/INSERT_UPDATE }

9.2、編寫MyMetaObjectHandler

package com.lagou.mp.handler; import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; import org.apache.ibatis.reflection.MetaObject; import org.springframework.stereotype.Component; @Component public class MyMetaObjectHandler implements MetaObjectHandler {@Overridepublic void insertFill(MetaObject metaObject) {Object password = getFieldValByName("version", metaObject);if(null == password){//字段為空,可以進?填充setFieldValByName("version", "123456", metaObject);}}@Overridepublic void updateFill(MetaObject metaObject) {} }

9.3、測試

@Test public void testInsert(){User user = new User();user.setName("冰冰");user.setAge(30);user.setVersion(1);int result = this.userMapper.insert(user);System.out.println("result = " + result); } 結果:

10. 邏輯刪除

開發系統時,有時候在實現功能時,刪除操作需要實現邏輯刪除,所謂邏輯刪除就是將數據標記為刪除,?并?真正的物理刪除(?DELETE 操作),查詢時需要攜帶狀態條件,確保被標記的數據不被查詢到。這樣做的?的就是避免數據被真正的刪除。 MP 就提供了這樣的功能,?便我們使?,接下來我們?起學習下。

10.1、修改表結構

ALTER TABLE `tb_user` ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表刪除,0代表未刪除' AFTER `version`; tb_user 表增加 deleted 字段,?于表示數據是否被刪除, 1 代表刪除, 0 代表未刪除。 同時,也修改 User 實體,增加 deleted 屬性并且添加 @TableLogic 注解: @TableLogic private Integer deleted;

10.2、配置

application.properties # 邏輯已刪除值(默認為 1) mybatis-plus.global-config.db-config.logic-delete-value=1 # 邏輯未刪除值(默認為 0) mybatis-plus.global-config.db-config.logic-not-delete-value=0

10.3、測試

@Test public void testDeleteById(){this.userMapper.deleteById(2L); } 執?的 SQL [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] == > Preparing: UPDATE tb_user SET deleted = 1 WHERE id = ? AND deleted = 0 [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] == > Parameters: 2 (Long) [main] [com.lagou.mp.mapper.UserMapper.deleteById]-[DEBUG] < == Updates: 1

測試查詢: @Test public void testSelectById(){User user = this.userMapper.selectById(2L);System.out.println(user); } 執?的 SQL [main] [com.lagou.mp.mapper.UserMapper.selectById]-[DEBUG] == > Preparing: SELECT id,user_name,password,name,age,email,version,deleted FROM tb_user WHERE id = ? AND deleted = 0 [main] [com.lagou.mp.mapper.UserMapper.selectById]-[DEBUG] == > Parameters: 2 (Long) [main] [com.lagou.mp.mapper.UserMapper.selectById]-[DEBUG] < == Total: 0 可?,已經實現了邏輯刪除。

11. 代碼?成器

AutoGenerator MyBatis-Plus 的代碼?成器,通過 AutoGenerator 可以快速?成 Entity Mapper Mapper XML Service Controller 等各個模塊的代碼,極?的提升了開發效率。

11.1、創建?程

pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.lagou</groupId><artifactId>lagou-mp-generator</artifactId><version>0.0.1-SNAPSHOT</version><name>lagou-mp-generator</name><description>Demo project for Spring Boot</description><properties><java.version>11</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--mybatis-plus的springboot?持--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.1</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.1.1</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><!--mysql驅動--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--簡化代碼的?具包--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> </project>

11.2、代碼

package com.lagou.mp.generator; import java.util.ArrayList; import java.util.List; import java.util.Scanner; import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException; import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.generator.AutoGenerator; import com.baomidou.mybatisplus.generator.InjectionConfig; import com.baomidou.mybatisplus.generator.config.DataSourceConfig; import com.baomidou.mybatisplus.generator.config.FileOutConfig; import com.baomidou.mybatisplus.generator.config.GlobalConfig; import com.baomidou.mybatisplus.generator.config.PackageConfig; import com.baomidou.mybatisplus.generator.config.StrategyConfig; import com.baomidou.mybatisplus.generator.config.TemplateConfig; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; /** * <p> * mysql 代碼?成器演示例? * </p> */ public class MysqlGenerator {/*** <p>* 讀取控制臺內容* </p>*/public static String scanner(String tip) {Scanner scanner = new Scanner(System.in);StringBuilder help = new StringBuilder();help.append("請輸?" + tip + ":");System.out.println(help.toString());if (scanner.hasNext()) {String ipt = scanner.next();if (StringUtils.isNotEmpty(ipt)) {return ipt;}}throw new MybatisPlusException("請輸?正確的" + tip + "!");}/*** RUN THIS*/public static void main(String[] args) {// 代碼?成器AutoGenerator mpg = new AutoGenerator();// 全局配置GlobalConfig gc = new GlobalConfig();String projectPath = System.getProperty("user.dir");gc.setOutputDir(projectPath + "/src/main/java");gc.setAuthor("lagou");gc.setOpen(false);mpg.setGlobalConfig(gc);// 數據源配置DataSourceConfig dsc = new DataSourceConfig();dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp? useUnicode=true&useSSL=false&characterEncoding=utf8");// dsc.setSchemaName("public");dsc.setDriverName("com.mysql.jdbc.Driver");dsc.setUsername("root");dsc.setPassword("root");mpg.setDataSource(dsc);// 包配置PackageConfig pc = new PackageConfig();pc.setModuleName(scanner("模塊名"));pc.setParent("com.lagou.mp.generator");mpg.setPackageInfo(pc);// ?定義配置InjectionConfig cfg = new InjectionConfig() {@Overridepublic void initMap() {// to do nothing}};List<FileOutConfig> focList = new ArrayList<>();focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {@Overridepublic String outputFile(TableInfo tableInfo) {// ?定義輸??件名稱return projectPath + "/lagou-mpgenerator/src/main/resources/mapper/" + pc.getModuleName()+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;}});cfg.setFileOutConfigList(focList);mpg.setCfg(cfg);mpg.setTemplate(new TemplateConfig().setXml(null));// 策略配置StrategyConfig strategy = new StrategyConfig();strategy.setNaming(NamingStrategy.underline_to_camel);strategy.setColumnNaming(NamingStrategy.underline_to_camel); //strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");strategy.setEntityLombokModel(true); //strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");strategy.setInclude(scanner("表名"));strategy.setSuperEntityColumns("id");strategy.setControllerMappingHyphenStyle(true);strategy.setTablePrefix(pc.getModuleName() + "_");mpg.setStrategy(strategy);// 選擇 freemarker 引擎需要指定如下加,注意 pom 依賴必須有!mpg.setTemplateEngine(new FreemarkerTemplateEngine());mpg.execute();} }

11.3、測試

代碼已?成:

實體對象:

12. MybatisX 快速開發插件

MybatisX 是?款基于 IDEA 的快速開發插件,為效率??。 安裝?法:打開 IDEA ,進? File -> Settings -> Plugins -> Browse Repositories ,輸? mybatisx 搜索并安裝。 功能:
  • Java XML 調回跳轉
  • Mapper ?法?動?成 XML

?

?

總結

以上是生活随笔為你收集整理的Mybatis-Plus 详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

99久久国产免费,99久久国产免费大片 | 国产最新91| 日本久久久亚洲精品 | 91看片在线播放 | 日韩欧美在线一区二区 | 婷婷丁香狠狠爱 | 国产色综合 | 免费看高清毛片 | 久久久www成人免费毛片麻豆 | 国产精品欧美日韩在线观看 | 亚洲欧美色婷婷 | 91大神视频网站 | 午夜精品一区二区三区免费 | 欧美日韩一区二区在线 | 一区二区三区免费在线观看视频 | 999久久久精品视频 日韩高清www | 在线精品观看国产 | 久久少妇av| 超碰在线cao | 久久 亚洲视频 | 欧美色图30p| 亚洲高清国产视频 | 成人免费在线看片 | 免费看黄的视频 | 涩涩网站在线看 | www欧美色| 三级黄色免费 | 日韩一三区| 婷婷国产在线 | 久久久www免费电影网 | 五月婷婷综合激情 | 六月色婷 | 国产黄大片 | 精品国产乱码久久久久久浪潮 | 亚洲欧洲精品在线 | 国产日韩在线看 | 天天操狠狠操夜夜操 | 免费看国产一级片 | 久久久www成人免费毛片 | 看国产黄色片 | 欧美国产不卡 | 一级成人网 | 日韩大片在线播放 | 中文字幕一区二区三区在线视频 | 久久97超碰 | 在线观看精品一区 | 久草在线精品观看 | 久草男人天堂 | 激情综合五月婷婷 | 最近中文字幕高清字幕免费mv | 精品成人a区在线观看 | 午夜久久久久久久久久久 | 美女免费视频黄 | 日韩色在线 | 久久99爱视频 | 黄色软件视频网站 | 亚洲高清在线精品 | 免费看精品久久片 | 欧美色图东方 | 日韩av一区二区三区四区 | 在线免费观看黄色av | 日日干,天天干 | 日本黄色免费在线观看 | 久久精品视频在线 | 91av久久 | 97超碰在线资源 | 91最新地址永久入口 | 欧美aa在线 | 毛片播放网站 | av网站免费线看精品 | 国产精品毛片久久久久久久久久99999999 | 国产一级电影在线 | 精品国产乱码久久久久久1区二区 | 国产99久久精品一区二区300 | 欧美日韩18 | 在线观看久草 | 99在线观看精品 | 青草视频在线播放 | 国产手机在线精品 | 五月婷婷中文字幕 | 欧美性春潮| 午夜丁香视频在线观看 | 久久精品96 | aa一级片| 麻豆视传媒官网免费观看 | 全黄网站 | www91在线观看| 毛片网在线播放 | 日韩久久久久久久久 | 97超碰人 | 日韩电影在线观看中文字幕 | 97超碰人人| 超碰97久久| 国产一区二区在线观看视频 | 欧美成人h版在线观看 | 欧美激情综合色 | 黄色午夜网站 | 狠狠操天天射 | 麻花天美星空视频 | 一区二区视频在线观看免费 | 免费观看一级成人毛片 | 夜夜躁日日躁狠狠躁 | 久草在线高清视频 | 亚洲精品动漫久久久久 | 久久高视频 | 97av在线视频免费播放 | 日韩一区二区三区免费电影 | 黄p网站在线观看 | 亚洲国产黄色片 | 久久成人国产精品一区二区 | 久久99久久精品国产 | 久久久国产精品免费 | 久久久精品网 | 成人黄色电影免费观看 | 国产一区二区在线看 | 国产精品久久久久免费观看 | 亚洲综合日韩在线 | 视频高清 | 婷婷日| 日韩一区二区三区在线观看 | www国产在线| 久久免费黄色大片 | 天天操·夜夜操 | 1024在线看片 | 777xxx欧美 | 天天操天天综合网 | 91麻豆精品91久久久久同性 | 国产精品永久在线 | 少妇视频一区 | 欧美人交a欧美精品 | www久草 | 精品国模一区二区三区 | 深爱激情五月婷婷 | 亚洲免费观看视频 | 国产 一区二区三区 在线 | 五月天婷婷在线播放 | 国产精品久久久久久吹潮天美传媒 | 成人超碰97| 欧美黑人巨大xxxxx | 国产精品美女999 | 日韩欧美综合在线视频 | 婷婷丁香花五月天 | 免费看一级特黄a大片 | 国产精品自产拍在线观看网站 | 亚洲视频一区二区三区在线观看 | 欧美aa一级片 | 成人黄大片 | 亚洲 精品在线视频 | 亚洲最新av在线网站 | 超碰在线人人97 | 久操视频在线免费看 | 中文字幕久久久精品 | 色在线视频网 | 蜜臀一区二区三区精品免费视频 | 高清av在线 | 中文字幕免费观看全部电影 | 91麻豆精品国产自产在线 | 中文免费| 丁香婷婷久久久综合精品国产 | 久久精品a | 玖玖精品在线 | 中文字幕精 | 日本少妇高清做爰视频 | 一级理论片在线观看 | 亚洲成人av电影 | 激情欧美一区二区三区 | 久久精品视频一 | 一区二区三区在线观看 | av在线进入| 久久黄色片子 | 国产精品高 | 成人久久18免费网站图片 | 国产韩国日本高清视频 | 日韩a级黄色片 | 国产精品久久久久久久久久久免费 | 国产中文字幕视频在线观看 | 国产精品美女久久久久久网站 | 国产a级精品 | 亚洲精品视频网站在线观看 | av视屏在线播放 | 中文字幕在线播放视频 | 天天玩天天干天天操 | 懂色av一区二区三区蜜臀 | 午夜精品一区二区三区免费 | 久久黄色网 | 久久精品国产精品亚洲 | 亚洲精品国产高清 | 爱爱av网 | 日本三级久久久 | 欧美日韩精品在线观看视频 | 18女毛片 | 91精品国自产在线偷拍蜜桃 | 国产精品久久久久久吹潮天美传媒 | 久久久免费少妇 | 色婷婷在线视频 | 成人欧美一区二区三区在线观看 | 99久久精品国产一区二区成人 | 亚洲欧美一区二区三区孕妇写真 | 国产色a在线观看 | 精品一二三区视频 | 天天操天天操一操 | 蜜桃av综合网 | 欧美a级一区二区 | 日韩xxx视频| 日韩精品不卡在线 | 香蕉在线视频播放网站 | 在线观看理论 | 日韩一级黄色大片 | 国产精品成人一区二区 | 欧美一二三区在线播放 | 亚洲国产三级在线 | 久久99热国产 | 亚洲精品美女久久久久 | 久久精品播放 | 精品国产亚洲在线 | 字幕网资源站中文字幕 | 久久大视频 | 国产精品电影在线 | 麻豆精品传媒视频 | 99产精品成人啪免费网站 | 国产视频网站在线观看 | 亚洲一区二区观看 | 成 人 黄 色 视频 免费观看 | 99久久婷婷 | 久久经典国产视频 | 色福利网站 | 97在线观看 | 美女网站在线观看 | 97超碰中文字幕 | 96精品视频 | 免费特级黄色片 | 欧美男同网站 | 黄色毛片观看 | 成人免费视频播放 | www.夜夜爱| www.五月婷 | 国产视频久久久久 | 一色屋精品视频在线观看 | 日韩av午夜 | 91av视屏 | 国产精品电影一区 | 992tv在线 | 久久不色| 国产小视频国产精品 | 果冻av在线 | 中文字幕在线观看亚洲 | 国产在线久久久 | 在线视频你懂得 | 日日躁夜夜躁aaaaxxxx | 又色又爽又激情的59视频 | 国产亚洲一区二区在线观看 | 国产免费久久av | 麻豆高清免费国产一区 | 在线а√天堂中文官网 | 久久久久久久久艹 | 黄色小网站免费看 | 黄色片毛片 | 国产成人专区 | 成人少妇影院yyyy | 97av在线视频 | 天天色综合三 | 国产91免费在线观看 | 久久av在线 | 亚洲精品乱码久久 | 国产精品99蜜臀久久不卡二区 | 成年人免费在线看 | www.天天操.com | 国产va饥渴难耐女保洁员在线观看 | 少妇性色午夜淫片aaaze | 久久精品视频播放 | 欧美a√大片 | 色偷偷88欧美精品久久久 | 国产成人一区二区三区免费看 | 国产精品一区二区av | 国产一区二区三区免费观看视频 | 久久久精品欧美一区二区免费 | 日韩免费成人av | 91污污视频在线观看 | 婷婷久久网站 | 久久精品理论 | 亚洲成a人片综合在线 | 国产成人免费观看久久久 | 五月婷婷在线视频观看 | 欧美精品久久久久久久免费 | 丁香激情综合 | 国内三级在线观看 | 五月婷婷一级片 | 韩国av一区二区 | 看黄色91| 97精品在线视频 | 国际精品网 | 在线播放日韩av | 美女网站久久 | 中文字幕免费观看 | 91在线视频观看免费 | 久草在线费播放视频 | 国内精品久久久久久久久久 | 亚洲性视频 | 久久精品7| 中文字幕九九 | 在线a亚洲视频播放在线观看 | 伊人婷婷久久 | 亚洲精品久久久蜜桃直播 | 成人午夜性影院 | 国内精品视频在线播放 | 国产精品久久婷婷六月丁香 | 欧美另类xxxxx| 国产一级在线看 | 久久电影国产免费久久电影 | 91在线免费观看国产 | 久久人人97超碰精品888 | 中文字幕欧美三区 | 一区二区三区日韩在线 | 又黄又爽又色无遮挡免费 | 精品福利国产 | 天天拍天天操 | 欧美性生活一级片 | 在线不卡a | 天天综合网入口 | 中文字幕在线中文 | 91免费看片黄| 久久视频这里只有精品 | 国产亚洲精品久 | 久草在线视频网站 | 成人午夜在线电影 | 欧美日本国产在线观看 | 国外av在线| 午夜精品久久久99热福利 | 精品国内自产拍在线观看视频 | 国产精品video爽爽爽爽 | 国产成人一二三 | 毛片网站在线观看 | 狠狠干成人综合网 | 欧美日韩精品网站 | 色亚洲网| 99午夜| 手机看片午夜 | 国产精品久久免费看 | 麻豆精品传媒视频 | 精品视频在线视频 | 国产一在线精品一区在线观看 | www.av免费| 中文字幕在线观看视频一区二区三区 | av网址最新| 韩国视频一区二区三区 | 伊人干综合 | 在线观看蜜桃视频 | 香蕉成人在线视频 | 91一区二区在线 | 免费观看一区二区三区视频 | 色婷婷狠狠干 | 日韩一区二区三区免费视频 | 亚洲免费观看视频 | 精品伦理一区二区三区 | 国产亚洲激情视频在线 | 在线观看视频色 | 国产精品高清免费在线观看 | 91人网站 | 午夜免费电影院 | 国产福利小视频在线 | 久久99久久99精品 | 亚洲国产精品久久 | 久久免费视频网站 | 一本一本久久a久久精品综合小说 | 99综合久久 | 亚洲视频久久久久 | av电影免费| 中文字幕久久精品亚洲乱码 | 日韩在线观看视频中文字幕 | 成人理论在线观看 | 欧美性色网站 | 国产精品区免费视频 | 在线中文字母电影观看 | 日韩精品一区二区不卡 | 久草在线播放视频 | 麻豆首页| 久久成视频 | 国产免费观看久久 | 日韩欧美综合精品 | 中文字幕第一页av | 美女网站在线播放 | 九色91av | 日本久久久久久久久 | 精品黄色片 | 福利一区在线视频 | 成人国产综合 | 激情综合网在线观看 | 天天色天天射天天综合网 | 久久久久久毛片精品免费不卡 | 人人超碰人人 | 精品国产一区二区三区四区在线观看 | 中文字幕av在线免费 | 啪啪免费观看网站 | 中文字幕有码在线 | 天天综合精品 | 国产999精品视频 | 久久精品高清 | 久久久精品国产免费观看一区二区 | 中文字幕精品三区 | 午夜影院在线观看18 | 久久av观看 | 日韩免费在线视频观看 | 亚洲aⅴ在线观看 | 久草在线资源观看 | 国产精品国产精品 | 国产伦精品一区二区三区免费 | 久久久久久国产精品999 | 国产一区免费在线 | 国产一级在线观看视频 | 国产精品区二区三区日本 | 久久极品| 一区二区不卡在线观看 | 五月婷婷在线观看视频 | 色婷婷综合五月 | 四虎成人免费影院 | 成年人免费av网站 | 国产99视频在线观看 | 国产乱对白刺激视频在线观看女王 | 狠狠色婷婷丁香六月 | 99国产在线视频 | 国产精品午夜久久 | 中文字幕成人 | 久久久久99精品成人片三人毛片 | 久久女教师 | 久久免费视频网 | 国产精品久久久久久久av电影 | 日韩高清免费在线 | 99在线视频观看 | 成人cosplay福利网站 | 四虎国产精 | 精品国产aⅴ麻豆 | 久久精品伊人 | 亚洲午夜久久久久久久久久久 | 成年人免费在线观看 | 婷婷黄色片 | 色婷婷啪啪免费在线电影观看 | 日韩专区在线观看 | 欧美日韩精品久久久 | 色婷婷综合五月 | 久久综合之合合综合久久 | 人人爱天天操 | 一级黄色片在线 | 一区二区三区电影在线播 | 韩国av电影在线观看 | 亚洲人在线 | 91九色视频在线观看 | 天天插日日插 | 日韩精品一区二区在线观看 | 久久久久久中文字幕 | 欧美极品一区二区三区 | 岛国av在线免费 | 成人免费电影 | 99中文字幕在线观看 | 免费观看全黄做爰大片国产 | 999久久久| 成人一级在线观看 | 国产精品久久久久久久久久久久久久 | 久久蜜臀一区二区三区av | 国产精品久久久久久69 | 国产精品久久久久久久久久久久午夜片 | 日本精品视频一区二区 | 欧洲精品久久久久毛片完整版 | 久99视频 | 五月天婷婷狠狠 | 精品一区在线看 | 在线看片a| 国产精品理论片在线观看 | 在线看av的网址 | 91精品秘密在线观看 | 99久久国产免费,99久久国产免费大片 | 在线观看黄av | 91精品国产99久久久久久红楼 | 国产亚洲一级高清 | 亚洲免费专区 | 国产1区2区3区在线 亚洲自拍偷拍色图 | 97成人免费视频 | 欧美日韩中文在线视频 | 国产中的精品av小宝探花 | 97视频在线免费 | 亚洲一级电影 | 成人午夜电影在线 | www·22com天天操 | 美女视频黄在线 | 国产精品高潮呻吟久久久久 | 香蕉网站在线观看 | 亚洲 中文字幕av | 日韩高清一区在线 | 国语精品久久 | 天天操天天摸天天射 | 蜜臀久久99精品久久久无需会员 | 色综合激情网 | 久久精品国产亚洲精品2020 | 日本久久成人中文字幕电影 | 婷婷国产v亚洲v欧美久久 | 人人舔人人 | 中文字幕日韩av | 国产精品福利无圣光在线一区 | 久久免费公开视频 | 久久艹久久 | 欧美极品一区二区三区 | 黄色免费电影网站 | 亚洲综合导航 | 天天人人 | 中文字幕在线观看免费 | 日韩狠狠操 | 欧美日韩在线免费观看 | 中文字幕av专区 | 国产一区二区在线免费观看 | 国产精品一区二区在线观看免费 | 制服丝袜一区二区 | 欧美精品久久久久久久 | 99热最新地址 | 久久久久久久久久久久亚洲 | 日韩一级电影网站 | 色婷婷视频 | 99成人在线视频 | av中文字幕亚洲 | 精品国产1区 | 久久国产精品一区二区 | 999国内精品永久免费视频 | 国产婷婷久久 | a午夜在线 | 色综合天天天天做夜夜夜夜做 | 日韩高清免费在线 | 天天干天天做天天操 | 五月天久久综合网 | 国产成人精品999 | 国产色在线| 91九色国产蝌蚪 | 中文字幕成人在线 | av再线观看 | 黄色精品国产 | 国产精品麻豆91 | 国产手机av在线 | 波多野结衣在线观看一区二区三区 | 国产精品99久久久久 | 欧美aa级 | 在线黄色免费 | 国产亚洲一区 | 亚洲精品动漫在线 | 亚洲精品在线视频观看 | 在线免费看黄色 | 亚洲精品乱码久久久久久高潮 | 叶爱av在线 | 久久久官网 | 国产91对白在线播 | 国内精品久久久久久久影视简单 | 午夜国产福利在线 | 国产亚洲aⅴaaaaaa毛片 | 玖玖玖国产精品 | 九色91在线 | 亚洲 欧美变态 另类 综合 | 亚洲电影一级黄 | 9在线观看免费高清完整版在线观看明 | 福利视频午夜 | 午夜视频在线观看一区二区三区 | 久久国语露脸国产精品电影 | 6080yy午夜一二三区久久 | a级一a一级在线观看 | 黄网站免费久久 | 日韩久久久久久 | 国产理伦在线 | 91成人免费在线 | 欧美国产高清 | a级片韩国| 99精品在线视频播放 | 2019中文| 婷婷色在线 | a视频免费 | 国产精品 国内视频 | 91av99| 国产欧美日韩一区 | 国产成人精品国内自产拍免费看 | 国产小视频网站 | 91精品区| 狠狠躁夜夜a产精品视频 | 精品国产一区二区三区噜噜噜 | 午夜精品一区二区三区可下载 | 视频在线观看亚洲 | 日本精品在线看 | 国产一级片毛片 | 欧美性色综合网 | 99热在线网站 | 九九综合在线 | 日本黄色大片免费 | 蜜臀久久99精品久久久酒店新书 | 精品久久毛片 | 国产精品乱码久久久久久1区2区 | 中文字幕在线视频网站 | 国产不卡av在线播放 | 91成人精品一区在线播放69 | 99热免费在线 | 少妇bbr搡bbb搡bbb| 久久久久北条麻妃免费看 | 在线观看免费av网 | 国产又黄又猛又粗 | 国产99久久久国产精品免费看 | 欧美亚洲xxx | 亚洲成人网在线 | 91黄视频在线 | 五月婷婷综 | 久久视频精品在线 | 久久最新| 日韩电影在线观看一区 | 狠狠干成人综合网 | 久久久国产精品免费 | 国产在线a不卡 | 久久色视频| 国产丝袜网站 | 欧美精品一级视频 | 国产色影院 | 国产专区在线 | 麻豆 91 在线 | 全久久久久久久久久久电影 | www.色com| 亚洲精品乱码久久久久久 | 日韩av成人在线观看 | 日韩高清一 | 人人射| 国产一区二区视频在线播放 | 成人黄色在线观看视频 | 日本黄色大片免费 | 韩日电影在线观看 | 婷婷深爱 | 久久久久国产一区二区三区 | 天天干com| 国产三级精品三级在线观看 | 黄色影院在线观看 | 婷婷丁香花五月天 | 亚在线播放中文视频 | 久久久久国产一区二区三区四区 | 在线久草视频 | 三级黄色片子 | 久久精品免费播放 | 免费在线观看av | 99综合影院在线 | 久草在线免费资源站 | 亚洲五月 | 国产成人三级一区二区在线观看一 | 色av男人的天堂免费在线 | 夜夜狠狠| 日韩电影中文字幕在线观看 | 9在线观看免费高清完整 | 免费黄色激情视频 | 国产女教师精品久久av | 日韩一区二区在线免费观看 | 国产视频91在线 | 日本精品久久久久中文字幕5 | 操操操av | 久久久久久久精 | 免费在线观看91 | 欧美另类激情 | 国产精品99久久久久久武松影视 | 99热日本| 亚洲va欧美va人人爽春色影视 | 黄网站免费久久 | 97国产| 日韩在线激情 | 亚洲国产三级在线观看 | 欧美va天堂va视频va在线 | 在线免费观看麻豆视频 | 91热爆视频 | 久草在线视频首页 | 成人播放器| 不卡中文字幕在线 | 一区二区三区国产欧美 | 久久国产精品99久久人人澡 | 99精品在线视频播放 | 久久久亚洲麻豆日韩精品一区三区 | www免费看| 美女网站在线 | 亚洲成人在线免费 | 激情婷婷丁香 | 伊人夜夜 | 天天综合网在线 | 亚洲毛片久久 | 在线看黄网站 | 91av在线免费看 | 9幺看片| 99精品视频在线观看播放 | 国产精品成 | 99re视频在线观看 | 国产精品久久影院 | 亚洲精品麻豆视频 | 99热这里只有精品8 久久综合毛片 | 色成人亚洲 | 日韩成人精品一区二区三区 | 国产黄网站在线观看 | 成人91免费视频 | 草久视频在线观看 | 亚洲最新在线视频 | 99精品偷拍视频一区二区三区 | 亚洲专区 国产精品 | 一区二区视频在线播放 | 婷婷丁香狠狠爱 | 成人av在线网 | 久久免费精品一区二区三区 | 久久情爱 | 亚洲精品女人 | 又黄又爽又色无遮挡免费 | 国产精品免费观看网站 | 国产成人黄色在线 | 国产在线综合视频 | 国产精品亚洲a | 亚洲最新视频在线播放 | 在线视频亚洲 | 亚洲少妇xxxx | 国产精品美乳一区二区免费 | 国产精品国产三级国产不产一地 | 久久99热国产 | 日日干日日 | 国产精品第二十页 | 依人成人综合网 | 91久久丝袜国产露脸动漫 | 91探花系列在线播放 | 黄在线免费看 | 久久精品人人做人人综合老师 | 天天艹天天干天天 | 丁香激情婷婷 | 国产黄色在线网站 | 91视频久久久 | 最近能播放的中文字幕 | a天堂一码二码专区 | 97在线免费视频观看 | 亚洲一级片在线看 | 2021国产精品视频 | 91精品国产91久久久久福利 | 免费观看91视频 | 99国产在线视频 | 国产一级在线观看 | 免费看污片| 欧美aa在线观看 | 91在线影院| 亚洲另类视频在线观看 | 婷婷综合影院 | 91在线麻豆 | 免费av大片 | 久久久精品日本 | 天天操天天操天天干 | 成人午夜网 | 狠狠色丁香婷综合久久 | 中国一级片在线 | a色视频| 精品国产一区二区三区男人吃奶 | 欧美电影在线观看 | 成人免费观看网址 | 深爱激情综合网 | 久久国产亚洲精品 | 午夜久久福利 | 日本精品va在线观看 | 九九久久精品视频 | 亚洲国产成人精品在线观看 | 国产精品麻豆免费版 | 亚洲成人xxx | 成人免费观看视频大全 | 99在线视频精品 | 99久久精品久久久久久动态片 | av短片在线观看 | 日本黄色免费电影网站 | 麻豆 videos| 日韩欧美一区视频 | 久99久在线视频 | 99在线视频网站 | 久久国产91 | 精品亚洲一区二区三区 | 在线免费中文字幕 | 蜜桃视频日韩 | 国产99中文字幕 | 美女黄久久 | 天天操综 | 国产三级精品三级在线观看 | 国产成人亚洲精品自产在线 | 婷婷亚洲五月色综合 | 亚州国产视频 | 日韩久久久久久久久久 | 欧美综合色在线图区 | 黄色www在线观看 | 日韩欧美网站 | av手机版| 国产成人免费av电影 | 久久午夜色播影院免费高清 | 综合中文字幕 | 亚洲狠狠干 | 色噜噜在线观看 | 精品国产区在线 | 中文字幕免费一区 | 91视频国产高清 | 狠色狠色综合久久 | 99热国产在线中文 | 国产黄色片网站 | 青青射| av解说在线观看 | 久久久99精品免费观看乱色 | 国产原厂视频在线观看 | 麻豆视频在线免费看 | 国产成人久 | 手机av在线免费观看 | 天天摸夜夜操 | 韩国av免费在线观看 | 狠狠的日| 日韩三级视频在线看 | 99 视频 高清 | 免费毛片一区二区三区久久久 | 狠狠狠色丁香综合久久天下网 | 欧美一区免费观看 | 日韩激情片在线观看 | 中文字幕久久亚洲 | 国产在线看| 免费瑟瑟网站 | 天天看天天干 | www.黄色网.com| 午夜色婷婷 | 成年人看片网站 | 日韩精品中文字幕一区二区 | 久久久久久福利 | 亚洲爱爱视频 | av在线免费网 | 午夜精品一区二区三区在线观看 | 99爱视频在线观看 | 久久久国产影院 | 免费黄色网止 | 久久在线观看视频 | 成人禁用看黄a在线 | 欧美一二三区播放 | 日韩av区| 欧美电影黄色 | 深爱激情综合 | 国产亚洲午夜高清国产拍精品 | 在线观看va | 91精品一区二区三区蜜桃 | 久久国产亚洲视频 | 午夜精品久久久久久中宇69 | 看片黄网站 | 久久国产高清 | 国产91精品看黄网站在线观看动漫 | 成人黄色在线视频 | 国产一级黄色片免费看 | 最近久乱中文字幕 | 草久久av| 国产在线精品播放 | 99在线观看免费视频精品观看 | 国产剧情一区二区 | 超碰在线人人草 | 在线观看色网 | 久久国产精品成人免费浪潮 | 亚洲黄色片在线 | 正在播放国产一区 | 久久不射影院 | 国产五月色婷婷六月丁香视频 | 国产麻豆传媒 | 91亚洲国产成人久久精品网站 | 精品国产一区二区三区不卡 | 免费观看一级一片 | 天天操天天射天天添 | 一区三区视频在线观看 | 国产一区二区在线观看视频 | 一级黄视频 | 亚洲在线a| 欧美日韩亚洲第一页 | 天天av综合网 | 在线视频观看你懂的 | 久草视频国产 | 91精品亚洲影视在线观看 | 免费看v片网站 | 亚州国产精品 | 亚洲1区 在线 | 天堂在线一区二区三区 | 97中文字幕 | 91精彩在线视频 | 日韩在线观看中文字幕 | 97久久精品午夜一区二区 | 久99久精品视频免费观看 | 久久公开视频 | 日韩大陆欧美高清视频区 | 激情丁香综合五月 | 天天干天天做天天爱 | 在线 日韩 av | 在线 视频 一区二区 | 在线视频观看你懂的 | 人人澡人 | 99久久婷婷国产精品综合 | 日本精品视频网站 | 久久久久久久99精品免费观看 | 久久久香蕉视频 | 国产精品久久久一区二区三区网站 | 九九九在线观看 | 在线观看va | 亚洲国产精品成人va在线观看 | 在线a亚洲视频播放在线观看 | 国产精品久久久久久久久大全 | 亚洲一区天堂 | 丝袜精品视频 | av夜夜操| 狠狠久久婷婷 | 成年人天堂com | 黄色毛片在线看 | 深爱激情五月综合 | 婷婷夜夜| 国外调教视频网站 | 中文av不卡 | 日韩免费一区二区在线观看 | 国产在线播放一区二区三区 | 少妇av片 | 欧美三级免费 | 免费在线观看av网址 | 最近免费中文字幕 | 亚洲国产高清在线 | 亚洲欧美在线视频免费 | 欧美日韩高清在线 | 精品国产精品一区二区夜夜嗨 | 99九九热只有国产精品 | 国产精品99久久久久久人免费 | 日韩精品一区二区三区免费视频观看 | 中文字幕免费在线 | 国产精品自产拍在线观看网站 | 91成人精品 | 狠狠躁夜夜a产精品视频 | 久久精品福利 | 亚洲国产av精品毛片鲁大师 | 亚洲综合在线视频 | 最新亚洲视频 | 国产无遮挡又黄又爽馒头漫画 | 亚洲一区欧美激情 | 欧美日韩激情网 | 欧美高清视频不卡网 | 国产一级片视频 | 免费黄色在线 | 日韩av影视在线 | www.com久久久 | 综合精品在线 | 日韩av网站在线播放 | 亚洲爱av | 国内一区二区视频 | 狠狠综合网 | 亚洲精品国产精品国自 | 欧美精品久久久久久久久老牛影院 | 97成人资源 | 成人黄色电影免费观看 | 911精品视频 | 亚洲电影影音先锋 | 久久亚洲电影 | 一区二区三区在线观看中文字幕 | 久久久久网站 | 在线中文字幕电影 | 99久久激情 | 91精品中文字幕 | 欧美性色综合网站 | 国产亚洲精品久久网站 | 在线免费观看国产黄色 | 天天草天天干天天 | 97综合视频| 国产伦理精品一区二区 | 久久视频在线看 | 日本中文在线 | 久久精品视频免费 | 97精品一区 | 91完整版 | 在线免费视频 你懂得 | 在线免费观看的av | 久久夜色精品国产欧美乱极品 | 天天草av| 91最新网址 | 夜夜摸夜夜爽 | 精品美女久久久久 | 国产不卡在线 | 日韩成片 | 高清国产在线一区 | 在线观看深夜视频 | 一区二区视频播放 | 亚洲国产片色 | 国产毛片久久久 | 爱色婷婷 | 在线看国产视频 | 天天操夜操视频 | 日韩精品中文字幕久久臀 | 国内精品久久久久久 | 国产福利小视频在线 | 久草网站在线观看 | 日韩久久久久久久久久久久 | 欧美精品一二 | 免费高清在线观看成人 | 91精品国自产在线偷拍蜜桃 | 麻豆免费在线播放 | 久久视频这里有久久精品视频11 | 日本h在线播放 | 成年美女黄网站色大片免费看 | 91九色综合| 亚洲精选99 | 麻花豆传媒mv在线观看 | 亚洲日本欧美在线 | 国产高清在线免费观看 | 欧美无极色 | 国产中文字幕视频在线 | 国产大片免费久久 | 黄色毛片一级 | 黄色www在线观看 | a视频免费 | 91av电影在线 |