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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

MyBatis_Plus(Spring版本笔记)

發布時間:2024/1/8 javascript 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis_Plus(Spring版本笔记) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • 前言
  • 一、MyBatis-Plus簡介
    • 1.1 簡介
    • 1.2 特性
    • 1.3 支持數據庫
    • 1.4 框架結構
    • 1.5 代碼及文檔地址
  • 二、 入門案例
    • 2.1 開發環境
    • 2.2 創建數據庫和表
      • 2.2.1 創建表
      • 2.2.2 添加數據
    • 2.3 創建maven工程
      • 2.3.1 打包方式 jar
      • 2.3.2 引入依賴
    • 2.4 Spring整合MyBatis
      • 2.4.1 創建實體
      • 2.4.2 創建MyBatis的核心配置文件
      • 2.4.3 創建mapper接口和映射文件
      • 2.4.4 創建jdbc.properties
      • 2.4.5 創建Spring的配置文件
      • 2.4.6 添加日志功能
      • 2.4.7 測試
    • 2.5 加入MyBatis-Plus
      • 2.5.1 創建Mapper接口
      • 2.5.2 測試
      • 2.5.3 結果
    • 2.6 總結
  • 三、基本CRUD
    • 3.1 BaseMapper
    • 3.2 BaseMapper功能測試
    • 3.3 通用Service
      • 3.3.1 IService
      • 3.3.2 創建Service接口和實現類
      • 3.3.3 在spring配置文件中設置自動掃描service的包
      • 3.3.4 測試查詢記錄條數和批量添加
  • 四、常用注解
    • 4.1 @TableName
      • 4.1.1 問題
      • 4.1.2 通過@TableName解決問題
      • 4.1.3 通過GlobalConfig解決問題
    • 4.2 @TableId
      • 4.2.1 問題引出
      • 4.2.2 通過@TableId解決問題
      • 4.2.3 @TableId的value屬性
      • 4.2.4 @TableId的type屬性
      • 4.2.5 雪花算法
    • 4.3 @TableField
    • 4.4 @TableLogic(邏輯刪除)
      • 4.4.1 邏輯刪除
      • 4.4.2 實現邏輯刪除
  • 五、條件構造器和常用接口
    • 5.1 wapper介紹
    • 5.2 QueryWrapper
      • 5.2.1 組裝查詢條件
      • 5.2.2 組裝排序條件
      • 5.2.3 組裝刪除條件
      • 5.2.4 條件的優先級
      • 5.2.5 組裝select子句
      • 5.2.6 實現子查詢
    • 5.3 UpdateWrapper
    • 5.4 condition
    • 5.5 LambdaQueryWrapper
    • 5.6 LambdaUpdateWrapper
  • 六、插件
    • 6.1 分頁插件
      • 6.1.1 添加配置
      • 6.1.2 測試
    • 6.2 xml自定義分頁
      • 6.2.1 UserMapper中定義接口方法
      • 6.2.2 UserMapper.xml中編寫SQL
      • 6.2.3 測試
    • 6.3 樂觀鎖
      • 6.3.1 場景
      • 6.3.2 樂觀鎖與悲觀鎖
      • 6.3.3 模擬修改沖突
      • 6.3.4 樂觀鎖實現流程
      • 6.3.5 Mybatis-Plus實現樂觀鎖
  • 七 、通用枚舉
    • 7.1 數據庫添加字段sex
    • 7.2 創建通用枚舉
    • 7.3 配置掃描通用枚舉
    • 7.4 測試
  • 八、代碼生成器
    • 8.1 引入依賴
    • 8.2 快速生成
  • 九 、MyBatisX插件
    • 9.1 安裝插件
    • 9.2 功能
      • 9.2.1 XML跳轉
      • 9.2.2 快速生成代碼
  • 十、總結


前言

本文主要參考嗶站尚硅谷楊博超講師課件整理而成,屬于自己復習使用。


提示:以下是本篇文章正文內容,下面案例可供參考

一、MyBatis-Plus簡介

1.1 簡介

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 查詢
  • 分頁插件支持多種數據庫:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多種數據庫
  • 內置性能分析插件:可輸出 SQL 語句以及其執行時間,建議開發測試時啟用該功能,能快速揪出慢查詢

1.3 支持數據庫

任何能使用MyBatis進行 CRUD, 并且支持標準 SQL 的數據庫,具體支持情況如下

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQLSQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
  • 達夢數據庫,虛谷數據庫,人大金倉數據庫,南大通用(華庫)數據庫,南大通用數據庫,神通數據庫,瀚高數據庫

1.4 框架結構

1.5 代碼及文檔地址

官方地址:http://mp.baomidou.com
代碼發布地址:
Github: https://github.com/baomidou/mybatis-plus
Gitee: https://gitee.com/baomidou/mybatis-plus
文檔發布地址:https://baomidou.com/pages/24112f


二、 入門案例

2.1 開發環境

以maven工程為例,以ssm整合為技術框架。

工具版本
IDEidea 2021.3
JDKJDK1.8
MAVENmaven 3.8.4
MySQLMySQL8.0.25
Spring5.3.1
MyBatis-Plus3.4.3.4

2.2 創建數據庫和表

2.2.1 創建表

CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */; use `mybatis_plus`; CREATE TABLE `user` ( `id` bigint(20) NOT NULL COMMENT '主鍵ID', `name` varchar(30) DEFAULT NULL COMMENT '姓名', `age` int(11) DEFAULT NULL COMMENT '年齡', `email` varchar(50) DEFAULT NULL COMMENT '郵箱', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2.2.2 添加數據

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 創建maven工程

2.3.1 打包方式 jar

<packaging>jar</packaging>

2.3.2 引入依賴

<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</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><!-- 連接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><!-- junit測試 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- MySQL驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.27</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.30</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.3</version></dependency><!-- lombok用來簡化實體類 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version></dependency><!--MyBatis-Plus的核心依賴--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus</artifactId><version>3.4.3.4</version></dependency><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency></dependencies><properties><spring.version>5.3.1</spring.version></properties>

注意:
Spring整合MyBatis,需要MyBatis以及Spring整合MyBatis的依賴:

但是,在以上的依賴列表中,并沒有MyBatis以及Spring整合MyBatis的依賴,因為當我們引入了
MyBatis-Plus的依賴時,就可以間接的引入這些依賴

并且依賴和依賴之間的版本必須兼容,所以我們不能隨便引入其他版本的依賴,以免發生沖突
在官網上有明確提示:

2.4 Spring整合MyBatis

2.4.1 創建實體

public class User {private Long id;private String name;private int age;private String email;public User(Long id, String name, int age, String email) {this.id = id;this.name = name;this.age = age;this.email = email;}public User() {}public Long getId() {return this.id;}public String getName() {return this.name;}public int getAge() {return this.age;}public String getEmail() {return this.email;}public SexEnum getSex() {return this.sex;}public int getIsDeleted() {return this.isDeleted;}public void setId(Long id) {this.id = id;}public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}public void setEmail(String email) {this.email = email;}public void setSex(SexEnum sex) {this.sex = sex;}public void setIsDeleted(int isDeleted) {this.isDeleted = isDeleted;}public String toString() {return "User(id=" + this.getId() + ", name=" + this.getName() + ", age=" + this.getAge() + ", email=" + this.getEmail() + ", sex=" + this.getSex() + ", isDeleted=" + this.getIsDeleted() + ")";} }

2.4.2 創建MyBatis的核心配置文件

在resources下創建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></configuration>

2.4.3 創建mapper接口和映射文件

  • mapper接口:
public interface TestMapper { /** * 查詢所有用戶信息 * @return */ List<User> getAllUser(); }
  • mapper映射文件:
    在resources下的com/atguigu/mp/mapper目錄下創建TestMapper.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.atguigu.mybatisplus.mapper.UserMapper"><!--SQL片段,記錄基礎字段--><!--<sql id="BaseColumns">id,name,age,email</sql>--><!--第一種寫法--><!--List<User> getAllUser();--><select id="getAllUser" resultType="User">select <include refid="BaseColumns"></include> from user</select><!--第二種寫法--><!--List<User> getAllUser();--><select id="getAllUser" resultType="User"><!--select <include refid="BaseColumns"></include> from user-->select id,name,age,email from user</select> </mapper>

2.4.4 創建jdbc.properties

在resources下創建jdbc.properties

jdbc.username=root jdbc.password=5864@WCY jdbc.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&useSSL=false jdbc.driver=com.mysql.cj.jdbc.Driver

2.4.5 創建Spring的配置文件

<?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/contexthttps://www.springframework.org/schema/context/spring-context.xsd"><!-- 引入jdbc.properties --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 配置Druid數據源 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="${jdbc.driver}"></property><property name="url" value="${jdbc.url}"></property><property name="username" value="${jdbc.username}"></property><property name="password" value="${jdbc.password}"></property></bean><!-- 配置用于創建SqlSessionFactory的工廠bean --><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!-- 設置MyBatis配置文件的路徑(可以不設置) --><property name="configLocation" value="classpath:mybatis-config.xml"></property><!-- 設置數據源 --><property name="dataSource" ref="dataSource"></property><!-- 設置類型別名所對應的包 --><property name="typeAliasesPackage" value="com.atguigu.mybatisplus.pojo"></property><!--設置映射文件的路徑若映射文件所在路徑和mapper接口所在路徑一致,則不需要設置--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/></bean><!--配置mapper接口的掃描配置由mybatis-spring提供,可以將指定包下所有的mapper接口創建動態代理并將這些動態代理作為IOC容器的bean管理--><bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.atguigu.mybatisplus.mapper"></property></bean><!--配置自動掃描的包--><context:component-scan base-package="com.atguigu.mybatisplus.service"></context:component-scan> </beans>

2.4.6 添加日志功能

在resources下創建logback.xml

<?xml version="1.0" encoding="UTF-8"?> <configuration debug="false"><!--定義日志文件的存儲地址 logs為當前項目的logs目錄 還可以設置為../logs --><property name="LOG_HOME" value="logs" /><!--控制臺日志, 控制臺輸出 --><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"><!--格式化輸出:%d表示日期,%thread表示線程名,%-5level:級別從左顯示5個字符寬度,%msg:日志消息,%n是換行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}- %msg%n</pattern></encoder></appender><!--myibatis log configure--><logger name="com.apache.ibatis" level="TRACE"/><logger name="java.sql.Connection" level="DEBUG"/><logger name="java.sql.Statement" level="DEBUG"/><logger name="java.sql.PreparedStatement" level="DEBUG"/><!-- 日志輸出級別 --><root level="DEBUG"><appender-ref ref="STDOUT" /></root></configuration>

2.4.7 測試

  • 方式一:通過IOC容器
public class MyBatisPlusTest {@Testpublic void testMyBatis(){ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");TestMapper mapper = ac.getBean(TestMapper.class);mapper.getAllUser().forEach(user -> System.out.println(user));} }
  • 方式二 Spring整合junit
//在Spring的環境中進行測試 @RunWith(SpringJUnit4ClassRunner.class) //指定Spring的配置文件 @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusTest {@Autowiredprivate TestMapper testMapper;@Testpublic void testMyBatisBySpring(){testMapper.getAllUser().forEach(user -> System.out.println(user));} }


2.5 加入MyBatis-Plus

Spring整合MyBatis

加入MyBatis-Plus之后

<!-- 此處使用的是MybatisSqlSessionFactoryBean --> <!-- 配置用于創建SqlSessionFactory的工廠bean --><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!-- 設置MyBatis配置文件的路徑(可以不設置) --><property name="configLocation" value="classpath:mybatis-config.xml"></property><!-- 設置數據源 --><property name="dataSource" ref="dataSource"></property><!-- 設置類型別名所對應的包 --><property name="typeAliasesPackage" value="com.atguigu.mybatisplus.pojo"></property><!--設置映射文件的路徑若映射文件所在路徑和mapper接口所在路徑一致,則不需要設置--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/></bean>

此處使用的是MybatisSqlSessionFactoryBean
經觀察,目前bean中配置的屬性和SqlSessionFactoryBean一致
MybatisSqlSessionFactoryBean是在SqlSessionFactoryBean的基礎上進行了增強
即具有SqlSessionFactoryBean的基礎功能,又具有MyBatis-Plus的擴展配置
具體配置信息地址(https://baomidou.com/pages/56bac0/#%E5%9F%BA%E6%9C%AC%E9%
85%8D%E7%BD%AE)


2.5.1 創建Mapper接口

public interface UserMapper extends BaseMapper<User> { }

BaseMapper是MyBatis-Plus提供的基礎mapper接口,泛型為所操作的實體類型,其中包含CRUD的各個方法,我們的mapper繼承了BaseMapper之后,就可以直接使用BaseMapper所提供的各種方法,而不需要編寫映射文件以及SQL語句,大大的提高了開發效率

2.5.2 測試

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusTest {/*沒有使用mybatis_plus@Testpublic void testMyBatis(){ApplicationContext ac = newClassPathXmlApplicationContext("applicationContext.xml");UserMapper mapper = ac.getBean(UserMapper.class);mapper.getAllUser().forEach(user -> System.out.println(user));}*/@Autowiredprivate UserMapper userMapper;/*---------------------------------使用MyBatisPlus之后-------------------------------------*/@Testpublic void testMyBatisPlus(){//查詢所有用戶信息// SELECT id,name,age,email FROM userSystem.out.println(userMapper.selectList(null));}

2.5.3 結果

2.6 總結

在Spring整合MyBatis中加入了MyBatis-Plus后,我們就可以使用MyBatis-Plus所提供的BaseMapper實現CRUD,并不需要編寫映射文件以及SQL語句
但是若要自定義SQL語句,仍然可以編寫映射文件而不造成任何影響。因為MyBatis-Plus只做增強,而不做改變。

三、基本CRUD

3.1 BaseMapper

MyBatis-Plus中的基本CRUD在內置的BaseMapper中都已得到了實現,我們可以直接使用,接口如下:

/*** Mapper 繼承該接口后,無需編寫 mapper.xml 文件,即可獲得CRUD功能* <p>這個 Mapper 支持 id 泛型</p>** @author hubin* @since 2016-01-23*/ public interface BaseMapper<T> extends Mapper<T> {/*** 插入一條記錄** @param entity 實體對象*/int insert(T entity);/*** 根據 ID 刪除** @param id 主鍵ID*/int deleteById(Serializable id);/*** 根據實體(ID)刪除** @param entity 實體對象* @since 3.4.4*/int deleteById(T entity);/*** 根據 columnMap 條件,刪除記錄** @param columnMap 表字段 map 對象*/int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根據 entity 條件,刪除記錄** @param queryWrapper 實體對象封裝操作類(可以為 null,里面的 entity 用于生成 where 語句)*/int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 刪除(根據ID 批量刪除)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 根據 ID 修改** @param entity 實體對象*/int updateById(@Param(Constants.ENTITY) T entity);/*** 根據 whereEntity 條件,更新記錄** @param entity 實體對象 (set 條件值,可以為 null)* @param updateWrapper 實體對象封裝操作類(可以為 null,里面的 entity 用于生成 where 語句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);/*** 根據 ID 查詢** @param id 主鍵ID*/T selectById(Serializable id);/*** 查詢(根據ID 批量查詢)** @param idList 主鍵ID列表(不能為 null 以及 empty)*/List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);/*** 查詢(根據 columnMap 條件)** @param columnMap 表字段 map 對象*/List<T> selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);/*** 根據 entity 條件,查詢一條記錄* <p>查詢一條記錄,例如 qw.last("limit 1") 限制取一條記錄, 注意:多條數據會報異常</p>** @param queryWrapper 實體對象封裝操作類(可以為 null)*/default T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {List<T> ts = this.selectList(queryWrapper);if (CollectionUtils.isNotEmpty(ts)) {if (ts.size() != 1) {throw ExceptionUtils.mpe("One record is expected, but the query result is multiple records");}return ts.get(0);}return null;}/*** 根據 Wrapper 條件,查詢總記錄數** @param queryWrapper 實體對象封裝操作類(可以為 null)*/Long selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 entity 條件,查詢全部記錄** @param queryWrapper 實體對象封裝操作類(可以為 null)*/List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄** @param queryWrapper 實體對象封裝操作類(可以為 null)*/List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄* <p>注意: 只返回第一個字段的值</p>** @param queryWrapper 實體對象封裝操作類(可以為 null)*/List<Object> selectObjs(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 entity 條件,查詢全部記錄(并翻頁)** @param page 分頁查詢條件(可以為 RowBounds.DEFAULT)* @param queryWrapper 實體對象封裝操作類(可以為 null)*/<P extends IPage<T>> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄(并翻頁)** @param page 分頁查詢條件* @param queryWrapper 實體對象封裝操作類*/<P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); }

3.2 BaseMapper功能測試

//插入@Testpublic void testInsert(){// INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )User user = new User(6,"張三",23,"zhangsan@126.com");int result = userMapper.insert(user);System.out.println("result="+result);}//刪除@Testpublic void testDelete(){//根據Id刪除用戶//DELETE FROM user WHERE id=?int result = userMapper.deleteById(2L);//根據map集合刪除//DELETE FROM user WHERE name = ? AND age = ?Map<String,Object> map = new HashMap<>();map.put("name","張三");map.put("age",23);int result = userMapper.deleteByMap(map);// 根據id批量刪除// DELETE FROM user WHERE id IN ( ? , ? , ? )List<Integer> list = Arrays.asList(1, 2, 3);int result = userMapper.deleteBatchIds(list);System.out.println("result="+result);}//修改@Testpublic void testUpdate(){ // UPDATE user SET name=?, email=? WHERE id=?User user = new User();user.setId(4L);user.setName("李四");user.setEmail("lisi@atguigu.com");int result = userMapper.updateById(user);System.out.println("result="+result);}//查詢@Testpublic void testSelect(){//根據Id查詢用戶 // SELECT id,name,age,email FROM user WHERE id=?User user = userMapper.selectById(5L);System.out.println(user);// SELECT id,name,age,email FROM user WHERE id IN ( ? , ? , ? )List<Integer> list = Arrays.asList(1, 2, 4);List<User> users = userMapper.selectBatchIds(list);users.forEach(System.out::println);Map<String,Object> map = new HashMap<>();map.put("age",23);List<User> users = userMapper.selectByMap(map);users.forEach(System.out::println);}

通過觀察BaseMapper中的方法,大多方法中都有Wrapper類型的形參,此為條件構造器,可針對于SQL語句設置不同的條件,若沒有條件,則可以為該形參賦值null,即查詢(刪除/修改)所有數據


3.3 通用Service

說明:

  • 通用 Service CRUD 封裝IService接口,進一步封裝 CRUD 采用 get 查詢單行 remove 刪除 list 查詢集合 page 分頁 , 前綴命名方式區分 Mapper 層避免混淆
  • 泛型 T 為任意實體對象
  • 建議如果存在自定義通用 Service 方法的可能,請創建自己的 IBaseService 繼承Mybatis-Plus 提供的基類
  • 官網地址:https://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3

3.3.1 IService

MyBatis-Plus中有一個接口 IService和其實現類 ServiceImpl,封裝了常見的業務層邏輯

詳情查看源碼IService和ServiceImpl

3.3.2 創建Service接口和實現類

UserService

/** * UserService繼承IService模板提供的基礎功能 */ public interface UserService extends IService<User> {}

UserServiceImpl

/** * ServiceImpl實現了IService,提供了IService中基礎功能的實現 * 若ServiceImpl無法滿足業務需求,則可以使用自定的UserService定義方法,并在實現類中實現 */ @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}

3.3.3 在spring配置文件中設置自動掃描service的包

在applicationContext.xml中添加掃描組件的配置,掃描業務層組件,用于測試

<context:component-scan base-package="com.atguigu.mybatisplus.service.impl"></context:component-scan>

3.3.4 測試查詢記錄條數和批量添加

//spring測試類寫法一 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisServiceTest {@Autowiredprivate UserService userService;@Testpublic void testCount(){//查詢總記錄條數//SELECT COUNT( * ) FROM userlong count = userService.count();System.out.println("總記錄條數" + count);}@Testpublic void testSaveBatch(){//實現新增用戶ArrayList<User> list = new ArrayList<>();// SQL長度有限制,海量數據插入單條SQL無法實行,// 因此MP將批量插入放在了通用Service中實現,而不是通用Mapperfor (int i = 0; i < 100 ; i++) {User user = new User();user.setName("abc"+i);user.setAge(20+i);list.add(user);}//INSERT INTO user ( id, name, age ) VALUES ( ?, ?, ? )boolean b = userService.saveBatch(list);System.out.println(b);}}

錯誤:
Duplicate entry ‘0’ for key ‘PRIMARY’
原因:發現了是數據庫表設計不合理導致的;
因為主鍵設置不能為空,因此默認是以"0"來進行填充的。因此在數據插入時數據的主鍵id值被0占據,但由于之前已經有數據了,id為“0”的索引已經被占,在使用就會報這個錯誤,因此我們只需要對表中的主鍵“id”設置成自增即可。

糾正:為什么會出現這個問題,是因為在創建實體類的時候id屬性的類型寫成long了,應該寫成Long不然雪花算法是不會實現的。大小寫要注意。

四、常用注解

4.1 @TableName

經過以上的測試,在使用MyBatis-Plus實現基本的CRUD時,我們并沒有指定要操作的表,只是在Mapper接口繼承BaseMapper時,設置了泛型User,而操作的表為user表:
由此得出結論,MyBatis-Plus在確定操作的表時,由BaseMapper的泛型決定,即實體類型決定,且默認操作的表名和實體類型的類名一致

4.1.1 問題

若實體類類型的類名和要操作的表的表名不一致,會出現什么問題?
我們將表user更名為t_user,測試查詢功能
程序拋出異常,Table ‘mybatis_plus.user’ doesn’t exist,因為現在的表名為t_user,而默認操作的表名和實體類型的類名一致,即user表

4.1.2 通過@TableName解決問題

在實體類類型上添加==@TableName(“t_user”)==,標識實體類對應的表,即可成功執行SQL語句。

4.1.3 通過GlobalConfig解決問題

在開發的過程中,我們經常遇到以上的問題,即實體類所對應的表都有固定的前綴,例如t_tbl_
此時,可以使用MyBatis-Plus提供的全局配置,為實體類所對應的表名設置默認的前綴,那么就不需要在每個實體類上通過@TableName標識實體類對應的表。

在spring配置文件中修改:spring-persist.xml中的sqlsessionfactorybean

<!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數據源--><property name="dataSource" ref="dataSource"/><!--設置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property></bean><bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean id="config" class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><!--設置實體類所對應的表的前綴--><property name="tablePrefix" value="t_"></property></bean></property></bean>

4.2 @TableId

經過以上的測試,MyBatis-Plus在實現CRUD時,會默認將id作為主鍵列,并在插入數據時,默認基于雪花算法的策略生成id。

4.2.1 問題引出

若實體類和表中表示主鍵的不是id,而是其他字段,例如uid,MyBatis-Plus會自動識別uid為主鍵列嗎?
我們實體類中的屬性id改為uid,將表中的字段id也改為uid,測試添加功能程序拋出異常,Field ‘uid’ doesn’t have a default value,說明MyBatis-Plus沒有將uid作為主鍵賦值

4.2.2 通過@TableId解決問題

在實體類中uid屬性上通過@TableId將其標識為主鍵,即可成功執行SQL語句。

4.2.3 @TableId的value屬性

若實體類中主鍵對應的屬性為id,而表中表示主鍵的字段為uid,此時若只在屬性id上添加注解@TableId,則拋出異常Unknown column ‘id’ in ‘field list’,即MyBatis-Plus仍然會將id作為表的主鍵操作,而表中表示主鍵的是字段uid
此時需要通過@TableId注解的value屬性,指定表中的主鍵字段@TableId(“uid”)或@TableId(value=“uid”)

public class User {//將屬性所對應的字段指定為主鍵// @TableId注解的value屬性用于指定主鍵的字段@TableId("uid")private Long id;

4.2.4 @TableId的type屬性

type屬性用來定義主鍵策略


[1]臨時修改

public class User {//將屬性所對應的字段指定為主鍵// @TableId注解的value屬性用于指定主鍵的字段// @TableId注解的type屬性設置主鍵生成策略// @TableId(value = "uid", type = IdType.AUTO)@TableId("uid")private Long id;

[2] 配置全局配置(全局有效)
在spring-persist.xml中修改。

<bean id="globalConfig" class="com.baomidou.mybatisplus.core.config.GlobalConfig"><property name="dbConfig"><bean id="config" class="com.baomidou.mybatisplus.core.config.GlobalConfig$DbConfig"><!--設置實體類所對應的表的前綴--><property name="tablePrefix" value="t_"></property><!--設置全局主鍵策略--><property name="idType" value="AUTO"></property></bean></property></bean>

4.2.5 雪花算法






4.3 @TableField

經過以上的測試,我們可以發現,MyBatis-Plus在執行SQL語句時,要保證實體類中的屬性名和表中的字段名一致
如果實體類中的屬性名和字段名不一致的情況,會出現什么問題呢?
a>情況1

若實體類中的屬性使用的是駝峰命名風格,而表中的字段使用的是下劃線命名風格
例如實體類屬性userName,表中字段user_name
此時MyBatis-Plus會自動將下劃線命名風格轉化為駝峰命名風格
相當于在MyBatis中配置

b>情況2

若實體類中的屬性和表中的字段不滿足情況1
例如實體類屬性name,表中字段username
此時需要在實體類屬性上使用@TableField(“username”)設置屬性所對應的字段名

//注意:如果實體類中屬性名為:name,表中字段名也要為:name// 在不加@TableField注解的情況下,表中字段為:user_name 代碼會報錯。//指定屬性對應的字段名//當實體類中是name,表中所對應的字段名是:user_name,可以使用該注解來實現指定屬性對應的字段名@TableField("user_name")private String name;

4.4 @TableLogic(邏輯刪除)

4.4.1 邏輯刪除

邏輯刪除

物理刪除:真實刪除,將對應數據從數據庫中刪除,之后查詢不到此條被刪除的數據
邏輯刪除:假刪除,將對應數據中代表是否被刪除字段的狀態修改為“被刪除狀態”,之后在數據庫中仍舊能看到此條數據記錄
使用場景:可以進行數據恢復

4.4.2 實現邏輯刪除

  • 數據庫中創建邏輯刪除狀態列,設置默認值為0

  • 實體類中添加邏輯刪除屬性

  • //邏輯刪除@TableLogicprivate Integer isDeleted;
  • 測試
    • 測試刪除功能,真正執行的是修改
      UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0
    • 測試查詢功能,被邏輯刪除的數據默認不會被查詢
      SELECT id,username AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0

    五、條件構造器和常用接口

    5.1 wapper介紹

    5.2 QueryWrapper

    5.2.1 組裝查詢條件

    @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusWrapperTest {@Autowiredpublic UserMapper userMapper;@Testpublic void test01(){//查詢用戶名包含a,年齡在20到30之間,并且郵箱不為null的用戶信息QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age BETWEEN ? AND ? AND email IS NOT NULL)queryWrapper.like("user_name","a").between("age",20,30).isNotNull("email");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

    5.2.2 組裝排序條件

    @Testpublic void test02(){//按年齡降序查詢用戶,如果年齡相同則按id升序排列//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age DESC,uid ASCQueryWrapper<User> queryWrapper = new QueryWrapper<>();queryWrapper.orderByDesc("age").orderByAsc("uid");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

    5.2.3 組裝刪除條件

    @Testpublic void test03(){//刪除email為空的用戶QueryWrapper<User> queryWrapper = new QueryWrapper<>();//UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (email IS NULL)//出現這個是因為我們設置了邏輯刪除,即刪除變成了修改,將狀態從0(未刪除狀態)--->1(已刪除狀態);queryWrapper.isNull("email");int result = userMapper.delete(queryWrapper);System.out.println("受影響的行數 : " + result);}

    5.2.4 條件的優先級

    /*** update(User entity,Wrapper<User> updateWrapper)* 第一個參數為修改的內容,第二個參數為設置修改的條件參數1設置修改的字段和值,參數2是查詢符合的條件**/@Testpublic void test04(){//條件包裝器中條件之間默認是and連接。我們不需要手動設置,但是如果是或,我們需要手動設置or.//將(年齡大于20并且用戶名中包含有a)或郵箱為null的用戶信息修改QueryWrapper<User> queryWrapper = new QueryWrapper<>();//UPDATE t_user SET user_name=?, age=?, email=? WHERE is_deleted=0 AND (user_name LIKE ? AND age > ? OR email IS NULL)queryWrapper.like("user_name","a").gt("age",20).or().isNull("email");User user = new User();user.setName("小明");user.setEmail("test@atguigu.com");int result = userMapper.update(user, queryWrapper);System.out.println("受影響的行數:" + result);} @Testpublic void test05(){//將(年齡大于20或郵箱為null)并且用戶名中包含有a的用戶信息修改//lambda表達式內的邏輯優先運算QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))queryWrapper.like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

    5.2.5 組裝select子句

    @Testpublic void test06(){//查詢用戶信息的username和age字段QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT user_name,age FROM t_user WHERE is_deleted=0queryWrapper.select("user_name","age");List<Map<String, Object>> maps = userMapper.selectMaps(queryWrapper);maps.forEach(System.out::println);}

    5.2.6 實現子查詢

    @Testpublic void test07(){//查詢id小于等于3的用戶信息QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (uid IN (select uid from t_user where uid <= 3))queryWrapper.inSql("uid","select uid from t_user where uid <= 3");List<User> userList = userMapper.selectList(queryWrapper);userList.forEach(System.out::println);}

    5.3 UpdateWrapper

    @Testpublic void test08(){//將用戶名中包含有a并且(年齡大于20或郵箱為null)的用戶信息修改// 組裝set子句以及修改條件UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();/*寫在一起updateWrapper.set("age",18).set("email","user@atguigu.com").like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));*///分開寫//UPDATE t_user SET user_name=?,email=? WHERE is_deleted=0 AND (user_name LIKE ? AND (age > ? OR email IS NULL))updateWrapper.like("user_name","a").and(i ->i.gt("age",20).or().isNull("email"));updateWrapper.set("user_name","小黑").set("email","abc@atguigu.xom");//這里必須要創建User對象,否則無法應用自動填充。如果沒有自動填充,可以設置為null//UPDATE t_user SET username=?, age=?,email=? WHERE (username LIKE ? AND(age > ? OR email IS NULL))//User user = new User();//user.setName("張三");//int result = userMapper.update(user, updateWrapper);//UPDATE t_user SET age=?,email=? WHERE (username LIKE ? AND (age > ? ORemail IS NULL))int result = userMapper.update(null, updateWrapper);System.out.println("result = " + result);}

    5.4 condition

    在真正開發的過程中,組裝條件是常見的功能,而這些條件數據來源于用戶輸入,是可選的,因此我們在組裝這些條件時,必須先判斷用戶是否選擇了這些條件,若選擇則需要組裝該條件,若沒有選擇則一定不能組裝,以免影響SQL執行的結果。

    思路一:

    @Testpublic void test09(){//定義查詢條件,有可能為null(用戶未輸入或未選擇)String username = null;Integer ageBegin = 20;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (age >= ? AND age <= ?)//StringUtils.isNotBlank()判斷某字符串是否不為空且長度不為0且不由空白符(whitespace)構成if(StringUtils.isNotBlank(username)){queryWrapper.like("user_name","a");}if (ageBegin != null){queryWrapper.ge("age",ageBegin);}if (ageEnd != null){queryWrapper.le("age",ageEnd);}List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}

    思路2:

    上面的實現方案沒有問題,但是代碼比較復雜,我們可以使用帶condition參數的重載方法構建查詢條件,簡化代碼的編寫

    @Testpublic void test10(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;QueryWrapper<User> queryWrapper = new QueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)queryWrapper.like(StringUtils.isNotBlank(username),"user_name","a").ge(ageBegin != null,"age",ageBegin).le(ageEnd != null,"age",ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}

    5.5 LambdaQueryWrapper

    @Testpublic void test11(){String username = "a";Integer ageBegin = null;Integer ageEnd = 30;LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();//SELECT uid AS id,user_name AS name,age,email,is_deleted FROM t_user WHERE is_deleted=0 AND (user_name LIKE ? AND age <= ?)queryWrapper.like(StringUtils.isNotBlank(username),User::getName,"a").ge(ageBegin != null,User::getAge,ageBegin).le(ageEnd != null,User::getAge,ageEnd);List<User> list = userMapper.selectList(queryWrapper);list.forEach(System.out::println);}

    5.6 LambdaUpdateWrapper

    @Testpublic void test12(){//將用戶名中包含有a并且(年齡大于20或郵箱為null)的用戶信息修改// 組裝set子句以及修改條件LambdaUpdateWrapper<User> updateWrapper = new LambdaUpdateWrapper<>();/*合在一起updateWrapper.set(User::getAge, 18).set(User::getEmail, "user@atguigu.com").like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));*///分開寫updateWrapper.like(User::getName, "a").and(i -> i.lt(User::getAge, 24).or().isNull(User::getEmail));updateWrapper.set(User::getName,"小黑").set(User::getEmail,"abc@atguigu.com");User user = new User();int result = userMapper.update(user, updateWrapper);System.out.println("受影響的行數:" + result);}

    六、插件

    6.1 分頁插件

    MyBatis Plus自帶分頁插件,只要簡單的配置即可實現分頁功能。

    6.1.1 添加配置

    <!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數據源--><property name="dataSource" ref="dataSource"/><!--設置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property></bean><!--配置MyBatis-Plus插件--><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref></list></property></bean><!--配置Mybatis-plus分頁插件的bean--><bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"><!--設置數據庫類型--><property name="dbType" value="MYSQL"></property></bean>

    6.1.2 測試

    @Testpublic void testPage(){//設置分頁參數Page<User> page = new Page<>(2,3);userMapper.selectPage(page,null);List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("每頁顯示的條數:"+page.getSize());System.out.println("總記錄數:"+page.getTotal());System.out.println("總頁數:"+page.getPages());System.out.println( "當前頁:" + page.getCurrent());System.out.println("是否有下一頁:" + page.hasNext());System.out.println("是否有上一頁:" + page.hasPrevious());}

    測試結果:
    User(id=1, name=Jone, age=18, email=test1@baomidou.com, isDeleted=0) User(id=2,name=Jack, age=20, email=test2@baomidou.com, isDeleted=0) User(id=3, name=Tom,age=28, email=test3@baomidou.com, isDeleted=0) User(id=4, name=Sandy, age=21,email=test4@baomidou.com, isDeleted=0) User(id=5, name=Billie, age=24, email=test5@baomidou.com, isDeleted=0) 當前頁:1 每頁顯示的條數:5 總記錄數:17 總頁數:4 是否有上一
    頁:false 是否有下一頁:true

    6.2 xml自定義分頁

    6.2.1 UserMapper中定義接口方法

    /*** 根據年齡查詢用戶列表,分頁顯示* @param page 分頁對象,xml中可以從里面進行取值,傳遞參數 Page 即自動分頁,必須放在第一位* @param age 年齡* @return*/IPage<User> selectPageVo(@Param("page") Page<User> page , @Param("age") Integer age);}

    6.2.2 UserMapper.xml中編寫SQL

    <!--IPage<User> selectPageVo(@Param("page") Page<User> page , @Param("age") Integer age);--><select id="selectPageVo" resultType="User">select uid,user_name,age,email from t_user where age > #{age}</select>

    6.2.3 測試

    @Testpublic void testPageVo(){Page<User> page = new Page<>(1,5);//第一頁索引為1,不是0userMapper.selectPageVo(page,20);List<User> list = page.getRecords();list.forEach(System.out::println);System.out.println("每頁顯示的條數:"+page.getSize());System.out.println("總記錄數:"+page.getTotal());System.out.println("總頁數:"+page.getPages());System.out.println( "當前頁:" + page.getCurrent());System.out.println("是否有下一頁:" + page.hasNext());System.out.println("是否有上一頁:" + page.hasPrevious());}

    結果:
    User(id=3, name=Tom, age=28, email=test3@baomidou.com, isDeleted=null)
    User(id=4,name=Sandy, age=21,email=test4@baomidou.com, isDeleted=null) User(id=5, name=Billie,age=24, email=test5@baomidou.com, isDeleted=null) User(id=8,name=ybc1, age=21,email=null, isDeleted=null)
    User(id=9, name=ybc2, age=22,email=null, isDeleted=null)
    當前頁:1 每頁顯示的條數:5 總記錄數:12 總頁數:3 是否有上一頁:false 是否有下一頁:true

    6.3 樂觀鎖

    6.3.1 場景

    一件商品,成本價是80元,售價是100元。老板先是通知小李,說你去把商品價格增加50元。小李正在玩游戲,耽擱了一個小時。正好一個小時后,老板覺得商品價格增加到150元,價格太高,可能會影響銷量。又通知小王,你把商品價格降低30元。
    此時,小李和小王同時操作商品后臺系統。小李操作的時候,系統先取出商品價格100元;小王也在操作,取出的商品價格也是100元。小李將價格加了50元,并將100+50=150元存入了數據
    庫;小王將商品減了30元,并將100-30=70元存入了數據庫。是的,如果沒有鎖,小李的操作就完全被小王的覆蓋了。
    現在商品價格是70元,比成本價低10元。幾分鐘后,這個商品很快出售了1千多件商品,老板虧1萬多。

    6.3.2 樂觀鎖與悲觀鎖

    上面的故事,如果是樂觀鎖,小王保存價格前,會檢查下價格是否被人修改過了。如果被修改過了,則重新取出的被修改后的價格,150元,這樣他會將120元存入數據庫。
    如果是悲觀鎖,小李取出數據后,小王只能等小李操作完之后,才能對價格進行操作,也會保證最終的價格是120元。

    6.3.3 模擬修改沖突

    a>數據庫中增加商品表

    CREATE TABLE t_product ( id BIGINT(20) NOT NULL COMMENT '主鍵ID', NAME VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名稱', price INT(11) DEFAULT 0 COMMENT '價格', VERSION INT(11) DEFAULT 0 COMMENT '樂觀鎖版本號', PRIMARY KEY (id) );

    b>添加數據

    INSERT INTO t_product (id, NAME, price) VALUES (1, '外星人筆記本', 100);

    c>添加實體

    */@Data public class Product {private Long id;private String name;private Integer price;}

    d>添加mapper

    public interface ProductMapper extends BaseMapper<Product> {}

    f>測試

    @Testpublic void testProduct01(){//小李查詢價格Product productLi = productMapper.selectById(1);System.out.println("小李查詢的商品價格:" + productLi.getPrice());//小王查詢價格Product productWang = productMapper.selectById(1);System.out.println("小王查詢的商品價格:" + productWang.getPrice());//小李將商品價格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王將商品價格-30productWang.setPrice(productWang.getPrice() - 30);int result = productMapper.updateById(productWang);//老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板查詢的商品價格為:" + productBoss.getPrice());}

    6.3.4 樂觀鎖實現流程

    數據庫中添加version字段
    取出記錄時,獲取當前version

    SELECT id,`name`,price,`version` FROM product WHERE id=1

    更新時,version + 1,如果where語句中的version版本不對,則更新失敗

    UPDATE product SET price=price+50, `version`=`version` + 1 WHERE id=1 AND `version`=1

    6.3.5 Mybatis-Plus實現樂觀鎖

    [1]修改實體類

    */@Data public class Product {private Long id;private String name;private Integer price;@Versionprivate Integer version;}

    [2]添加樂觀鎖插件配置

    <!--配置MyBatis-Plus插件--><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><ref bean="paginationInnerInterceptor"></ref><ref bean="optimisticLockerInnerInterceptor"></ref></list></property></bean><!--配置樂觀鎖插件--><bean id="optimisticLockerInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor"></bean>

    [3] 測試修改沖突

    小李查詢商品信息:
    SELECT id,name,price,version FROM t_product WHERE id=?
    小王查詢商品信息:
    SELECT id,name,price,version FROM t_product WHERE id=?
    小李修改商品價格,自動將version+1
    UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    Parameters: 外星人筆記本(String), 150(Integer), 1(Integer), 1(Long), 0(Integer)
    小王修改商品價格,此時version已更新,條件不成立,修改失敗
    UPDATE t_product SET name=?, price=?, version=? WHERE id=? AND version=?
    Parameters: 外星人筆記本(String), 70(Integer), 1(Integer), 1(Long), 0(Integer)
    最終,小王修改失敗,查詢價格:150
    SELECT id,name,price,version FROM t_product WHERE id=?

    [4]優化流程

    @Testpublic void testProduct01(){//小李查詢價格Product productLi = productMapper.selectById(1);System.out.println("小李查詢的商品價格:" + productLi.getPrice());//小王查詢價格Product productWang = productMapper.selectById(1);System.out.println("小王查詢的商品價格:" + productWang.getPrice());//小李將商品價格+50productLi.setPrice(productLi.getPrice() + 50);productMapper.updateById(productLi);//小王將商品價格-30productWang.setPrice(productWang.getPrice() - 30);int result = productMapper.updateById(productWang);if (result == 0){//操作失敗,重試Product productNew = productMapper.selectById(1);productNew.setPrice(productNew.getPrice() - 30);productMapper.updateById(productNew);}//老板查詢商品價格Product productBoss = productMapper.selectById(1);System.out.println("老板查詢的商品價格為:" + productBoss.getPrice());}

    七 、通用枚舉

    表中的有些字段值是固定的,例如性別(男或女),此時我們可以使用MyBatis-Plus的通用枚舉來實現。

    7.1 數據庫添加字段sex

    7.2 創建通用枚舉

    */@Getter public enum SexEnum {MALE(1,"男"),FEMALE(2,"女");@EnumValue //將注解所標識的屬性的值存儲到數據庫中private Integer sex;private String sexName;SexEnum(Integer sex, String sexName) {this.sex = sex;this.sexName = sexName;} }

    7.3 配置掃描通用枚舉

    <!--使用mybatisplus--><bean id="mybatisSqlSessionFactoryBean" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><!--指定mybatis配置文件--><property name="configLocation" value="classpath:mybatis-config.xml"/><!--指定mapper.xml--><property name="mapperLocations" value="classpath:mappers/*Mapper.xml"/><!--裝配數據源--><property name="dataSource" ref="dataSource"/><!--設置mybatisplus的全局配置,即表的前綴--><property name="globalConfig" ref="globalConfig"></property><!--配置掃描通用枚舉--><property name="typeEnumsPackage" value="com.atguigu.mybatisplus.enums"></property><!--配置插件--><property name="plugins"><array><ref bean="mybatisPlusInterceptor"></ref></array></property></bean>

    7.4 測試

    @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class MyBatisPlusEnumTest {@Autowiredprivate UserMapper userMapper;@Testpublic void testSexEnum(){User user = new User();user.setName("Enum");user.setAge(20);//設置性別信息為枚舉項,會將@EnumValue注解所標識的屬性值存儲到數據庫// INSERT INTO t_user ( user_name, age, sex, is_deleted ) VALUES ( ?, ?, ?, ? )user.setSex(SexEnum.MALE);userMapper.insert(user);}

    八、代碼生成器

    8.1 引入依賴

    <!--代碼生成器逆向工程依賴--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.1</version></dependency><!--代碼生成器中 freemarker引擎模板需要這個依賴--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version></dependency>

    8.2 快速生成

    public class FastAutoGeneratorTest {public static void main(String[] args) {FastAutoGenerator.create("jdbc:mysql://127.0.0.1:3306/mybatis_plus?characterEncoding=utf-8&userSSL=false","root", "5864@WCY").globalConfig(builder -> {builder.author("atguigu") // 設置作者// .enableSwagger() // 開啟 swagger 模式.fileOverride() // 覆蓋已生成文件.outputDir("F://JAVA listen//code//mybatis_plus"); // 指定輸出目錄}).packageConfig(builder -> {builder.parent("com.atguigu") // 設置父包名.moduleName("mybatisplus") // 設置父包模塊名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, "F://JAVA listen//code//mybatis_plus"));// 設置mapperXml生成路徑}).strategyConfig(builder -> {builder.addInclude("t_user") // 設置需要生成的表名.addTablePrefix("t_", "c_"); // 設置過濾表前綴}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker 引擎模板,默認的是Velocity引擎模板.execute();}}

    九 、MyBatisX插件

    MyBatis-Plus為我們提供了強大的mapper和service模板,能夠大大的提高開發效率。
    但是在真正開發過程中,MyBatis-Plus并不能為我們解決所有問題,例如一些復雜的SQL,多表聯查,我們就需要自己去編寫代碼和SQL語句,我們該如何快速的解決這個問題呢,這個時候可以使用MyBatisX插件。
    MyBatisX一款基于 IDEA 的快速開發插件,為效率而生。

    MyBatisX插件用法:https://baomidou.com/pages/ba5b24/

    9.1 安裝插件

    安裝方法:打開 IDEA,進入 File -> Settings -> Plugins -> Browse Repositories,輸入 mybatisx 搜索并安裝

    9.2 功能

    9.2.1 XML跳轉

    當mapper映射文件和mapper很多的時候,可以快速定位并跳轉到對應的類容上。

    9.2.2 快速生成代碼

    [1]首先需要在datasource中進行配置

    [2] 選擇驅動

    [3]可以直接選擇舊版本的驅動,或者按提示下載

    [4] 登錄后選擇數據庫、表,然后點擊右鍵選擇mybatisx。


    [5] 表的基本配置

    [6] 生成的基本配置

    [7]選擇好后會自動幫我們生成各種組件

    [8]如果我們要自定義查詢功能,我們只需要在mapper中寫我們的方法名,插件會自動幫助我們補全方法名并且快速生成相對應的sql語句放在mapper映射文件中。

    十、總結

    mybatsi-plus可以快速幫助我們完成spring和mybatsi的整合及搭建功能。

    總結

    以上是生活随笔為你收集整理的MyBatis_Plus(Spring版本笔记)的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    国产中文字幕视频在线观看 | 国产资源av | 97操碰| 久草在线久| 一级性视频 | 玖玖精品在线 | 亚洲va天堂va欧美ⅴa在线 | 中文字幕视频观看 | 亚洲黄色成人 | 亚洲精品玖玖玖av在线看 | 韩国视频一区二区三区 | 9999在线视频| 久久精品播放 | 高潮久久久久久久久 | 很黄很污的视频网站 | 顶级欧美色妇4khd | 在线观看av小说 | 亚洲人人av| 欧美一级欧美一级 | 国产福利一区二区在线 | 欧美作爱视频 | 国产欧美最新羞羞视频在线观看 | 国产v视频 | 五月天久久婷 | 激情综合狠狠 | 9i看片成人免费看片 | 国产精品亚州 | 美女精品久久 | 国产剧情一区 | 日韩激情免费视频 | 国产精品99久久久久久人免费 | 久久免视频| 欧美精品一区二区三区一线天视频 | 国产精品 日韩 | 亚洲国产日韩一区 | 色偷偷88欧美精品久久久 | 精品一区91 | 国产成人一区二区三区在线观看 | 国内99视频 | 精品国产伦一区二区三区观看说明 | 亚洲精品久久久久999中文字幕 | 91最新网址在线观看 | 2021国产精品视频 | 九九热精 | 91在线超碰 | 久久婷婷视频 | 91精品视屏 | 最新婷婷色| 国产精品免费久久久久久 | 日韩高清av | 色婷婷导航 | 中文字幕在线国产 | 亚洲免费av一区二区 | 国产一级免费在线 | 激情综合六月 | 久久天| 国产精品一区二区在线看 | 91九色丨porny丨丰满6 | 色婷婷久久久 | 2019国产精品 | 欧美精品久久久久久久久免 | 狠狠色丁香婷婷综合 | 国产精品国产三级在线专区 | 中文字幕亚洲国产 | 久草在线视频精品 | 色综合狠狠干 | 天天综合人人 | 日韩大片免费观看 | 麻豆传媒在线视频 | 亚洲精品一区二区三区在线观看 | 国产精品美女免费看 | 亚洲精品伦理在线 | 99这里有精品 | 精品人人爽 | 国产小视频你懂的 | 午夜精品视频免费在线观看 | 久久99热国产 | 日本精品视频网站 | 亚洲欧美综合精品久久成人 | 色激情在线 | 丝袜美女视频网站 | 国产精品国产精品 | 国产精品一区二区av | 国产视频1| 国产三级av在线 | 最新av中文字幕 | 天天拍天天爽 | 精品国产伦一区二区三区免费 | 国产精品永久久久久久久久久 | 在线观看一级视频 | 久久国产区 | 91精品国产高清 | 国产一级片免费播放 | 日韩精品在线一区 | 国产伦理一区 | 国产一区欧美在线 | 午夜精品电影 | 欧美视频xxx | 91色综合| 丁香激情综合久久伊人久久 | 亚洲国产mv | 四虎影视成人精品国库在线观看 | 五月亚洲综合 | 2021av在线 | av五月婷婷| 美女黄频在线观看 | 成片免费观看视频 | 国产日韩在线播放 | 韩国精品视频在线观看 | 久久兔费看a级 | 99热九九这里只有精品10 | 日韩高清国产精品 | 草久久久久 | 中文字幕在线观看第三页 | 欧美在线视频不卡 | 99久久夜色精品国产亚洲 | 91插插视频 | 三级黄色理论片 | 二区三区av | 91丨九色丨蝌蚪丰满 | 六月婷色| 看国产黄色大片 | 日本久久精品 | 日韩精品中文字幕久久臀 | 中文字幕在线看视频国产中文版 | 精品一区二区在线看 | 成人av教育| 国产精品精品国产婷婷这里av | 在线不卡中文字幕播放 | 天天久久综合 | 日日爱av | 成人午夜在线电影 | 在线性视频日韩欧美 | 又黄又爽又刺激视频 | 免费亚洲一区二区 | 国产精品欧美久久久久无广告 | 最近高清中文字幕在线国语5 | 久久综合久久综合这里只有精品 | 国产美女网 | 色婷婷九月 | 欧美日韩综合在线 | www.超碰 | 亚洲最大激情中文字幕 | 国产视频一区精品 | 成人黄色免费观看 | 99人成在线观看视频 | 五月婷婷在线播放 | 中国黄色一级大片 | 开心激情五月婷婷 | 91麻豆.com | 亚洲小视频在线 | 日日天天| 日韩三级久久 | 日韩av片在线 | 91 中文字幕| 97超碰在线免费观看 | www.天天色.com | 国产成人综合在线观看 | 国产原创在线 | 欧美另类老妇 | 亚洲精品99久久久久中文字幕 | 日本公妇色中文字幕 | 久久一视频 | 在线观看911视频 | 日日夜夜天天干 | 国产午夜一区二区 | 美女视频久久久 | 日韩在线视频网 | 色婷婷av在线 | 精品久久1 | av网站在线观看免费 | 96av视频 | 日日夜夜网站 | 97精品超碰一区二区三区 | 国产永久免费观看 | 992tv在线| 夜夜看av| 在线观看视频在线观看 | 日韩在线视频免费看 | 成人在线视频一区 | 久久精品久久综合 | 91麻豆精品国产91久久久使用方法 | 91在线观看黄 | 91久久国产自产拍夜夜嗨 | 成人国产精品电影 | 日本中文字幕系列 | 欧美9999| 97精品国产97久久久久久久久久久久 | 免费看毛片在线 | 国产91综合一区在线观看 | 91av美女| 美国三级黄色大片 | 国产成人久久精品亚洲 | 在线国产黄色 | 国产精品自在线 | 国产无区一区二区三麻豆 | 欧美日本在线观看视频 | 久久综合精品一区 | 久久久精品一区二区 | 九九九在线观看视频 | www.天天色 | 精品久久久久久亚洲综合网站 | 成年人在线观看视频免费 | 中文字幕影视 | 激情在线网址 | 国产一级片视频 | 国语自产偷拍精品视频偷 | 久久97超碰| 在线观看黄色 | 日韩亚洲在线视频 | 美女久久久久久久久久 | 亚洲人成影院在线 | 久久久久久高潮国产精品视 | 久久不色| 97日日碰人人模人人澡分享吧 | 国产婷婷一区二区 | 久色婷婷| av电影不卡在线 | av无限看| 久久久久看片 | 日韩精品中文字幕有码 | 精品视频免费看 | 国产精品嫩草69影院 | 91精品久久久久久 | 色综合久久中文字幕综合网 | 日韩亚洲国产精品 | 国产精品一区二区av影院萌芽 | 久久视频| 亚洲成年人av | 日韩高清不卡一区二区三区 | 亚洲人成影院在线 | 成人国产一区 | 亚洲九九九在线观看 | 91成人在线视频 | 国产午夜精品免费一区二区三区视频 | 国产在线中文字幕 | 免费亚洲片 | 91成人午夜 | 九九在线视频免费观看 | 国产五码一区 | 欧美日高清视频 | 色综合久久88色综合天天 | 国产亚洲亚洲 | 久久久综合色 | a'aaa级片在线观看 | 手机看片国产 | 成人午夜精品 | www免费网站在线观看 | 欧美一级免费片 | 久久中文欧美 | 免费看色的网站 | 日韩精品久久久久久 | 日韩欧美有码在线 | 又黄又爽又无遮挡免费的网站 | 97精品超碰一区二区三区 | 五月天网页 | 在线观看激情av | 亚洲精品乱码久久久久久蜜桃不爽 | 91亚洲网站 | 国产精品成人在线观看 | 日韩一二三 | 久久精品国产亚洲精品 | 欧美日韩一区二区三区在线观看视频 | 精品国产一区二区三区在线观看 | 国产视频1区2区 | 久久视频这里有精品 | 国产91av视频在线观看 | 日韩视频精品在线 | av免费观看高清 | 天天干天天做 | 91精品影视 | 国产精品久久久久久久久费观看 | 国产99久久精品一区二区永久免费 | 国产黄色精品在线 | 色五婷婷| 久久99久久99精品免观看粉嫩 | 97超碰国产精品女人人人爽 | 在线电影日韩 | 天天操综 | 国产又粗又猛又色又黄视频 | 日韩成人黄色av | 狠狠操狠狠操 | 最近中文字幕免费视频 | 午夜av免费看 | 成人av影院在线观看 | av日韩在线网站 | 亚洲综合五月天 | av高清一区二区三区 | 午夜精品久久久久久久99婷婷 | 五月婷婷在线观看视频 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 天天色天天骑天天射 | 天天干com| 操少妇视频 | 在线观看的黄色 | 91理论片午午伦夜理片久久 | 操久久免费视频 | 成人黄色免费在线观看 | 五月天中文字幕 | 综合视频在线 | 亚洲欧美国产精品久久久久 | 天堂av免费观看 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 黄色软件视频网站 | 亚洲精品国偷拍自产在线观看蜜桃 | 国产精彩视频一区二区 | www.亚洲黄色| 亚洲成人网在线 | 免费亚洲精品 | 久久免费福利 | 丝袜美女在线 | 激情电影影院 | 国产一区在线免费观看 | 草免费视频 | 欧美色精品天天在线观看视频 | 米奇狠狠狠888 | 97精品国产91久久久久久 | 中文国产在线观看 | 久久综合给合久久狠狠色 | 成人一区在线观看 | 女人久久久久 | 免费看污的网站 | 97人人澡人人添人人爽超碰 | 在线观看91网站 | 在线成人中文字幕 | 中文字幕人成乱码在线观看 | 爱爱av在线| 黄av免费在线观看 | 成年人免费看片网站 | 亚洲激情在线视频 | 婷婷av电影 | 天天色播 | 成人午夜黄色影院 | 久久久久久美女 | 黄a网站| 一本一本久久aa综合精品 | 日日夜夜精品视频天天综合网 | 欧美亚洲久久 | 在线有码中文 | 丁香狠狠 | 99精品一级欧美片免费播放 | 免费视频你懂的 | 在线黄色免费av | 99视频免费看 | 天天弄天天操 | 综合色伊人 | 欧洲亚洲精品 | 国产精品mv在线观看 | 四虎影视国产精品免费久久 | 亚洲激情在线观看 | 亚洲国产中文字幕在线 | 99视频导航 | 夜夜视频欧洲 | 日韩视频在线观看免费 | 日本中文字幕在线一区 | 在线观看一区二区精品 | 国产成人在线免费观看 | 日韩欧美成人网 | 国产视频中文字幕 | 欧美天天综合 | 超碰在线97国产 | 在线观看国产www | 久久伦理网 | 91综合视频在线观看 | 天天曰天天爽 | 欧美性黄网官网 | 中文字幕在线看 | 中文字幕资源在线 | 国内精品一区二区 | 欧美日韩另类在线 | 精品国产视频一区 | 播五月婷婷 | 亚洲妇女av | 在线色资源 | 亚洲 欧洲av | 久久www免费人成看片高清 | 亚洲aⅴ一区二区三区 | 日韩精品一区二区三区免费观看 | 久久字幕 | 久草手机视频 | 国产中出在线观看 | 欧美性天天 | avhd高清在线谜片 | 国产91勾搭技师精品 | 91资源在线免费观看 | 欧美精品一区二区在线观看 | 久草爱视频 | 97电影在线观看 | 国产亚洲情侣一区二区无 | 久久久亚洲网站 | 91社区国产高清 | 最近中文字幕在线中文高清版 | 亚洲成a人片在线www | 精品久久久久久久久中文字幕 | 麻豆视频成人 | 日韩在线网址 | 一区二区三区动漫 | 激情视频免费观看 | 狠狠干夜夜操 | 激情导航| 久久免费视频这里只有精品 | 在线观看一级 | 人人插人人爱 | 国产精品原创视频 | 伊人资源视频在线 | 国产一区二区三区久久久 | 国产一二三在线视频 | 美女网站色 | 国产一区精品在线观看 | 九九免费精品视频 | 五月天精品视频 | 麻豆高清免费国产一区 | 日韩三级视频在线观看 | 国产视频在线播放 | 亚洲精品久久久蜜臀下载官网 | 夜夜操夜夜干 | 久草在线资源观看 | 99久久精品久久久久久动态片 | 国产亚洲精品av | 91精品国产麻豆国产自产影视 | 国产成人精品av | 韩日在线一区 | 久久五月天综合 | 久热电影| 狠狠干在线播放 | 毛片在线播放网址 | 麻豆系列在线观看 | 成人国产精品久久久久久亚洲 | 麻豆一精品传二传媒短视频 | 一区二区三区在线电影 | 午夜少妇av| 久久久福利视频 | 免费一级特黄录像 | 精品亚洲一区二区 | 中文字幕高清 | www.天天操| 亚洲精品久久久久久久不卡四虎 | 免费久久久久久久 | 免费看黄色小说的网站 | 欧美日韩中文字幕综合视频 | 夜夜夜草 | 国产一级特黄毛片在线毛片 | 国产色 在线 | 国产精品无| 99久久久成人国产精品 | 亚洲一区精品人人爽人人躁 | 精品国产中文字幕 | 亚洲精品乱码久久久久久蜜桃不爽 | 一区二区三区韩国免费中文网站 | 91桃花视频| 五月香婷 | 久久国产福利 | 久久99亚洲精品久久 | 久久久精品网 | 色多多污污| 国产一级一片免费播放放 | 免费高清看电视网站 | 久久久久久久久久毛片 | 亚洲精品久久久久中文字幕m男 | 国产精品久久久视频 | 韩国av一区二区三区在线观看 | 欧美一级久久 | 久热免费 | 天天干天天射天天插 | 久久国产成人午夜av影院潦草 | 久久国产精品一国产精品 | 欧美中文字幕第一页 | 久久久久久久久久影视 | 久久美女视频 | 欧美国产不卡 | 在线有码中文字幕 | 欧美色图东方 | 国产成人精品综合久久久 | 中文乱码视频在线观看 | 色婷婷视频在线观看 | 亚洲另类在线视频 | 国产一区二区精品 | 久在线| 毛片精品免费在线观看 | 久久不卡国产精品一区二区 | 视频在线播放国产 | 日韩在线电影 | 亚洲一区二区三区毛片 | 五月婷婷深开心 | 91在线精品秘密一区二区 | 免费亚洲视频 | 91亚洲精品乱码久久久久久蜜桃 | 在线观看精品视频 | 久久成人在线视频 | 久久国产精品一区二区 | 天天操天天爱天天干 | av一级片网站 | 日本女人的性生活视频 | 国产精品一区二区麻豆 | 国产精品国产三级国产aⅴ入口 | 一区二区影院 | 欧美a√大片 | 国产精品福利无圣光在线一区 | 免费av在线 | 成人av在线直播 | 久久免费精品一区二区三区 | 日韩av一区二区在线 | 99精品免费久久久久久日本 | 久久成人国产精品免费软件 | 在线观看一区二区视频 | 国产v在线观看 | 91 在线视频 | 国产精品免费一区二区三区 | 美女视频一区二区 | 久久精品国亚洲 | 色综合久久久久综合 | 超碰官网 | 国产视频欧美视频 | 国内精品中文字幕 | 亚洲欧洲成人精品av97 | 激情综合五月婷婷 | 午夜av不卡 | 久久精品伊人 | 午夜av大片 | 91在线永久 | www视频在线免费观看 | 在线涩涩| 国产精品18久久久久vr手机版特色 | av福利第一导航 | 人人爽人人爽人人爽 | 欧美精品久久久久久久久免 | 福利二区视频 | 啪嗒啪嗒免费观看完整版 | 国产韩国日本高清视频 | 日韩二区精品 | 色九色| 毛片视频电影 | 国产黄色资源 | 成人网444ppp | 日韩欧美在线免费 | 久久乐九色婷婷综合色狠狠182 | 成人黄色片在线播放 | 欧美日韩在线视频免费 | 精品国产一区二区三区久久久久久 | 深夜免费福利在线 | 激情视频一区 | 国产美女在线免费观看 | 91免费黄视频| 久草视频在线播放 | 色综合天天综合 | 国产在线精品一区二区三区 | 日日夜夜精品视频天天综合网 | 伊人丁香 | 99久久久久久久久久 | 91豆花在线| 亚洲播放一区 | 亚洲一级性 | 成年人在线观看 | 在线91视频 | 日韩免费电影一区二区三区 | 免费美女久久99 | 久久人人爽人人片av | 一区二区中文字幕在线观看 | 欧美一级免费高清 | 久久激情视频免费观看 | 久久观看最新视频 | 丝袜一区在线 | 中文资源在线播放 | 亚洲永久精品一区 | 国产亚洲精品美女久久 | 亚洲精品乱码久久久久久久久久 | 中文字幕日韩在线播放 | 视频一区在线播放 | 天天操天天摸天天射 | 亚洲精品国产拍在线 | 最新高清无码专区 | 久久99精品国产99久久 | 国产日韩欧美中文 | 国产美女视频网站 | 伊人黄色网 | 亚洲成人家庭影院 | av在线网站免费观看 | 韩国精品在线观看 | 欧美巨大荫蒂茸毛毛人妖 | av在线进入 | 久二影院 | 色是在线视频 | 激情片av | 全黄色一级片 | 嫩草91影院 | 成人av一区二区三区 | 亚洲综合色播 | 欧美成人久久 | 久久久午夜精品理论片中文字幕 | 97视频免费在线观看 | 狠狠色狠狠色合久久伊人 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 天天爱天天操天天射 | 日日干天天干 | 天天干天天做 | 国产午夜精品免费一区二区三区视频 | 91手机在线看片 | 99热这里精品 | 粉嫩一区二区三区粉嫩91 | 日韩在线不卡视频 | 91精品国产91p65 | 日韩欧美一区二区在线播放 | 国产 日韩 在线 亚洲 字幕 中文 | 蜜臀av夜夜澡人人爽人人桃色 | 久精品视频免费观看2 | 日韩美女黄色片 | 在线观看深夜福利 | 欧美一二三区在线观看 | 97视频免费观看 | 久久精品国产亚洲精品 | 成人黄色在线视频 | 国产伦精品一区二区三区无广告 | 狠狠色综合欧美激情 | 亚洲夜夜综合 | 五月婷婷丁香 | 中文字幕在线观看第二页 | 99精品免费视频 | 在线观看成人av | 久久在现视频 | 精品国产人成亚洲区 | 日本护士三级少妇三级999 | 国产成人在线一区 | 国产成人精品一区二区三区免费 | 69国产精品视频免费观看 | 中文字幕资源在线 | 久久永久免费视频 | 久久精品伊人 | 中文字幕在线看 | 麻豆视频观看 | 日韩在线视频网站 | 中文字幕一区二区三区四区 | www.黄色小说.com | 亚洲视频观看 | 久久亚洲人 | 精品国产乱码久久久久久1区2匹 | 久av在线 | 成年人视频在线观看免费 | 四虎影视成人永久免费观看视频 | 国产 日韩 欧美 自拍 | 免费观看视频黄 | 久久国内免费视频 | 久久香蕉国产精品麻豆粉嫩av | 成年人免费看的视频 | 在线国产91 | 国产婷婷在线观看 | 黄色影院在线免费观看 | 91成人免费视频 | 欧美激情另类文学 | 黄色网址在线播放 | 五月天天在线 | 欧美精品一二 | 欧美午夜a | 国产美女视频网站 | 国产精品福利一区 | 五月天天色 | 视频 天天草 | 日韩欧美精品一区二区 | 一区二区三区精品在线 | 99久久婷婷国产一区二区三区 | 亚洲视频免费 | 日本久久影视 | 最近中文字幕国语免费av | 国产日韩欧美在线 | 亚洲国产三级在线 | 天天操天天操天天操天天操 | 天堂激情网 | 在线免费观看黄色小说 | 中文久草 | 欧美日韩在线观看一区 | 午夜av一区二区三区 | 黄色在线观看免费 | 天天综合狠狠精品 | 91av亚洲| 久久久综合电影 | 精品91| 欧美大片mv免费 | 日韩欧美视频在线播放 | 国产高清在线免费视频 | 久久久免费观看视频 | 69av视频在线 | 久久亚洲综合色 | av成人在线网站 | 精品国模一区二区三区 | 成人手机在线视频 | 麻豆免费视频网站 | 欧美日韩网址 | 人人看人人爱 | 久久影院精品 | 久久久久国产a免费观看rela | 国产黄色高清 | 亚洲精品乱码久久久久久按摩 | 成 人 黄 色 视频 免费观看 | 久久深夜 | 国产亚洲精品美女久久 | 日韩免费一级a毛片在线播放一级 | 久久成人高清 | av在线中文 | 四虎成人精品永久免费av | 黄色.com| 久久国内精品 | 波多野结衣综合网 | 日韩精品一区在线播放 | 97免费在线视频 | 99热国产精品 | 92国产精品久久久久首页 | 久久久久综合 | www.色五月.com | 欧美在线一二区 | 国产一区国产二区在线观看 | 婷婷六月在线 | 国产精品久久久久9999 | 国产精品成人a免费观看 | 欧美日韩亚洲第一页 | 天操夜夜操 | 又色又爽又激情的59视频 | 99在线免费视频 | 97自拍超碰 | 四虎永久免费 | 久久伊人精品天天 | 日韩免费b | 精品国产免费观看 | a在线免费观看视频 | 亚洲日日日 | 日韩高清成人在线 | 日韩中文字幕91 | 在线观看黄网 | 日韩成人免费电影 | 亚州国产精品 | 人人要人人澡人人爽人人dvd | 精品一区二区三区久久 | 久草免费色站 | 丁五月婷婷 | 片网站 | 九九在线视频 | 香蕉视频久久 | 亚洲精品视频在线看 | 91久久久久久久一区二区 | 中文字幕久久久精品 | 国产福利小视频在线 | 插久久| 国产欧美在线一区 | 欧美一二三视频 | 亚洲91网站 | 欧美日韩国产页 | 91av电影在线观看 | 91成人网页版 | 国产精品久久久久久高潮 | 成人欧美一区二区三区在线观看 | 99在线精品视频 | 一区二区三区四区五区在线 | 国产第一页在线播放 | 久久免费99精品久久久久久 | 蜜桃视频色 | 国产资源在线免费观看 | 国产精品免费在线观看视频 | 午夜视频99 | 久久午夜精品视频 | 黄色在线免费观看网站 | 久久色在线观看 | 99视频精品免费视频 | 中文字幕在线观看视频一区 | 国产精品一码二码三码在线 | 国产精品免费久久久久久 | 婷婷在线精品视频 | 国产在线观看av | 国产在线欧美在线 | 日本精品久久久久影院 | 9在线观看免费 | 色综合久久中文字幕综合网 | 国产裸体永久免费视频网站 | 久久久久二区 | 五月天婷婷综合 | 亚洲精品女人久久久 | 久久久久久久久久久久亚洲 | 岛国大片免费视频 | 九热在线 | 狠狠的干狠狠的操 | 一区二区精品国产 | 一区二区视频网站 | 三级av在线免费观看 | 日韩精品一区在线观看 | 成人网页在线免费观看 | 色av色av色av | 国产一级片免费视频 | 久久公开免费视频 | 久久久久一区二区三区四区 | 久久艹久久 | 国产精品黑丝在线观看 | 91网免费观看 | 久精品视频在线 | 久久黄色成人 | 国产精品2019 | 午夜视频不卡 | 毛片888 | 成人av亚洲 | 99精品在线看 | 一区二区三区在线免费观看 | 久久中文精品视频 | 成人午夜免费剧场 | 日韩电影在线一区二区 | 色狠狠操 | 国产成人免费精品 | 97视频精品 | 国产精品久久久久999 | 91热爆在线观看 | 波多野结衣视频网址 | 成人av资源 | 四虎永久国产精品 | 日韩av免费一区 | 久久午夜免费视频 | 97香蕉久久国产在线观看 | 日韩免费高清 | 久久精品免费 | 99爱精品视频| 视频在线一区 | 久久久黄视频 | 99视频在线精品国自产拍免费观看 | 97色在线观看免费视频 | 亚洲免费av一区二区 | 丁香色天天| 96视频在线 | 成年人视频在线 | 欧美最猛性xxx | 手机av永久免费 | 在线观看www91 | 国产在线中文字幕 | 国产伦精品一区二区三区在线 | 久久久久久国产精品亚洲78 | 天天爱天天操天天干 | 四虎成人av | 91精品爽啪蜜夜国产在线播放 | 国产成人亚洲精品自产在线 | 欧美综合色在线图区 | 国产精品门事件 | 午夜成人免费影院 | 九九av| 91精选在线 | 成人免费视频播放 | 久久99精品久久只有精品 | 美女视频黄网站 | 免费看成人 | 日日夜夜天天操 | 欧美在线观看视频一区二区 | 国产福利91精品一区 | 在线播放视频一区 | 中文在线免费看视频 | 91视频免费 | 国产一级黄色免费看 | 日本韩国欧美在线观看 | 91色在线观看 | 成在人线av | 黄色的视频 | 亚洲在线国产 | 国产在线国产 | 国产69精品久久久久9999apgf | 在线观看视频中文字幕 | 欧美日韩xx | av片在线观看 | 亚洲视频精品在线 | 人人狠 | 99视频精品 | 久久电影国产免费久久电影 | 欧洲精品久久久久毛片完整版 | 黄色电影在线免费观看 | 五月婷在线观看 | av中文字幕电影 | 国产亚洲字幕 | 欧美一二三区播放 | 97在线精品国自产拍中文 | 99在线看 | av中文字幕在线播放 | 亚洲色图27p| 日韩精品一区二区在线视频 | 亚洲在线a | 国产精品久久99 | 免费高清在线观看成人 | 97在线观看免费观看 | 天天操人| 日韩精品在线观看av | 久久久亚洲精品 | 激情五月***国产精品 | 久久久久久久久久影视 | 91福利区一区二区三区 | 97色狠狠| 日日干激情五月 | 国产伦理久久精品久久久久_ | 在线国产视频 | 午夜久久网站 | 欧美精品免费视频 | 青青啪| 欧美污在线观看 | 国产视频综合在线 | 亚洲电影av在线 | 欧美 日韩 国产 中文字幕 | a级国产乱理伦片在线播放 久久久久国产精品一区 | 97人人模人人爽人人喊网 | www.亚洲精品视频 | 国产精品一区二区麻豆 | 国产精品99久久99久久久二8 | 在线观看国产麻豆 | 免费在线观看av片 | 久久99久久精品国产 | 精品中文字幕在线播放 | 国产专区日韩专区 | 亚洲免费国产视频 | 国产精品一区二区久久精品爱涩 | 一区二区免费不卡在线 | 欧美与欧洲交xxxx免费观看 | 91精品国产91 | 一二三精品视频 | 亚洲天堂首页 | 亚洲综合色视频在线观看 | 日韩欧美精品免费 | 天天色天天操天天爽 | av三级在线看 | 四虎伊人 | 日韩精品久久中文字幕 | 成人香蕉视频 | 久久精品国产免费看久久精品 | 美女精品在线 | 福利视频一区二区 | 伊人va | 奇米网网址 | 精品视频免费在线 | 国产成人av电影 | 国产精品成人久久 | 久久精品视频在线免费观看 | av在线h | 精品国产乱码久久久久久1区二区 | 伊人视频 | 看片网站黄色 | 一区二区视频免费在线观看 | 久久99网站| 91亚洲精品国产 | a级国产乱理论片在线观看 伊人宗合网 | 99精品国产99久久久久久福利 | 午夜影院一级片 | 欧美日bb| 国产精品美女久久久久久久久 | 欧美一区二区三区激情视频 | 国产精品一区二区三区观看 | 久久黄色影院 | 四虎永久免费 | 成人在线观看影院 | 91传媒在线播放 | 狠狠黄| 欧美日韩国产精品爽爽 | 久久国产精品影视 | 麻豆系列在线观看 | 国产xxxx| 亚洲另类在线视频 | 一区二区三区免费在线观看视频 | 亚洲黄在线观看 | 尤物一区二区三区 | 999在线视频 | 最近高清中文字幕 | 深爱开心激情 | 成人av电影免费在线观看 | 久久 国产一区 | 99精品视频播放 | 中文字幕在线影院 | 一区二区三区免费在线观看 | 人人澡人人干 | 久草免费在线视频观看 | 国产精品美女视频网站 | 亚洲欧美日韩国产精品一区午夜 | 国产尤物在线观看 | 亚洲一区视频在线播放 | 日本性久久 | 中文av网站 | 欧美一二三区在线观看 | 综合铜03 | 黄色片视频免费 | 亚洲电影久久 | 麻豆视频观看 | 亚洲国产wwwccc36天堂 | 国产精品h在线观看 | 麻豆极品| 高清久久久 | av一区二区三区在线观看 | 亚洲精品国久久99热 | 在线观看完整版免费 | av官网在线 | 五月婷婷一级片 | a天堂在线看 | 日日草av | 97操碰 | 欧美日韩中文字幕视频 | 狠狠色婷婷丁香六月 | 综合久久一本 | 欧美电影在线观看 | 日韩精品免费在线观看 | 国产精品久久久久久久久久久不卡 | 9992tv成人免费看片 | 亚洲日本va午夜在线电影 | 成人av免费播放 | 精品99999| 6080yy精品一区二区三区 |