一、簡介
(一)什麼是MyBatis
1.概念:
MyBatis 是一款優秀的持久層框架,它支持定製化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBatis 可以使用簡單的 XML 或註解來配置和映射原生類型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 對象)爲數據庫中的記錄。
2.發展歷史:
MyBatis原來不叫MyBatis ,本是apache的一個開源項目iBatis,2010年這個項目遷移到了google code,並且改名爲MyBatis 。2013年11月遷移到Github。Github託管MyBatis地址
(二)什麼是持久層
持久是相對於瞬時來說的,其實就是可以把數據固化在硬盤或者磁帶一類可以保存很長時間的設備上,不像放在內存中一樣斷電就消失了。企業應用中數據很重要(各種訂單數據、客戶數據、庫存數據之類的),比應用程序本身更重要,所以需要把數據持久化。
一般地,持久更爲直接的理解就是對數據庫的各種操作,如CRUD(增加、刪除、修改、查詢)等操作,需要將已改變的數據保存起來。
持久層,就是把持久的動作封裝成一個獨立的層,這是爲了降低功能代碼之間的關聯,創建一個更清晰的抽象,提高代碼的內聚力,降低代碼的耦合度(高內聚,低耦合),從而使程序間以及程序內部都能夠獨立於其他程序,增加程序的可維護性、移植性和可重用性等等。
思考:持久層對應我們代碼架構的哪一層?
答:DAO層,它專注於處理數據庫的操作,這種方式開發效率低,要寫一堆JDBC的重複代碼。而我們更應該專注於SQL語句編寫,獲得SQL的返回值即可。
問:實現持久層的框架有哪些?
答:
- Hibernate:全自動的ORM(對象關係映射)框架,可以自動生成SQL語句,自動執行。
- MyBatis:半自動的ORM框架,需要我們自己編寫SQL語句。
(三)MyBatis的優缺點
優點:
-
簡潔:不用再去編寫一堆JDBC代碼,代碼量大大減少。
-
簡單易學:MyBatis是最簡單的持久化框架,小巧且容易上手。
-
靈活:不會對應用程序或者數據庫的現有設計強加任何影響,SQL寫在XML裏,便於統一管理和優化。
-
提供XML標籤,支持編寫動態SQL語句。
-
提供映射標籤,支持對象與數據庫的ORM字段關係映射。
-
實現解耦:通過提供DAO層,將SQL語句和程序代碼分離,使系統的設計更清晰,方便單元測試,降低了耦合度,提高了可維護性。
缺點:
-
字段多、關聯表多時,SQL語句的編寫工作量較大,要求開發人員要熟練掌握SQL語句的編寫。
-
SQL語句依賴於數據庫,導致數據庫移植性差,不能隨意更換數據庫。
(四)MyBatis和Hibernate的區別【面試題】
相同點:
- 都屬於ORM(對象關係映射)框架
- 都屬於持久層框架
- 都是對JDBC的包裝
不同點:
- 開發工作量方面:Hibernate是全自動的框架,MyBatis是半自動的框架,這是最大的區別。Hibernate因爲有良好的映射機制,可以自動生成SQL語句,不必手動編寫SQL語句,開發者可以無需擔心SQL的生成和結果映射,而是更關注於業務流程;而MyBatis必須手動編寫SQL語句以及結果映射(resultMap)。因此,MyBatis較Hibernate的開發工作量大。
- 移植性方面:Hibernate具有強大的數據庫無關性,可跨數據庫使用;而MyBatis的所有SQL語句依賴於數據庫,導致數據庫移植性差,不能隨意更換數據庫。
- SQL優化方面:Hibernate的查詢會將表中的所有字段查詢出來,這一點會有性能消耗;而Mybatis的SQL是手動編寫的,所以可以按需求指定查詢的字段。
- 日誌系統方面:Hibernate擁有完整的日誌系統,而MyBatis需要依靠log4j來實現。
- 開發速度方面:對於大型項目,複雜語句較多,選擇MyBatis就會加快許多,其簡單易上手,而且語句的管理也比較方便。
二、MyBatis使用入門
(一)準備一個數據庫
CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` INT(20) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES (1,'小明','123456'),(2,'小紅','abcdef'),(3,'小李','987654');
(二)創建一個Maven項目
目錄結構如下:
pom.xml文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.fox</groupId>
<artifactId>ssm-mybatis-study</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!--爲了方便單元測試,導入了Junit的依賴-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<!--mybatis的包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--連接數據庫的驅動包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
</dependencies>
<build>
<!--希望maven在導出項目的時,能夠將我們的配置及資源導出-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
(三)創建實體類
User類: 對應數據庫的user表
package com.fox.pojo;
public class User {
private int id;
private String name;
private String pwd;
public User() {
}
public User(int id, String name, String pwd) {
this.id = id;
this.name = name;
this.pwd = pwd;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", pwd='" + pwd + '\'' +
'}';
}
}
(四)編寫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>
<!--配置環境,這裏可以有多套環境 default代表默認的是那一套-->
<environments default="development">
<!--配置一套環境 id .環境的名字-->
<environment id="development">
<!--transactionManager:事務管理,用於決定事務作用域和控制方式-->
<transactionManager type="JDBC"/>
<!--dataSource 數據源-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<!--xml中不允許&符號直接出現,我們需要使用 & 代替-->
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
</configuration>
(五)創建工具類
每個基於 MyBatis 的應用都是以一個 SqlSessionFactory 的實例爲核心的。SqlSessionFactory 的實例可以通過 SqlSessionFactoryBuilder 獲得。而 SqlSessionFactoryBuilder 則可以從 XML 配置文件或一個預先定製的 Configuration 的實例構建出 SqlSessionFactory 的實例。
目的:爲了避免每次都需要寫獲得SqlSessionFactory實例(對象)的代碼,將這一步封裝爲工具類。
MyBatisUtils:
package com.fox.utils;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
//mybatis的工具類,避免重複代碼
public class MyBatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";//在maven中,所有的資源文件一般都放在resources目錄下,我們可以直接以resources爲根目錄拿到其下面的資源。
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//設置SqlSessionFactory公共的方法
public static SqlSessionFactory getSqlSessionFactory(){
return sqlSessionFactory;
}
}
(六)映射文件的接口,對應原來的dao接口
UserMapper接口: (相當於單體地獄中的DAO層的接口)
package com.fox.dao;
import com.fox.pojo.User;
import java.util.List;
public interface UserMapper {
//List集合獲取全部的用戶
List<User> selectUser();
}
(七)編寫對應的mapper映射文件
userMapper.xml: 在一個 XML 映射文件中,可以定義無數個映射語句。(映射文件相當於單體地獄模式中DAO的實現類)一個接口對應一個Mapper映射文件。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper標籤的namespace對應 Mapper接口的類-->
<mapper namespace="com.fox.dao.UserMapper">
<!--select標籤的id對應映射接口的方法名字 resultType:返回結果的類型 中間就編寫sql語句-->
<select id="selectUser" resultType="com.fox.pojo.User">
select * from user
</select>
</mapper>
(八)在mybatis配置文件中關聯映射文件
在原先寫好的mybatis-config.xml中的</configuration>
前面加上:
<!--關聯映射文件-->
<mappers>
<mapper resource="com/fox/dao/userMapper.xml"/>
</mappers>
(九)測試運行
在maven的test文件夾下編寫對應的測試類UserMapperTest:
package com.fox.dao;
import com.fox.pojo.User;
import com.fox.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void selectUser(){
//1.拿到sqlSessionFactory對象
SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
//2.通過sqlSessionFactory對象openSession()創建一個sqlSession。
SqlSession sqlSession = sqlSessionFactory.openSession();
//3.通過sqlSession獲得mapper對象 , 參數爲映射文件對應的接口類的class對象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
//4.通過mapper對象來執行操作;
List<User> users = mapper.selectUser();
//獲得結果集
for (User user : users) {
System.out.println(user);
}
}
}
(十)運行結果
這樣便通過MyBatis執行了select * from user
語句:
三、MyBatis中的增刪改查操作
Mapper接口本質就是原來的DAO接口,一個Mapper接口對應一個Mapper映射文件。
目錄結構:
(一)編寫接口
UserDao:
package com.fox.dao;
import com.fox.pojo.User;
public interface UserDao {
//根據id查找用戶
User selectUserById(int id);
//添加一個用戶
int addUser(User user);
//刪除用戶
int deleteUserByID(int id);
//修改用戶
int updateUser(User user);
}
(二)編寫對應的Mapper映射文件
userMapper.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對應 Mapper接口的類,包名+類名-->
<mapper namespace="com.fox.dao.UserDao">
<!--select標籤的id對應映射接口的方法名字 resultType:返回結果的類型 中間就編寫sql語句-->
<select id="selectUserById" resultType="com.fox.pojo.User">
select * from user where id = #{id}
</select>
<!--
我們需要接收一個自定義的對象(引用對象),需要設置parameterType,爲參數類型
接受這個對象的值,直接使用 #{對象字段名}
返回類型爲基本類型可以不用聲明resultType
-->
<insert id="addUser" parameterType="com.fox.pojo.User">
insert into user(id ,name, pwd) values (#{id},#{name},#{pwd})
</insert>
<delete id="deleteUserByID" parameterType="int">
delete from user where id = #{id}
</delete>
<update id="updateUser" parameterType="com.fox.pojo.User">
update user set name =#{name},pwd = #{pwd} where id = #{id}
</update>
</mapper>
(三)編寫測試類
UserMapperTest: 通過單元測試分別進行增刪改查操作
package com.fox.dao;
import com.fox.pojo.User;
import com.fox.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
public class UserMapperTest {
//查詢操作
@Test
public void selectUserById(){
SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
//接口 對象名 = new 接口實現類
User user = mapper.selectUserById(1);
System.out.println(user);
sqlSession.close(); //關閉sqlSession
}
//增加操作
@Test
public void addUser(){
User user = new User(4,"小張","666666");
SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
//i爲被影響的行數
int i = mapper.addUser(user);
//提交事務才能插入成功
sqlSession.commit(); //提交事務
sqlSession.close(); //關閉sqlSession
if (i>0){
System.out.println("插入成功!");
}
}
//刪除操作
@Test
public void deleteUserByID(){
SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
int i = mapper.deleteUserByID(4);
//記得提交事務,否則刪除不成功!
sqlSession.commit();//提交事務
sqlSession.close();//關閉
if (i>0){
System.out.println("刪除成功!");
}
}
//修改操作
@Test
public void updateUser(){
SqlSessionFactory sqlSessionFactory = MyBatisUtils.getSqlSessionFactory();
SqlSession sqlSession = sqlSessionFactory.openSession();
UserDao mapper = sqlSession.getMapper(UserDao.class);
User user = new User(1,"小趙","777777");
int i = mapper.updateUser(user);
sqlSession.commit();
sqlSession.close();
if (i>0){
System.out.println("修改成功!");
}
}
}
User類、MyBatisUtils工具類和mybatis-config.xml文件參考上面入門案例,不變。
(四)運行結果
1. 根據id查找用戶信息
2.插入一個用戶
3.刪除一個用戶
4.修改一個用戶
注意:
-
增刪改操作一定要記得提交事務,否則操作不成功!
-
Mapper映射文件中的參數
如果是基本數據類型,可以省略resultType,但建議寫上 ;
如果是引用類型必須寫指定的 包名+類名。