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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

【开发】后端框架——Mybatis

發布時間:2024/1/8 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【开发】后端框架——Mybatis 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前置知識:JDBC

學習視頻

Mybatis——一種ORM框架:將Java中的Bean映射為數據庫的記錄

  • ORM:用于實現面向對象編程語言里不同類型系統的數據之間的轉換

Mybatis運行過程——工廠模式

#{} 與 ${} ——三點區別

動態Sql

分頁——兩種方法

緩存——查詢緩存順序

MyBatis

文檔

官方文檔

下載鏈接

sql相關

  • sql引擎
  • innoDB底層
  • 索引
  • 索引優化

概述

JDBC

JDBC驅動程序:JDBC(Java Database Connectivity, Java 數 據 庫 連 接)是 一 種可用于執行 SQL 語句的 Java API(Application Programming Interface)

  • 實現了從 Java 程序內調用標準的 SQL命令 對數據庫進行查詢、插入、刪除和更新等操作, 并確保數據事務的正常進行

  • 基本層次結構由 Java 程序、JDBC 驅動程序管理器、數據庫驅動程序和數據庫四部分組成

  • Java 程序依賴于 JDBC API,通過 DriverManager 來獲取驅動,并且針對不同的數據庫可以使用不同的驅動。

  • 這是典型的橋接的設計模式,把 抽象 Abstraction 與 行為實現Implementation 分離 開來,從而可以保持各部分的獨立性以及應對他們的功能擴展。

JDBC步驟

public static void connectionTest(){Connection connection = null;Statement statement = null;ResultSet resultSet = null;try {// 1. 加載并注冊 MySQL 驅動器實例Class.forName("com.mysql.cj.jdbc.Driver").newInstance();// 2. 將Mysql驅動程序注冊到驅動管理程序中// 根據特定的數據庫連接URL,返回與此URL所匹配的數據庫驅動對象Driver driver = DriverManager.getDriver("jdbc:mysql://localhost:3306/[dbName]"); // 3. 傳入參數,比如說用戶名和密碼Properties props = new Properties();props.put("user", USER_NAME);props.put("password", PASSWORD);// 4. 使用數據庫驅動創建數據庫連接 Connectionconnection = driver.connect(URL, props);// 5. 從數據庫連接 connection 中獲得 Statement 對象statement = connection.createStatement();// 6. 執行 sql 語句,返回結果resultSet = statement.executeQuery("select * from activity");// 7. 處理結果,取出數據while(resultSet.next()){System.out.println(resultSet.getString(2));}.....}finally{// 8.關閉鏈接,釋放資源 按照JDBC的規范,使用完成后管理鏈接,// 釋放資源,釋放順序應該是: ResultSet ->Statement ->ConnectionresultSet.close();statement.close();connection.close();} }

JDBC存在的問題

  • 傳統的JDBC代碼復雜
  • 實現步驟多
  • 需要設計一種 將數據映射到數據庫的框架 來簡化JDBC的步驟

Mybatis特點

  • 持久層框架

    持久化:將程序中的數據從 瞬時狀態【內存:斷電即失】轉化為 持久狀態【數據庫jdbc,io文件持久化】的過程

    持久層:完成數據持久化工作的代碼塊,層次間界限分明

  • 定制化Sql

  • 避免JDBC代碼,手動設置參數和獲取結果集

優點

  • 簡單:兩個jar文件(mybatis.jar+mysql-connector.jar)+配置幾個sql映射文件(Mapper)
  • 靈活:sql寫在xml里,統一管理(mybatis-config.xml
  • 解除sql與程序的耦合:通過提供Mapper層,將業務邏輯與數據訪問邏輯分離
  • 提供映射標簽:JavaBean與數據庫字段的關系映射
  • 提供xml標簽,支持編寫動態sql

Mybatis執行流程

通過簡單的 XML 或注解來配置和映射原始類型、接口和 Java POJO

  • 獲取配置文件
  • 實例化 SqlSessionFactoryBuilder
  • 加載 mybatis-config.xml 中的配置信息
  • 實例化 SqlsessionFactory
  • 創建執行器 executor
  • 創建 SqlSession
  • 實現CRUD邏輯
  • CRUD后提交事務,判斷是否執行成功
  • #mermaid-svg-NVpap7Rp8SLvnviA {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .error-icon{fill:#552222;}#mermaid-svg-NVpap7Rp8SLvnviA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NVpap7Rp8SLvnviA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NVpap7Rp8SLvnviA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NVpap7Rp8SLvnviA .marker.cross{stroke:#333333;}#mermaid-svg-NVpap7Rp8SLvnviA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NVpap7Rp8SLvnviA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster-label text{fill:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster-label span{color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .label text,#mermaid-svg-NVpap7Rp8SLvnviA span{fill:#333;color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .node rect,#mermaid-svg-NVpap7Rp8SLvnviA .node circle,#mermaid-svg-NVpap7Rp8SLvnviA .node ellipse,#mermaid-svg-NVpap7Rp8SLvnviA .node polygon,#mermaid-svg-NVpap7Rp8SLvnviA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NVpap7Rp8SLvnviA .node .label{text-align:center;}#mermaid-svg-NVpap7Rp8SLvnviA .node.clickable{cursor:pointer;}#mermaid-svg-NVpap7Rp8SLvnviA .arrowheadPath{fill:#333333;}#mermaid-svg-NVpap7Rp8SLvnviA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NVpap7Rp8SLvnviA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NVpap7Rp8SLvnviA .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-NVpap7Rp8SLvnviA .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster text{fill:#333;}#mermaid-svg-NVpap7Rp8SLvnviA .cluster span{color:#333;}#mermaid-svg-NVpap7Rp8SLvnviA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NVpap7Rp8SLvnviA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Resources獲取加載全局配置文件 實例化SqlSessionFactoryBuilder構造器 解析配置文件流XMLConfigBuilder Configuration加載所有的配置信息 SqlSessionFactory實例化 transactional事務管理器 創建executor執行器 創建SqlSession 實現CRUD 查看是否執行成功 提交事務 關閉

    1. 導包——Maven

    <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version> </dependency>

    SqlSessionFactoryBuilder

    一旦創建了 SqlSessionFactory ,就不再需要它了。

    因此 SqlSessionFactoryBuilder 實例的最佳作用域是方法作用域

    • 作用域:局部變量

    SqlSessionFactory <=> 數據庫連接工廠

    每個基于 MyBatis 的應用都是以一個 SqlSessionFactory 的實例為核心

    構造方法:從xml中配置文件中構建SqlSessionFactory實例

    SqlSessionFactory 一旦被創建就應該在應用的運行期間一直存在

    • 作用域:應用作用域

    最簡單的就是使用單例模式或者靜態單例模式。

    SqlSession => JDBC:Connection對象

    通過 SqlSessionFactory 獲得 SqlSession 的實例。

    SqlSession 提供了在數據庫執行 SQL 命令所需的所有方法。

    SqlSession的實例時線程不安全的,不能被共享

    • 每次收到一個數據庫訪問請求,打開一個SqlSession,返回響應后,立即關閉

    Mapper => JDBC:Statement

    代理對象 執行具體業務

    將接口與xml進行綁定

    Mybatis示例程序

    #mermaid-svg-GeLKu5fxhYgbgLBt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .error-icon{fill:#552222;}#mermaid-svg-GeLKu5fxhYgbgLBt .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GeLKu5fxhYgbgLBt .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GeLKu5fxhYgbgLBt .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GeLKu5fxhYgbgLBt .marker.cross{stroke:#333333;}#mermaid-svg-GeLKu5fxhYgbgLBt svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GeLKu5fxhYgbgLBt .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster-label text{fill:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster-label span{color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .label text,#mermaid-svg-GeLKu5fxhYgbgLBt span{fill:#333;color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .node rect,#mermaid-svg-GeLKu5fxhYgbgLBt .node circle,#mermaid-svg-GeLKu5fxhYgbgLBt .node ellipse,#mermaid-svg-GeLKu5fxhYgbgLBt .node polygon,#mermaid-svg-GeLKu5fxhYgbgLBt .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-GeLKu5fxhYgbgLBt .node .label{text-align:center;}#mermaid-svg-GeLKu5fxhYgbgLBt .node.clickable{cursor:pointer;}#mermaid-svg-GeLKu5fxhYgbgLBt .arrowheadPath{fill:#333333;}#mermaid-svg-GeLKu5fxhYgbgLBt .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-GeLKu5fxhYgbgLBt .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-GeLKu5fxhYgbgLBt .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-GeLKu5fxhYgbgLBt .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster text{fill:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt .cluster span{color:#333;}#mermaid-svg-GeLKu5fxhYgbgLBt div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-GeLKu5fxhYgbgLBt :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 搭建環境 編寫代碼 測試 導入mysql驅動,MyBatis包 核心配置文件mybatis-config.xml 編寫工具類提供SqlSession對象

    1. 搭建數據庫

    create table user(id int(11) not null primary key,user_name varchar(30) default null,pwd varchar(30) default null )engine=InnoDB default charset=utf8;insert into user(id,user_name,pwd) values (1,'a','123456'), (2,'b','123456'), (3,'c','c123456');

    2. 新建項目

    3. 刪除src,使項目成為父工程

    4. maven導入依賴

    <!-- 父工程 --> <groupId>com.kuang.MyBatis</groupId> <artifactId>MyBatis</artifactId> <version>1.0-SNAPSHOT</version><!-- 導入依賴 --> <dependencies><!-- 導入MySql驅動 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency><!-- 導入MyBatis驅動 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.6</version></dependency><!-- 導入junit依賴 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency> </dependencies>

    5. 新建模塊

    6. 獲取數據庫連接對象

    a. 編寫核心配置文件——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><!-- 可配置多套環境,defaulte屬性選擇當前屬性 --><environments default="development"><environment id="development"><!-- 事務管理器 --><transactionManager type="JDBC"/><dataSource type="POOLED"><!-- 配置數據庫驅動器類型及連接參數 --><property name="driver" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/><property name="username" value="root"/><property name="password" value="2017002231"/></dataSource></environment></environments><!-- 每一個Mapper.xml都需要在MyBatis核心配置文件中注冊 --><mappers><mapper resource="com/kuang/dao/UserMapper.xml"/></mappers> </configuration>
    • useSSL:使用安全連接
    • useUnicode:保證中文不亂碼
    • characterEncoding:編碼格式

    b. 編寫MyBatis工具類

    新建dao包,utils包

    public class MyBatisUtils {private static SqlSessionFactory sqlSessionFactory;// 1.獲取SqlSessionFactory對象static{try {//1. 將資源中的配置文件以流的形式讀入String resource = "mybatis-config.xml";InputStream configuration = Resources.getResourceAsStream(resource);//2. 通過工廠類構建器構建SqlSessionFactory類sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);} catch (IOException e) {e.printStackTrace();}}// 2.獲取SqlSession對象public static SqlSession getSqlSession(){return sqlSessionFactory.openSession();} }

    7. 編寫代碼

    實體類

    pojo的作用就是將從數據庫獲取到的數據封裝為一個一個的對象,讓java能夠更好的進行操作DO、VO

    package com.kuang.pojo;public class User {private Integer id;private String user_name;private String pwd;public User(){}public User(Integer id, String user_name, String pwd) {this.id = id;this.user_name = user_name;this.pwd = pwd;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUser_name() {return user_name;}public void setUser_name(String user_name) {this.user_name = user_name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "User{" +"id=" + id +", user_name='" + user_name + '\'' +", pwd='" + pwd + '\'' +'}';} }

    Dao接口

    public interface UserDao{List<User> getUserList(); }

    接口的實現

    由 UserDaoImpl 轉化為 Mapper 配置文件

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!-- 綁定一個對應的Dao/Mapper接口 --> <mapper namespace="com.kuang.dao.UserDao"><!--id:方法名--><select id="getUserList" resultType="com.kuang.pojo.User">select *from mybatis.user;</select> </mapper>
    • namespace:相當于指定要實現的接口
      • 將不同的語句隔離開來,同時也實現了接口綁定
        • 全限定名(比如 “com.mypackage.MyMapper.selectAllThings)將被直接用于查找及使用
        • 短名稱(比如 “selectAllThings”)如果全局唯一也可以作為一個單獨的引用。 如果不唯一,有兩個或兩個以上的相同名稱(比如 “com.foo.selectAllThings” 和 “com.bar.selectAllThings”),那么使用時就會產生“短名稱不唯一”的錯誤,這種情況下就必須使用全限定名。
    • id:方法名
    • resultType:返回單個
    • resultMap:返回多個

    8. 測試

    新建 測試類

    編寫測試代碼

    package com.kuang.dao;import com.kuang.pojo.User; import com.kuang.utils.MyBatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test;import java.util.List;public class UserDaoTest {@Testpublic void test(){//1.獲取SqlSession對象SqlSession sqlSession = MyBatisUtils.getSqlSession();//2.執行Sql //通過反射機制,獲取方法區中UserMapper的Class類實例,這個實例中有UserMapper全部信息UserMapper userMapper = sqlSession.getMapper(UserMapper.class);List<User> userList = userMapper.getUserList();/*//方式二:強制類型轉換,不安全List<User> userList = sqlSession.selectOne("com.kuang.UserDao.getUserList");*/for (User user:userList){System.out.println(user);}//關閉sqlSessionsqlSession.close();} }

    遇到的各種錯誤

    org.apache.ibatis.io不存在——IDEA2020.1


    class not found:ClassTest

    執行UserDaoTest的test方法之前,要先 mvn test-compile 生成 test classes才可被部署并發現


    Type interface com.kuang.dao.UserDao is not known to the MapperRegistry

    <!-- 每一個Mapper.xml都需要在MyBatis核心配置文件中注冊 --> <mappers><mapper resource="com/kuang/dao/UserMapper.xml"/> </mappers>

    Could not find resource com/kuang/dao/UserMapper.xml

    Maven約定大于配置,自己寫的配置文件默認不會被導出或生效

    Maven默認的資源(自己配置的xml)位置在resources目錄下,當前項目的xml位于java目錄下,所以找不到

    <!-- build中配置resources,防止資源導出失敗問題 --> <build><resources><resource><!-- 使得directory目錄下的資源可以被導出 --><directory>src/main/java</directory><!-- 設置可被識別通過的文件類型 --><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource><resource><!-- 使得directory目錄下的資源可以被導出 --><directory>src/main/resources</directory><!-- 設置可被識別通過的文件類型 --><includes><include>**/*.propertes</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources> </build>

    終于成功

    增刪改查CRUD

    CUD 需要通過connection對象以Transition(事務)的形式提交

  • 編寫接口
  • (實現接口)編寫mapper中對應的sql語句
  • 測試
  • select

    選擇,查詢語句:

    • id:方法名
    • resultType:Sql語句執行的返回值
    • parameterType:參數類型

    通過id獲取用戶

  • 模糊查詢

  • Java代碼執行時,傳遞通配符 %%

  • 在sql語句拼接中使用通配符

    • 存在sql注入的風險

  • insert



    并沒有新增

    更新

    刪除



    參數傳遞&Map

    單個參數傳遞方式

    • 只有一個 基本數據類型 ,可省略
    • 實體類對象作為參數,sql語句中的參數取對象的屬性
    • Map作為參數,sql語句中參數取Map的屬性

    多個參數的傳遞

    使用Map的情況

    當字段過多時,考慮使用 Map,可以自定義需要傳遞的參數

    • 若使用實體類作為參數傳遞,當字段過多時,一個實體類的每個屬性都必須設置值
  • Plugin——通用Mapper

    核心配置——mybatis-config.xml

    configuration(配置)

    • properties(屬性)
    • settings(設置)
    • typeAliases(類型別名)
    • environments(環境配置)
      • environment(環境變量)
        • transactionManager(事務管理器)
        • dataSource(數據源)
    • mappers(映射器)

    屬性(properties)

    通過Properties引用配置文件

    • 優先使用外部配置文件
  • properties文件定義屬性的鍵值對——定義變量
  • #db.properties mysql_driver=com.mysql.cj.jdbc.Driver #不需要轉義&amp; MyBatis_url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8 db_username=root db_pwd=2017002231
  • 通過 <properties/> 聲明引用屬性

    <!-- properties引用屬性變量 --> <properties resource="db.properties"/>
  • 使用屬性

  • 設置Settings

    SettingDescriptionValid ValuesDefault
    cacheEnabled是否緩存Globally enables or disables any caches configured in any mapper under this configuration.true | falsetrue
    lazyLoadingEnabled懶加載,提高開發效率When enabled, all relations will be lazily loaded. This value can be superseded for a specific relation by using the fetchType attribute on it.true | falsefalse
    mapUnderscoreToCamelCaseEnables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names aColumn.true | falsefalse
    logImplMyBatis的日志實現方式Specifies which logging implementation MyBatis should use.LOG4J|STDOUT_LOGGINGNo Set
    日志實現——logImpl
    • SLF4J
    • LOG4J | LOG4J2
    • JDK_LOGGING
    • COMMONS_LOGGING
    • STDOUT_LOGGING
    • NO_LOGGING
    STDOUT_LOGGING
    <!--設置日志實現方式--> <settings><setting name="logImpl" value="STDOUT_LOGGING"/> </settings>

    • 由日志可見,MyBatis底層是基于JDBC實現的
    LOG4J
    • 控制日志信息輸送的目的地是控制臺、文件、GUI組件,甚至是套接口服務器、NT的事件記錄器、UNIX Syslog守護進程等
    • 控制每一條日志的輸出格式
  • 導入 LOG4J 包

    <dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version> </dependency>
  • 配置log4j.properties資源

  • # 將等級為DEBUG的日志信息輸出到console和file兩個目的地,console和file的定義在下面的代碼 log4j.rootLogger = debug,console,file# 控制臺處處的相關配置 log4j.appender.console = org.apache.log4j.ConsoleAppender log4j.appender.console.Target = System.out log4j.appender.console.Threshold=DEBUG log4j.appender.console.layout = org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n# 文件輸出的相關設置 log4j.appender.file = org.apache.log4j.RollingFileAppender log4j.appender.file.File = ./logs/log.log log4j.appender.file.MaxFileSize=10mb log4j.appender.file.Threshold = DEBUG log4j.appender.file.layout = org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n# 日志輸出級別 log4j.logger.org.mybatis=DEBUG log4j.logger.java.sql=DEBUG log4j.logger.java.sql.Statement=DEBUG log4j.logger.java.sql.ResultSet=DEBUG log4j.logger.java.sql.PreparedStatement=DEBUG

    程序中使用log4j
  • 導包

    import org.apache.log4j.Logger;
  • 設置變量

    static Logger logger = Logger.getLogger(UserMapperTest.class);

    Logger.getLogger(className):將日志對象與目標對象綁定

  • 使用

    log級別

    • info([信息])
    • debug([信息])
    • error([信息])

  • 環境配置 enviroments

    MyBatis 可以配置成適應多種環境,但每個 SqlSessionFactory 實例只能選擇一種環境

    如果你想連接兩個數據庫,就需要創建兩個 SqlSessionFactory 實例,每個數據庫對應一個。

    • 默認使用的環境 ID(比如:default=“development”)。
    • 每個 environment 元素定義的環境 ID(比如:id=“development”)。
    • 事務管理器的配置(比如:type=“JDBC”)。
    • 數據源的配置(比如:type=“POOLED”)。

    事務管理器(transactionManager)

    兩種類型的事務管理器(也就是 type=“[JDBC|MANAGED]”)

    • 使用 Spring + MyBatis,則沒有必要配置事務管理器,因為 Spring 模塊會使用自帶的管理器來覆蓋前面的配置。

    數據源(dataSource)

    連接數據庫:

    • jdbc
    • dbcp
    • c3p0
    • druid

    三種數據源類型

  • UNPOOLED——用完即銷毀

    • 無連接池,每次請求時打開和關閉連接

    • 浪費資源

  • POOLED——用完即回收

  • JNDI

  • 類型別名typeAliases

    用于減少完全限定名的冗余給Bean取別名

    配置方式

  • 實體類較少,可逐一指定

    <!-- mybatis-config.xml --> <typeAliases><typeAlias type="com.kuang.pojo.User" alias="User"/> </typeAliases><!-- UserMapper.xml --> <mapper namespace="com.kuang.mapper.UserMapper"><!--id:方法名--><select id="getUserList" resultType="User">select *from mybatis.user;</select> </mapper>
  • You can also specify a package where MyBatis will search for all beans.包中實體類的別名為 lowercase(類名的首字母)

    <!-- mybatis-config.xml --> <typeAliases><package name="com.kuang.pojo" /> </typeAliases><!-- UserMapper.xml --> <mapper namespace="com.kuang.mapper.UserMapper"><!--id:方法名--><select id="getUserList" resultType="user">select *from mybatis.user;</select> </mapper>
  • If the @Alias annotation is found its value will be used as an alias. 優先級 :注解別名>配置別名

  • MyBatis默認配置的別名

    AliasMapped Type
    _普通數據類型普通數據類型(int,short,long,byte,double,float,boolean)
    小寫首字母(數據類型名)首字母大寫的數據類型(基本數據類型 + Date,Object,Map,HashMap,List,ArrayList,Collection,Iterator)
    Integer,intBigDecimal
    decimal,bigdecimalInteger

    插件plugins

    • mybatis-generator-core

    • mybatis-plus

    • 通用mapper

    映射器mapper

    接口實現(mapper.xml)必須在configuration中注冊才可被發現

    第一種方式:資源路徑【推薦】

    <!-- Using classpath relative resources --> <mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"/><mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>

    第二種方式:類名

    <!-- Using mapper interface classes --> <mappers><mapper class="org.mybatis.builder.AuthorMapper"/><mapper class="org.mybatis.builder.BlogMapper"/><mapper class="org.mybatis.builder.PostMapper"/> </mappers>

    第三種方式:包內全導入

    <!-- Register all interfaces in a package as mappers --> <mappers><package name="org.mybatis.builder"/> </mappers>

    第二、三種方式的問題

    • 接口和Mapper配置文件必須同名
    • 接口和Mapper配置資源必須在同一包下

    Mapper.xml(Dao實現類)

    • resultMap – The most complicated and powerful element that describes how to load your objects from the database result sets.
      • javaType:class——POJO| ArrayList
      • ofType:list 或 set 中的POJO
    • insert – A mapped INSERT statement.
    • update – A mapped UPDATE statement.
    • delete – A mapped DELETE statement.
    • select – A mapped SELECT statement.

    解決屬性名和字段名不一致問題——resultMap

    簡單的例子

    public class User {private Integer id;private String user_name;private String password; }

    解決思路:起別名

    在 sql 中,用 as 關鍵字,可以給某一字段起別名

    select *from user where id=#{id}selectid as id,user_name as user_name,pwd as password from user where id=#{id};

    在 Mybatis 中,使用 ResultMap 做結果映射,只需要將有差異的屬性與字段映射即可

    • property:POJO中的屬性
    • column:數據庫中的字段

    復雜查詢

    實體間的復雜關系&環境搭建

    關聯association:多對一

    • 查到的是結果是滿足某種關系的個體集

    集合collection:一對多

    • 返回的結果是一個個體,其中某個屬性是個體集

    create table teacher(id int(10) not null,user_name varchar(30) default null,primary key(id) )engine=InnoDB default charset=utf8;insert into teacher(id,user_name) values(1,'秦老師'); insert into teacher(id,user_name) values(2,'江老師');create table student(id int(10) not null,user_name varchar(30) default null,tid int(10) default null,primary key (id),key fktid(tid),constraint fktid foreign key (tid) references teacher(id) )engine=InnoDB default charset=utf8;insert into student(id,user_name,tid) values(1,"小明",1); insert into student(id,user_name,tid) values(2,"小紅",2); insert into student(id,user_name,tid) values(3,"小張",1); insert into student(id,user_name,tid) values(4,"小李",1); insert into student(id,user_name,tid) values(5,"小王",2);
  • 導入lombok
  • 新建實體類
  • 建立Mapper接口
  • 建立Mapper.xml資源
  • 在核心配置文件中綁定注冊Mapper
  • 測試查詢成功
  • Association

    聯表查詢

    select s.id as sid,s.user_name as sname,t.id as tid,t.user_name as tname from student as s,teacher as t where s.tid=t.id

  • 接口

    List<Student> getStudent2();
  • 接口實現

    <!--BFS:聯表查詢,處理結果--> <select id="getStudent2" resultMap="StudentTeacher2">select s.id as sid,s.user_name as sname,t.id as tid,t.user_name as tnamefrom student as s,teacher as twhere s.tid=t.id </select><resultMap id="StudentTeacher2" type="student"><result property="id" column="sid"/><result property="user_name" column="sname"/><association property="teacher" javaType="teacher"><result property="id" column="tid"/><result property="user_name" column="tname"/></association> </resultMap>
  • 測試

  • 嵌套查詢
    select * from student as s where s.tid in (select t.id from teacher as t);

  • 定義接口

    //查詢學生對應的老師信息 List<Student> getStudent();
  • 實現接口

    <!--思路:DFS 查詢嵌套,1. 查詢所有學生信息2. 根據查出來學生的tid,查找對應的teacher --> <select id="getStudent" resultMap="StudentTeacher">select *from mybatis.student; </select><resultMap id="StudentTeacher" type="student"><!--簡單屬性用 <result property="" column=""/>映射即可--><!--復雜屬性多對*————關聯association一對*————集合collection--><association property="teacher" column="tid" javaType="teacher" select="getTeacher"/> </resultMap><select id="getTeacher" resultType="teacher">select *from mybatis.teacher where id=#{tid}; </select>
  • Collection

    @Data public class Student {private Integer id;private String user_name;private Integer tid; }@Data public class Teacher {private Integer id;private String user_name;//一個老師擁有多個學生private List<Student> students; }

    實現根據teacher.id查找該老師對應的所有學生

    聯表查詢
    select t.id tid,t.user_name tname, s.id sid,s.user_name sname from teacher t,student s where t.id=s.tid and t.id=1;

  • 定義接口

    //獲取某個老師下所有的學生信息 Teacher getTeacherById(@Param("tid") Integer id);
  • 實現接口

    <select id="getTeacherById" resultMap="StudentTeacher">select t.id tid,t.user_name tname, s.id sid,s.user_name snamefrom teacher t,student swhere t.id=s.tid and t.id=#{tid}; </select> <resultMap id="StudentTeacher" type="Teacher"><result property="id" column="tid"/><result property="user_name" column="tname"/><!-- 集合中的泛型用ofType指定 --><collection property="students" ofType="student"><result property="id" column="sid"/><result property="user_name" column="sname"/><result property="tid" column="tid"/></collection> </resultMap>
  • 測試

  • 嵌套查詢
    select tid,(select user_name from teacher where id=1) tname,id sid,user_name sname from student s where tid=1;

  • 定義接口

    Teacher getTeacherById2(@Param("tid") Integer id);
  • 實現接口

    <select id="getTeacherById2" resultMap="StudentTeacher2">select *from mybatis.teacher where id=#{tid} </select> <resultMap id="StudentTeacher2" type="teacher"><collection property="students" column="id" javaType="ArrayList" ofType="student" select="GetStudentByTid" /> </resultMap> <select id="GetStudentByTid" resultType="student">select *from mybatis.studentwhere tid=#{tid}; </select>
  • 測試

  • 動態sql

    根據不同的條件生成不同的sql語句

    搭建環境

    create table blog(id varchar(50) not null comment '博客id',title varchar(100) not null comment '博客標題',author varchar(30) not null comment '博客作者',create_time datetime not null comment '創建時間',views int(30) not null comment '瀏覽量' )engine=InnoDB default charset=utf8; @Data public class Blog {private String id;private String title;private String author;private Date createTime;private Integer views; } @SuppressWarnings("all")//抑制所有警告 public class TestBlog {@Testpublic void test(){SqlSession sqlSession = MyBatisUtils.getSqlSession();BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);Blog blog = new Blog();blog.setId(IDUtil.getId());blog.setAuthor("kuang");blog.setTitle("MyBatis如此簡單!");blog.setCreateTime(new Date());blog.setViews(9999);mapper.insert(blog);blog.setId(IDUtil.getId());blog.setTitle("Java如此簡單!");blog.setViews(9999);mapper.insert(blog);blog.setId(IDUtil.getId());blog.setTitle("Spring如此簡單!");mapper.insert(blog);blog.setId(IDUtil.getId());blog.setTitle("微服務如此簡單!");mapper.insert(blog);sqlSession.close();} }

    查詢

    IF

  • 接口

    //查詢blog信息List<Blog> queryBlogIF(Map map);
  • 接口實現

    <select id="queryBlogIF" resultType="blog" parameterType="map">select *from mybatis.blog where 1=1<if test="title!= null">and titie=#{title}</if><if test="author!= null">and author = #{author}</if> </select>
  • 測試


  • where優化
    <select id="queryBlogIF" resultType="blog" parameterType="map">select *from mybatis.blog<where><if test="title!= null">title=#{title}</if><if test="author!= null">and author = #{author}</if></where> </select>
    • The where element knows to only insert “WHERE” if there is any content returned by the containing tags. (滿足條件插入)
    • Furthermore, if that content begins with “AND” or “OR”, it knows to strip it off.(保證第一個 where前沒有邏輯判斷)
    choose-when-otherwise&where

    switch-case-default | if-else if - else

  • 定義接口

    List<Blog> queryBlogIF1(Map map);
  • 實現接口

    <select id="queryBlogIF1" parameterType="map" resultType="blog">select *from mybatis.blog<where><choose><when test="id!=null">id=#{id}</when><when test="title != null">title=#{title}</when><when test="author != null">author=#{author}</when><otherwise>views>1000</otherwise></choose></where> </select>
  • 測試

  • 更新

    set
    • The set element can be used to dynamically include columns to update, and leave out others.(選目標字段,刪除無關字符)
      • the set element will dynamically prepend the SET keyword,(前置)
      • and also eliminate any extraneous commas that might trail the value assignments after the conditions are applied.(刪逗號)
  • 定義接口

    //更新信息 int updateBlog(Map map);
  • 實現接口

    <update id="updateBlog" parameterType="map">update mybatis.blog<set><if test="title!=null">title=#{title},</if><if test="author!=null">author=#{author},</if><if test="views!=null">views=#{views},</if>create_time =#{createTime}</set>where id=#{id} </update>
  • 測試

  • trim替換

    前綴后綴都是 prefix,XXOverrides決定替換的位置

    <select id="queryBlogIFByTrim" resultType="blog" parameterType="map">select *from mybatis.blog<trim prefix="where" prefixOverrides="and |or "><if test="title!= null">title=#{title}</if><if test="author!= null">and author = #{author}</if></trim> </select>
    • The prefixOverrides attribute takes a pipe delimited list of text to override, where whitespace is relevant.前綴Overrides 屬性采用管道分隔文本列表來重寫,其中空白是相關的。(最好寫上,替換后可能會出問題)
      • The result is the removal of anything specified in the prefixOverrides attribute
      • and the insertion of anything in the prefix attribute
    <trim prefix="SET" suffixOverrides=",">... </trim>

    sql片段

    公共部分抽取出來,方便復用

    • <sql id=""></sql> 抽取
    • <include refid="" /> 引用
    <sql id="if-title-author"><if test="title!= null">title=#{title}</if><if test="author!= null">and author = #{author}</if> </sql><select id="queryBlogIFByTrim" resultType="blog" parameterType="map">select *from mybatis.blog<trim prefix="where" prefixOverrides="and |or "><include refid="if-title-author" /></trim> </select>
    • 基于單表查詢
    • 不要存在 <where> 標簽

    foreach

    sql in 的動態范圍查詢

    select *from user where 1=1 and (id=1 or id=2 or id=3);<foreach item="item" collection="ids" open="(" separator=" or " close=")">#{item} </foreach>
    • open:開始符
    • separator:分隔符
    • close:結束符
    • item:項
    • colloetion:遍歷集合
  • 定義接口

    List<Blog> queryBlogIn(Map map);
  • 實現接口

    <select id="queryBlogIn" parameterType="map" resultType="blog">select *from mybatis.blog<where><foreach collection="ids" item="id" open="(" separator="or" close=")">id=#{id}</foreach></where> </select>
  • 測試

  • 分頁

    limit實現分頁

    sql語句
    select *from [table_name] limit [offset],[limit];# [offset]缺省,默認從0開始,到[end] select *from [table_name] limit [end];
    MyBatis方式
  • 接口

    //分頁查詢用戶信息 List<User> getUserWithLimit(Map<String,Integer> map);
  • 接口配置

    <select id="getUserWithLimit" resultMap="UserMap" resultType="user" parameterType="map">select *from mybatis.user limit #{offset},#{limit}; </select>
  • 測試

    @Test public void testGetUserWithLimit(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);Map<String, Integer> map = new HashMap<String, Integer>();map.put("offset",1);map.put("limit",2);List<User> userList = mapper.getUserWithLimit(map);for (User user : userList) {System.out.println(user);}sqlSession.close(); }
  • RowBounds實現分頁[不建議使用]

    不在sql進行分頁,通過sqlSession對象實現分頁——RowBounds

  • 接口

    List<User> getUserWithLimit2();
  • 配置Mapper

    <select id="getUserWithLimit2" resultMap="UserMap" resultType="user">select *from mybatis.user; </select>
  • 測試

    @Test public void testGetUserWithLimit2(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);RowBounds rowbounds = new RowBounds(1,2);List<User> userList = sqlSession.selectList("com.kuang.mapper.UserMapper.getUserWithLimit2",null,rowbounds);for (User user : userList) {System.out.println(user);}sqlSession.close(); }
  • 插件——pageHelper

    緩存

    簡介

    問題:連接數據庫消耗資源

    解決:一次查詢,保存到高速存儲——> 內存

    緩存:

    • 放在內存中的臨時數據
    • 經常查詢且不常改變 的數據存放在緩存,直接從服務器內存取比從服務器磁盤IO速度快,提高查詢效率,解決高并發系統的性能問題

    使用緩存,減少與數據庫交互次數,減少系統開銷,提高系統效率

    #mermaid-svg-5j8hTzdinpGfqAUy {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .error-icon{fill:#552222;}#mermaid-svg-5j8hTzdinpGfqAUy .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5j8hTzdinpGfqAUy .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5j8hTzdinpGfqAUy .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5j8hTzdinpGfqAUy .marker.cross{stroke:#333333;}#mermaid-svg-5j8hTzdinpGfqAUy svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5j8hTzdinpGfqAUy .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster-label text{fill:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster-label span{color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .label text,#mermaid-svg-5j8hTzdinpGfqAUy span{fill:#333;color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .node rect,#mermaid-svg-5j8hTzdinpGfqAUy .node circle,#mermaid-svg-5j8hTzdinpGfqAUy .node ellipse,#mermaid-svg-5j8hTzdinpGfqAUy .node polygon,#mermaid-svg-5j8hTzdinpGfqAUy .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5j8hTzdinpGfqAUy .node .label{text-align:center;}#mermaid-svg-5j8hTzdinpGfqAUy .node.clickable{cursor:pointer;}#mermaid-svg-5j8hTzdinpGfqAUy .arrowheadPath{fill:#333333;}#mermaid-svg-5j8hTzdinpGfqAUy .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-5j8hTzdinpGfqAUy .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-5j8hTzdinpGfqAUy .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-5j8hTzdinpGfqAUy .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster text{fill:#333;}#mermaid-svg-5j8hTzdinpGfqAUy .cluster span{color:#333;}#mermaid-svg-5j8hTzdinpGfqAUy div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-5j8hTzdinpGfqAUy :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 緩存merCached緩存服務器 讀寫分離,主從復制

    MyBatis緩存

    系統默認定義兩級緩存:一級緩存和二級緩存

    • 一級緩存:SqlSession級,本地緩存
    • 二級緩存:手動開啟和配置,namespace級緩存
    • MyBatis自定義緩存接口Cache,通過實現接口自定義二級緩存
    一級緩存——Map

    一級緩存默認開啟,在一次SESSION期間有效

  • 開啟日志

  • 測試一個Session中查詢兩次相同記錄

    @Test public void test(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user1 = mapper.getUserById(1);System.out.println(user1);System.out.println("====================");User user2 = mapper.getUserById(1);System.out.println(user2);System.out.println(user1==user2);sqlSession.close(); }
  • 查看日志輸出

    兩次查找一次查表

    兩次結果引用同一對象

  • 緩存失效
    • R不同的東西

    • CUD必定刷新緩存

    • 不同的Mapper

    • 手動清理緩存

    二級緩存

    工作機制:

    一個Session期間的數據會被放到一級緩存,當Session關閉或提交,對應的一級緩存中的數據被保存到二級緩存中

    • 新的Session查詢信息,從二級緩存中獲取內容
    • 不同的mapper查出的數據會放到自己對應的緩存中
  • mybatis-config.xml 開啟二級緩存

    <!--開啟二級緩存--> <setting name="cacheEnabled" value="true"/>
  • 配置mapper.xml

    <!--在當前mapper中使用二級緩存--> <cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>
    • mapper.xml中的所有 select 語句的結果將會被緩存。
    • mapper.xml中的所有 insert、update 和 delete 語句會刷新緩存。
    • eviction:替換策略
      • LRU:默認
      • FIFO
    • flushInterval:刷新間隔
      • 以毫秒為單位
      • 不設置,也就是沒有刷新間隔,緩存僅僅會在調用語句時刷新
    • size:引用數目
      • 默認值是 1024
    • readOnly:只讀
      • 只讀的緩存會給所有調用者返回緩存對象的相同實例。 因此這些對象不能被修改
      • 可讀寫的緩存會(通過序列化)返回緩存對象的拷貝。 速度上會慢一些,但是更安全,因此默認值是 false
  • 測試

  • 問題

    • 將實體類序列化,否則保錯
    java.io.NotSerializableException: com.kuang.pojo.User package com.kuang.pojo;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;import java.io.Serializable;@Data @AllArgsConstructor @NoArgsConstructor public class User implements Serializable {private Integer id;private String user_name;private String pwd; }
  • 緩存原理

    查找順序:

  • 二級緩存
  • 一級緩存
  • 數據庫
  • @Test public void test(){SqlSession sqlSession1 = MyBatisUtils.getSqlSession();User user1 = sqlSession1.getMapper(UserMapper.class).getUserById(1);System.out.println(user1);sqlSession1.close();SqlSession sqlSession2 = MyBatisUtils.getSqlSession();User user2 = sqlSession2.getMapper(UserMapper.class).getUserById(1);System.out.println(user2);sqlSession2.close();System.out.println(user1==user2);SqlSession sqlSession3 = MyBatisUtils.getSqlSession();User user3 = sqlSession3.getMapper(UserMapper.class).getUserById(2);System.out.println(user3);sqlSession3.close(); }

    • 由Cache Hit Ratio的計算,可知cache機制是先查二級緩存,再數據庫

    自定義緩存——Ehcache

    開源Java分布式緩存

    <dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.1.0</version> </dependency> <!--mapper.xml--> <cache type="com.domain.something.MyCustomCache"/> public interface Cache {String getId();int getSize();void putObject(Object key, Object value);Object getObject(Object key);boolean hasKey(Object key);Object removeObject(Object key);void clear(); }

    注解開發

    面向接口編程

    目的:解耦

    接口的理解

    • 定義 與 實現 分離
    • 接口反映系統設計人員對系統的抽象理解
    • 接口分類:
      • 一個個體的抽象——抽象體(abstract class)
      • 一個個體的某一方面的抽象——抽象面(Interface)
    • 接口設計更多體現對系統整體的架構

    使用注解開發

    本質:反射機制

    底層:動態代理

    Java Annotations are both limited and messier for more complicated statements.

  • 注解在接口上實現

    public interface UserMapper {@Select("select *from user")List<User> getUsers(); }
  • 綁定接口

    <!--mybatis-config.xml--> <!-- 綁定接口 --> <mappers><mapper class="com.kuang.mapper.UserMapper"/> </mappers>
  • 測試

    @Test public void test(){SqlSession sqlSession = MyBatisUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);List<User> users = mapper.getUsers();for (User user : users) {System.out.println(user);}sqlSession.close(); }

  • 參數

    當有多個參數,基本數據類型或String的參數前加注解 @param關聯參數

    引用類型不需要加

    sql中使用的是@Param()中設定的屬性名


    #{} 與 ${} 的區別
    • ${}是字符串替換,,Mybatis 在處理${}時,就是把他替換成變量的值
    • #{}是預編譯處理,會將 #{}替換為?號,調用 PreparedStatement 的 set 方法來賦值;
    • 使用#{}可以有效的防止 SQL 注入,提高系統安全性

    自動提交事務

    public class MyBatisUtils{public static SqlSession getSqlSession(){return sqlSessionFactory.openSession(true);} }

    CRUD

    Create
    //UserMapper.java public interface UserMapper{@Insert("insert into user(id,user_name,pwd) values(#{id},#{user_name},#{pwd})") int insertUser(User user); }

    Update
    //UserMapper.java public interface UserMapper{@Update("update user set user_name=#{user_name},pwd=#{pwd} where id=#{id}")int updateUser(User user); }

    POJO方法的簡化——Lombok

  • IDEA中安裝插件

  • 項目中導入依賴

    <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope> </dependency>
  • 使用注解簡化

    @Getter and @Setter @ToString @EqualsAndHashCode @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog @Data
    • @Data,@AllArgsConstructor,@NoArgsConstructor

  • MybatisPlus

    簡介

    在MyBatis基礎上,只做增強不做改變,為簡化開發、提高效率而生

    • 無侵入
    • 損耗小:啟動即會自動注入基本 CURD,性能基本無損耗,直接面向對象操作
    • CRUD:內置通用 Mapper、通用 Service
    • 支持主鍵自動生成
    • 支持 XML 熱加載 :Mapper 對應的 XML 支持熱加載,對于簡單的 CRUD 操作,甚至可以無 XML 啟動
    • 支持 ActiveRecord 模式
    • 支持自定義全局通用操作:支持全局通用方法注入
    • 內置代碼生成器 :采用代碼或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 層代碼,支持模板引擎
    • 內置分頁插件 、性能分析插件
    • 全局攔截(提供全表 delete 、 update 操作智能分析阻斷,也可自定義攔截規則,預防誤操作)
    • 內置 Sql 注入剝離器:支持 Sql 注入剝離,有效預防 Sql 注入攻擊

    MtbatisPlus架構

    通過簡單語句,生成SQL語句,交給MyBatis執行

    使用

    1. 建庫建表

    創建數據庫 haoke

    use haoke;CREATE TABLE `user` (`id` bigint(20) NOT NULL AUTO_INCREMENT 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;-- 插入數據 INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('1', 'Jone', '18','test1@baomidou.com'); INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('2', 'Jack', '20','test2@baomidou.com'); INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('3', 'Tom', '28','test3@baomidou.com'); INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('4', 'Sandy', '21','test4@baomidou.com'); INSERT INTO `user` (`id`, `name`, `age`, `email`) VALUES ('5', 'Billie', '24','test5@baomidou.com');


    2. 創建工程及導入依賴

    <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.4.3</version> </parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><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.4.2</version></dependency><!--mysql驅動--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.16</version></dependency> </dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins> </build>

    3. 編寫application.properties文件

    spring.application.name = mybatis-plus spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://8.140.130.91:3306/haoke?characterEncoding=utf8&useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=root

    4. 創建User對象

    package com.mybatisplus.pojo;public class User {private Long id;private String name;private Integer age;private String email;public User() {}public User(Long id, String name, Integer age, String email) {this.id = id;this.name = name;this.age = age;this.email = email;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;} }

    5. 編寫UserMapper

    package com.mybatisplus.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;public interface UserMapper extends BaseMapper<User> {}

    6. 編寫SpringBoot啟動類

    package com.mybatisplus;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.mybatisplus.mapper") //設置mapper接口的掃描包 @SpringBootApplication public class Myapplication {public static void main(String[] args) {SpringApplication.run(Myapplication.class,args);} }

    7. 編寫SpringBoot啟動類

    package com.mybatisplus;import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.mybatisplus.mapper") //設置mapper接口的掃描包 @SpringBootApplication public class Myapplication {public static void main(String[] args) {SpringApplication.run(Myapplication.class,args);} }

    8. 編寫單元測試用例

    package com.mybatisplus;import com.mybatisplus.mapper.UserMapper; import com.mybatisplus.pojo.User; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest public class UserMapperTest {@Autowiredprivate UserMapper userMapper;@Testpublic void test(){System.out.println("-------selectAll method test-------");List<User> users = userMapper.selectList(null);for (User user : users) {System.out.println(user);}} }

    通用Mapper

    在MybatisPlus中,BaseMapper中定義了一些常用的CRUD方法,當我們自定義的Mapper接口繼承BaseMapper后即可擁有了這些方法 【這些方法僅適合單表操作】

    /*** Mapper 繼承該接口后,無需編寫 mapper.xml 文件,即可獲得CRUD功能*/ public interface BaseMapper<T> extends Mapper<T> {/*** 插入一條記錄** @param entity 實體對象*/int insert(T entity);/*** 根據 ID 刪除** @param id 主鍵ID*/int deleteById(Serializable id);/*** 根據 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 條件,查詢一條記錄** @param queryWrapper 實體對象封裝操作類(可以為 null)*/T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢總記錄數** @param queryWrapper 實體對象封裝操作類(可以為 null)*/Integer 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)*/<E extends IPage<T>> E selectPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);/*** 根據 Wrapper 條件,查詢全部記錄(并翻頁)** @param page 分頁查詢條件* @param queryWrapper 實體對象封裝操作類*/<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper); }

    通過id查詢——selectById

    @Test public void testSelectById(){System.out.println("通過Id查詢");User user = userMapper.selectById(3L);//數據類型為Long,id為3System.out.println(user); }

    模糊查詢——like

    條件查詢

    https://mp.baomidou.com/guide/wrapper.html#abstractwrapper

    插入數據

    @Test public void testSave(){User user = new User();user.setAge(25);user.setEmail("zhangsan@qq.com");user.setName("zhangsan");int count = userMapper.insert(user);System.out.println("新增數據成功! count=>"+count); }
    id自增問題


    所以自增問題出現在java參數傳遞中

    public class User {@TableId(value = "ID", type = IdType.AUTO)private Long id;private String name;private Integer age;private String email; }


    刪除數據

    修改數據

    根據id修改,只修改指定的字段


    分頁查詢

    /*** 分頁插件*/ @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 設置請求的頁面大于最大頁后操作, true調回到首頁,false 繼續請求 默認false// paginationInterceptor.setOverflow(false);// 設置最大單頁限制數量,默認 500 條,-1 不受限制// paginationInterceptor.setLimit(500);PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();paginationInnerInterceptor.setDbType(DbType.MYSQL);interceptor.addInnerInterceptor(paginationInnerInterceptor);return interceptor; }

    配置

    使用MyBatis原生配置文件

    # 指定全局配置文件 mybatis-plus.config-location = classpath:mybatis-config.xml # 指定mapper.xml文件 mybatis-plus.mapper-locations = classpath*:mybatis/*.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><!-- 每一個Mapper.xml都需要在MyBatis核心配置文件中注冊 --> </configuration>

    https://mp.baomidou.com/guide/config.html#%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE

    Lombok

    • @Data:注解在類上;提供類所有屬性的 getting 和 setting 方法,此外還提供了equals、canEqual、hashCode、toString 方法
    • @Setter:注解在屬性上;為屬性提供 setting 方法
    • @Getter:注解在屬性上;為屬性提供 getting 方法
    • @Slf4j:注解在類上;為類提供一個 屬性名為log 的 slf4j日志對象
    • @NoArgsConstructor:注解在類上;為類提供一個無參的構造方法
    • @AllArgsConstructor :注解在類上;為類提供一個全參的構造方法
    • @Builder :使用Builder模式構建對象


    總結

    以上是生活随笔為你收集整理的【开发】后端框架——Mybatis的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    欧美成人播放 | 国产毛片aaa | 精品久久免费 | 不卡视频一区二区三区 | 中文字幕在线观看的网站 | 国产午夜精品av一区二区 | 一级欧美日韩 | 国产小视频免费观看 | 日韩电影中文,亚洲精品乱码 | 色99之美女主播在线视频 | 一区二区三区免费网站 | 五月婷婷综合在线 | 日韩久久久久久 | 国产精品久久久久永久免费看 | 国产一级精品在线观看 | 992tv又爽又黄的免费视频 | 成人免费视频网 | 成人精品一区二区三区中文字幕 | 久久草| 日日夜夜天天干 | 91夫妻视频| 在线免费高清视频 | 最新av免费在线 | 久久99精品国产99久久6尤 | 91黄色视屏 | 亚洲精品xxx | 欧美少妇xx | 六月丁香久久 | 日本中文字幕网 | www.av小说 | 天天爱天天射 | 99久久激情 | 国产成人精品久久亚洲高清不卡 | 最新国产一区二区三区 | 伊人久久国产精品 | 91在线麻豆 | 天天干天天想 | 偷拍精偷拍精品欧洲亚洲网站 | 欧美污网站 | 色多多在线观看 | 国产在线国产 | 色综合久久中文综合久久牛 | 色婷婷综合视频在线观看 | 天天操夜夜想 | 国产成人久久av977小说 | av网站免费线看精品 | 色之综合网 | 精品99在线视频 | av中文字幕亚洲 | 一区二区三区在线免费观看 | 成人福利av | 6080yy午夜一二三区久久 | 国产精品久久99精品毛片三a | 少妇bbbb搡bbbb桶 | 天天操天天射天天插 | 91av蜜桃| 高清色免费| 日本激情中文字幕 | 啪啪激情网 | 久久免费在线视频 | 色婷婷在线视频 | 日本性生活一级片 | aaa黄色毛片 | 精品视频在线看 | 欧美午夜一区二区福利视频 | www.黄色在线 | 欧美日韩xx | 国产成人久久av免费高清密臂 | 在线一区二区三区 | 久久高清免费视频 | 日韩免费在线观看视频 | 999在线视频 | 91一区在线观看 | 亚洲免费av一区二区 | 日韩免费小视频 | 日日干影院 | 91系列在线观看 | 一区二区三区免费看 | 又色又爽又黄高潮的免费视频 | 久久久综合香蕉尹人综合网 | 日韩丝袜视频 | 日韩av影视在线观看 | 久草在线一免费新视频 | 91香蕉视频污在线 | 成人理论电影 | 欧美日韩不卡在线观看 | www激情网 | 天天亚洲 | 97操碰| 99激情网| 成人国产精品一区二区 | 日韩av黄| 精品久久一区二区三区 | 亚洲九九精品 | 五月综合网| 久久伊99综合婷婷久久伊 | 色av婷婷 | 天天弄天天操 | 在线一区观看 | 国产亚洲片 | 国产欧美日韩一区 | 9色在线视频| 日产乱码一二三区别在线 | 视频一区视频二区在线观看 | 天天干,夜夜爽 | 国产一级片网站 | 亚州免费视频 | 久久精品com | 久草在线高清 | 激情婷婷在线 | 在线视频一二三 | 成人精品视频久久久久 | 欧美激情片在线观看 | 国产涩涩在线观看 | 色婷婷丁香 | 久久丁香 | 婷婷六月丁香激情 | 欧美一区在线看 | 婷婷五月在线视频 | 久草精品视频在线播放 | 九九久久影院 | 欧美日韩在线播放一区 | 日韩一级电影网站 | 粉嫩av一区二区三区四区五区 | 中文字幕日韩精品有码视频 | 免费在线成人av | 国产色黄网站 | 黄色免费网站下载 | 一区二区三区在线观看 | 国产精品第一 | 久草在线视频中文 | 9999国产精品| 免费在线观看黄 | 午夜视频一区二区三区 | 久草久 | 国产一级久久 | 免费观看久久 | 国产精品久久久免费看 | 久久免费视频观看 | 国产91九色蝌蚪 | 国产一级片毛片 | 亚洲 精品在线视频 | 中文不卡视频在线 | 免费成人黄色av | 国产99在线播放 | 久久人人爽爽 | 伊人色综合久久天天 | 一区二区三区在线影院 | 9797在线看片亚洲精品 | 97超碰网 | 免费看一级| 9色在线视频 | 国产一级免费视频 | 久草在线视频首页 | 黄在线 | 成人国产精品免费观看 | 国产一区二区精品91 | 国产精品成人av在线 | 欧美一级片免费在线观看 | 亚洲精品国产精品乱码不99热 | 国产在线永久 | 中文在线a∨在线 | 激情综合狠狠 | 成人黄色大片在线免费观看 | 国产精品免费在线播放 | 玖玖国产精品视频 | 国产在线国产 | 五月婷婷六月丁香在线观看 | 亚洲精品在线一区二区 | 不卡的av | 欧美a在线看 | 99精品在线观看视频 | 久久久久久久久久久高潮一区二区 | 国产91av视频在线观看 | 日韩久久精品一区二区 | av一区二区三区在线播放 | 国产又粗又硬又长又爽的视频 | 亚洲综合婷婷 | 亚洲精品网站在线 | 久久伦理 | 亚洲精品日韩在线观看 | 人人舔人人射 | 天天鲁天天干天天射 | 四虎在线永久免费观看 | 91免费国产在线观看 | 日韩影视大全 | 夜色成人av | 夜夜操天天 | 国产精品区在线观看 | 中文字幕在线色 | av大片网站| 亚洲色图美腿丝袜 | 91av影视 | 色99中文字幕 | 久久久久久久久久久久国产精品 | 人人草网站| 亚洲动漫在线观看 | 国产精品毛片久久久久久久 | 玖玖精品在线 | 日日草夜夜操 | 久久久久国产精品一区二区 | 亚洲欧美日韩中文在线 | 精品在线播放视频 | 中中文字幕av在线 | 91亚洲精品在线观看 | 人人爱爱 | 一级黄色视屏 | 正在播放国产精品 | 在线观看一级 | 超碰夜夜 | 又湿又紧又大又爽a视频国产 | 日韩在线观看中文 | 欧美日韩高清在线一区 | 欧美日韩一级在线 | 免费看国产精品 | 91精品综合在线观看 | 国产不卡av在线播放 | 婷婷激情在线观看 | 国产精品毛片久久久久久久久久99999999 | 色综合久久88色综合天天 | 欧美激情精品久久久久久变态 | 欧美日本日韩aⅴ在线视频 插插插色综合 | 成人av片免费观看app下载 | 国产最新91 | 日韩区欧美久久久无人区 | 亚洲国产精品一区二区久久,亚洲午夜 | 亚洲在线网址 | 亚洲激情久久 | 97福利社| 久久网站av| 国产97在线观看 | 国产91区 | 一色屋精品视频在线观看 | 国产精品成人aaaaa网站 | 在线 欧美 日韩 | 亚洲色图 校园春色 | 国产黄色免费观看 | 麻豆精品传媒视频 | 二区三区在线 | 欧美日韩在线看 | 天堂成人在线 | 国产午夜麻豆影院在线观看 | 亚洲人av免费网站 | 中文字幕久久久精品 | 高清不卡免费视频 | 麻豆影视在线免费观看 | 亚洲区另类春色综合小说 | 亚洲乱码在线 | 成人免费视频a | 最近中文字幕免费av | 久久九九久久九九 | 色综合久久88色综合天天6 | 草莓视频在线观看免费观看 | 国产成人无码AⅤ片在线观 日韩av不卡在线 | 波多野结衣理论片 | 国产在线探花 | 最新国产视频 | 国产精品久久久久一区 | 综合激情婷婷 | 国产网红在线观看 | 欧美日韩精品在线 | 91在线看视频免费 | 午夜精品视频免费在线观看 | 三级av免费看 | av一级久久 | 又紧又大又爽精品一区二区 | 91九色在线播放 | 久草视频在线免费播放 | 99精品欧美一区二区三区黑人哦 | 在线观看中文字幕av | 亚洲精品乱码久久久久久高潮 | 久久精品视频18 | 精品一区二区三区久久 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 色网址99 | 亚洲国产免费看 | 国产日韩一区在线 | 国产精品久久久久久一区二区 | 免费av在线网站 | 99综合电影在线视频 | 成人av免费播放 | 亚洲九九九在线观看 | 最近日本韩国中文字幕 | 成人免费电影 | 激情综合狠狠 | 亚洲成人xxx | 亚洲精品中文字幕在线 | 人人爽人人香蕉 | www.五月婷 | 黄色av大片| 九九热精| 亚洲精品视频在线播放 | 日韩电影中文,亚洲精品乱码 | 亚洲成人动漫在线观看 | 男女激情免费网站 | 欧美日韩精品在线观看视频 | 亚洲精品国偷自产在线91正片 | 91亚洲在线| 欧美精品久久久久久久久久丰满 | 色综合久久88色综合天天人守婷 | 97av视频在线观看 | 欧美日性视频 | 天天色天天射天天综合网 | 婷婷色中文字幕 | 99精品在这里 | 久久国产精彩视频 | 国产精品免费一区二区 | 欧美一级片在线免费观看 | 日日麻批40分钟视频免费观看 | 91成人在线视频 | 久久不射电影网 | 欧美色婷 | www.com黄| 免费在线观看91 | 亚洲精品播放 | 在线小视频你懂的 | 男女精品久久 | 久久久国产在线视频 | 国产一级黄色av | a午夜电影 | 亚洲乱亚洲乱亚洲 | 欧洲一区二区三区精品 | 九九精品视频在线看 | 久久久私人影院 | 欧美成人久久 | 国产裸体无遮挡 | 亚洲午夜电影网 | 亚洲精品国产综合久久 | 精品资源在线 | 欧美一级在线看 | 天天色婷婷 | 在线观看免费日韩 | 中文字幕在线观看视频一区二区三区 | 欧美视频国产视频 | 久久婷婷亚洲 | 亚洲精品视频第一页 | 中国美女一级看片 | 国产黄网在线 | 九九九免费视频 | 国产中文字幕一区二区 | 日韩欧美在线高清 | 亚洲免费不卡 | 一区免费观看 | 日韩色在线观看 | 女人18毛片90分钟 | 欧美人体xx| 日韩欧美视频在线播放 | 91大片成人网 | 久久久国产精品一区二区三区 | 日韩三级精品 | 激情九九 | 亚洲精品国偷拍自产在线观看 | 国产在线播放一区 | 久热av在线 | 亚洲 欧洲 国产 精品 | 视频国产精品 | 男女全黄一级一级高潮免费看 | 91精选在线 | 久久人网| 黄av免费在线观看 | 国产视频在线观看一区 | 一区二区三区电影在线播 | 久久av网址 | 久久调教视频 | 国产一区电影在线观看 | 精品视频在线视频 | 久久久久久蜜桃一区二区 | 成人免费中文字幕 | 99久久精品电影 | 91视频高清 | 激情喷水 | 免费视频99 | 亚洲在线精品视频 | 欧美乱大交 | 在线观看成人av | 天堂在线一区二区三区 | 日韩欧美在线第一页 | 久久精品这里精品 | 黄色小说视频在线 | 久操视频在线播放 | 国产自在线| 国产成人av在线 | 日本中文字幕在线一区 | 狠狠色伊人亚洲综合网站色 | 深爱婷婷 | 精品久久1 | 亚洲午夜av久久乱码 | 国产精品午夜在线 | 黄色在线观看网站 | 国产一区在线观看视频 | 久久久久免费视频 | 久久a热6 | 伊人资源视频在线 | 色噜噜噜噜| 日韩在线观看的 | 色网站在线免费观看 | 在线看小早川怜子av | 国产精品va视频 | 在线看片成人 | 国产精品美女久久久久久久久 | 超碰精品在线 | 美女网站在线免费观看 | 日韩国产精品久久 | 日韩在线视频网站 | 免费观看av网站 | 成人一区二区三区在线观看 | 日韩精品中文字幕在线 | 91在线免费播放 | 91精品久久久久久综合五月天 | 97国产精品视频 | 国产拍揄自揄精品视频麻豆 | 日日干av| 国产91aaa| 免费看一级黄色大全 | 91视频黄色 | aa级黄色大片 | 国产日韩精品一区二区在线观看播放 | 日批在线观看 | 免费在线激情视频 | 天天躁天天狠天天透 | 国产麻豆果冻传媒在线观看 | 天天操一操| 国产一级特黄毛片在线毛片 | 欧洲色吧| 国产一区免费观看 | 五月婷婷久久综合 | 字幕网av | 91色网址| 国产精品18久久久久久首页狼 | 日韩午夜在线 | 婷婷五天天在线视频 | 久久艹人人| 午夜资源站 | 色视频在线 | www.色五月.com | 日韩三级在线观看 | 欧美一级专区免费大片 | 黄色片免费电影 | 99免在线观看免费视频高清 | 久久人视频| 亚洲第一香蕉视频 | 欧美美女激情18p | av在线播放免费 | 国产亚洲精品久久久网站好莱 | 午夜a区 | 欧美成人免费在线 | 久久久久久久久久电影 | 人人添人人澡人人澡人人人爽 | 狠狠做深爱婷婷综合一区 | 狠狠色综合网站久久久久久久 | 天天躁天天躁天天躁婷 | 日日操日日干 | 91视频一8mav | 亚洲涩涩涩涩涩涩 | 久久www免费人成看片高清 | 四虎在线观看 | 九九九热精品免费视频观看网站 | 在线看日韩av | 天天操天天操天天操天天操天天操 | 天天色综合三 | 国产精品美女在线 | 欧洲视频一区 | 超薄丝袜一二三区 | 丝袜制服天堂 | 伊人狠狠色丁香婷婷综合 | 激情五月***国产精品 | 成人久久亚洲 | 色综合久久久久综合体桃花网 | 999成人网 | 国产精品高清av | 又黄又刺激的视频 | 天天干一干 | 国产日韩精品一区二区 | 日本婷婷色 | 婷婷精品 | 日韩国产精品一区 | 黄av资源 | 天天操天天操天天干 | 日日夜夜91 | 国产99亚洲 | 国产亚洲视频在线免费观看 | 97av影院 | 免费成人黄色 | 久久在线一区 | 国产成人黄色在线 | 免费av在线网站 | 日韩欧美一区二区三区视频 | 久久国产精品久久精品国产演员表 | 久国产在线播放 | 欧美久久久久 | 国产精品一区二区在线观看 | 91麻豆福利| 国产一区二区在线播放视频 | 99久久精品国产亚洲 | 日韩av片免费在线观看 | 亚洲午夜精品久久久 | 黄色动态图xx | 不卡的av在线播放 | 青青草华人在线视频 | 91黄色在线看 | 中文字幕最新精品 | 欧美一级视频在线观看 | 三上悠亚一区二区在线观看 | 99爱视频在线观看 | 狠狠色狠狠综合久久 | 国产成人精品久久二区二区 | 免费视频a| 色偷偷中文字幕 | 中文字幕 国产视频 | 69国产盗摄一区二区三区五区 | 亚洲经典中文字幕 | 久久国产电影 | 免费成人av在线 | 成人资源在线 | 91亚洲影院 | 亚洲黄色一级电影 | 人成电影网 | 亚洲精品美女免费 | 手机成人在线电影 | 色婷婷激婷婷情综天天 | 日产av在线播放 | 精品国产一区二区三区噜噜噜 | 四虎最新域名 | 夜夜视频资源 | 欧美性直播 | www.香蕉视频在线观看 | 久久国产一区二区 | 99精品视频在线播放免费 | 99色在线观看 | 久久国语 | 精品一区 精品二区 | 欧美日韩国产亚洲乱码字幕 | 久久久久国产精品午夜一区 | 久久玖| 久久精品久久久久久久 | 97av.com | 亚洲精品xx| 国产午夜精品一区二区三区四区 | 亚洲欧美日本A∨在线观看 青青河边草观看完整版高清 | 日韩一区二区三免费高清在线观看 | 国产精品视频久久久 | 国产九九精品 | 天天操夜夜操天天射 | 亚洲免费观看在线视频 | 日本aaa在线观看 | 天堂va在线高清一区 | 色婷婷综合视频在线观看 | 日本久热 | 欧美日韩在线观看一区二区三区 | 欧美精品一区在线发布 | 中文字幕在线观看2018 | 亚洲精品网址在线观看 | 亚洲免费av观看 | av一级二级 | 国产一区二区在线免费观看 | 国产精品久久网站 | 欧美日韩国产色综合一二三四 | 波多野结依在线观看 | 国产午夜亚洲精品 | 国产亚洲成av片在线观看 | 国产一二三四在线观看视频 | 国产精品高潮久久av | 中文字幕大全 | 狠狠色网 | 国产午夜三级一区二区三桃花影视 | 亚洲免费av片 | 婷婷激情综合五月天 | 久久理论影院 | 香蕉视频国产在线观看 | 狠狠干天天 | 国产精品美女久久久久久2018 | 久久久精品国产一区二区 | 精品国产诱惑 | 国产精品一区二区三区在线 | 久草免费新视频 | 亚洲最新视频在线播放 | 黄色影院在线免费观看 | www.97色.com| 国产福利久久 | 黄色精品一区 | 97成人资源| 天天操天天添 | 久久婷婷丁香 | 国产精品免费在线播放 | 91av在线播放视频 | 欧美一区中文字幕 | 国产亚洲日| wwwwww国产 | 亚洲视频一 | 欧美日韩一区二区三区视频 | 国产精品一区二区免费 | 97超碰福利久久精品 | 久久九九国产精品 | 日本aaa在线观看 | 狂野欧美激情性xxxx | 热久久电影 | 国产一线在线 | 蜜臀久久99精品久久久无需会员 | 国产日韩中文在线 | 色婷婷免费视频 | 国产精品视频你懂的 | 黄色在线视频网址 | 97在线观看视频国产 | av成人动漫 | 五月婷婷在线播放 | 成人永久在线 | 久久99视频免费观看 | 免费网站看v片在线a | 国产黄影院色大全免费 | 欧美精品一级视频 | 大型av综合网站 | 在线免费看黄网站 | 正在播放 国产精品 | 五月婷婷久久丁香 | 91精品黄色 | 久久国产精品视频免费看 | 外国av网 | www国产亚洲精品久久麻豆 | 色www精品视频在线观看 | 免费观看www7722午夜电影 | 午夜精品av | 成人午夜电影网站 | 91在线九色 | 成人在线视频在线观看 | 91观看视频 | 国产成人精品电影久久久 | 天天色.com | 嫩草av在线| av免费看av | 日韩一区二区三免费高清在线观看 | 亚州av一区 | 91精品国产92久久久久 | 久久成人国产精品一区二区 | 久操中文字幕在线观看 | 中文久草 | 国产精品久久婷婷六月丁香 | 亚洲精品玖玖玖av在线看 | 日日干夜夜草 | 手机看国产毛片 | 精品视频www | 五月天婷婷丁香花 | 五月婷婷伊人网 | 国产精品女人网站 | 99精品视频在线观看播放 | 久久不卡视频 | 天天天天天天天操 | 九九久久精品视频 | 韩国视频一区二区三区 | 国产二区视频在线观看 | 国产999精品久久久久久绿帽 | 99免费在线视频 | 久久久久激情电影 | 欧美日本在线观看视频 | 亚色视频在线观看 | 九九九九免费视频 | 精品久久久久久亚洲综合网站 | 国产精品视频免费 | 国产一区二区三区高清播放 | 91大神精品视频在线观看 | 亚洲高清视频一区二区三区 | 久久久免费观看 | 操操日日 | 亚洲视频综合 | 久操视频在线观看 | 国产精品中文字幕在线 | 午夜精品久久久久久中宇69 | 国产精品wwwwww | 狠狠狠狠狠狠狠狠 | 国产一级视频在线观看 | 在线免费精品视频 | 午夜视频免费在线观看 | 久久久久伦理电影 | 国产一级视频在线观看 | 黄色1级大片 | 成人免费观看a | 国产日韩视频在线播放 | 91在线麻豆 | 黄色软件视频网站 | 丁香亚洲 | 中文字幕日韩国产 | 亚洲美女免费视频 | 最近最新中文字幕 | 久久精品79国产精品 | 免费看黄在线网站 | 激情小说 五月 | 97超级碰| 成人午夜电影久久影院 | 成人免费观看视频网站 | 国产精品久久久久久久久久不蜜月 | 久久久久国产精品免费免费搜索 | 久久久精品高清 | 免费a级观看 | 久草在线综合网 | 国产精品麻豆欧美日韩ww | 国产精品乱码一区二三区 | 免费观看国产精品 | 人九九精品 | 国产精品18久久久久久首页狼 | 亚洲国产精久久久久久久 | 麻豆传媒一区二区 | 97av视频| 日本公妇色中文字幕 | 丁香导航 | 91网址在线看 | 日韩久久久久久久久久久久 | 国产成人亚洲在线观看 | 日韩色综合 | 日日夜夜亚洲 | 玖玖在线观看视频 | 日韩精品观看 | 国产综合小视频 | 天天操天天射天天操 | 久久99视频 | 精品婷婷 | 丁香五月亚洲综合在线 | 亚洲综合欧美日韩狠狠色 | 99精品亚洲| 久草在线最新免费 | 色91在线视频 | 一级黄色大片在线观看 | 精品中文字幕在线播放 | 亚洲精品视频二区 | 毛片视频网址 | 欧美一级专区免费大片 | 亚洲欧美国产日韩在线观看 | 美国三级黄色大片 | 国产成人精品亚洲 | 成年人免费在线看 | 天天婷婷| 久久国产精品小视频 | 国产中文字幕91 | 欧美 日韩 视频 | 欧美成人免费在线 | 中文字幕色网站 | 亚洲婷婷在线 | 欧美一二三专区 | 97色资源 | 久久视频99 | bbbbb女女女女女bbbbb国产 | 99久久夜色精品国产亚洲96 | 91精品视频网站 | 免费福利片2019潦草影视午夜 | 日韩免费网站 | 五月导航 | 中文字幕在线一区二区三区 | 亚洲精品1区2区3区 超碰成人网 | 国产精品剧情在线亚洲 | 在线观看免费福利 | 日韩国产在线观看 | 色综合久久久 | 婷婷午夜天 | 天堂网在线视频 | 免费又黄又爽的视频 | 草久久久| 日韩一级理论片 | 一区二区三区在线播放 | 日韩免费播放 | 亚洲天堂va | 久久久久国产视频 | 91日韩在线 | 亚洲小视频在线观看 | 17videosex性欧美| 波多野结衣视频一区 | av一区二区在线观看中文字幕 | 五月婷婷综合激情网 | 国产精品久久久久久久久久尿 | 国产麻豆精品传媒av国产下载 | 亚洲国产三级在线观看 | 偷拍精偷拍精品欧洲亚洲网站 | 欧美日韩视频在线 | 国产精品麻豆一区二区三区 | 国产一区二区在线观看视频 | 99精品色| 国产91精品一区二区麻豆亚洲 | 天天射天天干天天爽 | 色99色| 午夜久久 | 99久久999久久久精玫瑰 | 日韩在线无| 国产福利91精品张津瑜 | 欧美一级片免费观看 | 亚洲视频1| 久久艹综合 | 91免费观看视频网站 | 日韩国产精品久久久久久亚洲 | www操操操 | 欧美一级黄色片 | 国产a视频免费观看 | 人人澡人人爽欧一区 | 中文字幕在线观看视频一区二区三区 | 色中色综合 | 色五月成人 | 日韩在线视频一区 | 久久手机看片 | 波多在线视频 | 免费人成在线观看 | 国产亚洲欧美在线视频 | 超碰人人做 | 人人插人人艹 | 免费看短 | 国内揄拍国内精品 | 99久久精品无免国产免费 | 日韩免费福利 | 久久99免费 | 国内精品久久久久久久 | 久久久久国产成人精品亚洲午夜 | 17videosex性欧美| 国产亚洲精品久久久久久大师 | 日日爽天天爽 | 日韩三级精品 | 99久精品 | 国产不卡免费视频 | 一级淫片在线观看 | 国产91在线免费视频 | 欧美大片aaa | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 日韩久久精品一区二区 | 亚洲高清视频在线观看 | 日本中文在线 | 国产精品乱码久久 | 最近中文字幕 | 波多野结衣一区三区 | 免费观看视频黄 | 亚洲一区二区精品 | 日韩精品一区二区三区视频播放 | 中文字幕在线资源 | 免费在线精品视频 | 99视频精品免费视频 | 中文字幕一区二区三区久久 | 成人日批视频 | 色综合久久久久网 | 国产精品乱看 | 天天综合网在线观看 | 国产精品成人自产拍在线观看 | 九九久久久久99精品 | 91在线porny国产在线看 | 亚洲精品综合一区二区 | 91av网站在线观看 | 亚洲欧美日韩在线看 | 亚洲老妇xxxxxx | 91精品久久久久久久99蜜桃 | 午夜美女视频 | 免费97视频| 色狠狠狠 | 亚洲午夜久久久久 | 日本三级香港三级人妇99 | 午夜精品一区二区三区免费 | 天天摸日日摸人人看 | 中文字幕第一页在线播放 | 日本中文字幕在线播放 | 人人dvd| 69久久久久久久 | 国产裸体视频网站 | 99久久婷婷国产 | 久久蜜臀一区二区三区av | 亚洲一级久久 | 亚洲国产精品va在线看黑人动漫 | av在线色 | 亚洲午夜精品在线观看 | 高潮久久久 | 国产成人精品午夜在线播放 | 日本久草电影 | 国产亚洲一区二区在线观看 | 五月天婷婷在线视频 | 久久久www成人免费毛片 | 中文字幕之中文字幕 | 国产精品午夜免费福利视频 | 日韩色av色资源 | 国产精品igao视频网网址 | 亚洲一二区精品 | 亚洲一级片在线看 | 99国产精品一区二区 | 日韩乱理| 免费国产ww | 视频一区视频二区在线观看 | 国产在线观看免费av | 亚洲一区黄色 | 人人插人人舔 | 成人资源网 | 国产精品免费一区二区三区 | 成人午夜剧场在线观看 | 最新中文字幕在线播放 | 亚洲作爱视频 | www.久久精品视频 | 久久国内免费视频 | 日韩欧美一区二区三区免费观看 | 成人av手机在线 | 伊人成人精品 | 国产精品一区在线观看 | 国产成人精品一区一区一区 | 国产免费嫩草影院 | 又污又黄网站 | 91在线国产观看 | 91色亚洲 | 精品久久一区二区 | av在线一 | 天天干天天想 | 日日夜夜天天综合 | 国产在线观看免费av | 又黄又爽又刺激的视频 | 国产精品青青 | av一区二区三区在线 | 亚洲婷婷网 | 高清精品视频 | 日日操日日插 | 国产精品一区二区在线看 | 国产一区二区免费看 | 国产精品爽爽久久久久久蜜臀 | 国产精品自产拍在线观看蜜 | 在线看不卡av | av在线日韩 | 国产中文字幕在线免费观看 | 91视频在线免费观看 | 97超碰成人在线 | 精品久久久久久久久久久久 | 久久久精品国产免费观看一区二区 | 中文字幕在线高清 | 免费亚洲黄色 | 亚洲综合情 | 2021国产在线 | 成人羞羞免费 | 九九热在线精品 | 久久国产成人午夜av影院潦草 | 五月婷婷六月丁香激情 | 久久成 | 久久超碰在线 | 久久久久免费电影 | 在线免费观看羞羞视频 | 手机在线中文字幕 | 98福利在线| 天天射天天爱天天干 | 久久久久久综合 | 精品国产美女 | 婷婷中文字幕在线观看 | 国内精品久久久 | 91香蕉视频色版 | 四虎亚洲精品 | 欧美一区三区四区 | 日韩xxx视频 | 成人在线观看资源 | 亚洲综合成人专区片 | 五月天中文在线 | 国产电影一区二区三区四区 | www.com久久 | 欧美日韩在线观看视频 | 国产精品美女免费视频 | av观看免费在线 | 在线不卡中文字幕播放 | 成人试看120秒| 亚洲 欧美变态 另类 综合 | 超碰在线97国产 | 天天干夜夜干 | 天天激情综合网 | 9992tv成人免费看片 | 四虎永久视频 | 欧美精品一区二区性色 | 国产视频亚洲视频 | 免费看污网站 | 日韩三级视频在线观看 | 国产一级视频在线 | 精品xxx | 黄色1级毛片 | 在线观看日韩国产 | 免费a视频| 国产精品一区在线 | 麻豆传媒一区二区 | 亚州av成人 | 国产精品免费一区二区三区在线观看 | 日本最新中文字幕 | 国产黄av | 欧美日韩在线视频一区 | 国模视频一区二区三区 | 91在线免费公开视频 | 中文字幕一区三区 | 国产免费一区二区三区最新6 | av无限看| 色伊人网| 99精品热视频| 毛片一区二区 | 在线激情影院一区 | 在线观看日韩精品 | 97在线视频网站 | 97在线观看免费高清完整版在线观看 | 午夜视频一区二区三区 | 欧美色图视频一区 | 天天插夜夜操 | 又紧又大又爽精品一区二区 | 欧美99精品 | 免费午夜av| 久久伊人精品天天 | 色com| 日本中文字幕一二区观 | 欧美日韩免费一区二区 | 成人a视频 | 在线观看播放av | 久久视频免费看 | 国产高清免费视频 | 婷婷精品国产欧美精品亚洲人人爽 |