mybatis學習筆記(一):第一個 Mybatis 例子,Mybatis 的基本用法


/**
 * ORM:對象關係映射;是一種對象數據到關係數據映射的 規則(框架/工具);
 *  優點:
 *      1、完全面向對象的編程思想,無 SQL 出現;
 *      2、減少代碼編寫,提高工作效率;
 *      3、提高訪問數據庫的性能,降低訪問數據庫的頻率;
 *      4、具有獨立性,發生變化時,不會影響上層的實現;
 *
 * 回顧 JDBC 開發:
 *  優點:
 *      簡單易學,上手快,非常靈活構建 SQL,效率高;
 *  缺點:
 *      代碼繁瑣,難以寫出高質量的代碼(例如,資源的釋放,SQL 注入安全性等);
 *      開發者既要寫業務邏輯,又要寫對象的創建和銷燬,必須管底層具體數據庫的語法;
 *  適合於超大批量數據的操作,速度快;
 *  開發步驟:
 *      1、加載數據庫驅動;
 *      2、通過 DriverManager 獲取數據庫的連接;
 *      3、通過 Connection 獲取 Statement、PreparedStatement 對象;
 *      4、將 SQL 語句綁定到 Statement、PreparedStatement 中去,準備向數據庫發送 SQL 語句;
 *      5、執行完 SQL 語句後,返回對象的結果;
 *      6、如果是查詢的話,迭代結果集(ResultSet)進行處理;
 *      7、依次關閉連接對象:ResultSet、Statement、Connection;
 *      如果上述操作需要做 非查詢的話,還需要事務支持:
 *          conn.setAutoCommit(false);      // 手動開啓事務
 *          conn.commit()/conn.rollback();  // 提交/回滾事務
 *
 * 回顧 Hibernate 開發:
 *  優點:
 *      不用寫 SQL,完全以面向對象的方式設計和訪問,不用管底層具體數據庫的語法;
 *  缺點:
 *      處理複雜業務時,靈活度差,複雜的 HQL 難寫難理解,例如多表查詢的 HQL 語句;
 *  適合於中小批量數據的操作,速度慢;
 *  開發步驟:
 *      1、創建 Configuration,加載 src/hibernate.cfg.xml 配置文件,該配置文件又會去加載 user.hbm.xml 映射文件;
 *      2、通過 Configuration 創建 SessionFactory;
 *      3、通過 SessionFactory 創建 Session;
 *      4、通過 Session 創建 Transaction;
 *      5、如果做 增、刪、改 操作的話,一定要開啓事務,如果做 查詢 操作,事務可選;
 *      6、操作 Session 的常用 API,例如 save()、update()、saveOrUpdate()、delete()、get();
 *      7、事務提交,出錯後事務回滾;
 *      8、關閉 Session;
 *
 * 什麼是 Mybatis,有什麼特點?
 *  1、基於上述 JDBC 和 Hibernate 的特點,Mybatis 處於他們中間,速度和難度 都是中等;
 *  2、Mybatis 原本是 apache 的一個開源項目 iBatis,2010 年這個項目由 apache software foundation
 *      遷移到了 google code,並且改名爲 Mybatis,2013 年 11 月遷移到 Github;
 *  3、iBatis 一詞來源於 internet 和 abatis 的組合,是一個基於 java 的持久層框架。iBatis 提供的持久層
 *      框架包括 SQL Maps 和 Data Access Objects(DAO);
 *  4、jdbc/dbUtils/springDao,Hibernate/springORM,Mybatis 同屬於 ORM 解決方案之一;
 */

 項目結構:

開發步驟:

1、導入 mybatis 、mysql 和 oracle 依賴的 jar 包:

2、創建一個 測試表:

--mysql語法
create table students(
   id  int(5) primary key,
   name varchar(10),
   sal double(8,2)
);
--oracle語法
create table students(
   id  number(5) primary key,
   name varchar2(10),
   sal number(8,2)
);

3、創建一個和表對應的 實體類 Student.java:

package com.mybatis.demo;

/**
 * 實體類
 */
public class Student {
    private int id;
    private String name;
    private Double sal;

    public Student() {
    }

    public Student(int id, String name, Double sal) {
        this.id = id;
        this.name = name;
        this.sal = sal;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

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

4、在 Student.java 同級目錄下創建一個映射配置文件 StudentMapper.xml:

<?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 是名稱空間,理論上可以隨便寫,但必須保證唯一 -->
<mapper namespace="studentNamespace">

    <!--
        resultMap 標籤:映射實體與表的關係;
            id:爲實體與表的映射 取一個任意的唯一編號;
            type:實體的全路徑名;
        注意:
            映射實體類與表的關係時,此處並沒有指定表的名字,
            是因爲下面的 insert 語句中指出了要操作的表的名字;
    -->
    <resultMap id="studentMap" type="com.mybatis.demo.Student">
        <!--
            id 標籤:映射主鍵屬性;
                property:表示實體類中的屬性;
                column:表示表中的主鍵;
        -->
        <id property="id" column="id"/>

        <!--
            result 標籤:映射非主鍵屬性;
                property:表示實體類中的屬性;
                column:表示表中的字段;
        -->
        <result property="name" column="name"/>
        <result property="sal" column="sal"/>
    </resultMap>

    <!--
        insert 標籤:表示標籤中要寫的是插入 sql 語句;
            id:爲插入 sql 語句取一個任意唯一的編號;
        注意:
            "哈哈" 字符串用雙引號可以插入到 mysql 數據庫中,但是不能插入
            到 oracle 數據庫中,會報錯:"ORA-00984: 列在此處不允許";
            oracle 中 varchar2 類型的字段插入字符數據時只能用 單引號!
    -->
    <insert id="add1">
        insert into students(id, name, sal) values (1, '哈哈', 7000)
    </insert>

    <!--
        parameterType:表示 dao 中調用執行此 SQL 語句的方法傳入的參數類型;如果是類的話,必須使用全路徑名;
            如果 SQL 語句沒有接收參數,可以不寫 parameterType 屬性;
            如果在 mybatis.xml 主配置文件中設置了類型別名,比如設置了 com.mybatis.demo.Student 的別名爲 student,
            那麼可以直接寫成 parameterType="student";

        在 sql 語句中用佔位符取值 (#{id}, #{name}, #{sal}),實際是調用 Student 對象的 getter 方法取值;
        Student 對象是 dao 中調用此 SQL 語句時傳入的;
    -->
    <insert id="add2" parameterType="com.mybatis.demo.Student">
        insert into students(id, name, sal) values (#{id}, #{name}, #{sal})
    </insert>

</mapper>

5、在 src 目錄下創建一個數據庫配置文件 db.properties:

mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mybatis
mysql.username=root
mysql.password=root

oracle.driver=oracle.jdbc.driver.OracleDriver
oracle.url=jdbc:oracle:thin:@localhost:1521:orcl
oracle.username=scott
oracle.password=tiger

6、在 src 目錄下創建 mybatis 主配置文件 mybatis.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

    <!--
        加載 src 路徑下的 配置文件(db.properties);
        下面通過 ${ 鍵 } 獲取對應的值;
    -->
    <properties resource="db.properties"/>

    <!--
        設置類型別名:在映射文件中所有的 com.mybatis.demo.Student 類型都可以使用 student 代替
    -->
    <typeAliases>
        <typeAlias type="com.mybatis.demo.Student" alias="student"/>
    </typeAliases>

    <!-- 設置一個默認的連接環境信息 -->
    <environments default="mysql_developer">

        <!-- 連接環境信息:取一個任意唯一的名字 -->
        <environment id="mysql_developer">
            <!-- mybatis 使用 jdbc 事務管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis 使用連接池方式來獲取連接 -->
            <dataSource type="pooled">
                <!--
                    配置與數據庫交互的4個必要屬性 ;
                    ${mysql.driver}:表示獲取 db.properties 配置文件中 mysql.driver 的值;
                -->
                <property name="driver" value="${mysql.driver}"/>
                <property name="url" value="${mysql.url}"/>
                <property name="username" value="${mysql.username}"/>
                <property name="password" value="${mysql.password}"/>
            </dataSource>
        </environment>

        <!-- 連接環境信息:取一個任意唯一的名字 -->
        <environment id="oracle_developer">
            <!-- mybatis 使用 jdbc 事務管理方式 -->
            <transactionManager type="jdbc"/>
            <!-- mybatis 使用連接池方式來獲取連接 -->
            <dataSource type="pooled">
                <!-- 配置與數據庫交互的4個必要屬性 -->
                <property name="driver" value="${oracle.driver}"/>
                <property name="url" value="${oracle.url}"/>
                <property name="username" value="${oracle.username}"/>
                <property name="password" value="${oracle.password}"/>
            </dataSource>
        </environment>

    </environments>

    <!-- 加載映射文件 -->
    <mappers>
        <mapper resource="com/mybatis/demo/StudentMapper.xml"/>
    </mappers>

</configuration>

7、創建一個工具類 MybatisUtils.java:

package com.mybatis.demo;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;

/**
 * 工具類
 */
public class MybatisUtils {

    /**
     * 禁止外界通過 new 方法創建 工具類對象:構造方法私有化;
     */
    private MybatisUtils(){}

    /**
     * 創建一個線程對象,目的是將 SqlSession 和當前線程綁定到一起,線程結束,SqlSession 銷燬;
     */
    private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<>();
    /**
     * SqlSession 工廠
     */
    private static SqlSessionFactory sqlSessionFactory;

    /**
     * 類加載的時候 自動加載 src/mybatis.xml 配置文件
     */
    static {
        try {
            // 加載配置文件
            Reader reader = Resources.getResourceAsReader("mybatis.xml");
            // 根據配置文件構造 SqlSession 工廠
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 獲取 SqlSession
     */
    public static SqlSession getSession() {
        // 從當前線程中獲取 SqlSession
        SqlSession sqlSession = threadLocal.get();
        // 如果線程中沒有 SqlSession 的話
        if (sqlSession == null) {
            // 找 SessionFactory 創建一個 SqlSession
            sqlSession = sqlSessionFactory.openSession();
            // 將當前線程與 SqlSession 綁定到一起
            threadLocal.set(sqlSession);
        }
        // 返回 SqlSession 對象
        return sqlSession;
    }

    /**
     * 關閉 SqlSession,並與當前線程分離
     */
    public static void closeSqlSession() {
        // 從當前線程中獲取 SqlSession
        SqlSession sqlSession = getSession();
        // 如果有的話就關閉
        if (sqlSession != null) {
            // 關閉
            sqlSession.close();
            // 分離當前線程與 SqlSession,目的是讓 GC 儘早回收
            threadLocal.remove();
        }
    }

    /**
     * 測試是否連接成功
     */
    public static void main(String[] args){
        Connection connection = MybatisUtils.getSession().getConnection();
        System.out.println(connection);
    }
}

8、創建一個 StudentDao.java 類進行測試:

package com.mybatis.demo;

import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

/**
 * 持久層
 */
public class StudentDao {

    /**
     * 增加學生:不帶參數
     */
    public void add1() throws Exception{
        SqlSession sqlSession = null;
        try {
            // 獲取 SqlSession 對象
            sqlSession = MybatisUtils.getSession();
            // 開始事務(默認開始)

            /**
             * 執行 insert 操作;
             * insert 的 sql 語句是從 StudentMapper.xml 映射文件中讀取的;
             * 參數爲 名稱空間.insert標籤的id;
             * 即 執行 insert 操作的 sql 語句是從 id 爲 add1 的 <insert/> 標籤中讀取的;
             */
            int num = sqlSession.insert("studentNamespace.add1");
            System.out.println("本次操作影響了 " + num + "行");

            // 提交事務(手動提交)
            sqlSession.commit();
        }catch (Exception e){
            e.printStackTrace();
            // 回滾事務
            sqlSession.rollback();
            throw e;
        }finally {
            // 關閉
            MybatisUtils.closeSqlSession();
        }
    }

    /**
     * 增加學生:帶參數
     */
    public void add2(Student student) throws Exception{
        SqlSession sqlSession = null;
        try{
            sqlSession = MybatisUtils.getSession();

            /**
             * 執行 insert 操作;
             * sql 語句是從 id 爲 add2 的 <insert/> 標籤中讀取的;
             * 參數2 student 是 實體類對象;
             */
            int num = sqlSession.insert("studentNamespace.add2", student);
            System.out.println("本次操作影響了 " + num + "行");

            sqlSession.commit();    // 提交事務
        }catch (Exception e){
            e.printStackTrace();
            sqlSession.rollback();  // 回滾事務
        }finally {
            MybatisUtils.closeSqlSession();
        }
    }

    /**
     * 測試
     */
    public static void main(String[] args) throws Exception{
        StudentDao dao = new StudentDao();
        dao.add1();
        dao.add2(new Student(2, "呵呵", 8000D));
    }
}

Mybatis 工作流程:

1)通過 Reader 對象讀取 src 目錄下的 mybatis.xml 配置文件(該文本的位置和名字可任意);

2)通過 SqlSessionFactoryBuilder 對象創建 SqlSessionFactory 對象;

3)從當前線程中獲取 SqlSession 對象;

4)事務開始,在 mybatis 中默認;

5)通過 SqlSession 對象讀取 StudentMapper.xml 映射文件中的操作編號,從而讀取 sql 語句;

6)事務提交,必寫;

7)關閉 SqlSession 對象,並且分開當前線程與 SqlSession 對象,讓 GC 儘早回收;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章