目錄
1 引導
框架的概念在以前的博文中也有提到,此處簡單說明下,框架實質是軟件開發中的一套解決方案,不同的框架解決的是不同的問題。
1)使用框架的好處:框架封裝了很多細節,開發者可以很簡單的實現某些功能,提高開發效率;
2)框架解決了什么問題?
看下三層架構和SSM框架的對應關系,MyBatis框架是解決的持久層的問題,與數據庫交互,進行增刪改查操作的。
3)持久層技術解決方案有哪些?
- JDBC技術:Connection、PreparedStatement、ResultSet;
- Spring的JdbcTemplate:Spring對Jdbc的簡單封裝;
- Apache的DBUtils,和Spring的JdbcTemplate類似,也是對Jdbc的簡單封裝;
以上都不是框架,JDBC是規范,后兩者都只是工具類,是對規范的實現,沒有系統的解決方案。
以前使用傳統jdbc的步驟很多,操作繁雜,我們要實現一個需求的功能,從數據庫表中查找一個結果,希望沒有這么多繁雜的操作步驟,把焦點放在功能的實現上即可,實現高效率開發,MyBatis框架就是幫我們解決這些問題的。
2 MyBatis框架入門
MyBatis是一個基於Java的持久層框架,封裝了jdbc操作的細節,開發者只需要關注sql語句本身,不需要關注注冊驅動、創建連接、創建statement等過程,它使用了ORM思想實現了結果集封裝。
注:ORM,Object Relational Mapping對象關系映射,就是把數據庫表和實體類的屬性對應起來,讓我們可以操作實體類就可以操作數據庫表。我們需要保證實體類屬性和數據庫表的字段名稱保持一致,有一個好習慣;
2.1 MyBatis環境搭建
下面以一個案例形式一步步看下如何搭建MyBatis環境。
1)准備數據庫,在本地數據庫db4中新建一個user表,插入數據:
-
CREATE DATABASE db4;
-
USE db4;
-
CREATE TABLE USER (
-
id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
-
username VARCHAR(32) NOT NULL COMMENT '用戶名稱',
-
birthday DATETIME DEFAULT NULL COMMENT '生日',
-
sex VARCHAR(1) DEFAULT NULL COMMENT '性別',
-
address VARCHAR(256) DEFAULT NULL COMMENT '地址'
-
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-
-
INSERT INTO `user`(`id`,`username`,`birthday`,`sex`,`address`) VALUES (1,'老王','2018-02-27 17:47:08','男','北京'),(2,'李四','2018-03-02 15:09:37','女','上海'),(3,'王五','2018-03-04 11:34:34','女','南京');
2)新建Maven工程,不使用模板,此處不展開了,需要回顧的可以看上一篇博文;
3)配置pom.xml文件,導入相關的jar包坐標:
-
-
<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.winter</groupId>
-
<artifactId>19.mybatis</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
-
<packaging>jar</packaging>
-
-
<dependencies>
-
<dependency>
-
<groupId>org.mybatis</groupId>
-
<artifactId>mybatis</artifactId>
-
<version>3.4.5</version>
-
</dependency>
-
-
<dependency>
-
<groupId>mysql</groupId>
-
<artifactId>mysql-connector-java</artifactId>
-
<version>5.1.6</version>
-
</dependency>
-
-
<dependency>
-
<groupId>log4j</groupId>
-
<artifactId>log4j</artifactId>
-
<version>1.2.12</version>
-
</dependency>
-
-
<dependency>
-
<groupId>junit</groupId>
-
<artifactId>junit</artifactId>
-
<version>4.10</version>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
</project>
4)寫一個User實體類,實現Serializable,數據庫表對應
-
public class User implements Serializable {
-
private Integer id;
-
private String username;
-
private Date birthday;
-
private String sex;
-
private String address;
-
-
public Integer getId() {
-
return id;
-
}
-
-
public void setId(Integer id) {
-
this.id = id;
-
}
-
-
public String getUsername() {
-
return username;
-
}
-
-
public void setUsername(String username) {
-
this.username = username;
-
}
-
-
public Date getBirthday() {
-
return birthday;
-
}
-
-
public void setBirthday(Date birthday) {
-
this.birthday = birthday;
-
}
-
-
public String getSex() {
-
return sex;
-
}
-
-
public void setSex(String sex) {
-
this.sex = sex;
-
}
-
-
public String getAddress() {
-
return address;
-
}
-
-
public void setAddress(String address) {
-
this.address = address;
-
}
-
-
-
public String toString() {
-
return "User{" +
-
"id=" + id +
-
", username='" + username + '\'' +
-
", birthday=" + birthday +
-
", sex='" + sex + '\'' +
-
", address='" + address + '\'' +
-
'}';
-
}
-
}
5)寫一個User的持久層接口
-
//User的持久層接口
-
public interface UserDao {
-
List<User> findAll();
-
}
至此,准備工作OK了,下面看下MyBatis的環境。
6)在resources包下新建SqlMapConfig.xml文件作為MyBatis的主配置文件,其中做兩件事:
- 配置MySQL的環境:事務類型、連接池、四個基本信息(驅動、url、用戶名、密碼);
- 指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件;
-
-
-
-
-
<!--mybatis的主配置文件 -->
-
<configuration>
-
<!--配置環境 -->
-
<environments default="mysql">
-
<!--配置mysql環境 -->
-
<environment id="mysql">
-
<!--配置事務類型 -->
-
<transactionManager type="JDBC"></transactionManager>
-
<!--配置數據源(連接池) -->
-
<dataSource type="POOLED">
-
<!--配置連接數據庫的四個基本信息 -->
-
<property name="driver" value="com.mysql.jdbc.Driver"/>
-
<property name="url" value="jdbc:mysql://localhost:3306/db4"/>
-
<property name="username" value="root"/>
-
<property name="password" value="root"/>
-
</dataSource>
-
</environment>
-
</environments>
-
<!--指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件 -->
-
<mappers>
-
<mapper resource="com/winter/dao/UserDao.xml"></mapper>
-
</mappers>
-
</configuration>
7)新建每個dao的獨立配置文件,注意三件事:
- 在resources包下新建com.winter.dao三級包(mybatis映射配置文件必須和dao接口的包結構相同),命名為UserDao.xml,和SqlMapConfig.xml中指定的名字要一致;
- mapper標簽下的namespace屬性要是UserDao接口的全限定類名;
- 操作配置(select標簽中配置sql語句)中id屬性要與UserDao接口中的方法名字一致;
-
-
-
-
-
-
<mapper namespace="com.winter.dao.UserDao">
-
<!--配置查詢所有 -->
-
<select id="findAll">
-
select * from user
-
</select>
-
</mapper>
映射配置文件中的限制很多,這么做的好處是什么呢?我們不需要再寫dao的實現類了!(上述的獨立配置文件還有點小問題,你發現了嗎?沒有的話繼續閱讀下文:))
完成以上后,工程目錄結構如下:
2.2 MyBatis入門案例實戰
2.2.1 MyBatis讀取數據庫的入門案例實戰
在上一節環境搭建的基礎上,我們看下如何使用MyBatis,使用的步驟是怎樣的,可以總結為如下幾個步驟:
- 1)讀取配置文件;
- 2)創建SqlSessionFactory工廠;
- 3)使用工廠生產SqlSession對象;
- 4)使用SqlSession創建Dao接口的代理對象;
- 5)使用代理對象執行方法;
- 6)釋放資源。
在src.test.java.com.winter.test包下新建一個測試類MyBatisTest.java:
-
public class MyBatisTest {
-
//MyBatis入門案例
-
-
public void test() throws Exception{
-
//1、讀取配置文件
-
InputStream in = Resources.getResourceAsStream( "SqlMapConfig.xml");
-
//2、創建SqlSessionFactory工廠
-
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
-
SqlSessionFactory factory = builder.build(in);
-
//3、使用工廠生產SqlSession對象
-
SqlSession session = factory.openSession();
-
//4、使用SqlSession創建Dao接口的代理對象
-
UserDao userDao = session.getMapper(UserDao.class);
-
// 5、使用代理對象執行方法
-
List<User> users = userDao.findAll();
-
for (User user : users) {
-
System.out.println(user);
-
}
-
//6、釋放資源
-
session.close();
-
in.close();
-
}
-
}
【運行測試】:發現如下異常問題出現:
### Error querying database. Cause: org.apache.ibatis.executor.ExecutorException: A query was run and no Result Maps were found for the Mapped Statement 'com.winter.dao.UserDao.findAll'. It's likely that neither a Result Type nor a Result Map was specified. |
我們在UserDao.xml里面寫了sql查詢語句,但是MyBatis不知道查詢結果要封裝到哪里去,所以要在UserDao.xml中對應提供另一個指定的對象類型,修正后的UserDao.xml如下:
-
-
-
-
-
-
<mapper namespace="com.winter.dao.UserDao">
-
<!--配置查詢所有 -->
-
<select id="findAll" resultType="com.winter.domain.User">
-
select * from user
-
</select>
-
</mapper>
再次運行測試OK:
【小插曲——調試問題】:開始MyBatisTest中使用public static void main(String[] args)方法測試,但是運行時始終報錯:
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:3.0.0:exec (default-cli) on project 19.mybatis: Command execution failed.
網上查找各種解決方法,如項目的java版本配置和JDK要一致等等,最后都沒解決,懷疑是Maven支持的JDK版本問題,我的是14.0.1,最后通過junit解決,@Test注解運行就可以了。
2.2.2 入門案例設計模式分析
基於上述案例,分析下設計模式。
1)讀取配置文件
不建議使用絕對路徑,或相對路徑,不夠靈活,實際項目中多使用以下兩種:
- 使用類加載器,它只能讀取類路徑的配置文件;
- 使用ServletContext對象的getRealPath();
2)創建SqlSessionFactory工廠
MyBatis使用了構建者模式,把對象的創建細節隱藏,使用者直接調用方法即可獲取對象。像我們自己蓋廠房一樣,不是事事親為,我們找個包工隊,告訴需求,給錢即可:
- SqlSessionFactoryBuilder類似於包工隊;
- in類似於我們給的錢;
3)創建SqlSession對象
使用了工廠模式,降低了類之間的依賴關系
4)創建dao接口的代理對象
使用了代理模式,不修改源碼的基礎上對已有方法增強;
2.2.3 MaBatis基於注解的入門案例
以上基於xml的實現方式是不是感覺有些麻煩,映射配置文件有很多要對應的關系,下面來看下比較簡單的方式,使用注解,相比於xml,主要改變在於:
- 移除UserDao.xml,在dao接口的方法上使用@Select注解,並且指定SQL語句;
- 在SqlMapConfig.xml中的mapper配置時,使用class屬性指定dao接口的全限定類名。
【UserDao接口】:
-
public interface UserDao {
-
-
List<User> findAll();
-
}
【SqlMapConfig.xml中mapper配置】:
-
<!--指定映射配置文件的位置,映射配置文件指的是每個dao獨立的配置文件
-
若使用注解配置,應該使用class屬性指定被注解的dao全限定類名
-
-->
-
<mappers>
-
<mapper class="com.winter.dao.UserDao"></mapper>
-
</mappers>
【注意】:實際MyBatis也是支持寫dao實現類的,但是實際開發中追求的理念就是越簡單越好,無論是xml還是注解形式,一般都是不寫dao實現類。