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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java EE——Mybatis 框架学习

發布時間:2024/9/30 java 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java EE——Mybatis 框架学习 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

        • 一、MyBatis 框架概述:
        • 二、 Mybatis 框架入門
        • 三、 基于代理 Dao 實現 CRUD 操作
          • 1、根據 ID 查詢:
          • 2、保存操作:
          • 3、用戶更新:
          • 4、用戶刪除:
        • 四、Mybatis 的參數深入
        • 五、Mybatis的輸出結果封裝
          • 1、resultType的配置結果類型:
        • 六、SqlMapConfig.xml配置文件
        • 七、Mybatis 連接池
          • 1、Mybatis 的連接池技術:
        • 八、Mybatis的動態SQL語句
        • 九、Mybatis多表查詢一對一(多對一)
        • 十、 Mybatis 多表查詢——多對多
        • 十一、 Mybatis 延遲加載策略
        • 十二、 Mybatis 緩存
        • 十三、 Mybatis 注解開發

一、MyBatis 框架概述:

1、什么是mybatis

  • mybatis 是一個優秀的基于 java 的持久層框架,它內部封裝了 jdbc,使開發者只需要關注 sql 語句本身,而不需要花費精力去處理加載驅動、創建連接、創建 statement 等繁雜的過程。

  • mybatis 通過 xml 或注解的方式將要執行的各種 statement 配置起來,并通過 java 對象和 statement 中sql 的動態參數進行映射生成最終執行的 sql 語句,最后由 mybatis 框架執行 sql 并將結果映射為 java 對象并返回。

  • 采用 ORM 思想解決了實體和數據庫映射的問題,對 jdbc 進行了封裝,屏蔽了 jdbc api 底層訪問細節,使我們不用與 jdbc api 打交道,就可以完成對數據庫的持久化操作。

2、mybatis在三層架構中的位置

二、 Mybatis 框架入門

1、基于XML的方式

1、創建 maven 工程:

2、添加 Mybatis的坐標:

  • 在 pom.xml 文件中添加 Mybatis3.4.5 的坐標,如下:
<dependencies><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.10</version></dependency></dependencies>

3、編寫 User 實體類:

public class User implements Serializable {private Integer id;private String username;private Date birthday;private String address;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", birthday=" + birthday +", address='" + address + '\'' +'}';} }

4、編寫持久層接口 IUserDao:

public interface IUserDao {/**查詢所有操作* */List<User> findAll(); }

5、編寫持久層接口的映射文件 IUserDao.xml:

注意:

  • 創建位置:必須和持久層接口在相同的包中。
  • 名稱:必須以持久層接口名稱命名文件名,擴展名是.xml

例:都是在com.smk.dao包中

<?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.smk.dao.IUserDao"><select id="findAll" resultType="com.smk.domain.User">select * from user</select> </mapper>

不要忘記在映射配置中告知mybatis要封裝到哪個實體類中。

配置的方式:指定實體類的全限定類名 即:resultType="com.smk.domain.User"

6、 編寫 SqlMapConfig.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"> <!--mybatis的主配置文件--> <configuration><!-- 配置環境--><environments default="mysql"><!-- 配置mysql環境--><environment id="mysql"><!--配置事物的類型--><transactionManager type="JDBC"></transactionManager><!--配置數據源/連接池2--><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/my_batis?useUnicode=true&amp;characterEncoding=utf8"/><property name="username" value="root"/><property name="password" value=""/></dataSource></environment></environments><!--指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件--><mappers><mapper resource="com/smk/dao/IUserDao.xml"></mapper></mappers> </configuration>

7、編寫測試類:

public class mybatis {public static void main(String[] args) throws IOException {//1.讀取配置文件InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.創建一個SqlsessionFactory工廠SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();SqlSessionFactory factory = builder.build(in);//3.使用工廠生產一個Sqlsession對象SqlSession session = factory.openSession();//4.使用SqlSession創建Dao接口對象IUserDao userDao = session.getMapper(IUserDao.class);//5.使用代理對象執行方法List<User> users = userDao.findAll();for (User user : users) {System.out.println(user);}//6.釋放資源session.close();in.close();} }

在測試類中運行:


2、基于注解的方式

在基于注解的的方式下就不再需要 IUserDao.xml配置文件,同時需要在SqlMapConfig.xml中的mapper配置時,使用class屬性指定dao接口的全限定類名。

1、在持久層接口中添加注解:

public interface IUserDao {/**查詢所有操作* */@Select("select * from user")List<User> findAll(); }

2、修改 SqlMapConfig.xml:

<mappers><mapper class="com.smk.dao.IUserDao"></mapper> </mappers>

注意:在使用基于注解的 Mybatis 配置時,須移除 xml 的映射配置(IUserDao.xml)。

運行結果:

補充:

  • 不管使用XML還是注解配置, Mybatis是支持寫dao實現類的。
  • 但在在實際開發中,都是越簡便越好,所以都是采用不寫dao實現類的方式。

三、 基于代理 Dao 實現 CRUD 操作

1、根據 ID 查詢:

步驟:

1、在持久層接口中添加 findById 方法:

public interface IUserDao {//根據 id 查詢User findById (Integer userId); }

2、配置映射文件:

<mapper namespace="com.smk.dao.IUserDao"><select id="findById" resultType="com.smk.domain.User" parameterType="int">select * from user where id= #{id}</select> </mapper>

解釋

  • resultType 屬性:用于指定結果集的類型。
  • parameterType 屬性:用于指定傳入參數的類型。
  • sql 語句中使用#{}字符:它代表占位符,相當于原來 jdbc 部分所學的,都是用于執行語句時替換實際的數據。具體的數據是由#{}里面的內容決定的。
  • #{}中內容的寫法:由于數據類型是基本類型,所以此處可以隨意寫。

3、 在測試類添加測試:

public class mybatis {private InputStream in;private SqlSessionFactory factory;private SqlSession session;private IUserDao userDao;@Testpublic void testFindOne() {//6.執行操作User user = userDao.findById(41);System.out.println(user);}@Before//在測試方法執行之前執行public void init() throws Exception {//1.讀取配置文件in = Resources.getResourceAsStream("SqlMapConfig.xml");//2.創建構建者對象SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//3.創建 SqlSession 工廠對象factory = builder.build(in);//4.創建 SqlSession 對象session = factory.openSession();//5.創建 Dao 的代理對象userDao = session.getMapper(IUserDao.class);}@After//在測試方法執行完成之后執行public void destroy() throws Exception {session.commit();//提交事務;在增刪改時需要提交,查詢時不需要。//7.釋放資源session.close();in.close();} }

運行結果:

2、保存操作:

同樣的套路

1、在持久層接口中添加新增方法

// 保存用戶int saveUser(User user);

2、配置映射文件

<insert id="saveUser" parameterType="com.smk.domain.User">insert into user(username,birthday,sex,address) value (#{username},#{birthday},#{sex},#{address}) </insert>

解釋:

#{}中內容的寫法:

  • 由于保存方法的參數是 一個 User 對象,此處要寫 User 對象中的屬性名稱。
    它用的是 ognl 表達式。

ognl 表達式:

  • 它是 apache 提供的一種表達式語言,全稱是:Object Graphic Navigation Language 對象圖導航語言,它是按照一定的語法格式來獲取數據的。語法格式就是使用 #{對象.對象} 的方式。

  • #{user.username} 它會先去找 user 對象,然后在 user 對象中找到 username 屬性,并調用 getUsername() 方法把值取出來。但是我們在 parameterType 屬性上指定了實體類名稱,所以可以省略 user 而直接寫 username。

3、測試

@Testpublic void testSave() {User user = new User();user.setUsername("modify User property");user.setAddress("北京市順義區");user.setSex("男");user.setBirthday(new Date());System.out.println("保存操作之前:" + user);//5.執行保存方法userDao.saveUser(user);System.out.println("保存操作之后:" + user);}

注意

在實現 增刪改 時需要進行控制事務的提交。

如何在mybatis 中如何控制事務提交?

  • 可以使用:session.commit(); 來實現事務提交。加入事務提交后的代碼如下:
@After//在測試方法執行完成之后執行 public void destroy() throws Exception{session.commit();//7.釋放資源session.close();in.close(); }

運行結果:



問題擴展:獲取新增用戶 id 的返回值

新增用戶后,同時還要返回當前新增用戶的 id 值,因為 id 是由數據庫的自動增長來實現的,所以就相當于我們要在新增后將自動增長 auto_increment 的值返回。

<insert id="saveUser" parameterType="com.smk.domain.User"><!-- 配置保存時獲取插入的id keypreperty:代表要返回的值對應實體類里的字段 ,keyColumn代表數據庫的字段名--><selectKey keyProperty="id" keyColumn="id" resultType="int">select last_insert_id();</selectKey>insert into user(username,birthday,sex,address) value (#{username},#{birthday},#{sex},#{address})</insert>

再次執行測試:


可以看到 id 的值已經獲取到了。

3、用戶更新:

1、在持久層接口中添加更新方法:

//更新用戶int updateUser(User user);

2、配置映射文件:

<update id="updateUser" parameterType="com.smk.domain.User">update user set username=#{username},birthday=#{birthday},sex=#{sex}, address=#{address} where id=#{id}</update>

3、更新的測試方法:

@Testpublic void testUpdateUser() throws Exception {//1.根據 id 查詢User user = userDao.findById(52);//2.更新操作user.setAddress("北京市順義區");int res = userDao.updateUser(user);System.out.println(res);}

運行結果:

4、用戶刪除:

1、在持久層接口中添加刪除方法:

//刪除用戶int deleteUser(int uid);

2、配置映射文件:

<delete id="deleteUser" parameterType="int">delete from user where id=#{uid} </delete>

3、刪除的測試方法:

@Testpublic void testdeleteUser(){int res = userDao.deleteUser(52);System.out.println(res);}

至此基于mybatis的增刪改查就完成了。


四、Mybatis 的參數深入

注:Mybatis使用ognl表達式解析對象字段的值,#{}或${}括號中的值為pojo屬性名稱。

什么是ognl

Object Graphic Navigation Language
??對象 ????圖??????????導航 ????????語言

它是通過對象的取值方法來獲取數據。在寫法上把get給省略了。

比如:我們獲取用戶的名稱

  • 類中的寫法:user.getUsername()
  • OGNL表達式寫法:user.username

mybatis中為什么能直接寫username,而不用user.呢?

  • 因為在parameterType中已經提供了屬性所屬的類,所以此時不需要寫對象名。

1、parameterType 配置參數

SQL 語句的傳參是通過使用標簽的 parameterType 屬性來設定。該屬性的取值可以是基本類型,引用類型(例如:String 類型),還可以是實體類類型(POJO 類)。同時也可以使用實體類的包裝類。

2、傳遞 pojo 包裝對象

開發中通過 pojo 傳遞查詢條件 。當查詢條件是綜合的查詢條件:不僅包括用戶查詢條件還包括其它的查詢條件(比如將用戶購買商品信息也作為查詢條件),這時可以使用包裝對象傳遞輸入參數。即: Pojo 類中包含 pojo

例:

需求:根據用戶名查詢用戶信息,查詢條件放到 QueryVo 的 user 屬性中。

1、編寫 QueryVo:

public class QueryVo {private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;} }

2、編寫持久層接口:

//根據 QueryVo 中的條件查詢用戶List<User> findByVo(QueryVo vo);

3、配置映射文件:

<!-- 根據用戶名稱模糊查詢,參數變成一個 QueryVo 對象了 --><select id="findByVo" resultType="com.smk.domain.User" parameterType="com.smk.domain.QueryVo">select * from user where username like #{user.username};</select>

4、添加測試類:

@Testpublic void testFindByQueryVo() {QueryVo vo = new QueryVo();User user = new User();user.setUsername("%王%");vo.setUser(user);List<User> users = userDao.findByVo(vo);for (User u : users) {System.out.println(u);}}

運行結果:

五、Mybatis的輸出結果封裝

1、resultType的配置結果類型:

resultType 屬性可以指定結果集的類型,它支持基本數據類型和實體類數據類型。

它和 parameterType 一樣,如果注冊過類型別名的,可以直接使用別名。

沒有注冊過的必須使用全限定類名。

例如:我們的實體類此時必須是全限定類名,同時,當是實體類名稱時,實體類中的屬性名稱必須和查詢語句中的列名(即數據庫里的表名列名)保持一致,否則無法實現封裝。

特殊情況示例

當實體類屬性和數據庫表的列名已經不一致時

1、實體類代碼:

public class User2 {public class User implements Serializable {private Integer userId;private String userName;private Date userBirthday;private String userSex;private String userAddress;public Integer getUserId() {return userId;}public void setUserId(Integer userId) {this.userId = userId;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public Date getUserBirthday() {return userBirthday;}public void setUserBirthday(Date userBirthday) {this.userBirthday = userBirthday;}public String getUserSex() {return userSex;}public void setUserSex(String userSex) {this.userSex = userSex;}public String getUserAddress() {return userAddress;}public void setUserAddress(String userAddress) {this.userAddress = userAddress;}@Overridepublic String toString() {return "User [userId=" + userId + ", userName=" + userName + ", userBirthday="+ userBirthday + ", userSex="+ userSex + ", userAddress=" + userAddress + "]";}}}

2、映射配置:

// 查詢所有用戶List<User> findAll();

3、測試查詢結果:

@Testpublic void testFindAll() {List<User2> users = userDao.findAll();for (User2 user : users) {System.out.println(user);}}

運行結果:


為什么名稱會有值呢?

因為:mysql 在 windows 系統中不區分大小寫!

應對措施

  • 使用別名查詢:
  • 使用resultMap 結果類型封裝
  • 1、使用別名查詢

    即給實體類的屬性名起對應數據的字段值別名

    2、resultMap 結果類型

    resultMap 標簽可以建立查詢的列名和實體類的屬性名稱不一致時建立對應關系。從而實現封裝。

    在 select 標簽中使用 resultMap 屬性指定引用即可。同時 resultMap 可以實現將查詢結果映射為復雜類型的 pojo,比如在查詢結果映射對象中包括 pojo 和 list 實現一對一查詢和一對多查詢。

    實現步驟

    1、定義 resultMap:

    <!-- 建立 Use實體和數據庫表的對應關系type屬性:指定實體類的全限定類名id 屬性:給定一個唯一標識,是給查詢 select 標簽引用用的--><resultMap type="com.smk.domain.User2" id="userMap"><id column="id" property="userId"/><result column="username" property="userName"/><result column="sex" property="userSex"/><result column="address" property="userAddress"/><result column="birthday" property="userBirthday"/></resultMap>
    • id 標簽:用于指定主鍵字段
    • result 標簽:用于指定非主鍵字段
    • column 屬性:用于指定數據庫列名
    • property 屬性:用于指定實體類屬性名稱

    2、映射配置:

    <!-- 配置查詢所有操作 --><select id="findAll" resultMap="userMap">select * from user</select>

    3、測試結果:


    可以看到查詢正常了。

    六、SqlMapConfig.xml配置文件

    1、properties(屬性)

    在使用 properties 標簽配置時,我們可以采用兩種方式指定屬性配置。

    1、第一種 :

    <properties><property name="jdbc.driver" value="com.mysql.jdbc.Driver"/><property name="jdbc.url"value="jdbc:mysql://localhost:3306/my_batis?useUnicode=true&amp;characterEncoding=utf8"/><property name="jdbc.username" value="root"/><property name="jdbc.password" value=""/></properties>

    2、第二種 :

    在 classpath (類路徑,resources目錄即為根 類路徑) 下定義 db.properties 文件

    db.properties 文件內容:

    jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/my_batis?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=

    注意:db.properties 文件中 數據庫連接,指定編碼格式不能用 &amp; 需改為 &

    配置信息:

    <properties resource="db.properties"> </properties>

    此時我們的 dataSource 標簽就變成了引用上面的配置:

    <!--配置數據源/連接池--><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="{$jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource>

    2、typeAliases(類型別名):、

    自定義別名:

    在 SqlMapConfig.xml 中配置:

    <typeAliases> <!-- 單個別名定義 --> <typeAlias type="com.itheima.domain.User" alias="user"/><!-- 批量別名定義,掃描整個包下的類,別名為類名(首字母大寫或小寫都可以)--> <package name="com.smk.domain"/> <package name="其它包"/> </typeAliases>

    3、mappers(映射器)

    <mapper resource=" "/> 使用相對于類路徑的資源,如:

    <mapper resource="com/smk/dao/IUserDao.xml" />

    <mapper class=" "/> 使用 mapper 接口類路徑,如:

    <mapper class="com.smk.dao.UserDao"/>

    package 標簽是用于指定dao接口所在的,當指定了之后,就不需要再寫 mapper標簽以及 resource 或者 class 了

    在 SqlMapConfig.xml 中配置:

    <package name=""/> 注冊指定包下的所有 mapper 接口,如:

    <mappers><package name="com.smk.dao"/> </mappers>

    注意:此種方法要求 mapper 接口名稱和 mapper 映射文件名稱相同,且放在同一個目錄中。

    七、Mybatis 連接池

    1、Mybatis 的連接池技術:

    在 web 開發中,常使用連接池技術來減少我們獲取連接所消耗的時間;在 Mybatis 中也有連接池技術,但是它采用的是自己的連接池技術。在 Mybatis 的 SqlMapConfig.xml 配置文件中,通過 <dataSource type = ""> 來實現 Mybatis 中連接池的配置。

    1.1、Mybatis 連接池的分類

    mybatis連接池提供了3種方式的配置:

    配置的位置:

    • 主配置文件SqlMapConfig.xml中的dataSource標簽,type屬性就是表示采用何種連接池方式。

    type屬性的取值:

    • POOLED 使用連接池的數據源
    • UNPOOLED 不使用連接池的數據源
    • JNDI 使用 JNDI 實現的數據源

    具體結構如下:

    相應地,MyBatis 內部分別定義了實現了 java.sql.DataSource 接口的 UnpooledDataSource,PooledDataSource 類來表示 UNPOOLED、POOLED 類型的數據源。

    1.2、Mybatis 中數據源的配置

    在SqlMapConfig.xml 進行配置

    <dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </dataSource>

    Mybatis 在初始化時,根據<dataSource>的 type 屬性來創建相應類型的的數據源 DataSource,即:

    • type=" POOLED ":MyBatis 會創建 PooledDataSource 實例。
    • type=" UNPOOLED ": MyBatis 會創建 UnpooledDataSource 實例。
    • type=" JNDI ":MyBatis 會從 JNDI 服務上查找 DataSource 實例,然后返回使用。

    八、Mybatis的動態SQL語句

    1、動態sql之<if>標簽

    • 根據實體類的不同取值,使用不同的 SQL 語句來進行查詢。比如在 id 如果不為空時可以根據 id 查詢,如果 username 不為空時還要加入用戶名作為條件。這種情況在我們的多條件組合查詢中經常會碰到。

    1、持久層 Dao 接口:

    //根據用戶信息,查詢用戶列表List<User> findByUser(User user);

    2、持久層 Dao 映射配置:

    <select id="findByUser" resultMap="userMap" parameterType="user">select * from user where 1=1<if test="userName!=null and userName != '' ">and username like #{userName}</if><if test="userAddress != null">or address like #{userAddress}</if></select>

    注:where 1=1 是為了避免 where 關鍵字后面的第一個詞直接就是 " and " 而導致語法錯誤。

    3、 測試:

    @Testpublic void testFindByUser() {User u = new User();u.setUserName("%王%");u.setUserAddress("%順義%");//6.執行操作List<User> users = userDao.findByUser(u);for (User user : users) {System.out.println(user);}}

    運行結果:


    可以看到,帶 “王” 的用戶和地址帶 “順義” 的用戶信息全查詢出來了。

    2、動態sql 之 <where>標簽

    為了簡化上面 where 1=1 的條件拼裝,可以采用 <where> 標簽來簡化開發。

    1、持久層 Dao 映射配置:

    <select id="findByUser" resultMap="userMap" parameterType="user">select * from user<where><if test="userName!=null and userName != '' ">and username like #{userName}</if><if test="userAddress != null">or address like #{userAddress}</if></where></select>

    3、動態標簽之<foreach>標簽

    在進行范圍查詢時,就要將一個集合中的值,作為參數動態添加進來。
    這樣將如何進行參數的傳遞?

    1、在 QueryVo 中加入一個 List 集合用于封裝參數:

    public class QueryVo {private User user;private List<Integer> ids;public List<Integer> getIds() {return ids;}public void setIds(List<Integer> ids) {this.ids = ids;}public User getUser() {return user;}public void setUser(User user) {this.user = user;}}

    2、持久層 Dao 接口:

    // 根據 id 集合查詢用戶List<User> findInIds(QueryVo vo);

    3、持久層 Dao 映射配置:

    <select id="findInIds" resultMap="userMap" parameterType="queryVo">select * from user<where><if test='ids !=null and ids.size>0'><foreach collection="ids" open="id in (" close=")" item="id" separator=",">#{id}</foreach></if></where></select>

    SQL 語句:

    • select 字段 from user where id in (?)

    <foreach> 標簽用于遍歷集合,它的屬性:

    • collection:代表要遍歷的集合元素,注意編寫時不要寫#{}
    • open:代表語句的開始部分
    • close:代表結束部分

    4、 測試:

    @Testpublic void testFindInIds() {QueryVo vo = new QueryVo();List<Integer> ids = new ArrayList<Integer>();ids.add(41);ids.add(42);ids.add(43);ids.add(46);ids.add(57);vo.setIds(ids);//6.執行操作List<User> users = userDao.findInIds(vo);for (User user : users) {System.out.println(user);}}

    運行結果:

    4、Mybatis 中簡化編寫的 sql 片段

    Sql 中可將重復的 sql語句 提取出來,使用時用 include 引用即可,最終達到 sql 重用的目的。

    1、定義代碼片段:

    <!-- 抽取重復的語句代碼片段 --><sql id="defaultSql">select * from user</sql>

    2、引用代碼片段:

    <!-- 配置查詢所有操作 --><select id="findAll" resultType="user"><include refid="defaultSql"></include></select><!-- 根據 id 查詢 --><select id="findById" resultType="UsEr" parameterType="int"><include refid="defaultSql"></include>where id = #{uid}</select>

    九、Mybatis多表查詢一對一(多對一)

    1、一對一查詢(多對一)

    以最為簡單的用戶和賬戶的模型來分析 Mybatis 多表關系。用戶為 User 表,賬戶為Account表。
    一個用戶(User)可以有一個或多個賬戶(Account)。

    需求

    查詢所有賬戶信息,關聯查詢下單用戶信息(只要用戶名和地址)。

    注意

    因為一個賬戶信息只能供某一個用戶使用,所以從查詢賬戶信息出發,關聯查詢用戶信息為一對一查詢。如果從用戶信息出發,查詢用戶下的賬戶信息則為一對多查詢,因為一個用戶可以有多個賬戶。

    方式一

    1、定義賬戶信息的實體類:

    public class Account implements Serializable {private Integer id;private Integer uid;private Double money;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", uid=" + uid +", money=" + money +'}';} }

    2、定義 AccountUser 類:

    為了能夠封裝上面 SQL 語句的查詢結果,定義 AccountCustomer 類中要包含賬戶信息同時還要包含用戶信息,所以在定義 AccountUser 類時可以繼承 User 類。

    public class AccountUser extends Account implements Serializable {private String username;private String address;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}@Overridepublic String toString() {return super.toString() + " AccountUser{" +"username='" + username + '\'' +", address='" + address + '\'' +'}';} }

    3、定義持久層 Dao 接口:

    /*** 查詢所有用戶,帶有用戶名和地址信息* @return*/List<AccountUser> findAllAccount();

    4、定義 IAccountDao.xml 文件中的查詢配置信息:

    <!--查詢所有賬戶同是包含用戶名和地址信息--><select id="findAllAccount" resultType="accountuser">select a.*,u.username,u.address from account a,user u where a.uid =u.id;</select>

    5、創建 AccountTest 測試類:

    @Testpublic void testFindAllAccount() {List<AccountUser> aus = accountDao.findAllAccount();for (AccountUser au : aus) {System.out.println(au);}}

    運行結果:

    小結:

    定義專門的 po 類作為輸出類型,其中定義了 sql 查詢結果集所有的字段。此方法較為簡單,企業中使用普遍。

    po: (persistant object)持久對象,可以看成是與數據庫中的表相映射的java對象。

    方式二

    使用 resultMap,定義專門的 resultMap 用于映射一對一查詢結果。

    我們可以在 Account 類中加入一個 User 類的對象來代表這個賬戶是哪個用戶的。

    1、在 Account 類中加入 User 類的對象作為 Account 類的一個屬性:

    public class Account implements Serializable {private Integer id;private Integer uid;private Double money;private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public Integer getUid() {return uid;}public void setUid(Integer uid) {this.uid = uid;}public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Account{" +"id=" + id +", uid=" + uid +", money=" + money +'}';} }

    2、修改 AccountDao 接口中的方法:

    List<Account> findAllAccount();

    把 AccountUser 改為 Account

    3、重新定義 AccountDao.xml 文件:

    <!-- 建立對應關系 --><resultMap type="account" id="accountMap"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/><!-- 它是用于指定 從表 方的引用實體屬性的 --><association property="user" javaType="user"><id column="id" property="id"/><result column="username" property="username"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/><result column="address" property="address"/></association></resultMap><select id="findAllAccount" resultMap="accountMap">select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid =u.id;</select>

    注:

    • a.id as aid :這里兩個表的字段重復了所以需要起別名。
    • javaType=" user ":即指定數據類型為user類,全限定類名或者別名(此處為別名)。

    4、加入測試方法:

    @Testpublic void testFindAllAccount() {List<Account> accounts = accountDao.findAllAccount();for (Account account : accounts) {System.out.println(account);System.out.println(account.getUser());}}

    測試結果:


    2、 一對多查詢

    需求:

    • 查詢所有用戶信息及用戶關聯的賬戶信息。

    分析:

    • 用戶信息和他的賬戶信息為一對多關系,并且查詢過程中如果用戶沒有賬戶信息,此時也要將用戶信息查詢出來,此時應該使用左外連接查詢比較合適。

    1、User 類加入 List <Account>:

    public class User implements Serializable {private Integer Id;private String username;private String Address;private String Sex;private Date Birthday;private List<Account> accounts;public List<Account> getAccounts() {return accounts;}public void setAccounts(List<Account> accounts) {this.accounts = accounts;}public Integer getId() {return Id;}public void setId(Integer Id) {this.Id = Id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return Address;}public void setAddress(String address) {Address = address;}public String getSex() {return Sex;}public void setSex(String sex) {Sex = sex;}public Date getBirthday() {return Birthday;}public void setBirthday(Date birthday) {Birthday = birthday;}@Overridepublic String toString() {return "User{" +"Id=" + Id +", username='" + username + '\'' +", Address='" + Address + '\'' +", Sex='" + Sex + '\'' +", Birthday=" + Birthday +'}';} }

    2、 Dao 接口中加入查詢方法:

    List<User> findAll();

    3、Dao 映射文件配置:

    <resultMap type="user" id="userMap"><id column="id" property="id"></id><result column="username" property="username"/><result column="address" property="address"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/><!-- collection 是用于建立一對多中集合屬性的對應關系ofType 用于指定集合元素的數據類型--><collection property="accounts" ofType="account"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/></collection></resultMap><!--查詢所有--><select id="findAll" resultMap="userMap">select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid</select>

    注:
    collection:

    • 部分定義了用戶關聯的賬戶信息。表示關聯查詢結果集

    property=" accList " :

    • 關聯查詢的結果集存儲在 User 對象的上哪個屬性。

    ofType=" account ":

    • 指定關聯查詢的結果集中的對象類型即List中的對象類型。此處可以使用別名,也可以使用全限定名。

    4、 測試方法:

    @Testpublic void testFindAll() {List<User> users = userDao.findAll();for (User user : users) {System.out.println("用戶的信息:");System.out.println(user);System.out.println(user.getAccounts());}}

    5、運行結果:

    十、 Mybatis 多表查詢——多對多

    1、實現 Role 到 User 多對多

    1、編寫 Role 實體類:

    public class Role implements Serializable {private Integer roleId;private String roleName;private String roleDesc;private List<User> users;public List<User> getUsers() {return users;}public void setUsers(List<User> users) {this.users = users;}public Integer getRoleId() {return roleId;}public void setRoleId(Integer roleId) {this.roleId = roleId;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public String getRoleDesc() {return roleDesc;}public void setRoleDesc(String roleDesc) {this.roleDesc = roleDesc;}@Overridepublic String toString() {return "Role{" +"roleId=" + roleId +", roleName='" + roleName + '\'' +", roleDesc='" + roleDesc + '\'' +'}';} }

    2、編寫 Role 持久層接口:

    /*** 查詢所有角色* @return*/List<Role> findAll();

    3、編寫映射文件:

    <mapper namespace="com.itheima.dao.IRoleDao"><!--定義role表的ResultMap--><resultMap id="roleMap" type="role"><id property="roleId" column="rid"></id><result property="roleName" column="role_name"></result><result property="roleDesc" column="role_desc"></result><collection property="users" ofType="user"><id column="id" property="id"></id><result column="username" property="username"></result><result column="address" property="address"></result><result column="sex" property="sex"></result><result column="birthday" property="birthday"></result></collection></resultMap><!--查詢所有--><select id="findAll" resultMap="roleMap">select u.*,r.id as rid,r.role_name,r.role_desc from role rleft outer join user_role ur on r.id = ur.ridleft outer join user u on u.id = ur.uid</select> </mapper>

    4、測試類:

    /*** 測試查詢所有*/@Testpublic void testFindAll() {List<Role> roles = roleDao.findAll();for (Role role : roles) {System.out.println("---每個角色的信息----");System.out.println(role);System.out.println(role.getUsers());}}

    運行結果:


    2、實現 User 到 Role 的多對多

    大體步驟和上面同理,其中sql語句需改為:

    select u.*,r.id as rid,r.role_name,r.role_desc from user uleft outer join user_role ur on u.id = ur.ridleft outer join role r on r.id = ur.uid

    十一、 Mybatis 延遲加載策略

    通過前面的學習,我們已經掌握了 Mybatis 中一對一,一對多,多對多關系的配置及實現,可以實現對象的關聯查詢。實際開發過程中很多時候我們并不需要總是在加載用戶信息時就一定要加載他的賬戶信息。此時就是我們所說的延遲加載。

    1、何為延遲加載?

    就是在需要用到數據時才進行加載,不需要用到數據時就不加載數據。延遲加載也稱懶加載。

    好處:

    • 先從單表查詢,需要時再從關聯表去關聯查詢,大大提高數據庫性能,因為查詢單表要比關聯查詢多張表速度要快。

    壞處:

    • 因為只有當需要用到數據時,才會進行數據庫查詢,這樣在大批量數據查詢時,因為查詢工作也要消耗時間,所以可能造成用戶等待時間變長,造成用戶體驗下降。

    2、使用 assocation 實現延遲加載

    需求:

    • 查詢賬戶(Account) 信息并且關聯查詢用戶(User) 信息。如果先查詢賬戶(Account) 信息即可滿足要求,當我們需要查詢用戶(User) 信息時再查詢用戶(User) 信息。把對用戶(User) 信息的按需去查詢就是延遲加載。

    1、DAO 接口:

    List<Account> findAll();

    2、持久層映射文件:

    <?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.itheima.dao.IAccountDao"><!-- 建立對應關系 --><resultMap type="account" id="accountMap"><id column="id" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/><!-- 它是用于指定從表方的引用實體屬性的 --><association property="user" javaType="user"select="com.itheima.dao.IUserDao.findById"column="uid"></association></resultMap><select id="findAll" resultMap="accountMap">select * from account</select> </mapper>

    其中:

    • select: 填寫我們要調用的 select 映射的 id
    • column : 填寫我們要傳遞給 select 映射的參數

    3、User 的持久層接口和映射文件:

    User findById(Integer userId); <!--根據 id 查詢--> <select id="findById" resultType="user" parameterType="int" >select * from user where id = #{uid} </select>

    4、開啟 Mybatis 的延遲加載策略:

    在 SqlMapConfig.xml 中配置

    <!--開啟延遲加載的支持--><settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/></settings>
    • lazyLoadingEnabled:延遲加載的全局開關。當開啟時,所有關聯對象都會延遲加載。
    • aggressiveLazyLoading:當開啟時,任何方法的調用都會加載該對象的所有屬性。否則,每個屬性會按需加載。

    5、測試查詢用戶信息時:

    @Testpublic void testFindAll() {List<Account> accounts = accountDao.findAll();for (Account account : accounts) {System.out.println("每個account的信息:--------------");System.out.println(account);System.out.println(account.getUser());}}

    測試結果:


    可以看到SQL語句全部執行了。

    6、測試只查賬戶信息不查用戶信息:

    @Testpublic void testFindAll() {List<Account> accounts = accountDao.findAll();/* for (Account account : accounts) {System.out.println("每個account的信息:--------------");System.out.println(account);System.out.println(account.getUser());}*/}

    運行結果:


    可以看到只執行了一條SQL語句,即執行了延遲加載。

    3、使用 Collection 實現延遲加載

    同樣我們也可以在一對多關系配置的<collection>結點中配置延遲加載策略。<collection>結點中也有 select 屬性,column 屬性。

    需求:

    • 完成加載用戶對象時,查詢該用戶所擁有的賬戶信息。

    1、 User 實體類:

    public class User implements Serializable {private Integer Id;private String username;private String Address;private String Sex;private Date Birthday;private List<Account> accounts;public List<Account> getAccounts() {return accounts;}public void setAccounts(List<Account> accounts) {this.accounts = accounts;}public Integer getId() {return Id;}public void setId(Integer Id) {this.Id = Id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return Address;}public void setAddress(String address) {Address = address;}public String getSex() {return Sex;}public void setSex(String sex) {Sex = sex;}public Date getBirthday() {return Birthday;}public void setBirthday(Date birthday) {Birthday = birthday;}@Overridepublic String toString() {return "User{" +"Id=" + Id +", username='" + username + '\'' +", Address='" + Address + '\'' +", Sex='" + Sex + '\'' +", Birthday=" + Birthday +'}';} }

    2、用戶(User)和賬戶(Account)持久層接口的方法:

    /*** 查詢所有用戶** @return*/List<User> findAll();/*** 根據用戶 id 查詢賬戶信息* @param uid* @return*/List<User> findByUid(Integer uid);

    3、編寫用戶持久層映射配置:

    <resultMap type="user" id="userMap"><id column="id" property="id"></id><result column="username" property="username"/><result column="address" property="address"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/><!-- collection 是用于建立一對多中集合屬性的對應關系 ofType 用于指定集合元素的數據類型--><collection property="accounts" ofType="account"select="com.itheima.dao.IAccountDao.findByUid"column="id"></collection></resultMap><!--查詢所有--><select id="findAll" resultMap="userMap">select * from user</select>

    <collection>標簽:

    • 主要用于加載關聯的集合對象

    select 屬性:

    • 用于指定查詢 account 列表的 sql 語句,所以填寫的是該 sql 映射的 id

    column 屬性:

    • 用于指定 select 屬性的 sql 語句的參數來源,上面的參數來自于 user 的 id 列,所以就寫成 id 這一個字段名了

    4、編寫賬戶持久層映射配置:

    <!-- 根據用戶 id 查詢賬戶信息 --><select id="findByUid" resultType="account" parameterType="int">select * from account where uid = #{uid}</select>

    5、延時加載 測試只加載用戶信息:

    @Testpublic void testFindAll() {List<User> users = userDao.findAll();/* for (User user : users) {System.out.println("用戶的信息:");System.out.println(user);System.out.println(user.getAccounts());}*/}

    測試結果:

    可以發現并沒有加載 Account 賬戶信息。

    十二、 Mybatis 緩存

    像大多數的持久化框架一樣,Mybatis 也提供了緩存策略,通過緩存策略來減少數據庫的查詢次數,從而提高性能。

    Mybatis 中緩存分為一級緩存,二級緩存。


    1、Mybatis 一級緩存

    一級緩存是 SqlSession 級別的緩存,只要 SqlSession 沒有 flush 或 close,它就存在。

    驗證一級緩存的存在:

    測試方法:

    @Testpublic void testFirstCache() {User user1 = userDao.findById(41);System.out.println(user1);User user2 = userDao.findById(41);System.out.println(user2);System.out.println(user1 == user2);}

    測試結果:



    可以發現,雖然在上面的代碼中查詢了兩次,但最后只執行了一次數據庫操作,這就是 Mybatis 提供給我們的一級緩存在起作用了。因為一級緩存的存在,導致第二次查詢 id 為 41 的記錄時,并沒有發出 sql 語句從數據庫中查詢數據,而是從一級緩存中查詢。

    測試一級緩存的清空:

    測試方法:

    @Testpublic void testFirstCache() {User user1 = userDao.findById(41);System.out.println(user1);// sqlSession.close();//再次獲取 SqlSession 對象// sqlSession = factory.openSession();//userDao = sqlSession.getMapper(IUserDao.class);sqlSession.clearCache();//此方法也可以清空緩存User user2 = userDao.findById(41);System.out.println(user2);System.out.println(user1 == user2);}

    測試結果:


    當執行 sqlSession.clearCache() 后,再次獲取sqlSession并查詢id=41的User對象時,又重新執行了sql語句,從數據庫進行了查詢操作。

    一級緩存的分析

    一級緩存是 SqlSession 范圍的緩存,當調用 SqlSession 的修改,添加,刪除,commit(),close()方法時,就會清空一級緩存。


    當第一次發起查詢用戶 id 為 1 的用戶信息,先去找緩存中是否有 id 為 1 的用戶信息,如果沒有,從數據庫查詢用戶信息。

    得到用戶信息,將用戶信息存儲到一級緩存中。

    如果 sqlSession 去執行 commit 操作(執行插入、更新、刪除),清空 SqlSession 中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。

    第二次發起查詢用戶 id 為 1 的用戶信息,先去找緩存中是否有 id 為 1 的用戶信息(此時已經沒有一級緩存了),如果緩存中有,則直接從緩存中獲取用戶信息,沒有則重新發起查詢。

    2、Mybatis 二級緩存

    它是 Mybatis 中 SqlSessionFactory 對象的緩存。由同一個 SqlSessionFactory 對象創建的 SqlSession 共享其緩存。


    假設:

    sqlSession1 去查詢用戶信息,查詢到用戶信息會將查詢數據存儲到二級緩存中。

    如果 SqlSession3 去執行相同 mapper 映射下 sql,執行 commit 提交,將會清空該 mapper 映射下的二級緩存區域的數據。

    sqlSession2 去查詢與 sqlSession1 相同的用戶信息,首先會去緩存中找是否存在數據,如果存在直接從緩存中取出數據,,否則重新發起查詢(本例)。

    二級緩存的使用步驟

    1、讓Mybatis框架支持二級緩存(在SqlMapConfig.xml中配置):

    <settings><!-- 開啟二級緩存的支持 --><setting name="cacheEnabled" value="true"/> </settings>

    因為 cacheEnabled 的取值默認就為 true,所以這一步可以省略不配置。

    true 代表開啟二級緩存;為false 代表不開啟二級緩存。

    2、讓當前的映射文件支持二級緩存(在IUserDao.xml中配置):

    <!-- 開啟二級緩存的支持 --><cache/>

    3、讓當前的操作支持二級緩存(在select標簽中配置):

    <!-- 根據 id 查詢 --> <select id="findById" resultType="user" parameterType="int" useCache="true">select * from user where id = #{uid} </select>

    將 IUserDao.xml 映射文件中的<select>標簽中設置 useCache=" true " 代表當前這個 statement 要使用二級緩存,如果不使用二級緩存可以設置為 false。

    注意:針對每次查詢都需要最新的數據 sql,要設置成 useCache=false,禁用二級緩存。

    測試:

    @Testpublic void testFirstLevelCache(){SqlSession sqlSession1 = factory.openSession();IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);User user1 = dao1.findById(41);System.out.println(user1);sqlSession1.close();//一級緩存消失SqlSession sqlSession2 = factory.openSession();IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);User user2 = dao2.findById(41);System.out.println(user2);sqlSession2.close();System.out.println(user1 == user2);}

    運行結果:



    經過上面的測試,發現執行了兩次查詢,并且在執行第一次查詢后,我們關閉了一級緩存,再去執行第二次查詢時,我們發現并沒有對數據庫發出 sql 語句,所以此時的數據就只能是來自于我們所說的二級緩存。

    user1 = user2 = false 的原因是 二級緩存存放的是 數據 而不是對象,每次查詢都會創建一個新的對象。

    十三、 Mybatis 注解開發

    1、mybatis 的常用注解

    @Insert: 實現新增 @Update: 實現更新 @Delete: 實現刪除 @Select: 實現查詢@Result: 實現結果集封裝 @Results: 可以與@Result 一起使用,封裝多個結果集 @ResultMap: 實現引用@Results 定義的封裝@One: 實現一對一結果集封裝 @Many: 實現一對多結果集封裝@SelectProvider: 實現動態 SQL 映射 @CacheNamespace: 實現注解二級緩存的使用

    2、使用 Mybatis 注解實現基本 CRUD

    1、實體類:

    public class User implements Serializable {private Integer id;private String username;private String address;private String sex;private Date birthday;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"id=" + id +", username='" + username + '\'' +", address='" + address + '\'' +", sex='" + sex + '\'' +", birthday=" + birthday +'}';} }

    2、使用注解方式開發持久層接口:

    public interface IUserDao {/*** 查詢所有* @return*/@Select("select * from user")List<User> findAll();/*** 根據 id 查詢一個用戶* @param userId* @return*/@Select("select * from user where id = #{uid} ")User findById(Integer userId);/*** 插入操作* @param user* @return*/@Insert("insert into user(username,sex,birthday,address)values(#{username},#{sex},#{birthday},#{address})")int saveUser(User user);/*** 更新操作* @param user* @return*/@Update("update user set username=#{username}, address =#{address}, sex =#{sex}, birthday =#{birthday}where id =#{id}")int updateUser(User user);/*** 刪除用戶* @param userId* @return*/@Delete("delete from user where id = #{uid} ")int deleteUser(Integer userId);/*** 查詢使用聚合函數* @return*/@Select("select count(*) from user ")int findTotal();/*** 模糊查詢* @param name* @return*/@Select("select * from user where username like #{username} ")List<User> findByName(String name); }

    3、SqlMapConfig 配置文件:

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!--引入外部文件--><properties resource="jdbcConfig.properties"/><!--配置別名--><typeAliases><package name="com.smk.domain"/></typeAliases><environments default="mysql"><environment id="mysql"><transactionManager type="JDBC"></transactionManager><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!-- 配置 dao 接口的位置,它有兩種方式第一種:使用 mapper 標簽配置 class 屬性第二種:使用 package 標簽,直接指定 dao 接口所在的包--><mappers><package name="com.smk.dao"/></mappers> </configuration>

    4、測試方法:

    測試方法和xml映射配置開發是一樣的。

    3、使用注解實現復雜關系映射開發

    實現復雜關系映射之前,可以在映射文件中通過配置 <resultMap> 來實現,在使用注解開發時我們需要借助@Results 注解,@Result 注解,@One 注解,@Many 注解。

    3.1、當POJO屬性和數據庫字段不一致時

    例:
    1、 實體類:

    private Integer userId;private String userName;private String userAddress;private String userSex;private Date userBirthday;

    2、dao接口:

    public interface IUserDao {/*** 查詢所有** @return*/@Select("select * from user")@Results(id = "userMap", value = {@Result(id = true, column = "id", property = "userId"),@Result(column = "username", property = "userName"),@Result(column = "address", property = "userAddress"),@Result(column = "sex", property = "userSex"),@Result(column = "birthday", property = "userBirthday")})List<User> findAll();/*** 根據 id 查詢用戶** @param userId* @return*/@Select("select * from user where id = #{uid} ")@ResultMap("userMap")User findById(Integer userId);/*** 模糊查詢** @param name* @return*/@Select("select * from user where username like #{username}")@ResultMap("userMap")List<User> findByName(String name); }

    其中:

    @Results 注解代替的是標簽<resultMap>

    @Resutl 注解代替了 <id>標簽和<result>標簽

    @Result 中 屬性介紹:

    • id 是否是主鍵字段
    • column 數據庫的列名
    • property 需要裝配的屬性名

    @Result定義后,在其他方法處,便可以使用該@Results定義的resultMap了。

    3.2、使用注解實現一對一復雜關系映射

    1、User 實體類及 Account 實體類:

    和上面xml配置方式相同。

    2、賬戶的持久層接口及注解配置:

    public interface IAccountDao {@Select("select * from account")@Results(id = "accountMap", value = {@Result(id = true, column = "id", property = "id"),@Result(column = "uid", property = "uid"),@Result(column = "money", property = "money"),@Result(property = "user", column = "uid", one = @One(select = "com.smk.dao.IUserDao.findById", fetchType = FetchType.EAGER))})List<Account> findAll(); }

    @One 注解(一對一):

    • 代替了<assocation>標簽,是多表查詢的關鍵,在注解中用來指定子查詢返回單一對象。

    @One 注解屬性介紹:

    • select 指定用來多表查詢的 sqlmapper
    • fetchType 會覆蓋全局的配置參數 lazyLoadingEnabled。。

    使用格式:

    • @Result(column="",property="",one=@One(select=""))

    3、用戶的持久層接口及注解配置:

    public interface IUserDao {/*** 查詢所有** @return*/@Select("select * from user")@Results(id = "userMap", value = {@Result(id = true, column = "id", property = "userId"),@Result(column = "username", property = "userName"),@Result(column = "address", property = "userAddress"),@Result(column = "sex", property = "userSex"),@Result(column = "birthday", property = "userBirthday")})List<User> findAll();/*** 根據 id 查詢用戶** @param userId* @return*/@Select("select * from user where id = #{uid} ")@ResultMap("userMap")User findById(Integer userId); }

    運行結果:


    3.3、使用注解實現一對多復雜關系映射

    1、User 實體類及 Account 實體類:

    • 和上面xml配置方式相同。

    2、用戶的持久層接口及注解配置:

    public interface IUserDao {/*** 查詢所有** @return*/@Select("select * from user")@Results(id = "userMap", value = {@Result(id = true, column = "id", property = "userId"),@Result(column = "username", property = "userName"),@Result(column = "address", property = "userAddress"),@Result(column = "sex", property = "userSex"),@Result(column = "birthday", property = "userBirthday"),@Result(property = "accounts", column = "id", many = @Many(select = "com.smk.dao.IAccountDao.findByUid",fetchType = FetchType.LAZY))})List<User> findAll(); }

    3、賬戶的持久層接口及注解配置:

    public interface IAccountDao {// 根據用戶 id 查詢用戶下的所有賬戶@Select("select * from account where uid = #{uid} ")List<Account> findByUid(Integer userId); }

    4、添加測試方法:

    //測試查詢所有@Testpublic void testFindAll() {List<User> users = userDao.findAll();for (User user : users) {System.out.println("-----每個用戶的內容-----");System.out.println(user);System.out.println(user.getAccounts());}}

    運行結果:


    測試延時加載:

    @Testpublic void testFindAll() {List<User> users = userDao.findAll();/* for (User user : users) {System.out.println("-----每個用戶的內容-----");System.out.println(user);System.out.println(user.getAccounts());}*/}

    運行結果:

    3.4、mybatis 基于注解的二級緩存

    1、在 SqlMapConfig 中開啟二級緩存支持:

    <!-- 配置二級緩存 --> <settings><!-- 開啟二級緩存的支持 --><setting name="cacheEnabled" value="true"/> </settings>

    2、在持久層接口中使用注解配置二級緩存:

    @CacheNamespace(blocking=true)//mybatis 基于注解方式實現配置二級緩存 public interface IUserDao {}

    🆗,至此mybatis的內容就總結完了( ̄︶ ̄)↗

    總結

    以上是生活随笔為你收集整理的Java EE——Mybatis 框架学习的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    欧美日韩高清一区二区三区 | 久久精品99精品国产香蕉 | 免费久久99精品国产 | 中文字幕人成人 | 国产综合在线视频 | 亚洲精品一区中文字幕乱码 | 天天射天天舔天天干 | 久久中文精品视频 | 亚洲一二三区精品 | 免费日韩电影 | 伊人手机在线 | 国产精品精品久久久 | 日韩亚洲国产中文字幕 | 成人久久综合 | 精品久久久久久久久久久院品网 | 国产精品18p | 91在线国内视频 | 国产在线观看国语版免费 | www.婷婷com | 亚洲高清国产视频 | 九九热99视频 | 99久久这里有精品 | 综合五月 | 国产中文字幕av | 久久久久影视 | 免费看成人av | 欧美尹人 | 精品久久亚洲 | 欧美色图另类 | 免费人人干 | 香蕉视频在线视频 | 在线你懂| 成人午夜精品福利免费 | 久久精品小视频 | 欧美另类视频 | 激情五月六月婷婷 | 成人av免费在线 | 91精品入口 | 免费观看视频的网站 | 亚洲免费视频在线观看 | 国产精品a久久久久 | 久久精品一区二区三区四区 | 精品在线观看视频 | 狠狠狠狠狠狠 | 91亚洲精品久久久蜜桃借种 | 五月婷婷六月丁香 | 国产专区在线看 | 欧美日韩在线观看不卡 | 亚洲黄色三级 | 色综合天天射 | 一区二区中文字幕在线播放 | 香蕉网站在线观看 | 伊人射 | 日韩av区| 久章操 | 天天在线视频色 | 最近更新的中文字幕 | 精品久久网 | 天天躁天天操 | 人人爱人人舔 | 婷婷日韩 | 丁香花在线视频观看免费 | 日韩成人免费在线观看 | 久久久国产精品电影 | 国产精品麻豆视频 | 成人午夜在线观看 | 日日综合 | 在线欧美日韩 | 在线欧美小视频 | 麻豆久久一区二区 | 亚洲码国产日韩欧美高潮在线播放 | 草久久久 | av在线日韩 | 色网站中文字幕 | 色夜影院| 日韩在线电影观看 | 久久新视频| 91精品区 | 偷拍精偷拍精品欧洲亚洲网站 | 久草视频在线免费播放 | 日韩在线观看视频网站 | 蜜臀av性久久久久蜜臀aⅴ流畅 | 美女福利视频一区二区 | 五月天丁香视频 | 国产在线观看91 | 92精品国产成人观看免费 | 一区二区三区四区五区在线 | 日韩免费视频线观看 | 福利一区在线视频 | 亚洲欧美一区二区三区孕妇写真 | 日韩av电影网站在线观看 | 99久热 | 国产裸体视频网站 | 97超视频免费观看 | 日本夜夜草视频网站 | 视频在线亚洲 | 亚洲人成在线电影 | 五月色婷 | 五月婷婷激情六月 | 日日射天天射 | 不卡日韩av| 国产高清视频在线播放一区 | 狠狠狠狠狠狠狠干 | 婷婷丁香视频 | 狠狠网亚洲精品 | 99久久这里只有精品 | 波多野结衣视频一区 | 国产日产精品一区二区三区四区的观看方式 | av在线播放观看 | 国产女v资源在线观看 | 亚洲自拍偷拍色图 | 日韩性片 | 日本精品一区二区在线观看 | 成人国产精品入口 | 久久久久久久久久久电影 | 96国产精品 | 超碰免费观看 | 黄色在线观看免费网站 | 精品久久久久久久久久久久 | 美腿丝袜一区二区三区 | 三级黄色a | 免费午夜av| 五月开心激情 | 亚洲人成网站精品片在线观看 | aa一级片| 婷婷丁香在线 | 中文字幕一二三区 | 国产剧情一区二区 | 五月开心六月婷婷 | 精品在线观看一区二区三区 | 亚洲精品动漫在线 | 久久久免费 | 婷婷网站天天婷婷网站 | 色欧美成人精品a∨在线观看 | 日韩电影在线观看一区二区三区 | 国产精品一区二区三区电影 | 天天干亚洲 | 最近中文字幕国语免费高清6 | 美女网站在线播放 | 97超碰在线免费观看 | 国产精品va视频 | 天天爽天天射 | 亚洲日本欧美 | 成人黄色电影在线播放 | 欧美午夜剧场 | 成人免费观看视频网站 | 国产精品黑丝在线观看 | 激情网站免费观看 | 激情五月播播久久久精品 | 新版资源中文在线观看 | 日批在线观看 | 久久狠狠干 | 韩日精品在线观看 | 欧美成人影音 | 成人免费观看视频网站 | 不卡av在线 | 国内视频在线观看 | 在线观看亚洲国产 | 91精品久久久久久综合乱菊 | 88av色 | 免费观看版 | 成人综合婷婷国产精品久久免费 | 在线不卡的av | 久久夜色精品国产欧美一区麻豆 | 亚洲成人二区 | 久久精品草 | 中文字幕欧美日韩va免费视频 | 激情导航 | 激情综合网在线观看 | 永久免费精品视频网站 | 国产一线天在线观看 | 亚洲日本黄色 | 一本到视频在线观看 | 91av中文字幕 | 欧美精品一区二区蜜臀亚洲 | av午夜电影 | 久久在线免费观看 | av在线在线 | 99热999| 日日夜夜综合网 | 国产xxxx做受性欧美88 | 久久久久久蜜桃一区二区 | 成人试看120秒 | 美女久久| 波多野结衣在线播放一区 | 日本黄色a级大片 | 国产无套精品久久久久久 | 正在播放国产精品 | www免费视频com━ | av导航福利| 69久久久久久久 | 国产aa精品 | 一区二区三区四区在线 | 在线观看成人小视频 | 最新av中文字幕 | 亚洲精品久久在线 | 亚洲人成精品久久久久 | 欧美精品免费视频 | 国产高清精品在线观看 | 综合网伊人| 日韩一片 | 国产亚洲综合精品 | 国产黄色片在线免费观看 | 九九99视频| 久草网视频在线观看 | 91精品国产99久久久久久久 | 操操综合网 | 久草观看视频 | 狠狠躁日日躁狂躁夜夜躁 | 久久久首页 | 中文字幕电影一区 | 久久综合欧美精品亚洲一区 | 日韩在线观看影院 | 国产午夜精品免费一区二区三区视频 | 最近的中文字幕大全免费版 | 亚洲国产成人在线 | 99精品国产福利在线观看免费 | 久久99久久99精品免观看粉嫩 | 在线观看一区二区视频 | 国内精品久久久久影院一蜜桃 | 欧美日韩在线观看视频 | 人人干人人超 | 在线观看久久久久久 | www.久久成人 | 一区二区精品国产 | 久久精品香蕉 | 天天草天天爽 | 亚洲高清在线精品 | 欧洲亚洲女同hd | www.夜夜操.com | 天天综合导航 | av电影不卡| 久久爽久久爽久久av东京爽 | 成人九九视频 | 激情动态 | 欧美a级在线 | 国产精品久久久电影 | 色婷婷狠狠18 | 久久 地址 | 成人免费看片网址 | 色婷婷a| 91麻豆精品国产91久久久无需广告 | 国内免费的中文字幕 | 亚洲最大在线视频 | 国产日产精品一区二区三区四区 | 亚洲欧洲精品久久 | 国产一级淫片免费看 | 国产在线精品区 | 在线天堂中文www视软件 | 五月婷婷av在线 | 黄色在线免费观看网址 | 操操操日日日干干干 | 久久久久久久久久久久国产精品 | 午夜av在线 | 九九热久久免费视频 | 亚洲深夜影院 | av中文天堂 | 久草视频在线免费 | 一级性视频 | 欧美a级片免费看 | 国产又粗又猛又黄 | 色婷婷电影 | 亚洲成人国产 | 在线观看亚洲 | 天天综合网~永久入口 | 欧美日本一二三 | 亚洲成a人片综合在线 | 久久情爱| 人人爽人人爽 | 欧美日韩中文国产一区发布 | 亚洲性视频 | 黄色午夜网站 | 国产手机视频精品 | 国产精品自拍av | 日韩色区| 久久一区国产 | 国产品久精国精产拍 | 国产在线观看免费av | 久久免费电影网 | 中文字幕在线观看你懂的 | 国产亚洲小视频 | 国产在线a视频 | 国产主播99| 91 中文字幕 | 日韩色在线 | 中文国产字幕在线观看 | 亚洲成人资源 | 亚洲天堂网在线视频 | 国产高清视频色在线www | 日韩性久久 | 国产中文欧美日韩在线 | 国产超碰97 | 中文字幕乱码电影 | 97超碰伊人 | 久久国产热 | 亚洲欧美日本一区二区三区 | 精品久久电影 | 在线观看 亚洲 | 久久有精品 | av黄色国产| 亚洲国产欧美一区二区三区丁香婷 | 最新中文字幕 | 天天射天天舔天天干 | 欧美粗又大 | 国产成人黄色网址 | 国产亚洲精品久久久久久 | 亚洲国产中文字幕在线观看 | 成人欧美一区二区三区黑人麻豆 | 亚洲国产精彩中文乱码av | 久久影视一区二区 | 久久精品婷婷 | 免费国产在线精品 | 久久久精品在线观看 | 二区精品视频 | 亚洲精品小视频在线观看 | 综合网av| 嫩草91影院 | 亚洲,国产成人av | 久久久一本精品99久久精品66 | 国产免费片 | 在线观看视频在线观看 | 福利久久久 | 99草在线视频 | aaaaaa毛片| 懂色av一区二区在线播放 | 91最新视频在线观看 | 久久影院午夜论 | 夜夜澡人模人人添人人看 | 亚洲国产精品va在线看黑人动漫 | 88av视频| 日韩免费一级a毛片在线播放一级 | 久久精品视频18 | 中文字幕久久久精品 | 国产大尺度视频 | 国产女人40精品一区毛片视频 | 国产一区二区在线精品 | www在线观看视频 | 亚洲性视频 | 免费福利在线 | av在线官网 | 日韩精品一区二区三区丰满 | 欧美一区中文字幕 | 狠狠网亚洲精品 | 探花视频在线观看免费版 | 五月婷婷在线播放 | 91在线一区二区 | 久久国产精品影片 | 色网av| 色综合天天色综合 | 视频一区二区免费 | 最近高清中文字幕 | 久久综合久久综合这里只有精品 | 久久久男人的天堂 | 亚洲伦理精品 | 亚洲网久久 | 毛片无卡免费无播放器 | 中文字幕在线影视资源 | 久久精品精品电影网 | 亚洲国产三级在线观看 | 色综合咪咪久久网 | 日躁夜躁狠狠躁2001 | 亚洲精品国产精品乱码不99热 | 日韩二区在线观看 | 97视频在线观看视频免费视频 | 久久精品国产精品亚洲 | 成年人免费在线看 | 久久在线免费观看视频 | 午夜久久久久久久久久影院 | 亚洲经典精品 | 国产精品v a免费视频 | 亚洲人在线 | 亚洲精品国产精品国自产在线 | japanesefreesex中国少妇 | 一本色道久久精品 | 国产日韩欧美在线观看 | 久久色在线观看 | 日韩性久久| 午夜电影中文字幕 | 久久久福利视频 | 欧美国产日韩在线视频 | 丁香六月网 | 久久久久夜色 | 一区二区电影在线观看 | 91桃色在线观看视频 | 国产精品入口66mio女同 | 激情网站五月天 | 91中文字幕在线观看 | 有码中文字幕 | 欧美黑人性爽 | 这里只有精彩视频 | 色综合久久久网 | 黄色免费大片 | 久久综合99| 在线有码中文 | 欧美一级艳片视频免费观看 | 免费看黄网站在线 | 天天爽夜夜爽精品视频婷婷 | 成人精品视频久久久久 | 日韩天天操 | 精品在线播放视频 | 久久人人爽爽人人爽人人片av | 天天色天天干天天 | 久久理论电影 | 国语自产偷拍精品视频偷 | 成人午夜电影在线播放 | 日韩在线大片 | 国产手机视频在线 | 国内少妇自拍视频一区 | 成人黄大片 | 99精品视频在线免费观看 | 亚洲成人欧美 | 久久久久97国产 | 日韩理论片在线观看 | 91亚洲影院 | 一级成人免费视频 | 日韩在线电影 | 国产精品久久久久久久久久三级 | 久久韩国免费视频 | 激情综合网五月 | 国产成人av网站 | 91成人免费在线视频 | 在线亚洲日本 | 制服丝袜在线91 | 激情久久久 | 国产中文字幕三区 | 九九九九精品九九九九 | 久久99亚洲精品久久久久 | 一级片黄色片网站 | 首页国产精品 | 久久综合狠狠 | 色之综合网 | 最近日本韩国中文字幕 | 免费看污在线观看 | 免费看的国产视频网站 | 女人18精品一区二区三区 | 一区二区三区四区五区在线 | 亚洲天堂网在线视频 | 久久精品高清视频 | 欧美精品视 | 国产不卡视频在线 | 日韩中文字幕在线观看 | 亚洲精品理论 | 视频在线观看日韩 | 国产一级黄色片免费看 | 免费观看www视频 | 伊人电影在线观看 | 欧美坐爱视频 | 亚洲天天综合网 | 99视频在线免费看 | 欧美一区免费观看 | 伊人热 | 国产日韩视频在线 | 少妇性bbb搡bbb爽爽爽欧美 | 国产精品久久电影观看 | 狠狠操91| 国产视频日韩视频欧美视频 | 又爽又黄又无遮挡网站动态图 | 久久精品久久久久电影 | 99福利影院 | 麻豆国产在线播放 | 亚洲精品久久久蜜桃直播 | 国产精品 日韩精品 | 精品国产片 | 99视频偷窥在线精品国自产拍 | 99色资源 | 亚洲成人av在线播放 | 91欧美日韩国产 | 久久在线免费观看 | 久久黄色片子 | 成年人三级网站 | 色综合天天综合网国产成人网 | 久久久蜜桃| www.色午夜,com| 黄色片免费看 | 91久久电影| 午夜视频免费播放 | 久久亚洲福利 | 精品女同一区二区三区在线观看 | .国产精品成人自产拍在线观看6 | av成人动漫 | 激情欧美丁香 | 亚洲 欧洲av| 色综合久久88色综合天天 | 久久成人在线视频 | 欧美一级淫片videoshd | 蜜臀av网站| 欧美极品xxxx | 一级片黄色片网站 | av高清在线 | 亚洲国产理论片 | 最新国产福利 | 国产精品久久久久亚洲影视 | 亚洲免费成人av电影 | 久久在线观看视频 | 狠狠狠狠狠狠干 | 五月天六月色 | 午夜av片 | 成人小视频在线观看免费 | 国产伦理久久精品久久久久_ | 超碰国产在线 | 久久久久久久久艹 | 国产欧美中文字幕 | 91麻豆免费视频 | 天堂网在线视频 | 四虎影视精品永久在线观看 | 韩国视频一区二区三区 | 日日夜夜精品免费视频 | 国产福利一区二区三区在线观看 | 中文字幕在线看人 | 亚洲 综合 国产 精品 | 国产二区av | 中文字幕日本在线 | 91超碰免费在线 | 综合久久一本 | 91亚洲精品久久久蜜桃借种 | 精品久久综合 | 玖玖在线免费视频 | 久久久精品 | 久久99精品国产麻豆宅宅 | 国产精品女 | 日韩精品视频久久 | 欧美片一区二区三区 | 国内精品久久久久久久影视麻豆 | avove黑丝 | 日本精品视频在线播放 | 正在播放 久久 | 国产精品人人做人人爽人人添 | 色综合久久天天 | 欧美一级免费黄色片 | 最新的av网站 | 日韩簧片在线观看 | 免费看三级网站 | 日韩在线视频观看免费 | 最新色站 | 99精品乱码国产在线观看 | 国产人成在线观看 | av中文电影| 久久久久婷 | 国产精品aⅴ | 国内精品久久久久久久97牛牛 | 精品99在线视频 | 免费观看91视频 | 天堂av网站 | 国产日韩在线视频 | 中文字幕一区二区三区四区视频 | 黄色国产精品 | 四虎亚洲精品 | 久福利 | 正在播放国产91 | 久香蕉 | 97在线成人 | 久久亚洲二区 | 国产福利一区二区三区视频 | 国产精品热视频 | 精品国产欧美 | 不卡av在线播放 | 色视频网页 | 精品视频亚洲 | 999抗病毒口服液 | 久久免费视频4 | 欧美成年网站 | 奇米网在线观看 | 欧美激情va永久在线播放 | 碰超人人 | 天天爱天天色 | 久久国产二区 | 国产一级在线视频 | 国产成人免费高清 | 黄色成人在线 | 中文字幕有码在线观看 | 成人欧美一区二区三区在线观看 | 亚洲色影爱久久精品 | 免费看三级网站 | av免费在线网站 | 亚洲天堂va| 成人97视频一区二区 | 四虎在线视频免费观看 | 日韩午夜剧场 | 91九色成人蝌蚪首页 | 亚洲黄在线观看 | 婷婷中文在线 | 成人毛片a | 国产99久久久精品视频 | 国产麻豆剧传媒免费观看 | 欧美片一区二区三区 | av成人在线网站 | 美女搞黄国产视频网站 | 亚洲国产成人精品久久 | 日韩精品一区二区三区电影 | 中文字幕在| 国产精品精品国产婷婷这里av | 久久综合色影院 | 在线看片成人 | 国产午夜三级一区二区三桃花影视 | 久久免费的精品国产v∧ | 日本激情视频中文字幕 | 午夜18视频在线观看 | 国产视频精品免费 | 色99中文字幕 | 9ⅰ精品久久久久久久久中文字幕 | 国产在线一区观看 | 午夜视频免费在线观看 | 91亚洲永久精品 | 久久不射电影网 | 久久这里只有精品9 | 波多野结衣一区二区三区中文字幕 | a√天堂资源 | 国产精品video爽爽爽爽 | 国产网站色 | 韩日精品在线观看 | 亚洲成人一二三 | 午夜精品电影一区二区在线 | 超碰97免费在线 | 国产高清无线码2021 | 黄色片软件网站 | 免费看的黄色 | 国产偷在线 | 精品在线视频一区二区三区 | 国产精品精| 在线91视频| 深夜免费网站 | 在线精品在线 | 成人毛片一区 | 天天色天天色天天色 | 超碰在线人人爱 | 国产欧美精品在线观看 | 在线直播av| 最近中文字幕mv免费高清在线 | 免费观看一级视频 | 五月婷婷六月丁香在线观看 | 在线 成人 | 欧美日韩在线视频观看 | 91精品少妇偷拍99 | 中文字幕免费一区 | 日韩免费在线网站 | 国产日韩欧美中文 | 综合久久婷婷 | 人人插人人澡 | av在线之家电影网站 | 欧美亚洲成人免费 | 最新中文字幕视频 | 在线观看av大片 | 黄色片免费看 | 在线影院 国内精品 | 亚欧日韩av| 亚洲精品午夜一区人人爽 | 中文字幕乱码一区二区 | 国产精品黄色影片导航在线观看 | 欧美日韩精品在线 | 99精品免费网 | 日韩中文字幕免费 | 在线看黄色的网站 | 欧美日韩一区二区视频在线观看 | 黄网站app在线观看免费视频 | 久久免费国产视频 | 91精品国产福利 | 精品国偷自产国产一区 | 99久久精品免费看 | 国产在线高清视频 | 日韩中文字幕第一页 | 国产精品久久一 | 欧美性免费 | 日韩免费观看一区二区 | 日韩免费网址 | 91精品久久久久久综合乱菊 | 精品96久久久久久中文字幕无 | av在线播放网址 | 一级a性色生活片久久毛片波多野 | 超碰电影在线观看 | 激情视频免费在线 | 国产午夜精品视频 | 98超碰在线 | 日韩欧美在线观看 | 国产精品岛国久久久久久久久红粉 | 五月天最新网址 | 98涩涩国产露脸精品国产网 | 国产精品99爱 | 久久久精品午夜 | av免费看在线 | 国产色视频网站 | 亚洲高清av| 五月婷婷导航 | 毛片精品免费在线观看 | 婷婷丁香导航 | 91中文字幕在线 | 国产精品夜夜夜一区二区三区尤 | 久久久久成人免费 | 日日碰狠狠躁久久躁综合网 | 亚洲最大色 | 午夜.dj高清免费观看视频 | 亚洲人在线 | 亚洲激情在线观看 | 久久99精品国产麻豆宅宅 | 黄色字幕网 | 青青河边草观看完整版高清 | 久久午夜国产 | 99精品视频在线看 | 9999国产精品 | 粉嫩一区二区三区粉嫩91 | 免费日韩电影 | 国产成人99av超碰超爽 | av一本久道久久波多野结衣 | 免费看十八岁美女 | 日韩午夜电影 | 91看片麻豆| 九色在线视频 | 日韩 精品 一区 国产 麻豆 | 亚色视频在线观看 | 国产精品去看片 | 亚洲国产影院 | 五月婷婷六月丁香激情 | 一区二区三区在线不卡 | 中文字幕五区 | 欧美一区二区三区在线看 | 久草久草在线观看 | 成人毛片网 | a视频在线 | 国语对白少妇爽91 | 久久夜色精品国产欧美一区麻豆 | 亚洲视频在线观看 | 国产精选在线 | 91大神dom调教在线观看 | 五月花丁香婷婷 | 成人欧美一区二区三区在线观看 | 日韩国产精品毛片 | 高清久久久 | 在线播放 日韩专区 | 婷婷久草 | 在线免费视 | 日日爽天天 | 国产一区二区在线免费播放 | 成人黄色免费观看 | 中文在线免费视频 | 亚洲视频播放 | 丁香六月婷婷开心婷婷网 | 婷婷新五月 | 色婷婷av国产精品 | 麻豆影视在线播放 | 国产手机精品视频 | 综合久久婷婷 | 中文字幕资源在线 | www.国产在线视频 | 免费中文字幕在线观看 | 国产a级片免费观看 | 久久综合狠狠综合久久激情 | 九九久久精品 | 中文乱码视频在线观看 | 成人久久久电影 | 色就干| 天干啦夜天干天干在线线 | 国产精品精品国产色婷婷 | 人人舔人人爱 | 日本丶国产丶欧美色综合 | 精品久久久网 | 国产精品久久一卡二卡 | 久久精品福利视频 | 99精品国产在热久久下载 | www看片网站 | 国产成人黄色 | 国产免费中文字幕 | 日韩美女久久 | 久久久久久久久久久久久国产精品 | 久久日本视频 | 中文字幕久久精品 | 日本女人在线观看 | 国产成人精品999 | 欧美在线久久 | 国产一区二区久久精品 | 天天综合天天综合 | 亚洲天堂精品视频 | 国产欧美中文字幕 | 日韩视频一区二区在线 | 欧美激情在线看 | 亚洲精品午夜一区人人爽 | 亚洲 欧洲 国产 精品 | 日韩免费观看一区二区 | 成年人在线观看免费视频 | 特级毛片在线 | 精品国产一区二区三区免费 | 欧洲精品在线视频 | 午夜国产在线 | 欧美精品三级 | 久久国产精品小视频 | 久久久精品99 | 亚洲精选在线 | 波多野结衣在线播放一区 | 欧美大片在线看免费观看 | 久久久久成人精品亚洲国产 | www.黄色在线 | 亚洲精品久久久蜜桃 | 久久久久久久久久久黄色 | 在线免费观看av网站 | 亚洲精品在线观看的 | 色香蕉在线视频 | 免费在线观看av不卡 | 在线看毛片网站 | 亚洲精区二区三区四区麻豆 | 国产精品久久久久久五月尺 | 日韩精品视频免费在线观看 | 在线天堂日本 | 日韩一二三区不卡 | 91精品免费看 | 天天天射| 久久精品一区二区三区视频 | 亚欧洲精品视频在线观看 | 中文字幕免费在线看 | 久久99热精品这里久久精品 | 日韩一区二区三区视频在线 | 国产精品一区欧美 | 69国产精品视频 | 天天射夜夜爽 | 国产第一二区 | 久久免费视频这里只有精品 | 天天色天天上天天操 | www久| 97色在线观看 | 亚洲理论片在线观看 | 日韩精品久久中文字幕 | 91网站免费观看 | av大全在线免费观看 | 亚洲国产成人精品在线 | 国产手机视频精品 | 欧美精品亚洲二区 | 香蕉影视在线观看 | 91精品国产高清自在线观看 | 国产精品96久久久久久吹潮 | 成人av电影在线 | 97精品国产 | 操操操夜夜操 | 久久久在线| 五月天九九 | 久久美女免费视频 | 狠狠色狠狠色合久久伊人 | 国产精品中文字幕在线播放 | 精品视频中文字幕 | 热久久影视 | 色搞搞| 久久91久久久久麻豆精品 | av成人亚洲 | 黄色影院在线观看 | 日韩精品aaa | 色婷婷国产精品一区在线观看 | 日韩在线观看视频在线 | 欧美性色黄大片在线观看 | 国产精品视频app | 九九九九九九精品任你躁 | 中文字幕色综合网 | 亚洲精品1区2区3区 超碰成人网 | 波多野结衣电影久久 | 国产亚洲激情视频在线 | 免费看久久久 | 日本深夜福利视频 | 国产精品高清在线 | 国产精品免费一区二区 | 黄免费网站 | 99热国产在线观看 | 中文字幕成人一区 | 久久国产精品免费视频 | 日黄网站| 精品福利在线观看 | 国产精品毛片一区视频 | 99久久影视| 人人澡人人模 | 久久艹国产视频 | 国产一级片视频 | 一区二区在线电影 | 在线国产能看的 | 国产一区二区播放 | 91探花视频 | 中文字幕一区二区三区乱码不卡 | 亚洲最大在线视频 | 国产精品a久久 | 久久精品国产一区 | 日韩高清一二三区 | 国产在线999 | v片在线看 | 免费看的黄色 | 国产精品久久久久av免费 | 免费在线一区二区 | 菠萝菠萝在线精品视频 | 波多野结衣一区二区 | 日日干天夜夜 | 国产精品一区二区三区四 | 国内外成人免费在线视频 | 日日精品 | 青青视频一区 | 国产精品美女www爽爽爽视频 | 中文字幕精品一区二区精品 | 西西444www高清大胆 | 欧美精品乱码99久久影院 | 国产一区二区三区网站 | 午夜丁香网 | 久久96国产精品久久99软件 | 色狠狠婷婷 | 精品免费观看 | 国产99免费视频 | 国产精品久久久久久久久久免费看 | 狠狠的操你 | 久久人人爽人人爽人人片av软件 | 在线 高清 中文字幕 | 五月天堂色 | www.人人草 | 精品亚洲国产视频 | 久久,天天综合 | 一本一本久久a久久精品综合小说 | 国产成人精品av在线 | 中文字幕在线有码 | 午夜狠狠操 | 五月婷婷六月丁香在线观看 | 精品久久国产精品 | www色片| 精品视频免费观看 | 国产一二三四在线观看视频 | 91福利影院在线观看 | 日日夜夜精品免费 | 婷婷五综合 | 国内精品久久久久久久久久 | 精品在线视频播放 | 亚洲 欧美 综合 在线 精品 | 国产视频久久久 | 国产中文字幕精品 | 久久久久久久看片 | 一区二区三区免费播放 | 91尤物国产尤物福利在线播放 | 日韩视频中文字幕在线观看 | 久久久国产精品久久久 | 婷婷色五 | 91免费看黄 | 欧美性极品xxxx做受 | 免费av观看网站 | 麻豆91在线看| 91人人澡人人爽人人精品 | 草草草影院 | 亚洲成人网在线 | 欧美在线aaa | 在线看av的网址 | 国产精品久久久久婷婷 | 亚洲热久久| 国产午夜精品一区二区三区在线观看 | 97成人精品区在线播放 | 狠狠久久婷婷 | 国产视频1 | 三级黄色免费片 | 91麻豆看国产在线紧急地址 | 在线国产能看的 | 色婷婷久久久综合中文字幕 | 亚洲激情视频在线观看 | 日韩精品久久久久久久电影99爱 | 日韩欧美视频一区二区 | 亚洲国产精品99久久久久久久久 | 国产成人一区二区三区 | 国产精品久久久久久久电影 | 在线播放视频一区 | 色小说在线 | www.色五月 | 激情综合色图 | 亚洲男男gaygay无套同网址 | 日韩在线视频网站 | av高清不卡 | 人人爽人人爽人人片 | 欧美激情亚洲综合 | 在线精品观看国产 | 玖玖视频| 日韩免费高清在线 | 天天色视频 | 六月丁香婷婷网 | 狠狠狠色丁香婷婷综合久久五月 | 成人a视频片观看免费 | 成人一区影院 | 最新av网址大全 | 精精国产xxxx视频在线播放 | 日韩一级片网址 | 91精品国产91p65 | 久久国内精品视频 | 国产精品免费久久久久久久久久中文 | 五月婷婷综 | 人人超碰人人 | 国产精品成人久久久久久久 | 一级成人免费视频 | 日韩欧美视频免费在线观看 | 97碰碰精品嫩模在线播放 | 欧美成人xxxx | 四虎视频 | 操久久网 | 欧洲激情在线 | 日日夜夜噜噜噜 | wwxxxx日本| 久久99九九99精品 | 亚洲影院一区 | 日韩色在线观看 | 日本性生活免费看 | 91精品在线免费观看 | 久久情爱 | 91超碰免费在线 | 亚洲综合色播 | 最新色站 | 国产亚洲精品久久久网站好莱 | 成年人视频免费在线播放 |