一、介紹
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指定爲全類名
- type:事務管理器的類型(有以下兩種事務管理器):
- dataSource:數據源
- type:數據源類型
UNPOOLED(UnpooledDataSourceFactory)不使用連接池
POOLED(PooledDataSourceFactory)使用連接池
JNDI(JndiDataSourceFactory)使用連接池
自定義數據源:實現DataSourceFactory接口,type是全類名
- 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映射
方式一:註冊配置文件
- resource:引用類路徑下的sql映射文件
mybatis/mapper/EmployeeMapper.xml
- url:引用網路路徑或者磁盤路徑下的sql映射文件
file:///var/mappers/AuthorMapper.xml
<mappers>
<mapper resource="mybatis/mapper/EmployeeMapper.xml"/>
</mappers>
方式二:註冊接口
class:引用(註冊)接口,
- 有sql映射文件,映射文件名必須和接口同名,並且放在與接口同一目錄下;
- 沒有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();
}
}
- mybatis允許增刪改直接定義以下類型返回值
Integer、Long、Boolean、void - 有以下兩種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
從參數中取值進行判斷
遇見特殊符號應該去寫轉義字符:
"":指的是'',即空字符;
&&:指的是&&,即條件與;
-->
<if test="id!=null">
id=#{id}
</if>
<if test="lastName!=null && lastName!=""">
and last_name like #{lastName}
</if>
<if test="email!=null and email.trim()!=""">
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 && lastName!=""">
last_name like #{lastName} and
</if>
<if test="email!=null and email.trim()!=""">
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裏;
與數據庫同一次會話期間查詢到的數據會放在本地緩存中。
以後如果需要獲取相同的數據,直接從緩存中拿,沒必要再去查詢數據庫;
一級緩存失效情況(沒有使用到當前一級緩存的情況,效果就是,還需要再向數據庫發出查詢):
- sqlSession不同。
- sqlSession相同,查詢條件不同.(當前一級緩存中還沒有這個數據)。
- sqlSession相同,兩次查詢之間執行了增刪改操作(這次增刪改可能對當前數據有影響)。
- sqlSession相同,手動清除了一級緩存(緩存清空:openSession.clearCache())。
5.2 二級緩存
二級緩存是全局緩存,基於namespace級別的緩存,即一個namespace對應一個二級緩存;
工作機制:
1、一個會話,查詢一條數據,這個數據就會被放在當前會話的一級緩存中;
2、如果會話關閉,一級緩存中的數據會被保存到二級緩存中;新的會話查詢信息,就可以查找二級緩存中的內容;
3、假如sqlSession裏有兩大塊內容:EmployeeMapper(Employee)與DepartmentMapper(Department),則二級緩存會根據不同namespace的值將這兩部門內容放在不同的Map裏存儲起來;不同namespace查出的數據會放在自己對應的緩存中(map);
效果:數據會從二級緩存中獲取,查出的數據都會被默認先放在一級緩存中。
注意:
只有會話提交或者關閉以後,一級緩存中的數據纔會轉移到二級緩存中
開啓二級緩存的步驟:
- 開啓全局二級緩存配置(默認已開啓):
如果設置爲false的話,關閉的是二級緩存,不是一級緩存,一級緩存無法關閉;
<setting name="cacheEnabled" value="true"/>
- 去要開啓二級緩存的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接口即可;
-->
- 我們的POJO需要實現序列化接口
關於緩存的設置/屬性講解
- cacheEnabled=false:false關閉的是二級緩存,沒有關閉一級緩存,一級緩存一直可用
- 每個select標籤都有一個屬性useCache=“true”:
設置爲false:不使用二級緩存,一級緩存依然使用 - 每個增刪改標籤的:flushCache=“true”:(一級二級都會清除)
增刪改執行完成後就會清楚緩存;
測試:flushCache=“true”:一級緩存與二級都會被清除;
查詢標籤:flushCache=“false”:
如果flushCache=true;每次查詢之後都會清空緩存,緩存是沒有被使用的; - sqlSession.clearCache()方法:只是清除當前session的一級緩存;
- 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();
}
}