MyBatis 是現現在最流行的 ORM 框架之一,咱們先來了解一下什麼是 ORM 框架。前端
對象關係映射(Object Relational Mapping,ORM)模式是一種爲了解決面向對象與關係數據庫存在的互不匹配的現象的技術。簡單的說,ORM 是經過使用描述對象和數據庫之間映射的元數據,將程序中的對象自動持久化到關係數據庫中。java
爲何須要 ORM?mysql
當你開發一個應用程序的時候(不使用 O/R Mapping),可能會寫很多數據訪問層代碼,用來從數據庫保存、刪除、讀取對象信息等;在 DAL 中寫了不少的方法來讀取對象數據、改變狀態對象等任務,而這些代碼寫起來老是重複的。針對這些問題 ORM 提供瞭解決方案,簡化了將程序中的對象持久化到關係數據庫中的操做。git
ORM 框架的本質是簡化編程中操做數據庫的編碼,在 Java 領域發展到如今基本上就剩兩家最爲流行,一個是宣稱能夠不用寫一句 SQL 的 Hibernate,一個是以動態 SQL 見長的 MyBatis,二者各有特色。在企業級系統開發中能夠根據需求靈活使用,會發現一個有趣的現象:傳統企業大都喜歡使用 Hibernate,而互聯網行業一般使用 MyBatis。github
MyBatis 是一款標準的 ORM 框架,被普遍的應用於各企業開發中。MyBatis 最先是 Apache 的一個開源項目 iBatis,2010 年這個項目由 Apache Software Foundation 遷移到了 Google Code,而且更名爲 MyBatis,2013 年 11 月又遷移到 Github。從 MyBatis 的遷移史,也能夠看出源碼託管平臺的發展史,GitHub 目前已經成爲世界上最大的開源軟件託管平臺,建議你們多多關注這個全球最大的同性社交網站。spring
MyBatis 支持普通的 SQL 查詢,存儲過程和高級映射的優秀持久層框架。MyBatis 消除了幾乎全部的 JDBC 代碼和參數的手工設置以及對結果集的檢索封裝。MaBatis 可使用簡單的 XML 或註解用於配置和原始映射,將接口和 Java 的 POJO(Plain Old Java Objects,普通的 Java 對象)映射成數據庫中的記錄。sql
做爲一款使用普遍的開源軟件,它的特色有哪些呢?數據庫
優勢編程
缺點mybatis
Mapper 配置可使用基於 XML 的 Mapper 配置文件來實現,也可使用基於 Java 註解的 MyBatis 註解來實現,甚至能夠直接使用 MyBatis 提供的 API 來實現。
Mapper 接口是指自行定義的一個數據操做接口,相似於一般所說的 DAO 接口。早期的 Mapper 接口須要自定義去實現,如今 MyBatis 會自動爲 Mapper 接口建立動態代理對象。Mapper 接口的方法一般與 Mapper 配置文件中的 select、insert、update、delete 等 XML 結點存在一一對應關係。
Executor,MyBatis 中全部的 Mapper 語句的執行都是經過 Executor 進行的,Executor 是 MyBatis 的一個核心接口。
SqlSession,是 MyBatis 的關鍵對象,是執行持久化操做的獨享,相似於 JDBC 中的 Connection,SqlSession 對象徹底包含以數據庫爲背景的全部執行 SQL 操做的方法,它的底層封裝了 JDBC 鏈接,能夠用 SqlSession 實例來直接執行被映射的 SQL 語句。
SqlSessionFactory,是 MyBatis 的關鍵對象,它是單個數據庫映射關係通過編譯後的內存鏡像。SqlSessionFactory 對象的實例能夠經過 SqlSessionFactoryBuilder 對象類得到,而 SqlSessionFactoryBuilder 則能夠從 XML 配置文件或一個預先定製的 Configuration 的實例構建出。
MyBatis 的工做流程以下:
在咱們具體的使用過程當中,就是按照上述的流程來執行。
mybatis-spring-boot-starter 是 MyBatis 幫助咱們快速集成 Spring Boot 提供的一個組件包,使用這個組件能夠作到如下幾點:
mybatis-spring-boot-starter 依賴於 MyBatis-Spring 和 Spring Boot,最新版 1.3.2 須要 MyBatis-Spring 1.3 以上,Spring Boot 版本 1.5 以上。
注意 mybatis-spring-boot-starter 是 MyBatis 官方開發的 Starter,而不是 Spring Boot 官方開發的啓動包,實際上是 MyBatis 看 Spring Boot 市場使用度很是高,所以主動開發出 Starter 包進行集成,但這一集成確實解決了不少問題,使用起來比之前簡單不少。mybatis-spring-boot-starter 主要提供了兩種解決方案,一種是簡化後的 XML 配置版,一種是使用註解解決一切問題。
MyBatis 之前只有 XML 配置這種使用的形式,到了後來註解使用特別普遍,MyBatis 也順應潮流提供了註解的支持,從這裏能夠看出 MyBatis 一直都跟隨着主流技術的變化來完善本身。接下來給你們介紹一下如何使用 XML 版本。
XML 版本保持映射文件的方式,最新版的使用主要體如今不須要實現 Dao 的實現層,系統會自動根據方法名在映射文件中找到對應的 SQL。
爲了方便項目演示,須要在 test 倉庫建立 users 表,腳本以下:
DROPTABLEIFEXISTS`users`;
CREATETABLE`users`(
`id`bigint20NOTNULLCOMMENT'主鍵id' ()AUTO_INCREMENT,
`userName`varchar32DEFAULTNULLCOMMENT'用戶名' (),
`passWord`varchar32DEFAULTNULLCOMMENT'密碼' (),
`user_sex`varchar32DEFAULTNULL (),
`nick_name`varchar32DEFAULTNULL (),
KEY`id` PRIMARY()
ENGINEInnoDB1DEFAULTCHARSET)=AUTO_INCREMENT==utf8;
固然任何模式都須要首先引入 mybatis-spring-boot-starter 的 pom 文件,如今最新版本是 1.3.2。
<dependency>
<groupId></groupId> org.mybatis.spring.boot
<artifactId></artifactId> mybatis-spring-boot-starter
<version></version> 1.3.2
</dependency>
application.properties 添加相關配置:
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
mybatis.type-aliases-package=com.neo.model
testtruetruespring.datasource.url=jdbc:mysql://localhost:3306/?serverTimezone=UTC&useUnicode=&characterEncoding=utf-8&useSSL=
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
其中:
Spring Boot 啓動時數據源會自動注入到 SqlSessionFactory 中,使用 SqlSessionFactory 構建 SqlSessionFactory,再自動注入到 Mapper 中,最後咱們直接使用 Mapper 便可。
在啓動類中添加對 Mapper 包掃描 @MapperScan,Spring Boot 啓動的時候會自動加載包路徑下的 Mapper。
@SpringBootApplication
@MapperScan"com.neo.mapper"()
publicclass Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
或者直接在 Mapper 類上面添加註解 @Mapper,建議使用上面那種,否則每一個 mapper 加個註解也挺麻煩的。
mybatis-config.xml 主要配置經常使用的 typeAliases,設置類型別名,爲 Java 類型設置一個短的名字。它只和 XML 配置有關,存在的意義僅在於用來減小類徹底限定名的冗餘。
<configuration>
type <Aliases>
typealias"Integer"type"java.lang.Integer" <Alias==/>
typealias"Long"type"java.lang.Long" <Alias==/>
typealias"HashMap"type"java.util.HashMap" <Alias==/>
typealias"LinkedHashMap"type"java.util.LinkedHashMap" <Alias==/>
typealias"ArrayList"type"java.util.ArrayList" <Alias==/>
typealias"LinkedList"type"java.util.LinkedList" <Alias==/>
type </Aliases>
</configuration>
這樣咱們在使用 Mapper.xml 的時候,須要引入能夠直接這樣寫:
"Integer"resultType=
//或者
"Long"parameterType=
第一步,指明對應文件的 Mapper 類地址:
namespace"com.neo.mapper.UserMapper"<mapper=>
第二部,配置表結構和類的對應關係:
<resultMap id="BaseResultMap" type="com.neo.model.User" >
<id column="id" property="id" jdbcType="BIGINT" />
<result column="userName" property="userName" jdbcType="VARCHAR" />
<result column="passWord" property="passWord" jdbcType="VARCHAR" />
<result column="user_sex" property="userSex" javaType="com.neo.enums.UserSexEnum"/>
<result column="nick_name" property="nickName" jdbcType="VARCHAR" />
</resultMap>
這裏爲了更好的貼近工做狀況,將類的兩個字段和數據庫字段設置爲不一致,其中一個使用了枚舉。使用枚舉有一個很是大的優勢,插入此屬性的數據會自動進行校驗,若是不是枚舉的內容會報錯。
第三步,寫具體的 SQL 語句,好比這樣:
select"getAll""BaseResultMap"<id=resultMap= >
SELECT
*
FROM users
select</>
MyBatis XML 有一個特色是能夠複用 XML,好比咱們公用的一些 XML 片斷能夠提取出來,在其餘 SQL 中去引用。例如:
<sql id="Base_Column_List" >
id, userName, passWord, user_sex, nick_name
</sql>
<select id="getAll" resultMap="BaseResultMap" >
SELECT
<include refid="Base_Column_List" />
FROM users
</select>
這個例子就是,上面定義了須要查詢的表字段,下面 SQL 使用 include 引入,避免了寫太多重複的配置內容。
下面是經常使用的增、刪、改、查的例子:
select"getOne""Long""BaseResultMap"<id=parameterType=resultMap=>
SELECT
"Base_Column_List" <include refid=/>
FROM users
#{id} WHERE id =
select</>
"insert""com.neo.model.User"<insert id=parameterType=>
INSERT INTO
users
(userName,passWord,user_sex)
VALUES
(#{userName}, #{passWord}, #{userSex})
</insert>
<update id"update""com.neo.model.User"=parameterType=>
UPDATE
users
SET
if"userName != null"#{userName},</if> <test=>userName =
if"passWord != null"#{passWord},</if> <test=>passWord =
#{nickName} nick_name =
WHERE
#{id} id =
</update>
"delete""Long"<delete id=parameterType=>
DELETE FROM
users
WHERE
#{id} id =
</delete>
上面 update 的 SQL 使用了 if 標籤,能夠根據不一樣的條件生產動態 SQL,這就是 MyBatis 最大的特色。
publicinterfaceUserMapper{
List<UserEntity> getAll() ;
UserEntity getOne(Long id) ;
void insert(UserEntity user) ;
void update(UserEntity user) ;
void delete(Long id) ;
}
注意:這裏的方法名須要和 XML 配置中的 id 屬性一致,否則會找不到方法去對應執行的 SQL。
按照 Spring 一向使用形式,直接將對應的 Mapper 注入便可。
Resource@
private UserMapper userMapper;
若是使用的是 Idea,這塊的註解常常會報「could not autowire」,Eclipse 卻沒有問題,其實代碼是正確的,這是 Idea 的誤報。能夠選擇下降 Autowired 檢測的級別,不要提示就好。
在 File | Settings | Editor | Inspections 選項中使用搜索功能找到 Autowiring for Bean Class,將 Severity 的級別由以前的 error 改爲 warning 便可。
接下來直接使用 userMapper 進行數據庫操做便可。
Test@
public void testUser() {
//增長
new"aa""a123456" userMapper.insert(User(,, UserSexEnum.MAN));
//刪除
intdelete2l count=userMapper.();
1l User user = userMapper.getOne();
"smile" user.setNickName();
//修改
userMapper.update(user);
//查詢
List<User> users = userMapper.getAll();
}
在示例代碼中,寫了兩份的使用示例,一個是 Test,一個在 Controller 層,方便你們下載查看。
多條件分頁查詢是實際工做中最常使用的功能之一,MyBatis 特別擅長處理這類的問題。在實際工做中,會對分頁進行簡單的封裝,方便前端使用。另外在 Web 開發規範使用中,Web 層的參數會以 param 爲後綴的對象進行傳參,以 result 結尾的實體類封裝返回的數據。
下面給你們以 User 多條件分頁查詢爲例進行講解。
先定義一個分頁的基礎類:
publicclassPageParam{
privateint//起始行 beginLine;
private3 Integer pageSize =;
private0// 當前頁 Integer currentPage=;
//getter setter省略
public int getBeginLine() {
return//自動計算起始行 pageSize*currentPage;
}
}
默認每頁 3 條記錄,能夠根據前端傳參進行修改。
user 的查詢條件參數類繼承分頁基礎類:
publicclass UserParam extends PageParam{
private String userName;
private String userSex;
//getter setter省略
}
接下來配置具體的 SQL,先將查詢條件提取出來。
"Base_Where_List"<sql id=>
iftest"userName != null and userName != ''" <=>
#{userName} and userName =
if </>
iftest"userSex != null and userSex != ''" <=>
#{userSex} and user_sex =
if </>
</sql>
從對象 UserParam 中獲取分頁信息和查詢條件,最後進行組合。
select"getList""BaseResultMap""com.neo.param.UserParam"<id=resultMap=parameterType=>
select
"Base_Column_List" <include refid=/>
from users
where11 =
"Base_Where_List" <include refid=/>
by orderid desc
#{beginLine} , #{pageSize} limit
select</>
前端須要展現總共的頁碼,所以須要統計出查詢結果的總數。
select"getCount""Integer""com.neo.param.UserParam"<id=resultType=parameterType=>
select
count(1)
from users
where 11=
"Base_Where_List" <include refid=/>
select</>
Mapper 中定義的兩個方法和配置文件相互對應。
publicinterfaceUserMapper{
List<UserEntity> getList(UserParam userParam) ;
int getCount(UserParam userParam) ;
}
具體使用:
Test@
public void testPage() {
new UserParam userParam=UserParam();
"WOMAN" userParam.setUserSex();
1 userParam.setCurrentPage();
List<UserEntity> users=userMapper.getList(userParam);
long count=userMapper.getCount(userParam);
new Page page =Page(userParam,count,users);
out System..println(page);
}
在實際使用中,只須要傳入 CurrentPage 參數便可,默認 0 就是第一頁,傳 1 就是第二頁的內容,最後將結果封裝爲 Page 返回給前端。
publicclass Page<E> implements Serializable {
privateint0//當前頁數 currentPage =;
privatelong//總頁數 totalPage;
privatelong//總記錄數 totalNumber;
private//數據集 List<E> list;
}
Page 將分頁信息和數據信息進行封裝,方便前端顯示第幾頁、總條數和數據,這樣分頁功能就完成了。
接下來爲你們介紹如何使用 MyBatis 配置多數據源使用。
首先咱們須要配置兩個不一樣的數據源:
mybatis.config-location=classpath:mybatis/mybatis-config.xml
testtruetruespring.datasource.one.jdbc-url=jdbc:mysql://localhost:3306/1?serverTimezone=UTC&useUnicode=&characterEncoding=utf-8&useSSL=
spring.datasource.one.username=root
spring.datasource.one.password=root
spring.datasource.one.driver-class-name=com.mysql.cj.jdbc.Driver
testtruetruespring.datasource.two.jdbc-url=jdbc:mysql://localhost:3306/2?serverTimezone=UTC&useUnicode=&characterEncoding=utf-8&useSSL=
spring.datasource.two.username=root
spring.datasource.two.password=root
spring.datasource.two.driver-class-name=com.mysql.cj.jdbc.Driver
注意,須要提早在 test1 和 test2 庫中建立好 User 表結構。
第一個數據源以 spring.datasource.one.* 爲前綴鏈接數據庫 test1,第二個數據源以 spring.datasource.two.* 爲前綴鏈接數據庫 test2。
同時須要將上述的 UserMapper.xml 文件複製兩份到 resources/mybatis/mapper/one 和 resources/mybatis/mapper/two 目錄下各一份。
爲兩個數據源建立不一樣的 Mapper 包路徑,將之前的 UserMapper 複製到包 com.neo.mapper.one 和 com.neo.mapper.two 路徑下,而且分別重命名爲:User1Mapper、User2Mapper。
配置第一個數據源,新建 DataSource1Config。
首先加載配置的數據源:
@Bean"oneDataSource"(name =)
@ConfigurationProperties"spring.datasource.one"(prefix =)
@Primary
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
注意,在多數據源中只能指定一個 @Primary 做爲默認的數據源使用。
根據建立的數據源,構建對應的 SqlSessionFactory。
@Bean"oneSqlSessionFactory"(name =)
@Primary
public SqlSessionFactory testSqlSessionFactory(@Qualifier("oneDataSource") DataSource dataSource) throws Exception {
new SqlSessionFactoryBean bean =SqlSessionFactoryBean();
bean.setDataSource(dataSource);
new"classpath:mybatis/mapper/one/*.xml" bean.setMapperLocations(PathMatchingResourcePatternResolver().getResources());
return bean.getObject();
}
代碼中須要指明須要加載的 Mapper xml 文件。
同時將數據源添加到事務中。
@Bean"oneTransactionManager"(name =)
@Primary
public DataSourceTransactionManager testTransactionManager(@Qualifier("oneDataSource") DataSource dataSource) {
returnnew DataSourceTransactionManager(dataSource);
}
接下來將上面建立的 SqlSessionFactory 注入,建立咱們在 Mapper 中須要使用的 SqlSessionTemplate。
@Bean"oneSqlSessionTemplate"(name =)
@Primary
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("oneSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
returnnew SqlSessionTemplate(sqlSessionFactory);
}
最後將上面建立的 SqlSessionTemplate 注入到對應的 Mapper 包路徑下,這樣這個包下面的 Mapper 都會使用第一個數據源來進行數據庫操做。
@Configuration
@MapperScan"com.neo.mapper.one""oneSqlSessionTemplate"(basePackages =, sqlSessionTemplateRef =)
publicclass OneDataSourceConfig {
...
}
DataSource2Config 的配置和上面相似,方法上須要去掉 @Primary 註解,替換對應的數據源和 Mapper 路徑便可。下面是 DataSource2Config 完整示例:
@Configuration
@MapperScan"com.neo.mapper.two""twoSqlSessionTemplate"(basePackages =, sqlSessionTemplateRef =)
publicclass DataSource2Config {
@Bean"twoDataSource" (name =)
@ConfigurationProperties"spring.datasource.two" (prefix =)
public DataSource testDataSource() {
return DataSourceBuilder.create().build();
}
@Bean"twoSqlSessionFactory" (name =)
public SqlSessionFactory testSqlSessionFactory(@Qualifier("twoDataSource") DataSource dataSource) throws Exception {
new SqlSessionFactoryBean bean =SqlSessionFactoryBean();
bean.setDataSource(dataSource);
new"classpath:mybatis/mapper/two/*.xml" bean.setMapperLocations(PathMatchingResourcePatternResolver().getResources());
return bean.getObject();
}
@Bean"twoTransactionManager" (name =)
public DataSourceTransactionManager testTransactionManager(@Qualifier("twoDataSource") DataSource dataSource) {
returnnew DataSourceTransactionManager(dataSource);
}
@Bean"twoSqlSessionTemplate" (name =)
public SqlSessionTemplate testSqlSessionTemplate(@Qualifier("twoSqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
returnnew SqlSessionTemplate(sqlSessionFactory);
}
}
從上面的步驟咱們能夠總結出來,建立多數據源的過程就是:首先建立 DataSource,注入到 SqlSessionFactory 中,再建立事務,將 SqlSessionFactory 注入到建立的 SqlSessionTemplate 中,最後將 SqlSessionTemplate 注入到對應的 Mapper 包路徑下。其中須要指定分庫的 Mapper 包路徑。
注意,在多數據源的狀況下,咱們不須要在啓動類添加:@MapperScan("com.xxx.mapper") 的註解。
這樣 MyBatis 多數據源的配置就完成了,若是有更多的數據源請參考第二個數據源的配置便可。
配置好多數據源以後,在項目中想使用哪一個數據源就把對應數據源注入到類中使用便可。
@RunWith(SpringRunner.class)
@SpringBootTest
publicclass UserMapperTest {
@Autowired
private User1Mapper user1Mapper;
@Autowired
private User2Mapper user2Mapper;
@Test
public void testInsert() throws Exception {
new"aa111""a123456" user1Mapper.insert(User(,, UserSexEnum.MAN));
new"bb111""b123456" user1Mapper.insert(User(,, UserSexEnum.WOMAN));
new"cc222""b123456" user2Mapper.insert(User(,, UserSexEnum.MAN));
}
}
上面的測試類中注入了兩個不一樣的 Mapper,對應了不一樣的數據源。在第一個數據源中插入了兩條數據,第二個數據源中插入了一條信息,運行測試方法後查看數據庫1有兩條數據,數據庫2有一條數據,證實多數據源測試成功。
這節課介紹了 ORM 框架 和 MyBatis 框架相關概念介紹,以用戶數據爲例演示了 MyBatis 的增、刪、改、查,以及分頁查詢、多數據源處理等常見場景。經過上面的示例能夠發現 MyBatis 將執行 SQL 和代碼作了隔離,保證代碼處理和 SQL 的相對獨立,層級劃分比較清晰,MyBatis 對動態 SQL 支持很是友好,能夠在 XML 文件中複用代碼高效編寫動態 SQL。