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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

Mybatis-Plus 详解 拉钩笔记

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

目錄

1. Mybatis-Plus概念

1.1 Mybatis-Plus介紹

1.3 架構

1.4 作者

2. Mybatis-Plus快速??

2.1 安裝

2.2 創建數據庫以及表

2.3 創建?程

2.4 Mybatis + MP

2.5 Spring + Mybatis + MP

2.6 SpringBoot + Mybatis + MP

3. 通?CRUD

3.1 插?操作

3.2 更新操作

3.3 刪除操作

3.3.4、deleteBatchIds

3.4 查詢操作

3.4.1、selectById

3.4.2、selectBatchIds

3.4.3、selectOne

3.4.4、selectCount

3.4.5、selectList

3.4.6、selectPage

3.5 SQL注?的原理

4. 配置

4.1、基本配置

4.1.1、configLocation

4.1.2、mapperLocations

4.1.3、typeAliasesPackage ?

4.2、進階配置

4.2.1、mapUnderscoreToCamelCase

4.2.2、cacheEnabled

4.3、DB 策略配置

4.3.1、idType

4.3.2、tablePrefix

5. 條件構造器

5.1、allEq

5.1.1、說明

5.1.2、測試?例

5.2、基本?較操作

5.3、模糊查詢

5.4、排序

5.6、select

6. ActiveRecord

6.1、開啟AR之旅

6.3、新增數據

?編輯?

6.4、更新操作

?編輯

6.5、刪除操作

6.6、根據條件查詢

7. 插件

7.1、mybatis的插件機制

7.2、執?分析插件

7.3、性能分析插件

7.4、樂觀鎖插件

7.4.1、主要適?場景

7.4.2、插件配置

7.4.3、注解實體字段

7.4.4、測試

7.4.5、特別說明

8. Sql 注?器

8.1、編寫MyBaseMapper

8.2、編寫MySqlInjector

8.3、編寫FindAll

8.4、注冊到Spring容器

8.5、測試

9. ?動填充功能

9.1、添加@TableField注解

9.2、編寫MyMetaObjectHandler

9.3、測試

10. 邏輯刪除

10.1、修改表結構

10.2、配置

10.3、測試

11. 代碼?成器

11.1、創建?程

11.2、代碼

11.3、測試

12. MybatisX 快速開發插件


1. Mybatis-Plus概念

1.1 Mybatis-Plus介紹

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

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

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+MPSpring+Mybatis+MPSpring 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

下?演示,通過純MybatisMybatis-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接?的實現類關系如下:

可以看到,AbstractWrapperAbstractChainWrapper是重點實現,接下來我們重點學習 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接?的部分?法,?如updatequerycommitrollback等?法,還有其他接?的?些?法等。 總體概括為: 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> 執?結果: Time11 ms - IDcom.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條件,并且更新的version2 如果再次執?,更新則不成功。這樣就避免了多?同時更新時導致數據的不?致。

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中,通過AbstractSqlInjectorBaseMapper中的?法注?到了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 MapperMapper XMLServiceController 等各個模塊的代碼,極?的提升了開發效率。

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 详解 拉钩笔记的全部內容,希望文章能夠幫你解決所遇到的問題。

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

五月婷婷丁香在线观看 | 亚洲精品美女免费 | 欧美一区二区三区在线视频观看 | 日韩精品国产一区 | 日韩激情网 | 久久久免费在线观看 | 亚洲国产午夜精品 | 久久久人人人 | 一区二区三区在线不卡 | 亚洲综合涩 | 欧美久久久久久久久中文字幕 | 午夜10000| 亚洲精品中文在线 | 人人干网站 | 国产黄色观看 | 天天操天天射天天插 | av大全在线看 | 欧美精品久久 | 亚洲精品免费在线 | 亚洲 av网站 | 欧美久久久一区二区三区 | 五月婷婷欧美 | 亚洲免费在线视频 | 久久久精品高清 | 麻豆视频免费在线 | 日本夜夜草视频网站 | 美女视频黄是免费的 | 狠狠色丁香久久婷婷综合五月 | 婷婷久久丁香 | 免费在线观看成人av | 国产精品久久久久影院 | 日韩欧美区 | 黄色在线观看网站 | 中文字幕国语官网在线视频 | 四虎小视频 | 99视频这里有精品 | 在线成人中文字幕 | 欧美a视频 | 国产精品精品国产婷婷这里av | 国产视频精品久久 | 国产成人精品一区二区三区免费 | 日韩欧美视频一区二区 | 四虎成人精品永久免费av九九 | 久久久久久久久毛片精品 | 91x色| 久久激情日本aⅴ | 国产精品美女久久久久久久 | 在线免费观看视频 | 亚洲国产日本 | 成人黄色小说网 | av电影在线观看 | 人人爽人人爽人人片av | 久久综合五月婷婷 | 日韩毛片在线免费观看 | 国产一区欧美日韩 | 精品国产1区二区 | 欧美日韩一级在线 | 蜜臀av夜夜澡人人爽人人桃色 | 久久视频99 | 国产精品手机在线观看 | 国内外成人免费在线视频 | 国产亚洲日本 | 黄色影院在线播放 | 国产精品手机在线 | 特级毛片在线免费观看 | 二区视频在线观看 | 91香蕉久久 | 中文av资源站 | 色久av| 天天做天天干 | 亚洲涩涩色 | 免费观看成人网 | 在线观看的av网站 | 视频成人永久免费视频 | 91成人免费看 | 狠狠操天天射 | 国产精华国产精品 | 在线观看午夜 | 毛片一区二区 | 四虎影视精品成人 | 久久久久久在线观看 | av手机版 | 国产免费三级在线观看 | 国产天天爽 | 在线国产精品视频 | 精品视频在线视频 | 一区二区三区四区五区在线 | 久久精品理论 | 国产福利电影网址 | 午夜免费视频网站 | 欧美美女激情18p | 亚洲一片黄 | 国产 日韩 在线 亚洲 字幕 中文 | 亚洲资源网| 九九九电影免费看 | 91少妇精拍在线播放 | 久久人人添人人爽添人人88v | 久久成人一区二区 | 毛片永久免费 | 国产黄色精品在线观看 | 天天干,狠狠干 | 久久激情久久 | 国产高清视频 | 午夜精品剧场 | 国内精品久久影院 | 超碰在线色 | 夜夜爽夜夜操 | 91精品国产高清 | 色在线网| 热99在线视频 | 九草视频在线 | 久久午夜鲁丝片 | 久久国产精品99久久久久久老狼 | 麻豆免费看片 | 日韩黄色免费在线观看 | 色先锋av资源中文字幕 | 精品在线观看一区二区 | 欧美韩国在线 | 久久久国产一区二区三区四区小说 | 人人草天天草 | 国产手机在线 | 国产精品资源在线 | 久久久久久久18 | 福利视频网址 | 亚洲视频电影在线 | 国产精品专区h在线观看 | 久久黄色免费视频 | 国产精品久久久久久久久软件 | 日韩精品一区二区三区在线视频 | 亚洲黄网址 | 欧美日韩免费一区二区三区 | 国产亚洲精品久久久网站好莱 | 9797在线看片亚洲精品 | 成年人电影免费在线观看 | 久久久久免费精品国产 | 日韩欧美视频免费在线观看 | 99色视频 | 99r国产精品 | 中日韩在线 | 国产欧美最新羞羞视频在线观看 | 91福利视频免费 | 久久五月天婷婷 | 久久精品三 | 日韩中文字幕在线看 | 国产亚洲精品久 | www色网站| 97理论电影| 狠狠精品| 久久免费视频观看 | 黄色中文字幕 | 免费的黄色的网站 | 日韩av免费一区二区 | 国产黄色成人 | 日韩伦理一区二区三区av在线 | 亚洲综合色av | 亚洲成人精品 | h网站免费在线观看 | 国产91学生粉嫩喷水 | 日韩免费电影一区二区 | 天天色图| 精品国自产在线观看 | 亚洲免费在线播放视频 | 亚洲春色成人 | 国产 日韩 在线 亚洲 字幕 中文 | 精品国产视频在线 | 中文字幕在线观看一区二区 | 国产精品www | 中字幕视频在线永久在线观看免费 | 欧美三级高清 | 国产精品一区二区在线观看 | 欧美日韩高清在线 | 日韩电影在线看 | 日本久久99 | 中文字幕一区二区三区在线视频 | 成片视频在线观看 | 久久天堂网站 | av无限看 | 一区二区三区免费在线 | 色香网 | 三级在线视频观看 | 黄色的片子 | 久久国产精品久久精品国产演员表 | 特级西西444www高清大视频 | www狠狠操| 日韩在线电影观看 | 欧美精品乱码久久久久久按摩 | 九九免费观看视频 | 五月综合色婷婷 | 福利网址在线观看 | 免费精品久久久 | 成人免费看片网址 | 国产999精品久久久 免费a网站 | 国产精品一区二区久久精品爱涩 | 日韩一区精品 | 久草视频在线免费看 | 久久久久欧美精品 | 久久理论电影 | 久久成人国产精品免费软件 | 一级淫片在线观看 | 国产视频1区2区 | 奇米影视四色8888 | 国产精品久久一区二区三区不卡 | 免费av网站在线 | 日韩啪啪小视频 | 亚洲日本在线视频观看 | 国产成人精品日本亚洲999 | 欧美精品黑人性xxxx | 久久久91精品国产一区二区三区 | 国产乱对白刺激视频不卡 | 激情综合色综合久久综合 | 人人草在线观看 | 国产1级视频 | 久久久久久久18 | 97色狠狠| 久草视频播放 | 国产精品一区免费在线观看 | 在线视频 91 | 久久超 | 国产精品夜夜夜一区二区三区尤 | www.午夜色.com | 麻豆传媒在线视频 | 亚洲aⅴ免费在线观看 | 亚洲三级av| 欧美精品天堂 | 麻豆视频大全 | 中文字幕成人 | 久久艹在线观看 | av一区在线 | 99久久久久国产精品免费 | 午夜国产一区 | 成人在线视频在线观看 | 国产成人777777| 日日操日日插 | 欧美巨大荫蒂茸毛毛人妖 | 亚洲国产免费av | 99精品久久只有精品 | 成人天堂网 | 欧美精品九九 | 久久经典视频 | 国产一区二区三区免费在线观看 | 欧美日韩国产一区二区三区 | 97国产大学生情侣酒店的特点 | 激情小说久久 | 一区在线电影 | 国产日韩精品在线观看 | 国产精品对白一区二区三区 | 日韩激情小视频 | 国产资源免费 | 中文字幕黄色网 | 久久久久成人精品 | 国产精品国产三级国产aⅴ9色 | 看毛片网站 | 在线中文视频 | 国产黄在线 | 国产精品国产毛片 | 日本三级中文字幕在线观看 | 亚洲污视频 | 国产精品久久久久久久久久东京 | 精品视频成人 | 高潮毛片无遮挡高清免费 | 激情五月综合网 | 最近中文字幕大全中文字幕免费 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 在线亚洲欧美视频 | 国产精品一区在线 | 欧美一区二区免费在线观看 | 亚洲美女精品区人人人人 | 欧美成人精品xxx | 欧美一级乱黄 | 美女视频久久黄 | 久久久久一区二区三区四区 | 在线观看日韩精品 | 色香蕉视频 | 久久免费a | 日韩二区在线播放 | 国产尤物在线视频 | 国产精品女同一区二区三区久久夜 | 久久久精品国产一区二区三区 | 久久精品国产成人精品 | 久久免费视频在线观看6 | 欧美激情视频在线观看免费 | 伊人狠狠 | 午夜影院先| 色老板在线视频 | 在线视频观看成人 | 2020天天干夜夜爽 | 日韩精品一卡 | 久久另类视频 | 久久久久久久久久久久影院 | 久久99国产精品免费 | 成人va在线观看 | 又爽又黄又无遮挡网站动态图 | 色婷婷婷| 黄污网站在线观看 | 日韩大片在线免费观看 | 国产成人精品一区二三区 | 亚洲精品婷婷 | 国产精品一区二区久久精品爱涩 | 99久久99久久精品国产片果冰 | 亚洲va欧美 | 欧美激情视频在线免费观看 | 国产一级在线 | 中文字幕在线免费 | 亚洲精品免费在线观看视频 | 日韩久久影院 | av成人免费在线观看 | 精品免费视频 | 午夜.dj高清免费观看视频 | 日韩av视屏 | 天天干夜夜操视频 | 久久男人中文字幕资源站 | 中文字幕高清在线 | 超碰97免费| av最新资源 | 欧美成人h版电影 | 国产在线高清 | 天天看天天干 | 婷婷精品国产一区二区三区日韩 | 日韩美女av在线 | 欧美一级片免费观看 | 99久久国产免费免费 | 日韩精品视频免费看 | 久久99精品视频 | 一级一级一片免费 | 最新极品jizzhd欧美 | 欧美污污网站 | 久香蕉 | 国产拍在线 | 国产在线中文 | 国产精品久久av | 天天射综合网视频 | 青草视频在线免费 | 精品一区二区久久久久久久网站 | 亚洲国产播放 | 一区二区三区在线观看免费视频 | www久久99 | 欧美地下肉体性派对 | 久久精品国产一区二区 | 99精品视频网站 | 韩日精品视频 | 日韩黄色免费电影 | 在线观看av中文字幕 | 久精品视频 | 人人超碰在线 | 国产成人久久精品 | 免费观看第二部31集 | 日韩久久在线 | 日韩区欠美精品av视频 | 不卡视频在线 | 国产在线观看a | 天天曰 | 中文字幕av免费观看 | 在线观看91 | 一区二区三区播放 | 奇米导航 | 美女久久久久久久久久 | 超碰97人 | 国产精品成人一区 | 国产免费不卡av | 久久99精品久久久久久久久久久久 | 日韩手机视频 | 天天射天天搞 | 日韩高清一二三区 | 欧美精品久久久久久 | 日韩理论在线观看 | 在线天堂8√| 婷婷久久网站 | www在线观看国产 | www色婷婷com | 国产精品久久精品 | 麻豆免费在线播放 | 丁香婷婷综合五月 | 日韩系列在线 | 国产黄a三级三级三级三级三级 | 最新色站 | 91福利视频免费观看 | 免费在线一区二区 | 中文在线8新资源库 | 丁香五月网久久综合 | 欧美亚洲成人免费 | 91久久国产精品 | 婷婷六月网| 日韩av午夜 | 国产91精品一区二区麻豆亚洲 | 国产亚洲va综合人人澡精品 | 亚洲在线精品视频 | 国产亚洲精品美女久久 | 午夜久久福利视频 | 亚洲乱亚洲乱妇 | 综合色伊人 | 91桃色在线免费观看 | 成年人在线免费看视频 | 免费午夜视频在线观看 | 国产视频一区在线 | 超级碰碰碰视频 | 国产最新在线 | 久久8| 日韩av在线网站 | 久久精品首页 | 精品特级毛片 | 国产精品不卡在线观看 | 免费a v网站 | 国产精品美女久久 | 日本午夜在线亚洲.国产 | 亚洲综合丁香 | 在线免费高清一区二区三区 | 91av在线免费播放 | 国产黄影院色大全免费 | 新版资源中文在线观看 | 又黄又网站 | 免费男女羞羞的视频网站中文字幕 | 欧美激情视频久久 | 18av在线视频| 探花视频在线观看免费版 | 免费视频 你懂的 | 超碰在线98 | 久久成人国产精品一区二区 | 最近日本韩国中文字幕 | 国产在线观看a | 六月丁香激情综合色啪小说 | 天天综合日日夜夜 | 久久电影中文字幕视频 | 成人宗合网 | 国产成人精品三级 | 黄色91免费观看 | 东方av在线免费观看 | 久久av伊人| 国产高清福利在线 | 91福利免费 | 亚州黄色一级 | 在线观看免费av片 | 午夜国产一区 | 9在线观看免费高清完整版在线观看明 | 亚洲精品在线播放视频 | 国产在线视频一区二区 | 欧美婷婷色 | 天天综合天天做 | 黄色大片日本免费大片 | 久久精品在线免费观看 | 91av蜜桃| 国内精品久久久久影院优 | 91自拍视频在线观看 | 日本激情动作片免费看 | 精品一二三四五区 | 日韩精品亚洲专区在线观看 | 国产一区二区久久久 | 亚洲精品视频免费在线 | 亚洲精品网页 | 最新超碰在线 | 国产一级大片免费看 | 四虎成人精品永久免费av | 国产精品亚洲片在线播放 | 高清国产一区 | 操综合| 福利二区视频 | a级国产乱理伦片在线观看 亚洲3级 | 中文字幕国产视频 | 999国内精品永久免费视频 | 五月激情丁香婷婷 | 中文字幕日韩av | 久久久国产精品麻豆 | 日日射av| 黄色av三级在线 | 日韩精品中文字幕av | 日韩资源在线观看 | 一区二区三区日韩在线观看 | 欧美激情va永久在线播放 | 麻豆视频在线免费观看 | 日日干日日操 | 日韩av中文在线观看 | 日本三级吹潮在线 | 日韩成人精品在线观看 | 国产精品影音先锋 | 久草免费在线视频观看 | 91精品国自产在线 | 国产经典三级 | 国产精品久久久久久久久久久久午夜 | 亚洲香蕉视频 | 在线看片91| 亚洲黄色激情小说 | 国产一级大片免费看 | 天天色官网 | 视频在线观看日韩 | 久久精品免费观看 | 欧美国产不卡 | 国产91丝袜在线播放动漫 | 日韩久久一区 | 99久久99久久精品国产片果冰 | 在线免费色 | 日本中文字幕网 | 久久男人免费视频 | 夜夜躁日日躁 | 精品一区三区 | 2018亚洲男人天堂 | www.夜夜操.com | 欧美乱大交 | 久久久久成人精品免费播放动漫 | 日韩最新理论电影 | av电影在线观看完整版一区二区 | 免费在线播放视频 | 欧美日本不卡 | 精品一区二区免费在线观看 | 波多野结衣在线观看一区二区三区 | 亚洲乱亚洲乱亚洲 | 天天操天天添 | 亚洲精品在线二区 | 黄色美女免费网站 | 在线一级片 | 国产99区 | 97超碰资源网 | 久久公开免费视频 | 免费高清国产 | 免费日韩一区二区三区 | 最近的中文字幕大全免费版 | 色999视频 | 999电影免费在线观看2020 | 免费福利在线观看 | 国产日韩一区在线 | 嫩草av在线 | 久久久久久久久黄色 | 久久久亚洲麻豆日韩精品一区三区 | 日韩免费观看视频 | 国产精品视频不卡 | 亚洲毛片在线观看. | 国产在线不卡视频 | 久久久 精品 | 人人插人人澡 | 91污污视频在线观看 | 欧美一区免费观看 | 婷婷久久综合网 | 五月在线 | 日本精品中文字幕 | 狂野欧美激情性xxxx | 自拍超碰在线 | 91成人破解版 | 91麻豆免费看 | 日韩电影中文字幕 | 射综合网 | 又黄又爽免费视频 | 国产999免费视频 | 国产手机在线精品 | 成人国产精品入口 | 天天激情站 | 2019中文在线观看 | 在线精品视频免费播放 | 视频99爱 | 天天艹天天 | 日韩欧美视频 | 97在线观看免费 | 国产精品成人免费精品自在线观看 | 国产成人一二片 | 欧美日本在线视频 | 国产高清av免费在线观看 | 综合久久网| av韩国在线 | 日韩精品在线看 | 日韩欧美高清在线观看 | 在线成人性视频 | 日韩在线网址 | 国产在线理论片 | 91人人澡人人爽 | 日韩欧美69| 亚洲精品小视频在线观看 | 中文字幕av最新更新 | 成人性生交视频 | 天天草天天爽 | 九九免费在线观看视频 | 中文字幕一区二区三区精华液 | 国产69熟| 在线黄av| 国产成年免费视频 | 99 国产精品| 成人免费一区二区三区在线观看 | 婷婷夜夜| 日韩美女av在线 | 成年人黄色免费网站 | 四虎影视精品永久在线观看 | 欧美性免费 | 99久热在线精品视频成人一区 | www.干| 友田真希av | 美女福利视频一区二区 | 在线有码中文 | 99在线精品免费视频九九视 | 香蕉影视app | 色视频 在线| 日本一区二区三区视频在线播放 | 深爱激情五月婷婷 | 九九色视频 | 精品久久久久久久久久久久久久久久久久 | 2024国产精品视频 | 国产在线传媒 | 日韩精品一区二区三区免费视频观看 | 91中文在线视频 | 97视频在线免费观看 | 亚洲在线视频免费观看 | 黄色成人免费电影 | 精品999在线 | 我要看黄色一级片 | 国产黄网站在线观看 | 国产视频精品免费播放 | bbb搡bbb爽爽爽 | 在线激情av电影 | 久久久色 | 久久99国产综合精品 | 一区二区三区日韩视频在线观看 | 91中文字幕在线播放 | 看污网站 | 黄色a一级视频 | 激情偷乱人伦小说视频在线观看 | 911久久| 日韩二区三区在线观看 | 丁香六月国产 | 中文字幕黄色 | 欧美精品乱码99久久影院 | 欧美日在线观看 | 天天操天天干天天操天天干 | 在线观看免费国产小视频 | av品善网 | 国产午夜影院 | 永久中文字幕 | 超碰97免费 | 香蕉在线视频播放网站 | 精品美女久久久久 | 国产精品久久久久久久久久久久午夜片 | 日韩午夜一级片 | 色婷婷av一区二 | 国产九九九九九 | 狠狠色婷婷丁香六月 | 免费观看黄色12片一级视频 | 成年人网站免费在线观看 | 亚洲精品在线观看的 | 久久亚洲欧美日韩精品专区 | 正在播放日韩 | 国产精品精品久久久 | 久久综合免费视频影院 | 久久国产剧场电影 | 91免费网址 | 成人精品影视 | 日韩欧美在线国产 | 九色精品| 国产黄色成人 | 91久久国产自产拍夜夜嗨 | 国产亚洲精品xxoo | 国产婷婷在线观看 | 国产日韩视频在线观看 | 亚洲视频1 | 91av在线免费视频 | 中文字幕视频一区 | 97超碰免费在线观看 | 草免费视频 | 久久精品国产精品亚洲精品 | 欧美做受69 | 国产午夜av | 香蕉久久久久久av成人 | 国产一级特黄电影 | 九九九电影免费看 | 欧美天堂视频在线 | 国产精品久久久久一区 | 国产成人精品久久二区二区 | 丝袜精品视频 | 成人h电影在线观看 | 黄网av在线| 最新国产在线观看 | 国产高清久久久 | 午夜国产影院 | 日韩欧美在线观看一区二区 | 97精品国产97久久久久久久久久久久 | av免费电影在线观看 | 人人搞人人爽 | 日本黄色大片免费 | 97在线观看视频国产 | 久久久久成人免费 | 在线观看日韩中文字幕 | a特级毛片 | 国产日韩视频在线观看 | 2021国产精品| 免费在线播放黄色 | 国产精品美女久久久久久免费 | 男女啪啪网站 | 91理论片午午伦夜理片久久 | 国产精品毛片一区二区在线 | 日本精品久久久一区二区三区 | 免费成人在线观看视频 | 国产一区国产精品 | 2024国产精品视频 | 成人a免费 | 国产福利中文字幕 | 综合精品在线 | 精品国产伦一区二区三区免费 | 午夜精品一区二区三区免费 | 日韩1级片 | 久久久国产精品免费 | 国产香蕉视频 | 天天综合中文 | 日本激情视频中文字幕 | 国产99久久精品一区二区永久免费 | 久草com| 久草影视在线观看 | 在线观看免费版高清版 | 97超碰人人| 久久国产精品小视频 | 日本少妇高清做爰视频 | 午夜国产在线观看 | 中文字幕在线视频一区 | 日韩三区在线观看 | 日韩不卡高清 | 日本三级在线观看中文字 | 久久精品毛片基地 | 天天干天天干天天 | 国产一区视频免费在线观看 | 国内丰满少妇猛烈精品播放 | 日本系列中文字幕 | 国产青春久久久国产毛片 | 久久国产精品小视频 | 91传媒在线播放 | 免费观看性生交大片3 | 国产在线观看网站 | 少妇精品久久久一区二区免费 | 激情文学丁香 | 国产精品中文字幕在线观看 | 91人人在线| 中文字幕有码在线播放 | 日韩av中文 | www好男人 | 最近中文字幕久久 | 中国美女一级看片 | 五月婷婷久草 | 久久亚洲私人国产精品 | 骄小bbw搡bbbb揉bbbb | 午夜久草 | 国产a国产a国产a | 黄污视频网站大全 | 久久一区二区三区四区 | 毛片永久新网址首页 | 久久首页 | 午夜免费福利视频 | 亚洲国产精品成人精品 | 欧美日本三级 | 久久国产精品久久精品 | 日韩一区二区三区在线观看 | 日日夜夜狠狠干 | 超碰免费观看 | 欧美日韩国产精品久久 | 成人在线免费视频观看 | 97免费在线视频 | 一区三区视频 | 免费欧美高清视频 | 久久国产精品久久精品国产演员表 | 色婷婷久久久综合中文字幕 | 中文字幕一区二区三区四区在线视频 | 天天爽人人爽 | 久久国产精品成人免费浪潮 | 五月天中文字幕 | 综合天堂av久久久久久久 | 久草视频在线播放 | 99热精品免费观看 | 人人爽人人干 | 丁香影院在线 | 人人狠狠 | 欧美日韩大片在线观看 | 国语麻豆 | 日韩视频精品在线 | 久久天天躁夜夜躁狠狠85麻豆 | 久久综合色天天久久综合图片 | 中文字幕 国产视频 | 欧美 日韩 成人 | 亚洲欧洲精品一区二区 | 国产精品video爽爽爽爽 | av福利网址导航 | 开心激情五月网 | 丝袜美女视频网站 | 高清在线观看av | 91污在线 | 色av色av色av | 高清不卡一区二区在线 | 波多野结衣在线播放视频 | 在线观看免费版高清版 | 久久夜色精品国产欧美一区麻豆 | 99视频这里只有 | 天天操天天舔天天爽 | 日本韩国中文字幕 | 精品九九九九 | 久久久久成人精品免费播放动漫 | 国产精品黄色影片导航在线观看 | 草久久久 | 五月丁香 | 国产精品免费久久久久影院仙踪林 | 在线国产精品一区 | 亚洲精品视频在线观看免费视频 | 欧美日韩视频免费看 | 国产精品成人久久久久久久 | 在线观看av小说 | 国产一级片视频 | 91精品国产入口 | 五月婷婷一区二区三区 | 狠狠的操狠狠的干 | 99国产精品久久久久老师 | 人人爱爱| 黄色成人在线 | av片子在线观看 | 亚洲男男gaygayxxxgv | 特黄一级毛片 | 中文字幕在线观看不卡 | 成年人黄色在线观看 | 91亚色视频在线观看 | 色婷婷综合视频在线观看 | 精品国产一区二区三区久久久蜜臀 | 狠狠88综合久久久久综合网 | 久久国产精品色婷婷 | 中文字幕在线播出 | 97手机电影网| 日本爽妇网| 日韩精品不卡在线观看 | 玖玖视频 | 伊人亚洲综合 | 国产精品永久久久久久久久久 | 缴情综合网五月天 | 国产视频1| 在线观看视频在线观看 | 99久久99久久精品国产片果冰 | 天天干天天搞天天射 | 人人网av | 四虎免费在线观看视频 | 婷婷伊人五月天 | 在线精品一区二区 | 国产精品美女免费 | 天堂在线一区二区 | 中文字幕在线观看91 | 免费在线观看污网站 | 91九色porny在线 | 免费亚洲精品 | 久久99视频免费 | 午夜免费视频网站 | 人人爽人人爽人人爽人人爽 | japanesefreesexvideo高潮| 天堂av免费看 | 蜜臀av在线一区二区三区 | 91在线免费观看网站 | 日韩二三区 | 精品成人a区在线观看 | 国产黄色片免费观看 | 一区二区理论片 | 草久久精品 | 手机av资源 | 日韩免费高清在线 | 麻豆国产电影 | 亚一亚二国产专区 | 91精品成人久久 | av黄色免费在线观看 | 国产中文字幕视频在线观看 | 日韩欧美高清 | 国产黄色a | 日韩免费高清在线观看 | 日韩电影黄色 | 午夜精品久久久久久久99婷婷 | 亚洲jizzjizz日本少妇 | 亚洲aⅴ在线观看 | 欧美综合在线视频 | 国产精品 中文字幕 亚洲 欧美 | 国产欧美精品在线观看 | www国产亚洲 | 免费黄色看片 | 国产xxxx做受性欧美88 | 青青草在久久免费久久免费 | ww视频在线观看 | 欧美精品在线观看免费 | 国产亚洲精品电影 | 亚洲免费国产视频 | 在线免费色视频 | 久草视频在线看 | 日本黄色大片免费看 | 日韩成人黄色av | 最近字幕在线观看第一季 | 国产精品久一 | 偷拍区另类综合在线 | 国产五码一区 | 色999视频| 久久九九久久精品 | 探花视频免费在线观看 | 日韩免费电影网 | 久草在线综合 | 国产精品美女视频网站 | 国产精品系列在线 | 99视频在线精品国自产拍免费观看 | 激情九九| 婷婷色网址 | 一区二区伦理电影 | 午夜天使 | 日韩精品一区二区三区在线播放 | 免费久久网 | 偷拍精偷拍精品欧洲亚洲网站 | 久草在线在线精品观看 | 波多野结衣资源 | 亚洲免费婷婷 | 久草综合视频 | 超碰在线亚洲 | 99久热| 日韩免费观看一区二区三区 | 色橹橹欧美在线观看视频高清 | 嫩草伊人久久精品少妇av | 免费日韩一区 | 欧美一区成人 | 在线三级av | 一本一本久久a久久精品综合妖精 | 午夜国产福利在线 | 午夜狠狠操 | 久久乱码卡一卡2卡三卡四 五月婷婷久 | 在线播放视频一区 | 中文字幕影片免费在线观看 | 国产精品自产拍在线观看桃花 | 国产精品一二三 | 国产资源中文字幕 | 久久久久免费网 | 国产97色 | 免费高清av在线看 | 久久精品美女视频 | 国产一级淫片免费看 | 国产午夜精品一区二区三区 | 热久久视久久精品18亚洲精品 | 国产精品毛片久久 | 久久香蕉电影网 | 久久看免费视频 | 中文字幕日韩国产 | 久久精品免视看 | 亚洲资源视频 | 粉嫩av一区二区三区入口 | 国产综合小视频 | 国产亚洲精品久 | 三级动图 | 96久久精品 | 日韩av免费大片 | 久久丁香 | 欧美成年黄网站色视频 | 久久婷婷久久 | av噜噜噜在线播放 | 人人精久 | 日韩精品一区二区三区电影 | 激情深爱五月 | 国产精品久久电影网 | 欧洲激情在线 | 亚洲污视频| 成年人国产精品 | 国产96在线视频 | 中文字幕麻豆 | 麻豆免费在线视频 | 日韩欧美一区二区三区视频 | 香蕉久草 | 在线观看的a站 | 国产一区二区高清视频 | 精品一区二区三区四区在线 | 久久久久久蜜av免费网站 | 亚洲欧美成人网 | 97免费在线视频 | 欧美性猛片 | 成人av网址大全 | 国产午夜免费视频 | 深爱婷婷久久综合 | 色婷婷欧美 | 天天干,天天干 | 日韩精品亚洲专区在线观看 | 久久久久久久久久久久久久av | 日韩欧美高清一区二区 | 色综合中文综合网 | 亚洲精品ww| 久草在线免费看视频 | 二区在线播放 | 国产一级淫片免费看 | 国产精品久久久久久久久久免费看 | 国产黄在线 | 欧洲在线免费视频 | 欧美人牲 | 亚洲天堂色婷婷 | 婷婷丁香狠狠爱 | 黄色av网站在线免费观看 | 日韩精品视频第一页 | 日韩久久精品一区 | 人人澡人人爱 | 毛片永久免费 | av资源网在线播放 | 日日爱999 | 久久久国产精品电影 | 中文字幕在线乱 | 免费在线激情视频 | 国产一区二区久久精品 | 高清免费在线视频 | 日韩大片免费观看 | 成人动图 | a级片在线播放 | 日韩大陆欧美高清视频区 | 成人性生交大片免费观看网站 | a爱爱视频| 国产精品永久免费视频 | 狠狠色综合欧美激情 | 久草精品视频在线播放 | 欧美日本在线视频 | 精品久久久久久国产 | 国产精品久久久久久久久久 |