學Mybatis,入門看這一篇就夠你學的了!

折翼之舞°發表於2020-11-19

首先什麼是MyBatis?

MyBatis 本是apache的一個開源專案iBatis, 2010年這個專案由apache software foundation 遷移到了google code,並且改名為MyBatis。是一個基於Java的持久層框架

基本概念你總得給摸清楚

為什麼我們要用Mybatis?

無論是Mybatis、Hibernate都是ORM的一種實現框架,都是對JDBC的一種封裝!

在這裡插入圖片描述

本人在這裡整理了20多家公司的面試題,以及各種關於Spring、Spring boot、Spring MVC、MyBatis、MySQL、JVM等知識點,如果有需要的小夥伴可以加群1149778920 來自行領取 暗號:qf

在這裡插入圖片描述
那我們為啥還要學Mybatis呢???現在Mybatis在業內大行其道,那為啥他能那麼火呢??

Hibernate是一個比較老舊的框架,用過他的同學都知道,只要你會用,用起來十分舒服…啥sql程式碼都不用寫…但是呢,它也是有的缺點::處理複雜業務時,靈活度差, 複雜的HQL難寫難理解,例如多表查詢的HQL語句

而JDBC很容易理解,就那麼幾個固定的步驟,就是開發起來太麻煩了,因為什麼都要我們自己幹…

而SpringDAO其實就是JDBC的一層封裝,就類似於dbutils一樣,沒有特別出彩的地方…

我們可以認為,Mybatis就是jdbc和Hibernate之間的一個平衡點…畢竟現在業界都是用這個框架,我們也不能不學呀!

Mybatis快速入門

其實我們已經學過了Hibernate了的話,對於Mybatis入門其實就非常類似的。因此就很簡單就能掌握基本的開發了…

匯入Mybatis開發包

  • mybatis-3.1.1.jar
  • commons-logging-1.1.1.jar
  • log4j-1.2.16.jar
  • cglib-2.2.2.jar
  • asm-3.3.1.jar

匯入mysql/oracle開發包

  • mysql-connector-java-5.1.7-bin.jar
  • Oracle 11g 11.2.0.1.0 JDBC_ojdbc6.jar

準備測試工作

建立一張表

create table students(
  id  int(5) primary key,
  name varchar(10),
  sal double(8,2)
);

建立實體:

/**
 * Created by ozc on 2017/7/21.
 */

public class Student {
    private Integer id;
    private String name;
    private Double sal;

    public Student() {
    }

    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 Double getSal() {
        return sal;
    }

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

建立mybatis配置檔案

建立mybatis的配置檔案,配置資料庫的資訊…資料庫我們可以配置多個,但是預設的只能用一個…

<?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>
	
	
	<!-- 載入類路徑下的屬性檔案 -->
	<properties resource="db.properties"/>

	<!-- 設定一個預設的連線環境資訊 -->
	<environments default="mysql_developer">
		<!-- 連線環境資訊,取一個任意唯一的名字 -->
		<environment id="mysql_developer">
			<!-- mybatis使用jdbc事務管理方式 -->
			<transactionManager type="jdbc"/>
			<!-- mybatis使用連線池方式來獲取連線 -->
			<dataSource type="pooled">
				<!-- 配置與資料庫互動的4個必要屬性 -->
				<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>
	
	
</configuration>

編寫工具類測試是否獲取到連線

使用Mybatis的API來建立一個工具類,通過mybatis配置檔案與資料庫的資訊,得到Connection物件

package cn.itcast.javaee.mybatis.util;

import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

/**
 * 工具類
 * @author AdminTC
 */
public class MybatisUtil {
	private static ThreadLocal<SqlSession> threadLocal = new ThreadLocal<SqlSession>();
	private static SqlSessionFactory sqlSessionFactory;
	/**
	 * 載入位於src/mybatis.xml配置檔案
	 */
	static{
		try {
			Reader reader = Resources.getResourceAsReader("mybatis.xml");
			sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	/**
	 * 禁止外界通過new方法建立 
	 */
	private MybatisUtil(){}
	/**
	 * 獲取SqlSession
	 */
	public static SqlSession getSqlSession(){
		//從當前執行緒中獲取SqlSession物件
		SqlSession sqlSession = threadLocal.get();
		//如果SqlSession物件為空
		if(sqlSession == null){
			//在SqlSessionFactory非空的情況下,獲取SqlSession物件
			sqlSession = sqlSessionFactory.openSession();
			//將SqlSession物件與當前執行緒繫結在一起
			threadLocal.set(sqlSession);
		}
		//返回SqlSession物件
		return sqlSession;
	}
	/**
	 * 關閉SqlSession與當前執行緒分開
	 */
	public static void closeSqlSession(){
		//從當前執行緒中獲取SqlSession物件
		SqlSession sqlSession = threadLocal.get();
		//如果SqlSession物件非空
		if(sqlSession != null){
			//關閉SqlSession物件
			sqlSession.close();
			//分開當前執行緒與SqlSession物件的關係,目的是讓GC儘早回收
			threadLocal.remove();
		}
	}	
	/**
	 * 測試
	 */
	public static void main(String[] args) {
		Connection conn = MybatisUtil.getSqlSession().getConnection();
		System.out.println(conn!=null?"連線成功":"連線失敗");
	}
}

建立實體與對映關係檔案

配置實體與表的對映關係

<?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="cn.itcast.javaee.mybatis.app04.Student">	
	
	<!-- resultMap標籤:對映實體與表 
		 type屬性:表示實體全路徑名
		 id屬性:為實體與表的對映取一個任意的唯一的名字
	-->
	<resultMap type="student" id="studentMap">
		<!-- id標籤:對映主鍵屬性
			 result標籤:對映非主鍵屬性
		     property屬性:實體的屬性名
		     column屬性:表的欄位名	 
		-->							
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="sal" column="sal"/>
	</resultMap>

</mapper>

現在我們已經有了Mybatis的配置檔案和表與實體之前的對映檔案了,因此我們要將配置檔案和對映檔案關聯起來

<mappers>
		<mapper resource="StudentMapper.xml"/>
	</mappers>

在測試類上,我們是可以獲取得到連線的

在這裡插入圖片描述

編寫DAO

public class StudentDao {


    public void add(Student student) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        sqlSession.insert();
    }

    public static void main(String[] args) throws Exception {

        StudentDao studentDao = new StudentDao();

        Student student = new Student(1, "zhongfucheng", 10000D);
        studentDao.add(student);

    }
}

到現在為止,我們實體與表的對映檔案僅僅對映了實體屬性與表的欄位的關係…

我們在Hibernate中如果想要插入資料什麼的,只要呼叫save()方法就行了。Hibernate是自動化遮蔽掉了資料庫的差異,而我們Mybatis是需要自己手動編寫SQL程式碼的…

那麼SQL程式碼是寫在哪裡的呢???明顯地,我們作為一個框架,不可能在程式中寫SQL,我們是在實體與表的對映檔案中寫的!

Mybatis實體與表的對映檔案中提供了insert標籤【SQL程式碼片段】供我們使用

//在JDBC中我們通常使用?號作為佔位符,而在Mybatis中,我們是使用#{}作為佔位符
	//parameterType我們指定了傳入引數的型別
	//#{}實際上就是呼叫了Student屬性的get方法

	<insert id="add" parameterType="Student">

		INSERT INTO ZHONGFUCHENG.STUDENTS (ID, NAME, SAL) VALUES (#{id},#{name},#{sal});
	</insert>

在程式中呼叫對映檔案的SQL程式碼片段

public void add(Student student) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            sqlSession.insert("StudentID.add", student);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

值得注意的是:Mybatis中的事務是預設開啟的,因此我們在完成操作以後,需要我們手動去提交事務!

Mybatis工作流程

  • 通過Reader物件讀取Mybatis對映檔案
  • 通過SqlSessionFactoryBuilder物件建立SqlSessionFactory物件
  • 獲取當前執行緒的SQLSession
  • 事務預設開啟
  • 通過SQLSession讀取對映檔案中的操作編號,從而讀取SQL語句
  • 提交事務
  • 關閉資源

完成CRUD操作

我們在上面中已經簡單知道了Mybatis是怎麼使用的以及工作流程了,這次我們使用Mybatis來完成CRUD的操作,再次鞏固Mybatis的開發步驟以及一些細節

包與類之間的結構

在這裡插入圖片描述
配置檔案

<?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>
	<!-- 載入類路徑下的屬性檔案 -->
	<properties resource="db.properties"/>

	<!-- 設定一個預設的連線環境資訊 -->
	<environments default="mysql_developer">
		<!-- 連線環境資訊,取一個任意唯一的名字 -->
		<environment id="mysql_developer">
			<!-- mybatis使用jdbc事務管理方式 -->
			<transactionManager type="jdbc"/>
			<!-- mybatis使用連線池方式來獲取連線 -->
			<dataSource type="pooled">
				<!-- 配置與資料庫互動的4個必要屬性 -->
				<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="zhongfucheng/StudentMapper.xml"/>
	</mappers>
</configuration>

對映檔案

<!-- namespace屬性是名稱空間,必須唯一 -->
<mapper namespace="StudentID">
	
	<!-- resultMap標籤:對映實體與表 
		 type屬性:表示實體全路徑名
		 id屬性:為實體與表的對映取一個任意的唯一的名字
	-->
	<resultMap type="zhongfucheng.Student" id="studentMap">
		<!-- id標籤:對映主鍵屬性
			 result標籤:對映非主鍵屬性
		     property屬性:實體的屬性名
		     column屬性:表的欄位名
		-->
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="sal" column="sal"/>
	</resultMap>

	<insert id="add" parameterType="zhongfucheng.Student">
		INSERT INTO ZHONGFUCHENG.STUDENTS (ID, NAME, SAL) VALUES (#{id},#{name},#{sal});
	</insert>

</mapper>

插入資料

public class StudentDao {

    public void add(Student student) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            sqlSession.insert("StudentID.add", student);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        Student student = new Student(3, "zhong3", 10000D);
        studentDao.add(student);
    }
}

在這裡插入圖片描述

根據ID查詢資料

增加select標籤

<!--
		查詢根據id
		resultMap這個屬性代表是返回值型別,返回值的型別是Student,就是上面實體型別
	-->
	<select id="findById" parameterType="int" resultMap="studentMap">
		SELECT * FROM STUDENTS WHERE id = #{id};
	</select>

查詢出來的結果是一個Student物件,我們呼叫SelectOne方法

public Student findById(int id) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            return sqlSession.selectOne("StudentID.findById",id);
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        Student student = studentDao.findById(1);
        System.out.println(student.getName());

    }

在這裡插入圖片描述

查詢所有資料

<!--
		查詢所有資料
		返回值型別講道理是List<Student>的,但我們只要寫集合中的型別就行了
	-->
	<select id="findAll" resultMap="studentMap">
		SELECT * FROM STUDENTS;
	</select>

我們查詢出來的結果不單單隻有一個物件了,因此我們使用的是SelectList這個方法

public List<Student> findAll() throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            return sqlSession.selectList("StudentID.findAll");
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        List<Student> students = studentDao.findAll();
        System.out.println(students.size());

    }

根據id刪除

<!--根據id刪除-->
<delete id="delete" parameterType="int">
	DELETE FROM STUDENTS WHERE id=#{id};

</delete>

呼叫delete方法刪除

   public void delete(int id ) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            sqlSession.delete("StudentID.delete", id);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        studentDao.delete(1);

    }

在這裡插入圖片描述

修改

<!--更新-->
<update id="update" parameterType="zhongfucheng.Student">

	update students set name=#{name},sal=#{sal} where id=#{id};

</update>

查詢出對應的物件,對其進行修改

   public void update(Student student ) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            sqlSession.update("StudentID.update", student);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        Student student = studentDao.findById(2);
        student.setName("fucheng");
        student.setSal(2000D);
        studentDao.update(student);

    }

在這裡插入圖片描述

小細節

  注意:這個insert/update/delete標籤只是一個模板,在做操作時,其實是以SQL語句為核心的
       即在做增/刪/時,insert/update/delete標籤可通用,
       但做查詢時只能用select標籤
       我們提倡什麼操作就用什麼標籤

Mybatis分頁

分頁是一個非常實用的技術點,我們也來學習一下使用Mybatis是怎麼分頁的…

我們的分頁是需要多個引數的,並不是像我們之前的例子中只有一個引數。當需要接收多個引數的時候,我們使用Map集合來裝載!

public List<Student>  pagination(int start ,int end) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL


            /**
             * 由於我們的引數超過了兩個,而方法中只有一個Object引數收集
             * 因此我們使用Map集合來裝載我們的引數
             */
            Map<String, Object> map = new HashMap();
            map.put("start", start);
            map.put("end", end);
            return sqlSession.selectList("StudentID.pagination", map);
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        List<Student> students = studentDao.pagination(0, 3);
        for (Student student : students) {

            System.out.println(student.getId());

        }

    }

那麼在實體與表對映檔案中,我們接收的引數就是map集合

	<!--分頁查詢-->
<select id="pagination" parameterType="map" resultMap="studentMap">

		/*根據key自動找到對應Map集合的value*/
		select * from students limit #{start},#{end};

	</select>

動態SQL

何為動態SQL??回顧一下我們之前寫的SSH專案中,有多條件查詢的情況,如下圖

在這裡插入圖片描述

我們當時剛開始做的時候,是需要在Controller中判斷SQL是否已經有條件了,因為SQL語句需要拼接起來…這樣乾的話,就非常容易出錯的。

如下的程式碼,如果有多個條件的話,那麼拼接起來很容易出錯!

public String listUI() {

        //查詢語句
        String hql = "FROM Info i ";
        List<Object> objectList  = new ArrayList<>();

        //根據info是否為null來判斷是否是條件查詢。如果info為空,那麼是查詢所有。
        if (info != null) {
            if (StringUtils.isNotBlank(info.getTitle())) {
                hql += "where i.title like ?";
                objectList.add("%" + info.getTitle() + "%");
            }
        }
        infoList = infoServiceImpl.findObjects(hql,objectList);
        ActionContext.getContext().getContextMap().put("infoTypeMap", Info.INFO_TYPE_MAP);
        return "listUI";
    }

後來,我們覺得這樣不好,於是就專門寫了一個查詢助手類:

package zhongfucheng.core.utils;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by ozc on 2017/6/7.
 */
public class QueryHelper {

    private String fromClause = "";
    private String whereClause = "";
    private String orderbyClause = "";
    private List<Object> objectList;

    public static String ORDER_BY_ASC = "asc";
    public static String ORDER_BY_DESC = "desc";



    //FROM子句只出現一次
    /**
     * 構建FROM字句,並設定查詢哪張表
     * @param aClass 使用者想要操作的型別
     * @param alias  別名
     */
    public QueryHelper(Class aClass, String alias) {
        fromClause = "  FROM " + aClass.getSimpleName() + "  " + alias;
    }
    //WHERE字句可以新增多個條件,但WHERE關鍵字只出現一次
    /**
     * 構建WHERE字句
     * @param condition
     * @param objects
     * @return
     */
    public QueryHelper addCondition(String condition, Object... objects) {
        //如果已經有字元了,那麼就說明已經有WHERE關鍵字了
        if (whereClause.length() > 0) {
            whereClause += " AND  " + condition;
        } else {
            whereClause += " WHERE" + condition;
        }
        //在新增查詢條件的時候,?對應的查詢條件值
        if (objects == null) {
            objectList = new ArrayList<>();
        }

        for (Object object : objects) {
            objectList.add(object);
        }

        return this;
    }
    /**
     *
     * @param property 要排序的屬性
     * @param order 是升序還是降序
     * @return
     */
    public QueryHelper orderBy(String property, String order) {

        //如果已經有字元了,那麼就說明已經有ORDER關鍵字了
        if (orderbyClause.length() > 0) {
            orderbyClause += " ,  " + property +"   " + order;
        } else {
            orderbyClause += "  ORDER BY " + property+"   " + order;
        }
        return this;
    }

    /**
     * 返回HQL語句
     */
    public String returnHQL() {
        return fromClause + whereClause + orderbyClause;
    }

    /**
     * 得到引數列表
     * @return
     */
    public List<Object> getObjectList() {
        return objectList;
    }
}

這樣一來的話,我們就不用自己手動拼接了,給我們的查詢助手類去拼接就好了。

而如果我們使用Mybatis的話,就可以免去查詢助手類了。因為Mybatis內部就有動態SQL的功能【動態SQL就是自動拼接SQL語句】!

動態查詢

<!--多條件查詢【動態SQL】-->
<!--會自動組合成一個正常的WHERE字句-->
<!--name值會從map中尋找-->

<select id="findByCondition" resultMap="studentMap" parameterType="map">

	select * from students

	<where>
		<if test="name!=null">
			and name=#{name}
		</if>
		<if test="sal!=null">
			and sal < #{sal}
		</if>
	</where>

</select>

查詢出來小於9000塊的人

public List<Student> findByCondition(String name,Double sal) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            /**
             * 由於我們的引數超過了兩個,而方法中只有一個Object引數收集
             * 因此我們使用Map集合來裝載我們的引數
             */
            Map<String, Object> map = new HashMap();
            map.put("name", name);
            map.put("sal", sal);
            return sqlSession.selectList("StudentID.findByCondition", map);
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }
    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        List<Student> students = studentDao.findByCondition(null,9000D);
        for (Student student : students) {
            System.out.println(student.getId() + "---" + student.getName() + "----" + student.getSal());
        }


    }

在這裡插入圖片描述

動態更新

在這裡插入圖片描述

<!--動態更新-->
<!--不要忘了逗號-->
<update id="updateByConditions" parameterType="map">

	update students
	<set>
		<if test="name!=null">
			 name = #{name},
		</if>
		<if test="sal!=null">
			 sal = #{sal},
		</if>
	</set>
	where id = #{id}
</update>

給出三個更新的欄位

public void updateByConditions(int id,String name,Double sal) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            /**
             * 由於我們的引數超過了兩個,而方法中只有一個Object引數收集
             * 因此我們使用Map集合來裝載我們的引數
             */
            Map<String, Object> map = new HashMap();
            map.put("id", id);
            map.put("name", name);
            map.put("sal", sal);
            sqlSession.update("StudentID.updateByConditions", map);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        studentDao.updateByConditions(2,"haha",500D);

    }

在這裡插入圖片描述

動態刪除

在這裡插入圖片描述
以前我們使用JDBC也好,Hibernate也好,想要批量刪除的時候,總是使用的是迴圈刪除。而我們現在使用的是Mybatis,SQL語句是自己寫的。所以我們可以寫下如下的SQL來進行刪除

delete from students where id in (?,?,?,?);

而我們的Mybatis又支援動態SQL,所以刪除起來就非常方便了!

<delete id="deleteByConditions" parameterType="int">

	<!-- foreach用於迭代陣列元素
		 open表示開始符號
		 close表示結束符合
		 separator表示元素間的分隔符
		 item表示迭代的陣列,屬性值可以任意,但提倡與方法的陣列名相同
		 #{ids}表示陣列中的每個元素值
	 -->
	delete from students where id in
	 <foreach collection="array" open="(" close=")" separator="," item="ids">
		 #{ids}
	 </foreach>

</delete>

刪除編號為2,3,4的記錄

public void deleteByConditions(int... ids) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            /**
             * 由於我們的引數超過了兩個,而方法中只有一個Object引數收集
             * 因此我們使用Map集合來裝載我們的引數
             */
            sqlSession.delete("StudentID.deleteByConditions", ids);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        studentDao.deleteByConditions(2,3,4);

    }

在這裡插入圖片描述

動態插入

我們要想動態插入的話,就比其他的DML語句稍微複雜一點,因為它有兩部分是不確定的,平常的SQL語句是這樣的:

insert into student(id,name,sal) values(?,?,?)

在這裡插入圖片描述

SQL程式碼塊是不能像之前那樣幫我們自動去除多餘的逗號的,因此我們需要使用trim標籤來自己手動去除…

編寫insertSQL語句的時候,不要忘了寫()括號。

 <!--SQL片段預設是不幫我們自動生成合適的SQL,因此需要我們自己手動除去逗號-->
    <sql id="key">
        <trim suffixOverrides=",">
            <if test="id!=null">
                id,
            </if>

            <if test="id!=null">
                name,
            </if>

            <if test="id!=null">
                sal,
            </if>
        </trim>
    </sql>

    <sql id="value">
        <trim suffixOverrides=",">
            <if test="id!=null">
                #{id},
            </if>

            <if test="id!=null">
                #{name},
            </if>

            <if test="id!=null">
                #{sal},
            </if>
        </trim>
    </sql>
    <!--動態插入-->
    <insert id="insertByConditions" parameterType="zhongfucheng.Student">
	
		insert into students (<include refid="key"/>) values
        (<include refid="value"/>)

	</insert>

測試三個不同內容的資料

public void insertByConditions(Student student) throws Exception {
        //得到連線物件
        SqlSession sqlSession = MybatisUtil.getSqlSession();
        try{
            //對映檔案的名稱空間.SQL片段的ID,就可以呼叫對應的對映檔案中的SQL
            sqlSession.insert("StudentID.insertByConditions", student);
            sqlSession.commit();
        }catch(Exception e){
            e.printStackTrace();
            sqlSession.rollback();
            throw e;
        }finally{
            MybatisUtil.closeSqlSession();
        }
    }

    public static void main(String[] args) throws Exception {
        StudentDao studentDao = new StudentDao();
        studentDao.insertByConditions(new Student(55, null, null));//name和sal為空

        studentDao.insertByConditions(new Student(66, "haxi", null));//sal為空
        studentDao.insertByConditions(new Student(77, null, 3999d));//name為空


    }

在這裡插入圖片描述

總結

  • Mybatis的準備工作與Hibernate差不多,都需要一個總配置檔案、一個對映檔案。
  • Mybatis的SQLSession工具類使用ThreadLocal來對執行緒中的Session來進行管理。
  • Mybatis的事務預設是開啟的,需要我們手動去提交事務。
  • Mybatis的SQL語句是需要手寫的,在程式中通過對映檔案的名稱空間.sql語句的id來進行呼叫!
  • 在Mybatis中,增刪改查都是需要我們自己寫SQL語句的,然後在程式中呼叫即可了。SQL由於是我們自己寫的,於是就相對Hibernate靈活一些。
  • 如果需要傳入多個引數的話,那麼我們一般在對映檔案中用Map來接收。
  • 由於我們在開發中會經常用到條件查詢,在之前,我們是使用查詢助手來幫我們完成對SQL的拼接的。而Mybatis的話,我們是自己手寫SQL程式碼的。
  • Mybatis也支援一些判斷標籤,於是我們就可以通過這些標籤來完成動態CRUD的操作了。
  • 值得注意的是,我們的sql片段程式碼是需要我們自己手動去分割,號的。

我在這裡整理出了Java進階架構師之路的核心知識,同時也是面試時面試官必問的知識點,篇章也是包括了很多知識點,其中包括了有基礎知識、Java集合、JVM、多執行緒併發、spring原理、微服務、Netty 與RPC 、Kafka、日記、設計模式、Java演算法、資料庫、Zookeeper、分散式快取、資料結構等等

有需要的小夥伴可以點選這裡來加群:1149778920 暗號:Q F
在這裡插入圖片描述
在這裡插入圖片描述

相關文章