最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
當前位置: 首頁 - 科技 - 知識百科 - 正文

mybatis完美實戰(zhàn)教程

來源:懂視網(wǎng) 責編:小采 時間:2020-11-09 14:09:40
文檔

mybatis完美實戰(zhàn)教程

mybatis完美實戰(zhàn)教程:寫在這個系列前面的話: 以前曾經(jīng)用過ibatis,這是mybatis的前身,當時在做項目時,感覺很不錯,比hibernate靈活。性能也比hibernate好。而且也比較輕量級,因為當時在項目中,沒來的及做很很多筆記。后來項目結(jié)束了,我也沒寫總結(jié)文檔。已經(jīng)過去好久了。但最
推薦度:
導讀mybatis完美實戰(zhàn)教程:寫在這個系列前面的話: 以前曾經(jīng)用過ibatis,這是mybatis的前身,當時在做項目時,感覺很不錯,比hibernate靈活。性能也比hibernate好。而且也比較輕量級,因為當時在項目中,沒來的及做很很多筆記。后來項目結(jié)束了,我也沒寫總結(jié)文檔。已經(jīng)過去好久了。但最

寫在這個系列前面的話: 以前曾經(jīng)用過ibatis,這是mybatis的前身,當時在做項目時,感覺很不錯,比hibernate靈活。性能也比hibernate好。而且也比較輕量級,因為當時在項目中,沒來的及做很很多筆記。后來項目結(jié)束了,我也沒寫總結(jié)文檔。已經(jīng)過去好久了。但最

寫在這個系列前面的話:

以前曾經(jīng)用過ibatis,這是mybatis的前身,當時在做項目時,感覺很不錯,比hibernate靈活。性能也比hibernate好。而且也比較輕量級,因為當時在項目中,沒來的及做很很多筆記。后來項目結(jié)束了,我也沒寫總結(jié)文檔。已經(jīng)過去好久了。但最近突然又對這個ORM 工具感興趣。因為接下來自己的項目中很有可能采用這個ORM工具。所以在此重新溫習了一下 mybatis, 因此就有了這個系列的 mybatis 教程.

什么是mybatis
MyBatis是支持普通SQL查詢,存儲過程和高級映射的優(yōu)秀持久層框架。MyBatis消除了幾乎所有的JDBC代碼和參數(shù)的手工設置以及結(jié)果集的檢索。MyBatis使用簡單的XML或注解用于配置和原始映射,將接口和Java的POJOs(Plan Old Java Objects,普通的Java對象)映射成數(shù)據(jù)庫中的記錄.

orm工具的基本思想
無論是用過的hibernate,mybatis,你都可以法相他們有一個共同點:
1. 從配置文件(通常是XML配置文件中)得到 sessionfactory.
2. 由sessionfactory 產(chǎn)生 session
3. 在session 中完成對數(shù)據(jù)的增刪改查和事務提交等.
4. 在用完之后關閉session 。

5. 在java 對象和 數(shù)據(jù)庫之間有做mapping 的配置文件,也通常是xml 文件。

mybatis實戰(zhàn)教程(mybatis in action)之一:開發(fā)環(huán)境搭建

mybatis 的開發(fā)環(huán)境搭建,選擇: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包。這些軟件工具均可以到各自的官方網(wǎng)站上下載。
首先建立一個名字為 MyBaits 的 dynamic web project
1. 現(xiàn)階段,你可以直接建立java 工程,但一般都是開發(fā)web項目,這個系列教程最后也是web的,所以一開始就建立web工程。
2. 將 mybatis-3.2.0-SNAPSHOT.jar,mysql-connector-java-5.1.22-bin.jar 拷貝到 web工程的lib目錄.
3. 創(chuàng)建mysql 測試數(shù)據(jù)庫和用戶表,注意,這里采用的是 utf-8 編碼
\
創(chuàng)建用戶表,并插入一條測試數(shù)據(jù)
程序代碼 程序代碼
Create TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userName` varchar(50) DEFAULT NULL,
`userAge` int(11) DEFAULT NULL,
`userAddress` varchar(200) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;


Insert INTO `user` VALUES ('1', 'summer', '100', 'shanghai,pudong');

到此為止,前期準備工作就完成了。下面開始真正配置mybatis項目了。
1. 在MyBatis 里面創(chuàng)建兩個源碼目錄,分別為 src_user,test_src, 用如下方式建立,鼠標右鍵點擊 JavaResource.
\

2. 設置mybatis 配置文件:Configuration.xml, 在src_user目錄下建立此文件,內(nèi)容如下:
程序代碼 程序代碼
< ?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>



















< /configuration>



3. 建立與數(shù)據(jù)庫對應的 java class,以及映射文件.
在src_user下建立package:com.yihaomen.mybatis.model ,并在這個 package 下建立 User 類:
程序代碼 程序代碼
package com.yihaomen.mybatis.model;

public class User {

private int id;
private String userName;
private String userAge;
private String userAddress;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserAge() {
return userAge;
}
public void setUserAge(String userAge) {
this.userAge = userAge;
}
public String getUserAddress() {
return userAddress;
}
public void setUserAddress(String userAddress) {
this.userAddress = userAddress;
}

}



同時建立這個User 的映射文件 User.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.yihaomen.mybatis.models.UserMapper">

< /mapper>



下面對這幾個配置文件解釋下:
1.Configuration.xml 是 mybatis 用來建立 sessionFactory 用的,里面主要包含了數(shù)據(jù)庫連接相關東西,還有 java 類所對應的別名,比如 這個別名非常重要,你在 具體的類的映射中,比如User.xml 中 resultType 就是對應這里的。要保持一致,當然這里的 resultType 還有另外單獨的定義方式,后面再說。
2. Configuration.xml 里面 的是包含要映射的類的xml配置文件。
3. 在User.xml 文件里面 主要是定義各種SQL 語句,以及這些語句的參數(shù),以及要返回的類型等.

開始測試
在test_src 源碼目錄下建立com.yihaomen.test這個package,并建立測試類Test:
程序代碼 程序代碼
package com.yihaomen.test;

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.yihaomen.mybatis.model.User;

public class Test {
private static SqlSessionFactory sqlSessionFactory;
private static Reader reader;

static{
try{
reader = Resources.getResourceAsReader("Configuration.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
}catch(Exception e){
e.printStackTrace();
}
}

public static SqlSessionFactory getSession(){
return sqlSessionFactory;
}

public static void main(String[] args) {
SqlSession session = sqlSessionFactory.openSession();
try {
User user = (User) session.selectOne("com.yihaomen.mybatis.models.UserMapper.selectUserByID", 1);
System.out.println(user.getUserAddress());
System.out.println(user.getUserName());
} finally {
session.close();
}
}
}


現(xiàn)在運行這個程序,是不是得到查詢結(jié)果了。恭喜你,環(huán)境搭建配置成功,接下來第二章,將講述基于接口的操作方式,增刪改查。
整個工程目錄結(jié)構(gòu)如下:
\


mybatis實戰(zhàn)教程(mybatis in action)之二:以接口的方式編程

前面一章,已經(jīng)搭建好了eclipse,mybatis,mysql的環(huán)境,并且實現(xiàn)了一個簡單的查詢。請注意,這種方式是用SqlSession實例來直接執(zhí)行已映射的SQL語句:
session.selectOne("com.yihaomen.mybatis.models.UserMapper.selectUserByID", 1)
其實還有更簡單的方法,而且是更好的方法,使用合理描述參數(shù)和SQL語句返回值的接口(比如IUserOperation.class),這樣現(xiàn)在就可以至此那個更簡單,更安全的代碼,沒有容易發(fā)生的字符串文字和轉(zhuǎn)換的錯誤.下面是詳細過程:

在src_user源碼目錄下建立 com.yihaomen.mybatis.inter 這個包,并建立接口類 IUserOperation , 內(nèi)容如下:
程序代碼 程序代碼
package com.yihaomen.mybatis.inter;
import com.yihaomen.mybatis.model.User;

public interface IUserOperation {
public User selectUserByID(int id);

}


請注意,這里面有一個方法名 selectUserByID 必須與 User.xml 里面配置的 select 的id 對應( select * from user where userName like #{userName}

在 IUserOperation 接口中增加方法:public List selectUsers(String userName);
現(xiàn)在在 Test 類中做測試
程序代碼 程序代碼
public void getUserList(String userName){
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
List users = userOperation.selectUsers(userName);
for(User user:users){
System.out.println(user.getId()+":"+user.getUserName()+":"+user.getUserAddress());
}

} finally {
session.close();
}
}

現(xiàn)在在main 方法中可以測試:
程序代碼 程序代碼
public static void main(String[] args) {
Test testUser=new Test();
testUser.getUserList("%");
}


可以看到,結(jié)果成功查詢出來。如果是查詢單個數(shù)據(jù)的話,用第二講用過的方法就可以了。

用mybatis 增加數(shù)據(jù)
在 IUserOperation 接口中增加方法:public void addUser(User user);
在 User.xml 中配置
程序代碼 程序代碼
< !--執(zhí)行增加操作的SQL語句。id和parameterType分別與IUserOperation接口中的addUser方法的名字和參數(shù)類型一致。以#{name}的形式引用Student參數(shù)的name屬性,MyBatis將使用反射讀取Student參數(shù)的此屬性。#{name}中name大小寫敏感。引用其他的gender等屬性與此一致。seGeneratedKeys設置為"true"表明要MyBatis獲取由數(shù)據(jù)庫自動生成的主鍵;keyProperty="id"指定把獲取到的主鍵值注入到Student的id屬性-->

insert into user(userName,userAge,userAddress)
values(#{userName},#{userAge},#{userAddress})


然后在 Test 中寫測試方法:
程序代碼 程序代碼
/**
* 測試增加,增加后,必須提交事務,否則不會寫入到數(shù)據(jù)庫.
*/
public void addUser(){
User user=new User();
user.setUserAddress("人民廣場");
user.setUserName("飛鳥");
user.setUserAge(80);
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
userOperation.addUser(user);
session.commit();
System.out.println("當前增加的用戶 id為:"+user.getId());
} finally {
session.close();
}
}

用mybatis 更新數(shù)據(jù)
方法類似,先在 IUserOperation 中增加方法:public void addUser(User user);
然后配置 User.xml
程序代碼 程序代碼

update user set userName=#{userName},userAge=#{userAge},userAddress=#{userAddress} where id=#{id}


Test 類總的測試方法如下:
程序代碼 程序代碼
public void updateUser(){
//先得到用戶,然后修改,提交。
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
User user = userOperation.selectUserByID(4);
user.setUserAddress("原來是魔都的浦東創(chuàng)新園區(qū)");
userOperation.updateUser(user);
session.commit();

} finally {
session.close();
}
}


用mybatis 刪除數(shù)據(jù)
同理,IUserOperation 增加方法:public void deleteUser(int id);
配置User.xml
程序代碼 程序代碼

delete from user where id=#{id}


然后在Test類中寫測試方法:
程序代碼 程序代碼

/**
* 刪除數(shù)據(jù),刪除一定要 commit.
* @param id
*/
public void deleteUser(int id){
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
userOperation.deleteUser(id);
session.commit();
} finally {
session.close();
}
}



這樣,所有增刪改查都完成了,注意在增加,更改,刪除的時候要調(diào)用session.commit(),這樣才會真正對數(shù)據(jù)庫進行操作,否則是沒有提交的。

到此為止,簡單的單表操作,應該都會了,接下來的時間了,我會講多表聯(lián)合查詢,以及結(jié)果集的選取。

mybatis實戰(zhàn)教程(mybatis in action)之四:實現(xiàn)關聯(lián)數(shù)據(jù)的查詢


有了前面幾章的基礎,對一些簡單的應用是可以處理的,但在實際項目中,經(jīng)常是關聯(lián)表的查詢,比如最常見到的多對一,一對多等。這些查詢是如何處理的呢,這一講就講這個問題。我們首先創(chuàng)建一個Article 這個表,并初始化數(shù)據(jù).
程序代碼 程序代碼
Drop TABLE IF EXISTS `article`;
Create TABLE `article` (
`id` int(11) NOT NULL auto_increment,
`userid` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
`content` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

-- ----------------------------
-- 添加幾條測試數(shù)據(jù)
-- ----------------------------
Insert INTO `article` VALUES ('1', '1', 'test_title', 'test_content');
Insert INTO `article` VALUES ('2', '1', 'test_title_2', 'test_content_2');
Insert INTO `article` VALUES ('3', '1', 'test_title_3', 'test_content_3');
Insert INTO `article` VALUES ('4', '1', 'test_title_4', 'test_content_4');

你應該發(fā)現(xiàn)了,這幾個文章對應的userid都是1,所以需要用戶表user里面有id=1的數(shù)據(jù)。可以修改成滿足自己條件的數(shù)據(jù).按照orm的規(guī)則,表已經(jīng)創(chuàng)建了,那么肯定需要一個對象與之對應,所以我們增加一個 Article 的class
程序代碼 程序代碼
package com.yihaomen.mybatis.model;

public class Article {

private int id;
private User user;
private String title;
private String content;

public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}

public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}

}

注意一下,文章的用戶是怎么定義的,是直接定義的一個User對象。而不是int類型。

多對一的實現(xiàn)
場景:在讀取某個用戶發(fā)表的所有文章。當然還是需要在User.xml 里面配置 select 語句, 但重點是這個 select 的resultMap 對應什么樣的數(shù)據(jù)呢。這是重點,這里要引入 association 看定義如下:
程序代碼 程序代碼
< !-- User 聯(lián)合文章進行查詢 方法之一的配置 (多對一的方式) -->












< select id="getUserArticles" parameterType="int" resultMap="resultUserArticleList">
select user.id,user.userName,user.userAddress,article.id aid,article.title,article.content from user,article
where user.id=article.userid and user.id=#{id}


這樣配置之后,就可以了,將select 語句與resultMap 對應的映射結(jié)合起來看,就明白了。用association 來得到關聯(lián)的用戶,這是多對一的情況,因為所有的文章都是同一個用戶的。

還有另外一種處理方式,可以復用我們前面已經(jīng)定義好的 resultMap ,前面我們定義過一個 resultListUser ,看這第二種方法如何實現(xiàn):
程序代碼 程序代碼

















將 association 中對應的映射獨立抽取出來,可以達到復用的目的。

好了,現(xiàn)在在Test 類中寫測試代碼:
程序代碼 程序代碼
public void getUserArticles(int userid){
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
List articles = userOperation.getUserArticles(userid);
for(Article article:articles){
System.out.println(article.getTitle()+":"+article.getContent()+
":作者是:"+article.getUser().getUserName()+":地址:"+
article.getUser().getUserAddress());
}
} finally {
session.close();
}
}



漏掉了一點,我們一定要在 IUserOperation 接口中,加入 select 對應的id 名稱相同的方法:
public List getUserArticles(int id);

然后運行就可以測試。

mybatis實戰(zhàn)教程(mybatis in action)之五:與spring3集成(附源碼)


在這一系列文章中,前面講到純粹用mybatis 連接數(shù)據(jù)庫,然后 進行增刪改查,以及多表聯(lián)合查詢的的例子,但實際項目中,通常會用 spring 這個沾合劑來管理 datasource 等。充分利用spring 基于接口的編程,以及aop ,ioc 帶來的方便。用spring 來管理 mybatis 與管理hibernate 有很多類似的地方。今天的重點就是數(shù)據(jù)源管理以及 bean的配置。

你可以下載源碼后,對比著看,源代碼沒有帶jar包,太大了,空間有限. 有截圖,你可以看到用到哪些jar包,源碼在本文最后.

1. 首先對前面的工程結(jié)構(gòu)做一點改變,在src_user源代碼目錄下建立文件夾config ,并將原來的 mybatis 配置文件 Configuration.xml 移動到這個文件夾中, 并在config 文家夾中建立 spring 配置文件:applicationContext.xml ,這個配置文件里最主要的配置:
程序代碼 程序代碼
< !--本示例采用DBCP連接池,應預先把DBCP的jar包復制到工程的lib目錄下。 -->






















[b]這里面的重點就是 org.mybatis.spring.SqlSessionFactoryBean 與 org.mybatis.spring.mapper.MapperFactoryBean[b] 實現(xiàn)了 spring 的接口,并產(chǎn)生對象。詳細可以查看 mybatis-spring 代碼。(http://code.google.com/p/mybatis/),如果僅僅使用,固定模式,這樣配置就好。

然后寫測試程序
程序代碼 程序代碼
package com.yihaomen.test;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yihaomen.mybatis.inter.IUserOperation;
import com.yihaomen.mybatis.model.Article;
import com.yihaomen.mybatis.model.User;


public class MybatisSprintTest {

private static ApplicationContext ctx;

static
{
ctx = new ClassPathXmlApplicationContext("config/applicationContext.xml");
}

public static void main(String[] args)
{
IUserOperation mapper = (IUserOperation)ctx.getBean("userMapper");
//測試id=1的用戶查詢,根據(jù)數(shù)據(jù)庫中的情況,可以改成你自己的.
System.out.println("得到用戶id=1的用戶信息");
User user = mapper.selectUserByID(1);
System.out.println(user.getUserAddress());

//得到文章列表測試
System.out.println("得到用戶id為1的所有文章列表");
List articles = mapper.getUserArticles(1);

for(Article article:articles){
System.out.println(article.getContent()+"--"+article.getTitle());
}

}


}


運行即可得到相應的結(jié)果.
工程圖:
\
用到的jar包,如下圖:
\

mybatis實戰(zhàn)教程(mybatis in action)之六:與Spring MVC 的集成


前面幾篇文章已經(jīng)講到了mybatis與spring 的集成。但這個時候,所有的工程還不是web工程,雖然我一直是創(chuàng)建的web 工程。今天將直接用mybatis與Spring mvc 的方式集成起來,源碼在本文結(jié)尾處下載.主要有以下幾個方面的配置
1. web.xml 配置 spring dispatchservlet ,比如為:mvc-dispatcher
2. mvc-dispatcher-servlet.xml 文件配置
3. spring applicationContext.XML文件配置(與數(shù)據(jù)庫相關,與mybatis sqlSessionFaction 整合,掃描所有mybatis mapper 文件等.)
4. 編寫controller 類
5. 編寫頁面代碼.
先有個大概映像,整個工程圖如下:
[/code]\

1. web.xml 配置 spring dispatchservlet ,比如為:mvc-dispatcher
程序代碼 程序代碼

contextConfigLocation
classpath*:config/applicationContext.xml


org.springframework.web.context.ContextLoaderListener



org.springframework.web.context.ContextCleanupListener


mvc-dispatcher
org.springframework.web.servlet.DispatcherServlet
1


mvc-dispatcher
/


2. 在web.xml 同目錄下配置 mvc-dispatcher-servlet.xml 文件,這個文件名前面部分必須與你在web.xml里面配置的DispatcherServlet 的servlet名字對應.其內(nèi)容為:
程序代碼 程序代碼










/WEB-INF/pages/


.jsp



< /beans>

3. 在源碼目錄 config 目錄下配置 spring 配置文件 applicationContext.xml
程序代碼 程序代碼
< !--本示例采用DBCP連接池,應預先把DBCP的jar包復制到工程的lib目錄下。 -->























不知道為什么,一旦我用了 MapperScannerConfigurer 去掃描所有的mapper 接口時,數(shù)據(jù)庫配置datasource 就不能用讀取database.properties文件了。報錯: Cannot load JDBC driver class '${jdbc.driverClassName}',網(wǎng)上有人說在spring 3.1.1 下用 sqlSessionFactionBean 注入可以解決,但我用 spring 3.1.3 還是有問題,所以只好把數(shù)據(jù)庫連接信息直接配置在了XML 文件里面。

4. 編寫 controller 層
程序代碼 程序代碼
package com.yihaomen.controller;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.yihaomen.inter.IUserOperation;
import com.yihaomen.model.Article;

@Controller
@RequestMapping("/article")
public class UserController {
@Autowired
IUserOperation userMapper;

@RequestMapping("/list")
public ModelAndView listall(HttpServletRequest request,HttpServletResponse response){
List articles=userMapper.getUserArticles(1);
ModelAndView mav=new ModelAndView("list");
mav.addObject("articles",articles);
return mav;
}
}


5. 頁面文件:
[code]
< c:forEach items="${articles}" var="item">
${item.id }--${item.title }--${item.content }



運行結(jié)果:
\

當然還有 mybatis 的Configure.xml 配置文件,與上一講的差不多,唯一不同的就是不用再配置類似如下的: ,所有這些都交給 在配置 sqlSessionFactory 的時候,由 去導入了。


mybatis實戰(zhàn)教程(mybatis in action)之七:實現(xiàn)mybatis分頁(源碼下載)


上一篇文章里已經(jīng)講到了mybatis與spring MVC的集成,并且做了一個列表展示,顯示出所有article 列表,但沒有用到分頁,在實際的項目中,分頁是肯定需要的。而且是物理分頁,不是內(nèi)存分頁。對于物理分頁方案,不同的數(shù)據(jù)庫,有不同的實現(xiàn)方法,對于mysql 來說 就是利用 limit offset,pagesize 方式來實現(xiàn)的。oracle 是通過rownum 來實現(xiàn)的,如果你熟悉相關數(shù)據(jù)庫的操作,是一樣的很好擴展,本文以mysql 為例子來講述.先看一下效果圖(源代碼在文章最后提供下載):
\
實現(xiàn)mybatis 物理分頁,一個最簡單的方式是,是在你的mapper的SQL語句中直接寫類似如下方式 :
程序代碼 程序代碼


請注意這里的 parameterType 是你傳入的參數(shù)類,或者map ,里面包含了offset,pagesize ,和其他你需要的參數(shù),用這種方式,肯定可以實現(xiàn)分頁。這是簡單的一種方式。但更通用的一種方式是用 mybatis 插件的方式. 參考了網(wǎng)上的很多資料 ,mybatis plugin 方面的資料。寫自己的插件.

程序代碼 程序代碼
package com.yihaomen.util;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.xml.bind.PropertyException;

import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.ExecutorException;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class PagePlugin implements Interceptor {

private static String dialect = "";
private static String pageSqlId = "";

@SuppressWarnings("unchecked")
public Object intercept(Invocation ivk) throws Throwable {

if (ivk.getTarget() instanceof RoutingStatementHandler) {
RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk
.getTarget();
BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper
.getValueByFieldName(statementHandler, "delegate");
MappedStatement mappedStatement = (MappedStatement) ReflectHelper
.getValueByFieldName(delegate, "mappedStatement");

if (mappedStatement.getId().matches(pageSqlId)) {
BoundSql boundSql = delegate.getBoundSql();
Object parameterObject = boundSql.getParameterObject();
if (parameterObject == null) {
throw new NullPointerException("parameterObject error");
} else {
Connection connection = (Connection) ivk.getArgs()[0];
String sql = boundSql.getSql();
String countSql = "select count(0) from (" + sql + ") myCount";
System.out.println("總數(shù)sql 語句:"+countSql);
PreparedStatement countStmt = connection
.prepareStatement(countSql);
BoundSql countBS = new BoundSql(
mappedStatement.getConfiguration(), countSql,
boundSql.getParameterMappings(), parameterObject);
setParameters(countStmt, mappedStatement, countBS,
parameterObject);
ResultSet rs = countStmt.executeQuery();
int count = 0;
if (rs.next()) {
count = rs.getInt(1);
}
rs.close();
countStmt.close();

PageInfo page = null;
if (parameterObject instanceof PageInfo) {
page = (PageInfo) parameterObject;
page.setTotalResult(count);
} else if(parameterObject instanceof Map){
Map map = (Map)parameterObject;
page = (PageInfo)map.get("page");
if(page == null)
page = new PageInfo();
page.setTotalResult(count);
}else {
Field pageField = ReflectHelper.getFieldByFieldName(
parameterObject, "page");
if (pageField != null) {
page = (PageInfo) ReflectHelper.getValueByFieldName(
parameterObject, "page");
if (page == null)
page = new PageInfo();
page.setTotalResult(count);
ReflectHelper.setValueByFieldName(parameterObject,
"page", page);
} else {
throw new NoSuchFieldException(parameterObject
.getClass().getName());
}
}
String pageSql = generatePageSql(sql, page);
System.out.println("page sql:"+pageSql);
ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql);
}
}
}
return ivk.proceed();
}

private void setParameters(PreparedStatement ps,
MappedStatement mappedStatement, BoundSql boundSql,
Object parameterObject) throws SQLException {
ErrorContext.instance().activity("setting parameters")
.object(mappedStatement.getParameterMap().getId());
List parameterMappings = boundSql
.getParameterMappings();
if (parameterMappings != null) {
Configuration configuration = mappedStatement.getConfiguration();
TypeHandlerRegistry typeHandlerRegistry = configuration
.getTypeHandlerRegistry();
MetaObject metaObject = parameterObject == null ? null
: configuration.newMetaObject(parameterObject);
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
PropertyTokenizer prop = new PropertyTokenizer(propertyName);
if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry
.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else if (boundSql.hasAdditionalParameter(propertyName)) {
value = boundSql.getAdditionalParameter(propertyName);
} else if (propertyName
.startsWith(ForEachSqlNode.ITEM_PREFIX)
&& boundSql.hasAdditionalParameter(prop.getName())) {
value = boundSql.getAdditionalParameter(prop.getName());
if (value != null) {
value = configuration.newMetaObject(value)
.getValue(
propertyName.substring(prop
.getName().length()));
}
} else {
value = metaObject == null ? null : metaObject
.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
if (typeHandler == null) {
throw new ExecutorException(
"There was no TypeHandler found for parameter "
+ propertyName + " of statement "
+ mappedStatement.getId());
}
typeHandler.setParameter(ps, i + 1, value,
parameterMapping.getJdbcType());
}
}
}
}


private String generatePageSql(String sql, PageInfo page) {
if (page != null && (dialect !=null || !dialect.equals(""))) {
StringBuffer pageSql = new StringBuffer();
if ("mysql".equals(dialect)) {
pageSql.append(sql);
pageSql.append(" limit " + page.getCurrentResult() + ","
+ page.getShowCount());
} else if ("oracle".equals(dialect)) {
pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (");
pageSql.append(sql);
pageSql.append(") tmp_tb where ROWNUM<=");
pageSql.append(page.getCurrentResult() + page.getShowCount());
pageSql.append(") where row_id>");
pageSql.append(page.getCurrentResult());
}
return pageSql.toString();
} else {
return sql;
}
}

public Object plugin(Object arg0) {
// TODO Auto-generated method stub
return Plugin.wrap(arg0, this);
}

public void setProperties(Properties p) {
dialect = p.getProperty("dialect");
if (dialect ==null || dialect.equals("")) {
try {
throw new PropertyException("dialect property is not found!");
} catch (PropertyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
pageSqlId = p.getProperty("pageSqlId");
if (dialect ==null || dialect.equals("")) {
try {
throw new PropertyException("pageSqlId property is not found!");
} catch (PropertyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

}

此插件有兩個輔助類:PageInfo,ReflectHelper,你可以下載源代碼參考。
寫了插件之后,當然需要在 mybatis 的配置文件Configuration.xml 里配置這個插件
程序代碼 程序代碼








請注意,這個插件定義了一個規(guī)則,也就是在mapper中sql語句的id 必須包含ListPage才能被攔截。否則將不會分頁處理.

插件寫好了,現(xiàn)在就可以在 spring mvc 中的controller 層中寫一個方法來測試這個分頁:
程序代碼 程序代碼
@RequestMapping("/pagelist")
public ModelAndView pageList(HttpServletRequest request,HttpServletResponse response){
int currentPage = request.getParameter("page")==null?1:Integer.parseInt(request.getParameter("page"));
int pageSize = 3;
if (currentPage<=0){
currentPage =1;
}
int currentResult = (currentPage-1) * pageSize;

System.out.println(request.getRequestURI());
System.out.println(request.getQueryString());

PageInfo page = new PageInfo();
page.setShowCount(pageSize);
page.setCurrentResult(currentResult);
List articles=iUserOperation.selectArticleListPage(page,1);

System.out.println(page);

int totalCount = page.getTotalResult();

int lastPage=0;
if (totalCount % pageSize==0){
lastPage = totalCount % pageSize;
}
else{
lastPage =1+ totalCount / pageSize;
}

if (currentPage>=lastPage){
currentPage =lastPage;
}

String pageStr = "";

pageStr=String.format("上一頁 下一頁",
request.getRequestURI()+"?page="+(currentPage-1),request.getRequestURI()+"?page="+(currentPage+1) );


//制定視圖,也就是list.jsp
ModelAndView mav=new ModelAndView("list");
mav.addObject("articles",articles);
mav.addObject("pageStr",pageStr);
return mav;
}

然后運行程序,進入分頁頁面,你就可以看到結(jié)果了:
\

mybatis實戰(zhàn)教程(mybatis in action)之八:mybatis 動態(tài)sql語句


mybatis 的動態(tài)sql語句是基于OGNL表達式的??梢苑奖愕脑?sql 語句中實現(xiàn)某些邏輯. 總體說來mybatis 動態(tài)SQL 語句主要有以下幾類:
1. if 語句 (簡單的條件判斷)
2. choose (when,otherwize) ,相當于java 語言中的 switch ,與 jstl 中的choose 很類似.
3. trim (對包含的內(nèi)容加上 prefix,或者 suffix 等,前綴,后綴)
4. where (主要是用來簡化sql語句中where條件判斷的,能智能的處理 and or ,不必擔心多余導致語法錯誤)
5. set (主要用于更新時)
6. foreach (在實現(xiàn) mybatis in 語句查詢時特別有用)
下面分別介紹這幾種處理方式

1. mybaits if 語句處理
程序代碼 程序代碼


這條語句的意思非常簡單,如果你提供了title參數(shù),那么就要滿足title=#{title},同樣如果你提供了Content和Owner的時候,它們也需要滿足相應的條件,之后就是返回滿足這些條件的所有Blog,這是非常有用的一個功能,以往我們使用其他類型框架或者直接使用JDBC的時候, 如果我們要達到同樣的選擇效果的時候,我們就需要拼SQL語句,這是極其麻煩的,比起來,上述的動態(tài)SQL就要簡單多了

2.2. choose (when,otherwize) ,相當于java 語言中的 switch ,與 jstl 中的choose 很類似
程序代碼 程序代碼


when元素表示當when中的條件滿足的時候就輸出其中的內(nèi)容,跟JAVA中的switch效果差不多的是按照條件的順序,當when中有條件滿足的時候,就會跳出choose,即所有的when和otherwise條件中,只有一個會輸出,當所有的我很條件都不滿足的時候就輸出otherwise中的內(nèi)容。所以上述語句的意思非常簡單, 當title!=null的時候就輸出and titlte = #{title},不再往下判斷條件,當title為空且content!=null的時候就輸出and content = #{content},當

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

文檔

mybatis完美實戰(zhàn)教程

mybatis完美實戰(zhàn)教程:寫在這個系列前面的話: 以前曾經(jīng)用過ibatis,這是mybatis的前身,當時在做項目時,感覺很不錯,比hibernate靈活。性能也比hibernate好。而且也比較輕量級,因為當時在項目中,沒來的及做很很多筆記。后來項目結(jié)束了,我也沒寫總結(jié)文檔。已經(jīng)過去好久了。但最
推薦度:
標簽: 教程 完美 前面
  • 熱門焦點

最新推薦

猜你喜歡

熱門推薦

專題
Top