Mybatis概覽
ORM是什么?
ORM是Object Realtion Mapping的縮寫,顧名思義,即對象關系映射。
ORM是一種以面向對象的方式來進行數據庫操作的技術。Web開發中常用的語言,都會有對應的ORM框架,而Mybatis就是Java開發中一種常用的ORM框架。
簡單地理解,通過Java進行數據庫訪問的正常流程可以分為以下幾步:
- 准備好SQL語句
- 調用JDBC的API傳入SQL語句,設置參數
- 解析JDBC返回的結果
這個過程實際上非常麻煩,比如:
- 在Java代碼中拼接SQL非常麻煩,而且易於出錯
- JDBC的代碼調用有很多重復性的代碼
- 從JDBC返回的結果轉換成領域模型的Java對象非常繁瑣
而使用ORM框架,則可以讓我們用面向對象的方式來操作數據庫,比如通過一個簡單的函數就完成上面的流程,直接返回映射為Java對象的結果。這個流程中很大一部分工作就交給ORM自動化幫我們執行了。
Mybatis是支持定制化SQL,存儲過程以及高級映射的優秀持久層框架。MyBatis避免了幾乎所有的JDBC代碼和手動設置參數以及獲取結果集。Mybatis可以對配置和原生Map使用簡單的XML或標注,將接口和Java的POJOS(Plan Old Java Objects,普通的Java對象)映射成數據庫中的記錄。
簡單地理解,你可以認為Mybatis將SQL語句,以及SQL返回結果到Java對象的映射,都放到一個易於配置的XML文件里了,你的Java代碼會變得異常簡單。當然除了XML,Mybatis同時也支持基於標注的方式,但是功能上會有一些限制。總體來說,還是推薦使用XML方式,一些簡單的SQL使用標注會更方便一些。
創建項目
新建一個Maven項目,接下來引入Mybatis和MySQL的依賴:
<!-- mybatis依賴 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.0</version> </dependency> <!-- MySQL數據庫依賴 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency>
既然是ORM的練習,先設計Object,再設計Relation,最后再看怎么做Mapping
實體類設計
分析我們的業務場景,可以設計三個類:
Question
表示問題Answer
表示回答Tag
表示問題標簽
其中:
Question
可以有多個Answer
,一個Answer
對應唯一一個Question
,一對多的關系Question
可以有多個Tage
,一個Tag
可用於多個Question
,多對多的關系
暫時先不管Answer和Tag,只關注Question:
Question.java
package com.fpc.Entity; import java.util.Date; import java.util.List; public class Question { private int id; private String title; private String description; private Date createdTime; private List<Tag> tags; private List<Answer> answers; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Date getCreatedTime() { return createdTime; } public void setCreatedTime(Date createdTime) { this.createdTime = createdTime; } public List<Tag> getTags() { return tags; } public void setTags(List<Tag> tags) { this.tags = tags; } public List<Answer> getAnswers() { return answers; } public void setAnswers(List<Answer> answers) { this.answers = answers; } }
這里的Question實現了Serializable接口,實現這個接口是為了后面緩存查詢結果是需要的。
數據庫設計
除了設計Question,Answer和Tag數據表,還需要定義一張維護Question和Tag之間多對多關系的表。最終數據庫設計如下:
創建question表:
CREATE TABLE question( id INT PRIMARY KEY AUTO_INCREMENT, createdTime DATETIME, description LONGTEXT, title VARCHAR(255) );
接下來添加MyBatis的配置,在resources目錄下簡歷mybatis.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> <!-- 引用db.properties配置文件 --> <properties resource="db.properties"></properties> <!-- development:開發模式 work:工作模式 --> <typeAliases> <!-- <typeAlias type="com.fpc.Entity.User" alias="_User"/> --> <package name="com.fpc.Entity"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <!-- 配置數據庫連接信息 --> <dataSource type="POOLED"> <!-- value屬性值引用db.properties配置文件中配置的值 --> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${name}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <!-- 注冊userMapper.xml文件, userMapper.xml位於me.gacl.mapping這個包下,所以resource寫成me/gacl/mapping/userMapper.xml--> <mapper resource="com/fpc/Mapping/questionMapper.xml"/> <!-- <mapper class="com.fpc.Mapping.questionMapperI"/> --> </mappers> </configuration>
這就是一個最簡單的MyBatis配置文件,定義了數據源和mapper文件的位置。
關於MyBatis配置:
后面會發現有了Spring和SpringBoot支持,很多配置不需要手動設置了,比如映射文件的位置,數據源和事務管理器等,這個文件需要的內容非常少,甚至可以不需要這個文件了。
需要修改MyBatis配置文件的幾種常用的情況包括:
- 要增加插件,比如后面需要用到的分頁插件
- 修改MyBatis的運行時行為,參考settings選項
- 重寫類型處理器或創建自定義的類型處理器來處理非標准類型。
定義Mapper接口
Mapper的Java接口,這是數據庫訪問的接口:
package com.fpc.Mapping; import org.apache.ibatis.annotations.Param; import com.fpc.Entity.Question; public interface questionMapperI { Question findOne(@Param("id") int id); }
@Param是MyBatis提高的一個標注,表示id會解析成SQL語句的參數。
使用XML定義Mapper
對應於Mapper接口,還需要通過XML來給出Mapper的實現,將映射放在com/fpc/Mapping/下
<?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,namespace的值習慣上設置成包名+sql映射文件名,這樣就能夠保證namespace的值是唯一的 例如namespace="me.gacl.mapping.userMapper"就是me.gacl.mapping(包名)+userMapper(userMapper.xml文件去除后綴) --> <mapper namespace="com.fpc.Mapping.questionMapperI"> <select id="findOne" resultType="com.fpc.Entity.Question"> select * from question where id = #{id} </select> </mapper>
Mapper的配置是MyBatis的精華,注意兩點:
- 對應於每一個Mapper的Java接口方法,XML配置中有對應的一個元素來描述其SQL語句
- resultType元素定義了數據庫返回(一行記錄)如何映射到一個Java對象
使用Mapper
已經有一個可以根據id獲取問題的接口方法了,編寫測試類測試:
package com.fpc.Test; import java.io.IOException; import java.io.Reader; 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 com.fpc.Entity.Question; import com.fpc.Mapping.questionMapperI; public class TestMybatis { public static void main(String[] args) { String resource = "mybatis.xml"; Reader reader; try { reader = Resources.getResourceAsReader(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader); SqlSession sqlSession = sqlSessionFactory.openSession(); questionMapperI questionMapper = sqlSession.getMapper(questionMapperI.class); Question question = questionMapper.findOne(1); System.out.println(question.getDescription()); sqlSession.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
把這個main方法運行起來就能看到結果了,調用看起來有點復雜,這里涉及Mybatis的幾個關鍵類:
- SqlSessionFactoryBuilder
- SqlSessionFactory
- SqlSession
其實引入Spring Boot之后,你會發現這幾個類都被屏蔽掉了,你只需專注於寫Mapper即可。不過了解一下這幾個類,對於我們調試程序和理解MyBatis都是大有裨益的。