MyBatis精講

一、介紹

MyBatis介紹
MyBatis是一流的持久性框架,支持自定義SQL,存儲過程和高級映射。MyBatis消除了幾乎所有的JDBC代碼以及參數的手動設置和結果檢索。MyBatis可以使用簡單的XML或註釋進行配置,並將圖元,映射接口和Java POJO(普通的舊Java對象)映射到數據庫記錄。
官網介紹:https://mybatis.org/mybatis-3/

爲什麼要使用MyBatis

  • MyBatis是一個半自動化的持久化層框架。
  • JDBC
    • SQL夾在Java代碼塊裏,耦合度高導致硬編碼內傷
    • 維護不易且實際開發需求中sql是有變化,頻繁修改的情況多見 • Hibernate和JPA
    • 長難複雜SQL,對於Hibernate而言處理也不容易
    • 內部自動生產的SQL,不容易做特殊優化。
    • 基於全映射的全自動框架,大量字段的POJO進行部分映射時比較困難。
      導致數據庫性能下降。 對開發人員而言,核心sql還是需要自己優化
  • MyBatis
    • sql和java編碼分開,功能邊界清晰,一個專注業務、一個專注數據
    • MyBatis 是支持定製化 SQL、存儲過程以及高級映射的優秀的持久層框架。
    • MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。
    • MyBatis可以使用簡單的XML或註解用於配置和原始映射,將接口和Java的POJO(Plain Old Java Objects,普通的Java對象)映射成數據庫中的記錄

下載MyBatis
https://github.com/mybatis/mybatis-3/
在這裏插入圖片描述
打開頁面後,即可找到下載地址
在這裏插入圖片描述
如果是maven項目直接引入mybatis依賴即可

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

二、操作

2.1、原理介紹

根據全局配置文件,利用SqlSessionFactoryBuilder創建SqlSessionFactory

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = SqlSessionFactoryBuilder().build(inputStream);

使用SqlSessionFactory獲取sqlSession對象。一個SqlSession對象代表和數據庫的一次會話

SqlSession openSession = sqlSessionFactory.openSession();
try {
	// 3、獲取接口的實現類對象
	//會爲接口自動的創建一個代理對象,代理對象去執行增刪改查方法
	EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
	Employee employee = mapper.getEmpById(1);
	System.out.println(mapper.getClass());
	System.out.println(employee);
} finally {
	openSession.close();
}

使用SqlSession根據方法id進行操作

try {
	Employee employee = openSession.selectOne(
			"com.atguigu.mybatis.EmployeeMapper.selectEmp", 1);
	System.out.println(employee);
} finally {
	openSession.close();
}

SqlSession

  • SqlSession 的實例不是線程安全的,因此是不能被共享的。
  • SqlSession每次使用完成後需要正確關閉,這個關閉操作是必須的。
  • SqlSession可以直接調用方法的id進行數據庫操作,但是我們一般還是推薦使用SqlSession獲取到Dao接口的代理類,執行代理對象的方法,可以更安全的進行類型檢查操作。

2.2、代碼實戰

創建MyBatis全局配置文件mybatis-config.xml
MyBatis 的全局配置文件包含了影響 MyBatis 行爲甚深的設置(settings)和屬性(properties)信息、如數據庫連接池信息等。指導着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>
	<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" />
				<property name="username" value="root" />
				<property name="password" value="123456" />
			</dataSource>
		</environment>
	</environments>
	<!-- 將我們寫好的sql映射文件(EmployeeMapper.xml)一定要註冊到全局配置文件(mybatis-config.xml)中 -->
	<mappers>
		<mapper resource="EmployeeMapper.xml" />
	</mappers>
</configuration>

properties屬性:
在這裏插入圖片描述
如果屬性在不只一個地方進行了配置,那麼 MyBatis 將按照下面的順序來加載:

  • 在 properties 元素體內指定的屬性首先被讀取。
  • 然後根據 properties 元素中的 resource 屬性讀取類路徑下屬性文件或根據 url 屬性指定的路徑讀取屬性文件,並覆蓋已讀取的同名屬性。
  • 最後讀取作爲方法參數傳遞的屬性,並覆蓋已讀取的同名屬性。

創建SQL映射文件EmployeeMapper.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">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
<!-- 
namespace:名稱空間;指定爲接口的全類名
id:唯一標識
resultType:返回值類型
#{id}:從傳遞過來的參數中取出id值
public Employee getEmpById(Integer id);
-->
	<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
		select id,last_name lastName,email,gender from tbl_employee where id = #{id}
	</select>
</mapper>

創建DAO層Mapper接口EmployeeMapper

package com.atguigu.mybatis.dao;

import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapper {
	public Employee getEmpById(Integer id);
}

測試

package com.atguigu.mybatis.test;

import java.io.IOException;
import java.io.InputStream;

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 org.junit.Test;

import com.atguigu.mybatis.bean.Employee;
import com.atguigu.mybatis.dao.EmployeeMapper;

/**
 * @author sgw
 */
public class MyBatisTest {
	public SqlSessionFactory getSqlSessionFactory() throws IOException {
		String resource = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(resource);
		return new SqlSessionFactoryBuilder().build(inputStream);
	}

	/**
	 * 1、根據xml配置文件(全局配置文件)創建一個SqlSessionFactory對象 有數據源一些運行環境信息
	 * 2、sql映射文件;配置了每一個sql,以及sql的封裝規則等。 
	 * 3、將sql映射文件註冊在全局配置文件中
	 * 4、寫代碼:
	 * 		1)、根據全局配置文件得到SqlSessionFactory;
	 * 		2)、使用sqlSession工廠,獲取到sqlSession對象使用他來執行增刪改查
	 * 			一個sqlSession就是代表和數據庫的一次會話,用完關閉
	 * 		3)、使用sql的唯一標誌來告訴MyBatis執行哪個sql。sql都是保存在sql映射文件中的。
	 * 
	 * @throws IOException
	 */
	@Test
	public void test() throws IOException {

		// 2、獲取sqlSession實例,能直接執行已經映射的sql語句
		// sql的唯一標識:statement Unique identifier matching the statement to use.
		// 執行sql要用的參數:parameter A parameter object to pass to the statement.
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();

		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			Employee employee = openSession.selectOne(
					"com.atguigu.mybatis.EmployeeMapper.selectEmp", 1);
			System.out.println(employee);
		} finally {
			openSession.close();
		}
	}

	@Test
	public void test01() throws IOException {
		// 1、獲取sqlSessionFactory對象
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		// 2、獲取sqlSession對象
		SqlSession openSession = sqlSessionFactory.openSession();
		try {
			// 3、獲取接口的實現類對象
			//MyBatis會爲接口自動的創建一個代理對象,代理對象去執行增刪改查方法
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			Employee employee = mapper.getEmpById(1);
			System.out.println(mapper.getClass());
			System.out.println(employee);
		} finally {
			openSession.close();
		}
	}
}

總結

  • 1、接口式編程
    原生: Dao ====> DaoImpl
    mybatis: Mapper ====> xxMapper.xml

  • 2、SqlSession
    SqlSession 代表和數據庫的一次會話;用完必須關閉;
    SqlSession和Connection一樣都是非線程安全的。每次使用都應該去獲取新的對象(不要放在成員變量裏)。

  • 3、mapper接口沒有實現類,但是mybatis會爲這個接口生成一個代理對象。
    (將接口和xml進行綁定)
    EmployeeMapper empMapper = sqlSession.getMapper(EmployeeMapper.class);

  • 5、兩個重要的配置文件:
    mybatis的全局配置文件:包含數據庫連接池信息,事務管理器信息等…系統運行環境信息
    sql映射文件:保存了每一個sql語句的映射信息,將sql抽取出來。

2.3、全局配置文件mybatis-config.xml

properties屬性
官方介紹

  • mybatis可以使用properties來引入外部properties配置文件的內容;
    resource:引入類路徑下的資源
    url:引入網絡路徑或者磁盤路徑下的資源
<?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="dbconfig.properties"></properties>
	<environments default="dev_mysql">
		<environment id="dev_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>
	<!-- 將我們寫好的sql映射文件(EmployeeMapper.xml)一定要註冊到全局配置文件(mybatis-config.xml)中 -->
	<!-- 6、mappers:將sql映射註冊到全局配置中 -->
	<mappers>
		<!-- 
			mapper:註冊一個sql映射 
				註冊配置文件
				resource:引用類路徑下的sql映射文件
					mybatis/mapper/EmployeeMapper.xml
				url:引用網路路徑或者磁盤路徑下的sql映射文件
					file:///var/mappers/AuthorMapper.xml
					
				註冊接口
				class:引用(註冊)接口,
					1、有sql映射文件,映射文件名必須和接口同名,並且放在與接口同一目錄下;
					2、沒有sql映射文件,所有的sql都是利用註解寫在接口上;
					推薦:
						比較重要的,複雜的Dao接口我們來寫sql映射文件
						不重要,簡單的Dao接口爲了開發快速可以使用註解;
		-->
		<!-- <mapper resource="mybatis/mapper/EmployeeMapper.xml"/> -->
		<!-- <mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/> -->
		
		<!-- 批量註冊: -->
		<package name="com.atguigu.mybatis.dao"/>
	</mappers>
</configuration>

對應的dbconfig.properties文件

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

settings屬性

官方介紹

  • settings包含很多重要的設置項
    setting:用來設置每一個設置項
    name:設置項名
    value:設置項取值

例如:設置開啓自動駝峯命名策略(mapUnderscoreToCamelCase默認值是false,不開啓),即數據庫字段是下劃線A_COLUMN,而javaBean裏是aColumn,開啓駝峯命名後,這樣就會把數據庫裏的字段映射到javaBean裏了;

<?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="dbconfig.properties"></properties>

	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings>

	<environments default="dev_mysql">
		<environment id="dev_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>
	
	<mappers>
		<!-- 批量註冊: -->
		<package name="com.atguigu.mybatis.dao"/>
	</mappers>
</configuration>

typeAliases別名屬性
官方文檔
類型別名是爲 Java 類型設置一個短的名字。 它只和 XML 配置有關,存在的意義僅在於用來減少類完全限定名的冗餘。例如:

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

typeAliases:別名處理器:可以爲我們的java類型起別名 ,別名不區分大小寫;

不指定別名,使用默認的別名:

<typeAliases>
		<!-- 1、typeAlias:爲某個java類型起別名
				type:指定要起別名的類型全類名;默認別名就是類名小寫;employee
		 -->
		 <typeAlias type="com.atguigu.mybatis.bean.Employee" /> 
</typeAliases>

指定別名:

<typeAliases>
	<!-- alias:指定新的別名-->
	<typeAlias type="com.atguigu.mybatis.bean.Employee" alias="emp"/> 
</typeAliases>

爲某個包下的所有類批量起別名:

<typeAliases>
		<!-- 2、package:爲某個包下的所有類批量起別名 
				name:指定包名(爲當前包以及下面所有的後代包的每一個類都起一個默認別名(別名是類名小寫))
		-->
		<package name="com.atguigu.mybatis.bean"/>
</typeAliases>

使用上邊package批量起別名的前提下,在javaBean上使用@Alias註解爲每個實體類起自己的起別名:

//別名
Alias("emp")
public class Employee {
	
	private Integer id;
	private String lastName;
	private String email;
	private String gender;
	
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	@Override
	public String toString() {
		return "Employee [id=" + id + ", lastName=" + lastName + ", email="
				+ email + ", gender=" + gender + "]";
	}
}

在mybatis-config.xml配置了別名後,在Mapper.xml的文件中,所有寫com.atguigu.mybatis.bean.Employee的地方(一般是resultType的值)都可以換成別名了
在這裏插入圖片描述

MyBatis已經起好的別名:
在這裏插入圖片描述
注意:我們自己的別名不可以與上邊的重複

typeHandlers類型處理器
官方文檔
typeHandlers是架起javaBean與數據庫的橋樑,即通過typeHandlers將java裏的數據類型與數據庫裏的數據類型進行一一映射;
在這裏插入圖片描述
typeHandlers後邊會細講;

plugins插件
官方文檔
主要是在攔截以下四大對象前後做一些事情

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)
  • ResultSetHandler (handleResultSets, handleOutputParameters)
  • StatementHandler (prepare, parameterize, batch, update, query)

plugins插件後邊會詳細介紹;

environments環境配置
官方文檔

MyBatis 可以配置成適應多種環境,這種機制有助於將 SQL 映射應用於多種數據庫之中;

  • environments:環境們,mybatis可以配置多種環境 ,default指定使用某種環境。可以達到快速切換環境。
    • environment:配置一個具體的環境信息;必須有兩個標籤;id代表當前環境的唯一標識
    • transactionManager:事務管理器(項目中的事務一般交給了Spring去管理,不在MyBatis配置);
      • type:事務管理器的類型(有以下兩種事務管理器):
        JDBC(JdbcTransactionFactory) | MANAGED(ManagedTransactionFactory)
        自定義事務管理器:實現TransactionFactory接口.type指定爲全類名
    • dataSource:數據源
      • type:數據源類型
        UNPOOLED(UnpooledDataSourceFactory)不使用連接池
        POOLED(PooledDataSourceFactory)使用連接池
        JNDI(JndiDataSourceFactory)使用連接池
        自定義數據源:實現DataSourceFactory接口,type是全類名
<environments default="dev_mysql">
	<environment id="dev_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>

	<environment id="dev_oracle">
		<transactionManager type="JDBC" />
		<dataSource type="POOLED">
			<property name="driver" value="${orcl.driver}" />
			<property name="url" value="${orcl.url}" />
			<property name="username" value="${orcl.username}" />
			<property name="password" value="${orcl.password}" />
		</dataSource>
	</environment>
</environments>

databaseIdProvider數據庫廠商標識
官方文檔
MyBatis 可以根據不同的數據庫廠商執行不同的語句,這種多廠商的支持是基於映射語句中的databaseId 屬性;
在全局平配置文件裏進行配置來支持多數據庫廠商

  • type=“DB_VENDOR”:VendorDatabaseIdProvider
    作用就是得到數據庫廠商的標識(驅動getDatabaseProductName()),mybatis就能根據數據庫廠商標識來執行不同的sql;

MySQL,Oracle,SQL Server,xxxx

<databaseIdProvider type="DB_VENDOR">
	<!-- 爲不同的數據庫廠商起別名 value值是別名 -->
	<property name="MySQL" value="mysql"/>
	<property name="Oracle" value="oracle"/>
	<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>

全局配置好後,在Mapper.xml裏,通過databaseId的值告訴MyBatis當前sql是那種數據庫的語句

<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"
		databaseId="oracle">
		select EMPLOYEE_ID id,LAST_NAME	lastName,EMAIL email 
		from employees where EMPLOYEE_ID=#{id}
</select>

<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee"
		databaseId="mysql">
		select * from tbl_employee where id = #{id}
</select>

mappers映射器
官方文檔

mappers:將sql映射註冊到全局配置中

mapper:註冊一個sql映射

方式一:註冊配置文件

  1. resource:引用類路徑下的sql映射文件
mybatis/mapper/EmployeeMapper.xml
  1. url:引用網路路徑或者磁盤路徑下的sql映射文件
file:///var/mappers/AuthorMapper.xml
<mappers>
	<mapper resource="mybatis/mapper/EmployeeMapper.xml"/>
</mappers>

方式二:註冊接口
class:引用(註冊)接口,

  1. 有sql映射文件,映射文件名必須和接口同名,並且放在與接口同一目錄下;
  2. 沒有sql映射文件,所有的sql都是利用註解寫在接口上;
    sql利用註解寫在接口上的方式:
package com.atguigu.mybatis.dao;

import org.apache.ibatis.annotations.Select;

import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapperAnnotation {
	@Select("select * from tbl_employee where id=#{id}")
	public Employee getEmpById(Integer id);
}

全局配置文件:

<mappers>
    <mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/>
</mappers>

以上兩種方式可以同時配置

<mapper resource="mybatis/mapper/EmployeeMapper.xml"/> 
<mapper class="com.atguigu.mybatis.dao.EmployeeMapperAnnotation"/> 

方式三:批量註冊
映射文件名必須和接口同名,並且放在與接口同一目錄下(註解版不需要);

<mappers>
	<package name="com.atguigu.mybatis.dao"/>
</mappers>

推薦:
比較重要的,複雜的Dao接口我們來寫sql映射文件;
不重要,簡單的Dao接口爲了開發快速可以使用註解的方式;

一個比較完整的全局配置文件:

<?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="dbconfig.properties"></properties>
	
	
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
	</settings>
	
	<typeAliases>
		<package name="com.atguigu.mybatis.bean"/>
	</typeAliases>
		
	<environments default="dev_mysql">
		<environment id="dev_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>
	
		<environment id="dev_oracle">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${orcl.driver}" />
				<property name="url" value="${orcl.url}" />
				<property name="username" value="${orcl.username}" />
				<property name="password" value="${orcl.password}" />
			</dataSource>
		</environment>
	</environments>
	
	<databaseIdProvider type="DB_VENDOR">
		<!-- 爲不同的數據庫廠商起別名 -->
		<property name="MySQL" value="mysql"/>
		<property name="Oracle" value="oracle"/>
		<property name="SQL Server" value="sqlserver"/>
	</databaseIdProvider>
	
	<mappers>
		<package name="com.atguigu.mybatis.dao"/>
	</mappers>
</configuration>

注意,配置文件裏的標籤是有順序的,比如 <databaseIdProvider >標籤不可以放在<environments>之前
標籤的順序如下:
在這裏插入圖片描述

三、MyBatis的sql映射文件Mapper.xml

官方文檔

3.1、MyBatis實現增刪改操作

接口

package com.atguigu.mybatis.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;

import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapper {

	public Long addEmp(Employee employee);

	public boolean updateEmp(Employee employee);

	public void deleteEmpById(Integer id);
}

映射文件

<?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">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">
 
	<!-- parameterType:參數類型,可以省略, 
	獲取自增主鍵的值:
		mysql支持自增主鍵,自增主鍵值的獲取,mybatis也是利用statement.getGenreatedKeys();
		useGeneratedKeys="true";使用自增主鍵獲取主鍵值策略
		keyProperty;指定對應的主鍵屬性,也就是mybatis獲取到主鍵值以後,將這個值封裝給javaBean的哪個屬性
	-->
	<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
		useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
		insert into tbl_employee(last_name,email,gender) 
		values(#{lastName},#{email},#{gender})
	</insert>
	
	<!-- 
	獲取非自增主鍵的值:
		Oracle不支持自增;Oracle使用序列來模擬自增;
		每次插入的數據的主鍵是從序列中拿到的值;如何獲取到這個值;
	 -->
	<insert id="addEmp" databaseId="oracle">
		<!-- 
		keyProperty:查出的主鍵值封裝給javaBean的哪個屬性
		order="BEFORE":當前sql在插入sql之前運行
			   AFTER:當前sql在插入sql之後運行
		resultType:查出的數據的返回值類型
		
		BEFORE運行順序:
			先運行selectKey查詢id的sql;查出id值封裝給javaBean的id屬性
			在運行插入的sql;就可以取出id屬性對應的值
		AFTER運行順序:
			先運行插入的sql(從序列中取出新值作爲id);
			再運行selectKey查詢id的sql-->
		<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
			<!-- 編寫查詢主鍵的sql語句 -->
			<!-- BEFORE-->
			select EMPLOYEES_SEQ.nextval from dual 
			<!-- AFTER:
			 select EMPLOYEES_SEQ.currval from dual -->
		</selectKey>
		
		<!-- 插入時的主鍵是從序列中拿到的 -->
		<!-- BEFORE:-->
		insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
		values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->}) 
		<!-- AFTER:
		insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
		values(employees_seq.nextval,#{lastName},#{email}) -->
	</insert>
	
	<update id="updateEmp">
		update tbl_employee 
		set last_name=#{lastName},email=#{email},gender=#{gender}
		where id=#{id}
	</update>
	
	<delete id="deleteEmpById">
		delete from tbl_employee where id=#{id}
	</delete>
</mapper>

測試:

    /**
	 * 	測試增刪改
	 * @throws IOException 
	 */
	@Test
	public void test03() throws IOException{
		
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		//1、獲取到的SqlSession不會自動提交數據
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			//測試添加
			Employee employee = new Employee(null, "jerry4",null, "1");
			mapper.addEmp(employee);
			System.out.println(employee.getId());
			
			//測試修改
			//Employee employee = new Employee(1, "Tom", "[email protected]", "0");
			//boolean updateEmp = mapper.updateEmp(employee);
			//System.out.println(updateEmp);
			//測試刪除
			//mapper.deleteEmpById(2);
			//2、手動提交數據
			openSession.commit();
		}finally{
			openSession.close();
		}
	}
  1. mybatis允許增刪改直接定義以下類型返回值
    Integer、Long、Boolean、void
  2. 有以下兩種SqlSession
    SqlSession openSession =sqlSessionFactory.openSession();——>需要手動提交
    SqlSession openSession =sqlSessionFactory.openSession(true);——>自動提交

上邊的插入操作,主鍵值是自增的,當執行完插入操作後,想得到返回的主鍵時,MyBatis利用statement.getGenrentedKeys()來獲取,只需要在<insert>節點裏配置useGeneratedKeys="true" 即可
,默認是false;keyProperty="id"指定主鍵對應的屬性,即MyBatis獲取到主鍵值後保存到JavaBean的id屬性裏;

<insert id="addEmp" parameterType="com.atguigu.mybatis.bean.Employee"
		useGeneratedKeys="true" keyProperty="id" databaseId="mysql">
		insert into tbl_employee(last_name,email,gender) 
		values(#{lastName},#{email},#{gender})
</insert>

oracle不支持自增,需要使用序列來實現自增,每次插入的數據的主鍵是從序列中拿到的值,那如何獲取到這個值?

<insert id="addEmp" databaseId="oracle">
		<!-- 
		keyProperty:查出的主鍵值封裝給javaBean的哪個屬性
		order="BEFORE":當前sql在插入sql之前運行
			   AFTER:當前sql在插入sql之後運行
		resultType:查出的數據的返回值類型
		
		BEFORE運行順序:
			先運行selectKey查詢id的sql;查出id值封裝給javaBean的id屬性
			再運行插入的sql;就可以取出id屬性對應的值
		AFTER運行順序:
			先運行插入的sql(從序列中取出新值作爲id);
			再運行selectKey查詢id的sql-->
		<selectKey keyProperty="id" order="BEFORE" resultType="Integer">
			<!-- 編寫查詢主鍵的sql語句 -->
			<!-- BEFORE-->
			select EMPLOYEES_SEQ.nextval from dual 
			<!-- AFTER:
			 select EMPLOYEES_SEQ.currval from dual -->
		</selectKey>
		
		<!-- 插入時的主鍵是從序列中拿到的 -->
		<!-- BEFORE:-->
		insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
		values(#{id},#{lastName},#{email<!-- ,jdbcType=NULL -->}) 
		<!-- AFTER:
		insert into employees(EMPLOYEE_ID,LAST_NAME,EMAIL) 
		values(employees_seq.nextval,#{lastName},#{email}) -->
</insert>

3.2、MyBatis對參數的處理

單個參數
mybatis不會做特殊處理,#{參數名/任意名}:取出參數值。注意,大括號裏寫任意值都行,沒必要與接口方法的參數名保持一致
接口:

import java.util.List;

public interface EmployeeMapper {
	public Employee getEmpById(Integer id);
}

映射文件

<!--注意大括號裏,是可以隨便寫的,因爲只有一個參數-->
<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
		select * from tbl_employee where id = #{idabc}
</select>

多個參數

接口

public Employee getEmpByIdAndLastName(Integer id,String lastName);

映射文件

<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee">
 		select * from tbl_employee where id = #{id} and last_name=#{lastName}
</select>

上邊這樣是會報錯的:

org.apache.ibatis.binding.BindingException:
Parameter ‘id’ not found.
Available parameters are [1, 0, param1, param2]

這是因爲MyBatis遇到多個參數的時候會做特殊處理,多個參數會被封裝成 一個map,key的值是param1…paramN,或者參數的索引也可以,value的值是傳入的參數值,所以,接口如果不變的情況下,映射文件正確的寫法應該是:

<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee">
 		select * from tbl_employee where id = #{param1} and last_name=#{param2}
</select>

上邊這樣寫沒有問題,但是閱讀起來很不友好,所以採用@Param命名參數的方式,明確指定封裝參數時map的key;@Param(“id”),多個參數會被封裝成 一個map,key:使用@Param註解指定的值,value:參數值,#{指定的key}取出對應的參數值;

接口:

public Employee getEmpByIdAndLastName(@Param("id")Integer id,@Param("lastName")String lastName);

映射文件:

<select id="getEmpByIdAndLastName" resultType="com.atguigu.mybatis.bean.Employee">
 		select * from tbl_employee where id = #{id} and last_name=#{lastName}
</select>

POJO作爲參數
如果多個參數正好是我們業務邏輯的數據模型(javaBean),我們就可以直接傳入pojo;
#{屬性名}:即可取出傳入的pojo的屬性值

Map作爲參數
如果多個參數不是業務模型中的數據(javaBean),沒有對應的pojo,不經常使用,爲了方便,我們也可以傳入map
#{key}:取出map中對應的值;

接口

public Employee getEmpByMap(Map<String, Object> map);

映射文件

<select id="getEmpByMap" resultType="com.atguigu.mybatis.bean.Employee">
 	select * from ${tableName} where id=${id} and last_name=#{lastName}
</select>

幾種特殊參數形式,對於的mapper取值的寫法
1、接口

public Employee getEmp(@Param("id")Integer id,String lastName);

對應的mapper取值:

id==>#{id/param1}   lastName==>#{param2}

2、接口

public Employee getEmp(Integer id,@Param("e")Employee emp);

對應的mapper取值:

id==>#{param1}    lastName===>#{param2.lastName/e.lastName}

3、特別注意:如果參數是Collection(List、Set)類型、或者是數組類型,mybatis也會特殊處理,會把傳入的list或者數組封裝在map中
map裏key的值:

  • 參數是Collection:key就是collection,如果Collection是List,key可以使用這個list
  • 參數是數組Array:key就是array

例如接口:

public Employee getEmpById(List<Integer> ids);

對應mapper裏的取值:

取出第一個id的值:   #{list[0]}

mybatis中#與$的區別
$會自動將參數填充到指定位置,而#會使用佔位符填充
在這裏插入圖片描述
區別:

  • #{}:是以預編譯的形式,將參數設置到sql語句中;PreparedStatement預編譯,可以防止sql注入;
  • ${}:取出的值直接拼裝在sql語句中,存在安全問題;

大多情況下,我們取參數的值都應該去使用#{};

原生jdbc不支持佔位符的地方我們就可以使用${}進行取值,比如分表、排序。。。;按照年份分表拆分

# "#"只能獲取參數裏的值,sql裏表名的地方不是參數,不可以使用#來獲取表名
select * from ${year}_salary where xxx;
# 表名、排序,不支持預編譯,即不可以使用#來取值
select * from tbl_employee order by ${f_name} ${order}

#{}:更豐富的用法:
規定參數的一些規則:
javaType、 jdbcType、 mode(存儲過程)、 numericScale、
resultMap、 typeHandler、 jdbcTypeName、 expression(未來準備支持的功能);

jdbcType通常需要在某種特定的條件下被設置:
在我們數據爲null的時候,有些數據庫可能不能識別mybatis對null的默認處理。比如Oracle(報錯):
JdbcType OTHER:無效的類型;因爲mybatis對所有的null都映射的是原生Jdbc的OTHER類型,oracle不能正確處理;

由於全局配置中:jdbcTypeForNull=OTHER;oracle不支持;如果email字段爲空,有兩種解決辦法
1、mapper文件裏取值的地方:#{email,jdbcType=OTHER};
2、修改全局配置:jdbcTypeForNull=NULL

<setting name="jdbcTypeForNull" value="NULL"/>

在這裏插入圖片描述

3.3、select查詢元素

返回類型是List集合
如果返回的是一個list集合類型,則resultType要寫集合中元素的類型
接口:

public List<Employee> getEmpsByLastNameLike(String lastName);

mapper文件

<select id="getEmpsByLastNameLike" resultType="com.atguigu.mybatis.bean.Employee">
		select * from tbl_employee where last_name like #{lastName}
</select>

返回類型是Map集合
1、返回結果只有一條Map記錄
如果返回的是一個Map集合類型,且只有一條記錄,則resultType就是map(mybatis爲Map集合取的別名)
接口:

//返回一條記錄的map;key就是列名,值就是對應的值
public Map<String, Object> getEmpByIdReturnMap(Integer id);

mapper文件

<select id="getEmpByIdReturnMap" resultType="map">
 	select * from tbl_employee where id=#{id}
</select>

2、返回結果只有多條Map記錄
如果返回的是一個Map集合類型,且有多條記錄,則resultType是集合裏元素的類型

接口:

//多條記錄封裝一個map:Map<Integer,Employee>:鍵是這條記錄的主鍵,值是記錄封裝後的javaBean
//@MapKey:告訴mybatis封裝這個map的時候使用哪個屬性作爲map的key
@MapKey("lastName")
public Map<String, Employee> getEmpByLastNameLikeReturnMap(String lastName);

mapper.xml:

<select id="getEmpByLastNameLikeReturnMap" resultType="com.atguigu.mybatis.bean.Employee">
 	select * from tbl_employee where last_name like #{lastName}
</select>

resultType自定義結果集映射
數據庫列名與javaBean屬性名對應不上的話,可以有三種解決方式
1、起別名
2、全局配置文件裏開啓駝峯命名(前提是數據庫列符合駝峯規則)
3、使用resultMap來自定義映射
切記:resultType與resultType只能使用其中的一個

mapper.xml裏自定義映射規則

<!--自定義某個javaBean的封裝規則
	type:自定義規則的Java類型
	id:唯一id,方便引用
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MySimpleEmp">
		<!--指定主鍵列的封裝規則
		id定義主鍵會底層有優化;
		column:指定哪一列
		property:指定對應的javaBean屬性
		  -->
		<id column="id" property="id"/>
		<!-- 定義普通列封裝規則 -->
		<result column="last_name" property="lastName"/>
		<!-- 其他不指定的列會自動封裝:我們只要寫了resultMap,就把全部的映射規則都寫上。 -->
		<result column="email" property="email"/>
		<result column="gender" property="gender"/>
</resultMap>

<select id="getEmpById"  resultMap="MySimpleEmp">
		select * from tbl_employee where id=#{id}
</select>

場景:
查詢Employee員工的同時,查詢該員工對應的部門
Employee===Department;
一個員工有與之對應的部門信息;

接口:

public Employee getEmpAndDept(Integer id);

方式一、級聯屬性封裝結果集
resultMap 結果集:

<!--
	聯合查詢:級聯屬性封裝結果集
-->
<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp">
		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		<result column="did" property="dept.id"/>
		<result column="dept_name" property="dept.departmentName"/>
</resultMap>

查詢sql:

<select id="getEmpAndDept" resultMap="MyDifEmp">
		SELECT e.id id,e.last_name last_name,e.gender gender,e.d_id d_id,
		d.id did,d.dept_name dept_name FROM tbl_employee e,tbl_dept d
		WHERE e.d_id=d.id AND e.id=#{id}
</select>

方式二、使用association(聯合)定義關聯的單個對象的封裝規則
resultMap 結果集:

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyDifEmp2">
		<id column="id" property="id"/>
		<result column="last_name" property="lastName"/>
		<result column="gender" property="gender"/>
		
		<!--  association可以指定聯合的javaBean對象
		property="dept":指定哪個屬性是聯合的對象
		javaType:指定這個屬性對象的類型[不能省略]
		-->
		<association property="dept" javaType="com.atguigu.mybatis.bean.Department">
			<id column="did" property="id"/>
			<result column="dept_name" property="departmentName"/>
		</association>
</resultMap>

方式三、使用association進行分步查詢
1、先按照員工id查詢員工信息
2、根據查詢員工信息中的d_id值去部門表查出部門信息
3、將部門信息設置到員工屬性中;

定義部門的接口(之前只有員工的接口):

public Department getDeptById(Integer id);

對應的部門mapper.xml:

<select id="getDeptById" resultType="com.atguigu.mybatis.bean.Department">
		select id,dept_name departmentName from tbl_dept where id=#{id}
</select>

員工接口:

public Employee getEmpByIdStep(Integer id);

員工mapper.xml:

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpByStep">
	 <id column="id" property="id"/>
	 <result column="last_name" property="lastName"/>
	 <result column="email" property="email"/>
	 <result column="gender" property="gender"/>
	 <!-- association定義關聯對象的封裝規則
	 		select:表明當前屬性是調用select指定的方法查出的結果
	 		column:指定將哪一列的值傳給這個方法
	 		
	 		流程:使用select指定的方法(傳入column指定的這列參數的值)查出對象,並封裝給property指定的屬性(dept)
	 	 -->
 	 <association property="dept" 
	 		select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
	 		column="d_id">
 	</association>
</resultMap>

 <select id="getEmpByIdStep" resultMap="MyEmpByStep">
	 	select * from tbl_employee where id=#{id}
	 	<if test="_parameter!=null">
	 		and 1=1
	 	</if>
</select>

association 的延遲加載(懶加載):
上邊的場景裏,我們每次查詢Employee對象的時候,都將Department一起查詢出來了。
延遲加載:部門信息在我們使用的時候再去查詢;
要實現懶加載,在之前association 分段查詢的基礎之上,在全局配置文件里加上以下兩個配置即可:

<settings>
	<!--顯示的指定每個我們需要更改的配置的值,即使他是默認的。防止版本更新帶來的問題  -->
	<setting name="lazyLoadingEnabled" value="true"/>
	<setting name="aggressiveLazyLoading" value="false"/>
</settings>

javaBean裏的屬性是集合類型
方式一:嵌套集合
場景:查詢部門的時候,將當前部門裏所有員工都查出來(部門的javaBean裏,員工屬性是集合類型)

部門接口:

public Department getDeptByIdPlus(Integer id);

部門mapper.xml:

<!--嵌套結果集的方式,使用collection標籤定義關聯的集合類型的屬性封裝規則  -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDept">
		<id column="did" property="id"/>
		<result column="dept_name" property="departmentName"/>
		<!-- 
			collection定義關聯集合類型的屬性的封裝規則 
			ofType:指定集合裏面元素的類型
		-->
		<collection property="emps" ofType="com.atguigu.mybatis.bean.Employee">
			<!-- 定義這個集合中元素的封裝規則 -->
			<id column="eid" property="id"/>
			<result column="last_name" property="lastName"/>
			<result column="email" property="email"/>
			<result column="gender" property="gender"/>
		</collection>
</resultMap>

<select id="getDeptByIdPlus" resultMap="MyDept">
		SELECT d.id did,d.dept_name dept_name,
				e.id eid,e.last_name last_name,e.email email,e.gender gender
		FROM tbl_dept d
		LEFT JOIN tbl_employee e
		ON d.id=e.d_id
		WHERE d.id=#{id}
</select>

方式二:分步查詢

接口:

public Department getDeptByIdStep(Integer id);

mapper.xml:

<!-- collection:分段查詢 -->
<resultMap type="com.atguigu.mybatis.bean.Department" id="MyDeptStep">
		<id column="id" property="id"/>
		<id column="dept_name" property="departmentName"/>
		<collection property="emps" 
			select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
			column="{id}" fetchType="lazy">
		</collection>
</resultMap>

<select id="getDeptByIdStep" resultMap="MyDeptStep">
		select id,dept_name from tbl_dept where id=#{id}
</select>

擴展:多列的值傳遞過去,將多列的值封裝map傳遞,如下:

column="{key1=column1,key2=column2}"
即:
<collection property="emps" 
	select="com.atguigu.mybatis.dao.EmployeeMapperPlus.getEmpsByDeptId"
	column="{deptId=id}" fetchType="lazy">
</collection>

fetchType=“lazy”:表示使用延遲加載,即懶加載;

  • lazy:延遲
  • eager:立即

discriminator鑑別器
mybatis可以使用discriminator判斷某列的值,然後根據該列的值改變封裝行爲

場景:如果查出的員工是女生:就把部門信息查詢出來,否則不查詢部門信息;如果是男生,把last_name這一列的值賦值給email;

mapper.xml:

<resultMap type="com.atguigu.mybatis.bean.Employee" id="MyEmpDis">
	 	<id column="id" property="id"/>
	 	<result column="last_name" property="lastName"/>
	 	<result column="email" property="email"/>
	 	<result column="gender" property="gender"/>
	 	<!--
	 		column:指定判定的列名
	 		javaType:列值對應的java類型  -->
	 	<discriminator javaType="string" column="gender">
	 		<!--女生  resultType:指定封裝的結果類型;不能缺少。/resultMap-->
	 		<case value="0" resultType="com.atguigu.mybatis.bean.Employee">
	 			<association property="dept" 
			 		select="com.atguigu.mybatis.dao.DepartmentMapper.getDeptById"
			 		column="d_id">
		 		</association>
	 		</case>
	 		<!--男生 ;如果是男生,把last_name這一列的值賦值給email; -->
	 		<case value="1" resultType="com.atguigu.mybatis.bean.Employee">
		 		<id column="id" property="id"/>
			 	<result column="last_name" property="lastName"/>
			 	<result column="last_name" property="email"/>
			 	<result column="gender" property="gender"/>
	 		</case>
	 	</discriminator>
</resultMap>

四、動態sql

4.1 MyBatis之if標籤

場景:當查詢條件有多個字段時,則sql裏就將那些不爲空的字段作爲查詢條件
接口:

public List<Employee> getEmpsByConditionIf(Employee employee);

mapper.xml:

<select id="getEmpsByConditionIf" resultType="com.atguigu.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	<!-- where -->
	 	<where>
		 	<!-- test:判斷表達式(OGNL)
		 	OGNL參照官方文檔。
		 	  	 c:if  test
		 	從參數中取值進行判斷
		 	
		 	遇見特殊符號應該去寫轉義字符:
		 	&quot;&quot:指的是'',即空字符;
		 	&amp;&amp:指的是&&,即條件與;
		 	-->
		 	<if test="id!=null">
		 		id=#{id}
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		and last_name like #{lastName}
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		and email=#{email}
		 	</if> 
		 	<!-- ognl會進行字符串與數字的轉換判斷  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	and gender=#{gender}
		 	</if>
	 	</where>
</select>

4.2 MyBatis之where標籤

4.1章節中,已經使用了where條件,mybatis會將where標籤中拼裝的sql,多出來的and或者or去掉,where只會去掉第一個多出來的and或者or,即and或or只能放在if標籤裏的最前邊。

4.3 MyBatis之trim標籤

trim標籤可以自定義字符串的截取規則
接口:

public List<Employee> getEmpsByConditionTrim(Employee employee);

mapper.xml:

<select id="getEmpsByConditionTrim" resultType="com.atguigu.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	<!-- 後面多出的and或者or where標籤不能解決 
	 	prefix="":前綴:trim標籤體中是整個字符串拼串 後的結果。
	 			prefix給拼串後的整個字符串加一個前綴 
	 	prefixOverrides="":
	 			前綴覆蓋: 去掉整個字符串前面多餘的字符
	 	suffix="":後綴
	 			suffix給拼串後的整個字符串加一個後綴 
	 	suffixOverrides=""
	 			後綴覆蓋:去掉整個字符串後面多餘的字符
	 			
	 	-->
	 	<!-- 自定義字符串的截取規則 -->
	 	<trim prefix="where" suffixOverrides="and">
	 		<if test="id!=null">
		 		id=#{id} and
		 	</if>
		 	<if test="lastName!=null &amp;&amp; lastName!=&quot;&quot;">
		 		last_name like #{lastName} and
		 	</if>
		 	<if test="email!=null and email.trim()!=&quot;&quot;">
		 		email=#{email} and
		 	</if> 
		 	<!-- ognl會進行字符串與數字的轉換判斷  "0"==0 -->
		 	<if test="gender==0 or gender==1">
		 	 	gender=#{gender}
		 	</if>
	   </trim>
</select>

4.4 MyBatis之choose(when, otherwise)標籤

choose標籤,即分支選擇,相當於java裏帶了break的swtich-case;

場景:
如果id不爲空,則使用id作爲查詢條件,如果lastName不爲空,則使用lastName作爲查詢條件,即最後只使用其中一種作爲條件;

接口:

public List<Employee> getEmpsByConditionChoose(Employee employee);

mapper.xml:

<select id="getEmpsByConditionChoose" resultType="com.atguigu.mybatis.bean.Employee">
	 	select * from tbl_employee 
	 	<where>
	 		<!-- 如果帶了id就用id查,如果帶了lastName就用lastName查;只會進入其中一個 -->
	 		<choose>
	 			<when test="id!=null">
	 				id=#{id}
	 			</when>
	 			<when test="lastName!=null">
	 				last_name like #{lastName}
	 			</when>
	 			<when test="email!=null">
	 				email = #{email}
	 			</when>
	 			<otherwise>
	 				gender = 0
	 			</otherwise>
	 		</choose>
	 	</where>
</select>

4.5 MyBatis之set標籤

where是用來封裝查詢條件的, 而set是用來封裝修改條件的;

接口:

public void updateEmp(Employee employee);

mapper.xml:

<update id="updateEmp">
	 	<!-- Set標籤的使用 -->
	 	update tbl_employee 
		<set>
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender}
			</if>
		</set>
		where id=#{id} 
<!-- 		
		Trim:更新拼串
		update tbl_employee 
		<trim prefix="set" suffixOverrides=",">
			<if test="lastName!=null">
				last_name=#{lastName},
			</if>
			<if test="email!=null">
				email=#{email},
			</if>
			<if test="gender!=null">
				gender=#{gender}
			</if>
		</trim>
		where id=#{id}  -->
</update>

4.6 MyBatis之foreach標籤

foreach標籤用來遍歷集合

4.6.1、foreach遍歷查詢

接口:

public List<Employee> getEmpsByConditionForeach(@Param("ids")List<Integer> ids);

mapper.xml:

<select id="getEmpsByConditionForeach" resultType="com.atguigu.mybatis.bean.Employee">
	 	select * from tbl_employee
	 	<!--
	 		collection:指定要遍歷的集合:
	 			list類型的參數會特殊處理封裝在map中,map的key就叫list
	 		item:將當前遍歷出的元素賦值給指定的變量
	 		separator:每個元素之間的分隔符
	 		open:遍歷出所有結果拼接一個開始的字符
	 		close:遍歷出所有結果拼接一個結束的字符
	 		index:索引。遍歷list的時候index就是索引,item就是當前值
	 			  遍歷map的時候index表示的就是map的key,item就是map的值
	 		
	 		#{變量名}就能取出變量的值也就是當前遍歷出的元素
	 	  -->
	 	<foreach collection="ids" item="item_id" separator=","
	 		open="where id in(" close=")">
	 		#{item_id}
	 	</foreach>
</select>

4.6.2、foreach遍歷插入

接口:

public void addEmps(@Param("emps")List<Employee> emps);

場景一:MySql數據庫
mapper.xml;

<!--MySQL下批量保存:可以foreach遍歷   mysql支持values(),(),()語法-->
<insert id="addEmps">
	 	insert into tbl_employee(
	 		last_name,email,gender,d_id
	 	) 
		values
		<foreach collection="emps" item="emp" separator=",">
			(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
		</foreach>
</insert>

mapper.xml也可以這樣寫(執行多條插入語句):

<!--這種方式需要數據庫連接屬性allowMultiQueries=true;
	這種分號分隔多個sql可以用於其他的批量操作(刪除,修改)-->
<insert id="addEmps">
	 	<foreach collection="emps" item="emp" separator=";">
	 		insert into tbl_employee(last_name,email,gender,d_id)
	 		values(#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
	 	</foreach>
</insert>

在properties裏配置allowMultiQueries=true:

jdbc.url=jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true

場景二:Oracle數據庫

方式一:begin-end方式
即在oracle直接執行的語句就是:

begin
	insert into employees(employee_id,last_name,email) 
			    values(employees_seq.nextval,'test_001','[email protected]');
	insert into employees(employee_id,last_name,email) 
			    values(employees_seq.nextval,'test_002','[email protected]');
end;

mapper.xml:

<insert id="addEmps" databaseId="oracle">
	<foreach collection="emps" item="emp" open="begin" close="end;">
		 		insert into employees(employee_id,last_name,email) 
				    values(employees_seq.nextval,#{emp.lastName},#{emp.email});
	</foreach>
</insert>

方式二:利用中間表
即在oracle直接執行的語句就是:

insert into employees(employee_id,last_name,email)
	select employees_seq.nextval,lastName,email from(
		   select 'test_a_01' lastName,'test_a_e01' email from dual
		   union
		   select 'test_a_02' lastName,'test_a_e02' email from dual
		   union
		   select 'test_a_03' lastName,'test_a_e03' email from dual
     )	

mapper.xml:

<insert id="addEmps" databaseId="oracle">
	 	<!-- oracle第二種批量方式  -->
	 	insert into employees(
	 		employee_id,last_name,email
	 	) 
	 	select employees_seq.nextval,lastName,email from
	    (
			<foreach collection="emps" item="emp" separator="union">
				 	select #{emp.lastName} lastName,#{emp.email} email from dual
			</foreach>
	    )
</insert>

上邊mapper.xml優化:

<insert id="addEmps" databaseId="oracle">
    insert into employees(
	 		employee_id,last_name,email
	 	) 
	<foreach collection="emps" item="emp" separator="union"
		 				open="select employees_seq.nextval,lastName,email from("
		 				close=")">
		 				select #{emp.lastName} lastName,#{emp.email} email from dual
		 			</foreach>
</insert>

4.7 兩個內置參數

不只是方法傳遞過來的參數可以被用來判斷、取值,mybatis默認還有兩個內置參數

參數一 :_parameter
_parameter代表整個參數
接口傳遞單個參數:_parameter就是這個參數
接口傳遞多個參數:參數會被封裝爲一個map,_parameter就是代表這個map

參數二 :_databaseId
如果全局配置文件配置了databaseIdProvider標籤,則_databaseId就是代表當前數據庫的別名,如oracle、mysql等
全局配置文件:

<databaseIdProvider type="DB_VENDOR">
	<!-- 爲不同的數據庫廠商起別名 -->
	<property name="MySQL" value="mysql"/>
	<property name="Oracle" value="oracle"/>
	<property name="SQL Server" value="sqlserver"/>
</databaseIdProvider>

接口:

public List<Employee> getEmpsTestInnerParameter(Employee employee);

mapper.xml:

<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
	  		<if test="_databaseId=='mysql'">
	  			select * from tbl_employee
	  			<if test="_parameter!=null">
	  				where last_name like #{lastName}
	  			</if>
	  		</if>
	  		<if test="_databaseId=='oracle'">
	  			select * from employees
	  			<if test="_parameter!=null">
	  				where last_name like #{_parameter.lastName}
	  			</if>
	  		</if>
</select>

bind屬性
可以將OGNL表達式的值綁定到一個變量中,方便後來引用這個變量的值

<select id="getEmpsTestInnerParameter" resultType="com.atguigu.mybatis.bean.Employee">
	  	<!-- bind:將lastName的值取到後,拼接上模糊查詢%,賦值給_lastName-->
	  		<bind name="_lastName" value="'%'+lastName+'%'"/>
	  		<if test="_databaseId=='mysql'">
	  			select * from tbl_employee
	  			<if test="_parameter!=null">
	  				where last_name like #{_lastName}
	  			</if>
	  		</if>
</select>

4.8 MyBatis之sql標籤與include標籤

sql標籤抽取可重用的sql片段,方便後面引用(使用include引用)

<sql id="insertColumn">
	  employee_id,last_name,email
</sql>

引用上邊的標籤

<insert id="addEmps" databaseId="oracle">
	 	insert into employees(
	 		<!-- 引用外部定義的sql -->
	 		<include refid="insertColumn"></include>
	 	)
	 	<foreach collection="emps" item="emp" separator="union"
	 			open="select employees_seq.nextval,lastName,email from("
	 			close=")">
	 		select #{emp.lastName} lastName,#{emp.email} email from dual
	 	</foreach>
</insert>

動態判斷

<sql id="insertColumn">
  		<if test="_databaseId=='oracle'">
  			employee_id,last_name,email
  		</if>
  		<if test="_databaseId=='mysql'">
  			last_name,email,gender,d_id
  		</if>
</sql>

include還可以自定義一些property,sql標籤內部就能使用自定義的屬性
include-property:取值的正確方式${prop},#{不能使用這種方式}

<insert id="addEmps" databaseId="oracle">
	 	insert into employees(
	 		<!-- 引用外部定義的sql -->
	 		<include refid="insertColumn">
	 			<property name="testColomn" value="abc"/>
	 		</include>
	 	 )
	 	<foreach collection="emps" item="emp" separator="union"
	 			open="select employees_seq.nextval,lastName,email from("
	 			close=")">
	 		select #{emp.lastName} lastName,#{emp.email} email from dual
	 	</foreach>
</insert>

五、MyBatis緩存機制

MyBatis包含非常強大的緩存機制,可以進行方便的配置和定義,極大的提高查詢效率;MyBatis定義了兩級緩存,默認開啓一級緩存;

5.1 一級緩存

一級緩存也叫本地緩存,是sqlSession級別的緩存。一級緩存是一直開啓的,無法關閉;
SqlSession級別的一個Map:即MyBatis查出數據後,會將數據放在當前SqlSession的Map裏;
與數據庫同一次會話期間查詢到的數據會放在本地緩存中。
以後如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫;

一級緩存失效情況(沒有使用到當前一級緩存的情況,效果就是,還需要再向數據庫發出查詢):

  1. sqlSession不同。
  2. sqlSession相同,查詢條件不同.(當前一級緩存中還沒有這個數據)。
  3. sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前數據有影響)。
  4. sqlSession相同,手動清除了一級緩存(緩存清空:openSession.clearCache())。

5.2 二級緩存

二級緩存是全局緩存,基於namespace級別的緩存,即一個namespace對應一個二級緩存;
工作機制:
1、一個會話,查詢一條數據,這個數據就會被放在當前會話的一級緩存中;
2、如果會話關閉,一級緩存中的數據會被保存到二級緩存中;新的會話查詢信息,就可以查找二級緩存中的內容;
3、假如sqlSession裏有兩大塊內容:EmployeeMapper(Employee)與DepartmentMapper(Department),則二級緩存會根據不同namespace的值將這兩部門內容放在不同的Map裏存儲起來;不同namespace查出的數據會放在自己對應的緩存中(map);
效果:數據會從二級緩存中獲取,查出的數據都會被默認先放在一級緩存中。

注意:
只有會話提交或者關閉以後,一級緩存中的數據纔會轉移到二級緩存中

開啓二級緩存的步驟:

  1. 開啓全局二級緩存配置(默認已開啓):
    如果設置爲false的話,關閉的是二級緩存,不是一級緩存,一級緩存無法關閉;
<setting name="cacheEnabled" value="true"/>
  1. 去要開啓二級緩存的mapper.xml中配置使用二級緩存:
	<cache></cache>

在這裏插入圖片描述
也可以配置緩存的回收策略,即緩存太多後,刪除哪些緩存

<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
<!-- <cache eviction="FIFO" flushInterval="60000" readOnly="false" size="1024"></cache> -->
	<!--  
	eviction:緩存的回收策略:
		• LRU(默認策略) – 最近最少使用的:移除最長時間不被使用的對象。
		• FIFO – 先進先出:按對象進入緩存的順序來移除它們。
		• SOFT – 軟引用:移除基於垃圾回收器狀態和軟引用規則的對象。
		• WEAK – 弱引用:更積極地移除基於垃圾收集器狀態和弱引用規則的對象。
		• 默認的是 LRU。
	flushInterval:緩存刷新間隔
		緩存多長時間清空一次,默認不清空,設置一個毫秒值
	readOnly:是否只讀:
		true:只讀;mybatis認爲所有從緩存中獲取數據的操作都是隻讀操作,不會修改數據。
				 mybatis爲了加快獲取速度,直接就會將數據在緩存中的引用交給用戶。不安全,速度快
		false:非只讀:mybatis覺得獲取的數據可能會被修改。
				mybatis會利用序列化&反序列的技術克隆一份新的數據給你。安全,速度慢
	size:緩存存放多少元素;
	type="":指定自定義緩存的全類名;
			緩存類實現Cache接口即可;
	-->
  1. 我們的POJO需要實現序列化接口

關於緩存的設置/屬性講解

  1. cacheEnabled=false:false關閉的是二級緩存,沒有關閉一級緩存,一級緩存一直可用
  2. 每個select標籤都有一個屬性useCache=“true”:
    設置爲false:不使用二級緩存,一級緩存依然使用
  3. 每個增刪改標籤的:flushCache=“true”:(一級二級都會清除)
    增刪改執行完成後就會清楚緩存;
    測試:flushCache=“true”:一級緩存與二級都會被清除;
    查詢標籤:flushCache=“false”:
    如果flushCache=true;每次查詢之後都會清空緩存,緩存是沒有被使用的;
  4. sqlSession.clearCache()方法:只是清除當前session的一級緩存;
  5. localCacheScope:本地緩存作用域,有以下兩種取值:SESSION與STATEMENT;默認是SESSION,SESSION是一級緩存,將當前會話的所有數據保存在會話緩存中;STATEMENT:可以禁用一級緩存;

MyBatis查詢數據的順序:
先找二級緩存(因爲二級緩存範圍廣),再找一級緩存,都沒有的話再去數據庫查數據;

六、MyBatis與Spring(以及SpringMvc)整合

6.1 介紹

mybatis官網:https://github.com/mybatis
MyBatis整合Spring需要的jar包
在這裏插入圖片描述
整合文檔
在這裏插入圖片描述
各個版本對應表格
在這裏插入圖片描述
整合包下載:
在這裏插入圖片描述

6.2 SSM整合

導入需要的jar包
Spring與SpringMvc需要的jar包
在這裏插入圖片描述
MyBatis需要的jar包:
在這裏插入圖片描述
Spring與MyBatis整合的jar包
在這裏插入圖片描述
數據庫驅動需要的jar包
在這裏插入圖片描述
編寫配置文件
MyBatis全局配置文件mybatis-config.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>
	<settings>
		<setting name="mapUnderscoreToCamelCase" value="true"/>
		<setting name="jdbcTypeForNull" value="NULL"/>
		
		<!--顯式的指定每個我們需要更改的配置的值,即使他是默認的。防止版本更新帶來的問題  -->
		<setting name="cacheEnabled" value="true"/>
		<setting name="lazyLoadingEnabled" value="true"/>
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>
	
	<databaseIdProvider type="DB_VENDOR">
		<property name="MySQL" value="mysql"/>
		<property name="Oracle" value="oracle"/>
		<property name="SQL Server" value="sqlserver"/>
	</databaseIdProvider>
</configuration>

數據庫配置文件dbconfig.properties

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

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

MyBatis接口:

package com.maltose.mybatis.dao;

import java.util.List;
import com.atguigu.mybatis.bean.Employee;

public interface EmployeeMapper {
	
	public Employee getEmpById(Integer id);
	
	public List<Employee> getEmps();
}

MyBatis的mapper.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">
<mapper namespace="com.atguigu.mybatis.dao.EmployeeMapper">

	<select id="getEmpById" resultType="com.atguigu.mybatis.bean.Employee">
		select * from tbl_employee where id=#{id}
	</select>
	
	<select id="getEmps" resultType="com.atguigu.mybatis.bean.Employee">
		select * from tbl_employee
	</select>
</mapper>

配置web.xml,使得SpringMvc的IOC容器跟隨項目一起啓動

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>classpath:applicationContext.xml</param-value>
</context-param>

<!-- Bootstraps the root web application context before servlet initialization -->
<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

配置web.xml,添加SpringMvc的配置文件

<servlet>
		<servlet-name>spring</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
<servlet-mapping>
		<servlet-name>spring</servlet-name>
		<url-pattern>/</url-pattern>
</servlet-mapping>

spring配置文件applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- Spring希望管理所有的業務邏輯組件,等。。。 -->
	<context:component-scan base-package="com.maltose.mybatis">
	    <!--除了Controller控制器不掃描以外,其他都掃描-->
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>

	<!-- 引入數據庫的配置文件 -->
	<context:property-placeholder location="classpath:dbconfig.properties" />
	<!-- Spring用來控制業務邏輯。數據源、事務控制、aop -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>
	<!-- spring事務管理 -->
	<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<!-- 開啓基於註解的事務 -->
	<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
	
	<!-- 
	整合mybatis 
		目的:1、spring管理所有組件,包含mapper的實現類。
				service==>Dao   @Autowired:自動注入mapper,不需要再自己創建openSession了;
			 2、spring用來管理事務,spring聲明式事務
	-->
	<!--創建出SqlSessionFactory對象  -->
	<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<!-- configLocation指定全局配置文件的位置 -->
		<property name="configLocation" value="classpath:mybatis-config.xml"></property>
		<!--mapperLocations: 指定mapper文件的位置-->
		<property name="mapperLocations" value="classpath:mybatis/mapper/*.xml"></property>
	</bean>
	
	<!--配置一個可以進行批量執行的sqlSession  -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
		<constructor-arg name="executorType" value="BATCH"></constructor-arg>
	</bean>
	
	<!-- 掃描所有的mapper接口的實現,讓這些mapper能夠自動注入;
	base-package:指定mapper接口的包名
	 -->
	<mybatis-spring:scan base-package="com.atguigu.mybatis.dao"/>
	<!-- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.atguigu.mybatis.dao"></property>
	</bean> -->
	
</beans>

在web.xml同級目錄創建SpringMvc的配置文件spring-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!--SpringMVC只是控制網站跳轉邏輯,即只管Controller  -->
	<!-- 只掃描控制器 -->
	<context:component-scan base-package="com.maltose.mybatis" use-default-filters="false">
	    <!--只掃描當前包下標了@Controller註解的類-->
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!-- 視圖解析器,解析頁面地址 -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<mvc:annotation-driven></mvc:annotation-driven>
	<mvc:default-servlet-handler/>
</beans>

6.3 MyBatis逆向工程—MBG

MyBatis逆向工程,即代碼生成器,根據數據庫裏的表,創建出對應的javaBean、接口、mapper.xml文件

下載代碼生成器

官網地址:https://github.com/mybatis
在這裏插入圖片描述
官方使用文檔以及下載代碼生成器:

在這裏插入圖片描述
點擊下載即可:
在這裏插入圖片描述
使用MyBatis代碼生成器

解壓後將下邊這個包導入到項目裏
在這裏插入圖片描述
官方使用介紹:http://mybatis.org/generator/quickstart.html

在項目根目錄下創建配置文件mbg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
  PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
  "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

	<!-- 
		targetRuntime="MyBatis3Simple":生成簡單版的CRUD
		MyBatis3:豪華版
	
	 -->
  <context id="DB2Tables" targetRuntime="MyBatis3Simple">
  	<!-- jdbcConnection:指定如何連接到目標數據庫 -->
    <jdbcConnection driverClass="com.mysql.jdbc.Driver"
        connectionURL="jdbc:mysql://localhost:3306/mybatis?allowMultiQueries=true"
        userId="root"
        password="123456">
    </jdbcConnection>

	<!-- java類型解析器 -->
    <javaTypeResolver >
      <property name="forceBigDecimals" value="false" />
    </javaTypeResolver>

	<!-- javaModelGenerator:指定javaBean的生成策略 
	targetPackage="test.model":生成的目標javaBean包名
	targetProject="\MBGTestProject\src":目標工程
	-->
    <javaModelGenerator targetPackage="com.maltose.mybatis.bean" 
    		targetProject=".\src">
      <property name="enableSubPackages" value="true" />
      <property name="trimStrings" value="true" />
    </javaModelGenerator>

	<!-- sqlMapGenerator:sql映射生成策略: -->
    <sqlMapGenerator targetPackage="com.atguigu.mybatis.dao"  
    	targetProject=".\conf">
      <property name="enableSubPackages" value="true" />
    </sqlMapGenerator>

	<!-- javaClientGenerator:指定mapper接口所在的位置 -->
    <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.dao"  
    	targetProject=".\src">
      <property name="enableSubPackages" value="true" />
    </javaClientGenerator>

	<!-- 指定要逆向分析哪些表:根據表要創建javaBean,domainObjectName只對應的javaBean -->
    <table tableName="tbl_dept" domainObjectName="Department"></table>
    <table tableName="tbl_employee" domainObjectName="Employee"></table>
  </context>
</generatorConfiguration>

新建一個測試類,加入如下方法:

package com.maltose.mybatis.test;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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 org.junit.Test;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.internal.DefaultShellCallback;

import com.atguigu.mybatis.bean.Employee;
import com.atguigu.mybatis.bean.EmployeeExample;
import com.atguigu.mybatis.bean.EmployeeExample.Criteria;
import com.atguigu.mybatis.dao.EmployeeMapper;

public class MyBatisTest {
	@Test
	public void testMbg() throws Exception {
		List<String> warnings = new ArrayList<String>();
		boolean overwrite = true;
		File configFile = new File("mbg.xml");
		ConfigurationParser cp = new ConfigurationParser(warnings);
		Configuration config = cp.parseConfiguration(configFile);
		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config,
				callback, warnings);
		myBatisGenerator.generate(null);
	}
}

執行完上邊的方法後,就會生成相應的文件;

代碼生成器生成複雜邏輯的文件
以上是生成簡單的增刪改查文件,其實代碼生成器也支持生成複雜的邏輯,如帶條件的查詢等等,將配置文件裏的targetRuntime="MyBatis3Simple"改爲targetRuntime="MyBatis3"即可;

七、MyBatis分頁插件之PageHelper

官網:https://github.com/pagehelper/Mybatis-PageHelper
在這裏插入圖片描述
添加依賴

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>x.x.x</version>
</dependency>

接口:

public List<Employee> getEmps();

mapper.xml:

<select id="getEmps" resultType="com.atguigu.mybatis.bean.Employee">
	select id,last_name lastName,email,gender from tbl_employee
</select>

在MyBatis全局配置文件裏配置攔截器

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

使用PageHelper實現分頁:

EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//獲取第2頁,每頁顯示三條數據
Page<Object> page = PageHelper.startPage(2, 3);
//執行下邊的查詢方法之前,執行上邊的分頁邏輯,得到的結果就是分頁後的數據	
List<Employee> emps = mapper.getEmps();
System.out.println("當前頁碼:"+page.getPageNum());
System.out.println("總記錄數:"+page.getTotal());
System.out.println("每頁的記錄數:"+page.getPageSize());
System.out.println("總頁碼:"+page.getPages());

使用PageInfo獲取更多分頁數據:

EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Page<Object> page = PageHelper.startPage(5, 1);
List<Employee> emps = mapper.getEmps();
//第二個參數:傳入要連續顯示多少頁
PageInfo<Employee> info = new PageInfo<>(emps, 5);

System.out.println("當前頁碼:"+info.getPageNum());
System.out.println("總記錄數:"+info.getTotal());
System.out.println("每頁的記錄數:"+info.getPageSize());
System.out.println("總頁碼:"+info.getPages());
System.out.println("是否第一頁:"+info.isIsFirstPage());

八、MyBatis批量操作—BATCH

MyBatis未與Spring整合時實現批量操作

獲取openSession 時,傳入BATCH參數

    @Test
	public void testBatch() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		
		//可以執行批量操作的sqlSession
		SqlSession openSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
		long start = System.currentTimeMillis();
		try{
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			for (int i = 0; i < 10000; i++) {
				mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), "b", "1"));
			}
			openSession.commit();
			long end = System.currentTimeMillis();
			//批量操作耗時:(預編譯sql一次==>設置參數===>10000次===>執行(1次))
			//Parameters: 616c1(String), b(String), 1(String)==>4598
			//非批量操作耗時:(預編譯sql=設置參數=執行)==》10000    10200
			System.out.println("執行時長:"+(end-start));
		}finally{
			openSession.close();
		}
	}

MyBatis與spring整合之後,實現批量操作

applicationContext.xml裏添加批量操作的配置

<!--配置一個可以進行批量執行的sqlSession  -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactoryBean"></constructor-arg>
	<constructor-arg name="executorType" value="BATCH"></constructor-arg>
</bean>

配置完後,代碼裏使用:

package com.maltose.mybatis.service;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.maltose.mybatis.bean.Employee;
import com.maltose.mybatis.dao.EmployeeMapper;

@Service
public class EmployeeService {

	@Autowired
	private SqlSession sqlSession;
	
	public List<Employee> getEmps(){
		EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);
		return mapper .getEmps();
	}
}

九、MyBatis操作存儲過程

場景:oracle實現分頁

分頁javaBean

package com.maltose.mybatis.bean;

import java.util.List;

/**
 * 封裝分頁查詢數據
 * @author sgw
 *
 */
public class OraclePage {
	
	private int start;
	private int end;
	private int count;
	private List<Employee> emps;
	
	public int getStart() {
		return start;
	}
	public void setStart(int start) {
		this.start = start;
	}
	public int getEnd() {
		return end;
	}
	public void setEnd(int end) {
		this.end = end;
	}
	public int getCount() {
		return count;
	}
	public void setCount(int count) {
		this.count = count;
	}
	public List<Employee> getEmps() {
		return emps;
	}
	public void setEmps(List<Employee> emps) {
		this.emps = emps;
	}
}

在oracle裏編寫一個分頁的存儲過程
在這裏插入圖片描述
MyBatis調用存儲過程來完成分頁

接口:

public void getPageByProcedure(OraclePage page);

mapper.xml:

<!--
	1、使用select標籤定義調用存儲過程
	2、statementType="CALLABLE":表示要調用存儲過程
	3、{call procedure_name(params)}
-->
<select id="getPageByProcedure" statementType="CALLABLE" databaseId="oracle">
		{call hello_test(
			#{start,mode=IN,jdbcType=INTEGER},
			#{end,mode=IN,jdbcType=INTEGER},
			#{count,mode=OUT,jdbcType=INTEGER},
			#{emps,mode=OUT,jdbcType=CURSOR,javaType=ResultSet,resultMap=PageEmp}
		)}
</select>

<resultMap type="com.atguigu.mybatis.bean.Employee" id="PageEmp">
	<id column="EMPLOYEE_ID" property="id"/>
	<result column="LAST_NAME" property="email"/>
	<result column="EMAIL" property="email"/>
</resultMap>

代碼調用的實現

    @Test
	public void testProcedure() throws IOException{
		SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
		SqlSession openSession = sqlSessionFactory.openSession();
		try{
			EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
			OraclePage page = new OraclePage();
			page.setStart(1);
			page.setEnd(5);
			mapper.getPageByProcedure(page);
			
			System.out.println("總記錄數:"+page.getCount());
			System.out.println("查出的數據:"+page.getEmps().size());
			System.out.println("查出的數據:"+page.getEmps());
		}finally{
			openSession.close();
		}
     }
發佈了45 篇原創文章 · 獲贊 12 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章