1. 程式人生 > 其它 >顯式等待與隱式等待

顯式等待與隱式等待

mybatis

1、簡介

1.1、什麼是 MyBatis?

  1. MyBatis 是一款優秀的持久層框架

  2. 它支援自定義 SQL、儲存過程以及高階對映。

  3. MyBatis 免除了幾乎所有的 JDBC 程式碼以及設定引數和獲取結果集的工作。

  4. MyBatis 可以通過簡單的 XML 或註解來配置和對映原始型別、介面和 Java POJO(Plain Old Java Objects,普通老式 Java 物件)為資料庫中的記錄。

  5. MyBatis本是apache的一個開源專案iBatis,2010年這個專案由apache software foundation遷移到了google code,並且改名為MyBatis。

  6. 2013年11月遷移到Github

    如何獲得mybatis?

1.2、持久化

資料持久化

  • 持久化就是將程式的資料在持久狀態和順時狀態轉化的過程

  • 記憶體:斷電即失

  • 資料庫(JDBC)、io檔案持久化

  • 生活:冷藏、罐頭

    為什麼需要持久化?

    • 有一些物件,不能丟掉

    • 記憶體太貴了

     

1.3、持久層

  • Dao層、Service層、controller層

    • 完成持久化的程式碼塊

    • 層界限十分明顯

     

1.4、為什麼需要MyBatis

  • 幫助程式設計師將資料存入資料庫

  • 方便

  • 傳統的JDBC程式碼太複雜了。簡化。框架。自動化。

  • 不用MyBatis也可以,更容易上手。技術沒有高低之分。

  • 優點

    • 簡單易學:本身就很小且簡單。沒有任何第三方依賴,最簡單安裝只要兩個jar檔案+配置幾個sql對映檔案。易於學習,易於使用。通過文件和原始碼,可以比較完全的掌握它的設計思路和實現。

    • 靈活:mybatis不會對應用程式或者資料庫的現有設計強加任何影響。 sql寫在xml裡,便於統一管理和優化。通過sql語句可以滿足操作資料庫的所有需求。

    • 解除sql與程式程式碼的耦合:通過提供DAO層,將業務邏輯和資料訪問邏輯分離,使系統的設計更清晰,更易維護,更易單元測試。sql和程式碼的分離,提高了可維護性。

    • 提供對映標籤,支援物件與資料庫的orm欄位關係對映。

    • 提供物件關係對映標籤,支援物件關係組建維護。

    • 提供xml標籤,支援編寫動態sql。

最重要得到一點:使用的人多!

2、第一個Mybais程式

思路:搭建環境->匯入mybatis-->編寫程式碼-->測試

2.1、搭建環境

搭建資料庫

create database mybatis;
use mybatis;
create table user(
   id int not null primary key auto_increment,
   name varchar(30) default null,
   pwd varchar(30) default null
);
insert into user values (null,"zhangsan","123456");
insert into user values (null,"lisi","123456");
insert into user values (null,"wangwu","123456");
insert into user values (null,"yueyunpeng","123456");

新建專案

  1. 新建一個普通的maven專案

  2. 刪除src目錄

  3. 匯入Maven依賴

    <!--匯入依賴-->
   <dependencies>
   <!--mysql依賴-->
       <dependency>
           <groupId>mysql</groupId>
           <artifactId>mysql-connector-java</artifactId>
           <version>5.1.47</version>
       </dependency>
       <!--mybatis-->
       <dependency>
           <groupId>org.mybatis</groupId>
           <artifactId>mybatis</artifactId>
           <version>3.5.2</version>
       </dependency>
       <!--junit-->

       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.12</version>
           <scope>test</scope>
       </dependency>

   </dependencies>

2.2、建立一個模組

編寫mybatis核心配置檔案

<configuration>

   <environments default="development">
       <environment id="development">
           <transactionManager type="JDBC"/><!--事務管理-->
           <dataSource type="POOLED">
               <property name="driver" value="com.mysql.jdbc.Driver"/>
               <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;userUnicode=true&amp;characterEncoding=UTF-8"/>
               <property name="username" value="root"/>
               <property name="password" value="root"/>
           </dataSource>
       </environment>
   </environments>
   <mappers>
       <mapper resource="org/mybatis/example/BlogMapper.xml"/>
   </mappers>
</configuration>

2、編寫mybatis工具類

public class MybatisUtils {
  public static SqlSessionFactory sqlSessionFactory = null;

  static {
      try {
          //使用mybatis第一步 獲取sqlSessionFactory物件
          String resource = "mybatis-config.xml";
          InputStream inputStream = Resources.getResourceAsStream(resource);
          sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
      } catch (IOException e) {
          e.printStackTrace();
      }
  }
  //既然有了 SqlSessionFactory,
  // 顧名思義,我們可以從中獲得 SqlSession 的例項。
  // SqlSession 提供了在資料庫執行 SQL 命令所需的所有方法。
  // 你可以通過 SqlSession 例項來直接執行已對映的 SQL 語句。
  public static SqlSession getSqlSeesion() {
      return sqlSessionFactory.openSession();
  }
}

2.3、編寫程式碼

  • 實體類

    package com.qiang.pojo;

    public class User {
       private Integer id;
       private String name;
       private  String pwd;

       public User() {
      }

       public User(Integer id, String name, String pwd) {
           this.id = id;
           this.name = name;
           this.pwd = pwd;
      }

       public Integer getId() {
           return id;
      }

       public void setId(Integer id) {
           this.id = id;
      }

       public String getName() {
           return name;
      }

       public void setName(String name) {
           this.name = name;
      }

       public String getPwd() {
           return pwd;
      }

       public void setPwd(String pwd) {
           this.pwd = pwd;
      }

       @Override
       public String toString() {
           return "User{" +
                   "id=" + id +
                   ", name='" + name + '\'' +
                   ", pwd='" + pwd + '\'' +
                   '}';
      }
    }

     

  • Dao介面

    package com.qiang.dao;

    import com.qiang.pojo.User;

    import java.util.List;

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

     

  • 介面實現類-由原來的的UserDao轉變一個Mapper配置檔案

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
           PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
           "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <!--namespace名稱空間=繫結一個對應的Dao/Mapper介面-->
    <mapper namespace="com.qiang.dao.UserDao">

       <select id="getUserList" parameterType="com.qiang.pojo.User">
          select * from mybatis.user
       </select>
    </mapper>

    2.4、測試

    可能會遇見的問題:

    1. 配置檔案沒有註冊

    2. 繫結介面錯誤

    3. 方法名不對

    4. 返回型別不對

    5. Maven匯出資源問題

public class UserDaoTest {
   @Test
   public void test(){
       SqlSession sqlSeesion =null;
       try {
           //1、獲取SqlSession物件
           sqlSeesion = MybatisUtils.getSqlSeesion();
           //2、執行sql
           //3、方式一:getMapper
           UserDao mapper = sqlSeesion.getMapper(UserDao.class);
           List<User> userList = mapper.getUserList();
           //方式二:
           // List<User> userList = sqlSeesion.selectList("com.qiang.dao.UserDao.getList");

           for (User user : userList) {
               System.out.println(user);
          }
      } finally {
           sqlSeesion.close();
      }

  }
}

 

3、CRUD

1|、namespace

namespace中的包名要和介面的包名一致!

2、select

選擇,查詢語句

  • id:就是對應的namespace中的方法名;

  • resultType:SQL語句執行的返回值!

  • parameterType:引數型別

1、編寫介面

//獲取全部使用者
    List<User> getUserList();

2、編寫對應的mapper中的sql語句

 <select id="getUserList" resultType="com.qiang.pojo.User">
        select * from mybatis.user
    </select>

3、測試

    @Test
    public void test() {
        SqlSession sqlSeesion = null;
        try {
            //1、獲取SqlSession物件
            sqlSeesion = MybatisUtils.getSqlSeesion();
            //2、執行sql
            //3、方式一:getMapper
            UserMapper mapper = sqlSeesion.getMapper(UserMapper.class);
            List<User> userList = mapper.getUserList();
            // User list = mapper.gerUserById(1);
            //方式二:
            // List<User> userList = 			sqlSeesion.selectList("com.qiang.dao.UserDao.getList");
            //System.out.println(list);
            for (User user : userList) {
                System.out.println(user);
            }
        } finally {
            sqlSeesion.close();
        }

    }

 

3、delete

  1. 編寫介面

     //刪除使用者
        int deleteUser(int id);
    
  2. 編寫對應的mapper中的sql語句

    <delete id="deleteUser" parameterType="int">
            delete from mybatis.user where id = #{id}
        </delete>
    
  3. 測試

      @Test
        public void test4() {
            SqlSession sqlSeesion = null;
            try {
                sqlSeesion = MybatisUtils.getSqlSeesion();
                UserMapper mapper = sqlSeesion.getMapper(UserMapper.class);
                User user = new User(1, "wuqiang", "123456");
                int i = mapper.deleteUser(3);
                sqlSeesion.commit();
                System.out.println(i > 0 ? "刪除成功" : "刪除失敗");
            } finally {
                sqlSeesion.close();
            }
        }
    

     

4、update

  1. 編寫介面

      //修改使用者
       int updateUser(User user);
  2. 編寫對應的mapper中的sql語句

     <update id="updateUser" parameterType="com.qiang.pojo.User">
          update mybatis.user set name = #{name},pwd = #{pwd} where id = #{id}
       </update>
  3. 測試

         @Test
       public void test3() {
           SqlSession sqlSeesion = null;
           try {
               sqlSeesion = MybatisUtils.getSqlSeesion();
               UserMapper mapper = sqlSeesion.getMapper(UserMapper.class);
               User user = new User(1, "wuqiang", "123456");
               int i = mapper.updateUser(user);
               sqlSeesion.commit();
               System.out.println(i > 0 ? "修改成功" : "修改失敗");
          } finally {
               sqlSeesion.close();
          }
      }

     

5、insert

  1. 編寫介面

      //增加使用者
        int addUser(User user);
    
  2. 編寫對應的mapper中的sql語句

    	<insert id="addUser" parameterType="com.qiang.pojo.User" >
            insert into mybatis.user (id,name,pwd) values(#{id},#{name},#{pwd})
        </insert>
    
  3. 測試

      @Test
        public void test2() {
            SqlSession sqlSeesion = null;
            try {
                sqlSeesion = MybatisUtils.getSqlSeesion();
                UserMapper mapper = sqlSeesion.getMapper(UserMapper.class);
                User user = new User(null, "aaa", "11111");
                int i = mapper.addUser(user);
                sqlSeesion.commit();
                System.out.println(i > 0 ? "新增成功" : "新增失敗");
            } finally {
                sqlSeesion.close();
            }
        }
    

注意點

  • 增刪改需要提交事務

6、分析錯誤

  1. 標籤不要匹配錯

  2. resource繫結mapper,需要使用路徑

  3. 程式配置檔案必須符合規範!

     

7、萬能Map

假設我們得實體類,或者資料庫中的表,欄位或者引數過多,我們應當考慮使用map!

  1. 編寫介面

      //萬能map
        int addUser2(Map<String,Object> map);
    
  2. 編寫對應的mapper中的sql語句

    	  <insert id="addUser2" parameterType="map">
             insert into mybatis.user (id,name,pwd) values(#{userId},#{userNamae},#{userPassword})
        </insert>
    
  3. 測試

    @Test
        public void  test5(){
            SqlSession sqlSeesion = MybatisUtils.getSqlSeesion();
            UserMapper mapper = sqlSeesion.getMapper(UserMapper.class);
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("userId",null);
            map.put("userNamae","zhangsan");
            map.put("userPassword","123456");
            int i = mapper.addUser2(map);
    
            sqlSeesion.commit();
            sqlSeesion.close();
        }
    

    map傳遞引數,直接在SQL中取出key即可!【parameterType="map"】

    物件傳遞引數,直接在sql中取物件的屬性即可!【parameterType="Object"】

    只有一個基本型別引數的情況下,可以直接在SQL中取到。

    多個引數用map,或註解

    8、模糊查詢

    1. java程式碼執行的時候,傳遞萬用字元

      List<User> a = mapper.getUserLike("%a%");
      
    2. 在sql拼接中使用萬用字元

       select * from user where name  like "%"#{value}"%"
      

       

 

4、配置解析

1、核心配置檔案

  1. mybatis-config.xm

  2. Mybatis的配置檔案包含了會深深影響Mybatis行為的設定和屬性資訊。

    configuration(配置)
    properties(屬性)
    settings(設定)
    typeAliases(類型別名)
    typeHandlers( )
    objectFactory(物件工廠)
    plugins(外掛)
    environments(環境配置)
    environment(環境變數)
    transactionManager(事務管理器)
    dataSource(資料來源)
    databaseIdProvider(資料庫廠商標識)
    mappers(對映器)
    

    2、環境配置(environments)

    MyBatis 可以配置成適應多種環境,

    不過要記住:儘管可以配置多個環境,但每個 SqlSessionFactory 例項只能選擇一種環境。

    學會使用配置多套執行環境

    mybatis的預設事務管理器就是JDBC,連線池:POOLED

    3、屬性(properties)

    我們可以通過properties屬性來實現引用配置檔案

    這些屬性可以在外部進行配置,並可以進行動態替換。你既可以在典型的 Java 屬性檔案中配置這些屬性,也可以在 properties 元素的子元素中設定。例如: 這些屬性可以在外部進行配置,並可以進行動態替換。你既可以在典型的 Java 屬性檔案中配置這些屬性,也可以在 properties 元素的子元素中設定。例如:【druid.properties】

    編寫一個配置檔案

    druid.properties

    #key=value
    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;userUnicode=true&amp;characterEncoding=UTF-8
    #url=jdbc:mysql://localhost:3306/itheima
    username=root
    password=root
    #initial connection Size
    initialSize=10
    #min idle connecton size
    minIdle=5
    #max active connection size
    maxActive=20
    #max wait time (5000 mil seconds)   最大等待時間
    maxWait=5000
    

    在核心配置檔案中引入

     <properties resource="druid.properties"/>
      <environments default="development">
    
    • 可以直接引入外部檔案

    • 可以在其中增加一些屬性配置

    • 如果兩個檔案有同一個欄位,優先使用外部配置檔案的!

 

4、類型別名(typeAliases)

  • 類型別名可為 Java 型別設定一個縮寫名字。

  • 它僅用於 XML 配置,意在降低冗餘的全限定類名書寫

    <!--可以給實體類起別名-->
        <typeAliases>
            <typeAlias type="com.qiang.pojo.User" alias="User"/>
        </typeAliases>
    

    也可以指定一個包名,MyBatis 會在包名下面搜尋需要的 Java Bean 比如:

    掃描實體類的包,他預設別名就為這個類的類名,首字母小寫

 <typeAliases>
       <package name="com.qiang.pojo"/>
   </typeAliases>

在實體類比較少的情況下,建議使用第一種方式

如果實體類非常多,建議使用第二種。

第一種可以DIY,第二種則不行(相對來說,可以在實體類上加註解起)

優先順序:類型別名>註解別名>包別名

5、設定(settings)

這是 MyBatis 中極為重要的調整設定,它們會改變 MyBatis 的執行時行為

設定名 描述 有效值 預設值
cacheEnabled 全域性性地開啟或關閉所有對映器配置檔案中已配置的任何快取。 true | false true
lazyLoadingEnabled 延遲載入的全域性開關。當開啟時,所有關聯物件都會延遲載入。 特定關聯關係中可通過設定 fetchType 屬性來覆蓋該項的開關狀態。 true | false false
logImpl 指定 MyBatis 所用日誌的具體實現,未指定時將自動查詢。 SLF4J LOG4J(deprecated since 3.5.9)

6、其他配置

 

7、對映器(mappers)

MapperRegistry:註冊繫結我們得Mapper檔案

方式一:

<!--每一個Mapper.xml都需要在Mybatis核心配置檔案中註冊!-->
	<mappers>
        <mapper resource="com/qiang/dao/UserMapper.xml"/>
    </mappers>

方式二:使用class檔案註冊繫結

<!--每一個Mapper.xml都需要在Mybatis核心配置檔案中註冊!-->
	<mappers>
        <mapper class="com/qiang/dao/UserMapper"/>
    </mappers>

注意點:

  • 介面必須和他的Mapper檔案必須同名

  • 介面必須和他的Mapper檔案必須在同一個包下!

方式三:使用掃描包進行註冊繫結

<!--每一個Mapper.xml都需要在Mybatis核心配置檔案中註冊!-->
	<mappers>
        <package class="com/qiang/dao"/>
    </mappers>

注意點:

  • 介面必須和他的Mapper檔案必須同名

  • 介面必須和他的Mapper檔案必須在同一個包下!

8、生命週期

生命週期、類別是至關重要的,因為錯誤的使用會導致非常嚴重的併發問題

SqlSessionFactoryBuilder

  • 一旦建立了SqlSessionFactory就不需要它了

  • 區域性變數

SqlSessionFactory

  • 說白了就可以想象成:資料庫連線池

  • SqlSessionFactory 一旦被建立就應該在應用的執行期間一直存在 , 沒有任何理由丟棄它或重新建立另一個例項

  • 因此 SqlSessionFactory 的最佳作用域是應用作用域

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

SqlSession

  • 連線到連線池的一個請求!

  • SqlSession 的例項不是執行緒安全的,因此是不能被共享的,所以它的最佳的作用域是請求或方法作用域。

  • 用完之後需要趕緊關閉,否則資源被佔用!

這裡的每一個mapper程式碼,就代表一個具體的業務!

5、解決屬性名和欄位名不一致的問題

1、問題

資料庫中的欄位與實體對應pojo欄位不一樣

解決方式一:起別名

<select id="getUserList" resultType="user">
         select id,name,pwd as password from mybatis.user
 </select>

2、resultMap

結果集對映

id name pwd
id name  password
<!--結果集對映-->
    <resultMap id="UserMap" type="User">
<!-- column:資料庫對映欄位   property:實體類屬性  -->
        <result column="pwd" property="password"/>
    </resultMap>
  • resultMap元素是MyBatis中最強大的元素

  • ResultMap的設計思想是,對於簡單的語句根本不需要配置顯式

的結果集對映,而對於複雜一點的語句只需要描述他們的關係就行了

 

6、日誌

1、面象介面程式設計

- 大家之前都學過面向物件程式設計,也學習過介面,但在真正的開發中,很多時候我們會選擇面向介面程式設計 - 根本原因:解耦,可拓展,提高複用,分層開發中,上層不用管具體的實現,大家都遵守共同的標準,使得開發變得更容易,規範性更好 - 在一個面向物件的系統中,系統的各種功能是由許許多多的不同物件協作完成的。在這種情況下,各個物件內部是如何實現自己的,對系統設計人員來講就不那麼重要了; - 而各個物件之前的協作關係則成為系統設計的關鍵,小到不同類之間的通訊,大到各模組之間的互動,在系統設計之初都是要著重考慮的,這也是系統設計的主要工作內容,面向介面程式設計就是指按照這種思想來程式設計。關於介面的理解

- 介面從更深層次的理解,應是定義(規範,約束)與實現(名實分離)的分離。

- 介面的本身反映了系統設計人員對系統的抽象理解。

- 介面應有兩類:

- 第一類是對一個個體的抽象,它可對應為一個抽象體(abstract class); - 第二類是對一個個體某一方面的抽象,即形成一個抽象面(interface);

- 一個體有可能有多個抽象面,抽象體與抽象面是有區別的

 

三個面向區別

- 面向物件是指,我們考慮問題時,以物件為單位,考慮它的屬性及方法 - 面向過程是指,我們考慮問題時,以一個具體的流程(事務過程)為單位,考慮它的實現。 - 介面設計與非介面設計是針對複用技術而言的,與面向物件(過程)不是一個問題,更多的體現就是對系統整體的架構

6.1、日誌工廠

如果一個數據庫操作,出現了異常,我們需要拍錯。日誌就是最好的助手!

曾經:sout、debug

現在日誌工廠

  • SLF4J

  • LOG4J(deprecated since 3.5.9) 【掌握】

  • LOG4J2

  • JDK_LOGGING

  • COMMONS_LOGGING

  • STDOUT_LOGGING 【掌握】

  • NO_LOGGING

 

在Mybatis中具體使用使用哪一個日誌實現,在設定中設定

STDOUT_LOGGING 標準日誌輸出

    <settings>
<!--       標準的日誌工廠實現-->
       <setting name="logImpl" value="STDOUT_LOGGING"/>
   </settings>
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
Class not found: org.jboss.vfs.VFS
JBoss 6 VFS API is not available in this environment.
Class not found: org.jboss.vfs.VirtualFile
VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.
Using VFS adapter org.apache.ibatis.io.DefaultVFS
Find JAR URL: file:/F:/code/mybatis/mybatis-03/target/classes/com/qiang/pojo
Not a JAR: file:/F:/code/mybatis/mybatis-03/target/classes/com/qiang/pojo
Reader entry: User.class
Listing file:/F:/code/mybatis/mybatis-03/target/classes/com/qiang/pojo
Find JAR URL: file:/F:/code/mybatis/mybatis-03/target/classes/com/qiang/pojo/User.class
Not a JAR: file:/F:/code/mybatis/mybatis-03/target/classes/com/qiang/pojo/User.class
Reader entry: ����   1 <
Checking to see if class com.qiang.pojo.User matches criteria [is assignable to Object]
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.
PooledDataSource forcefully closed/removed all connections.