什么是mybatis
MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录.
orm工具的基本思想
无论是用过的hibernate还是mybatis,你都可以法相他们有如下共同点:
开发环境搭建
mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包。这些软件工具均可以到各自的官方网站上下载。
首先建立一个名字为 MyBaits 的 dynamic web project
创建用户表,并插入一条测试数据
程序代码
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项目了。
程序代码
< ?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>
<typeAliases>
<typeAlias alias="User" type="com.yihaomen.mybatis.model.User"/>
typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis" />
<property name="username" value="root"/>
<property name="password" value="password"/>
dataSource>
environment>
environments>
<mappers>
<mapper resource="com/yihaomen/mybatis/model/User.xml"/>
mappers>
< /configuration>
3. 建立与数据库对应的 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">
<select id="selectUserByID" parameterType="int" resultType="User">
select * from `user` where id = #{id}
select>
< /mapper>
下面对这几个配置文件解释下:
1、Configuration.xml 是 mybatis 用来建立 sessionFactory 用的,里面主要包含了数据库连接相关东西,还有 java 类所对应的别名,比如
这个别名非常重要,你在 具体的类的映射中,比如User.xml 中 resultType 就是对应这里的。要保持一致,当然这里的 resultType 还有另外单独的定义方式,后面再说。
2、Configuration.xml 里面 的
是包含要映射的类的xml配置文件。
3、 在User.xml 文件里面 主要是定义各种SQL 语句,以及这些语句的参数,以及要返回的类型等.
开始测试
在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();
}
}
}
现在运行这个程序,是不是得到查询结果了。恭喜你,环境搭建配置成功,接下来第二章,将讲述基于接口的操作方式,增删改查。
以接口的方式编程
前面已经搭建好了eclipse,mybatis,mysql的环境,并且实现了一个简单的查询。请注意,这种方式是用SqlSession实例来直接执行已映射的SQL语句:
session.selectOne("com.yihaomen.mybatis.models.UserMapper.selectUserByID", 1)
其实还有更简单的方法,而且是更好的方法,使用合理描述参数和SQL语句返回值的接口(比如IUserOperation.class),这样现在就可以至此那个更简单,更安全的代码,没有容易发生的字符串文字和转换的错误.下面是详细过程:
在src_user源码目录下建立 com.yihaomen.mybatis.inter 这个包,并建立接口类 IUserOperation , 内容如下:
程序代码
package com.yihaomen.mybatis.inter;
import com.yihaomen.mybatis.model.User;
public interface IUserOperation {
public User selectUserByID(int id);
}
请注意,这里面有一个方法名 selectUserByID 必须与 User.xml 里面配置的 select 的id 对应(
重写测试代码
public static void main(String[] args) {
SqlSession session = sqlSessionFactory.openSession();
try {
IUserOperation userOperation=session.getMapper(IUserOperation.class);
User user = userOperation.selectUserByID(1);
System.out.println(user.getUserAddress());
System.out.println(user.getUserName());
} finally {
session.close();
}
}
运行这个测试程序,就可以看到结果了。
实现数据的增删改查
前面已经讲到用接口的方式编程。这种方式,要注意的一个地方就是。在User.xml 的配置文件中,mapper namespace=”com.yihaomen.mybatis.inter.IUserOperation” ,命名空间非常重要,不能有错,必须与我们定义的package 和 接口一致。如果不一致就会出错,这一章主要在上一讲基于接口编程的基础上完成如下事情:
查询数据,前面已经讲过简单的,主要看查询出列表的
查询出列表,也就是返回list, 在我们这个例子中也就是 List
, 这种方式返回数据,需要在User.xml 里面配置返回的类型 resultMap, 注意不是 resultType, 而这个resultMap 所对应的应该是我们自己配置的
程序代码
< !-- 为了返回list 类型而定义的returnMap -->
"User" id="resultListUser">
<id column="id" property="id" />
<result column="userName" property="userName" />
<result column="userAge" property="userAge" />
<result column="userAddress" property="userAddress" />
查询列表的语句在 User.xml
程序代码
< !-- 返回list 的select 语句,注意 resultMap 的值是指向前面定义好的 -->
<select id="selectUsers" parameterType="string" resultMap="resultListUser">
select * from user where userName like #{userName}
select>
在 IUserOperation 接口中增加方法:public List
现在在 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();
}
}
现在在main 方法中可以测试:
程序代码
public static void main(String[] args) {
Test testUser=new Test();
testUser.getUserList("%");
}
可以看到,结果成功查询出来。如果是查询单个数据的话,用第二讲用过的方法就可以了。
用mybatis 增加数据
在 IUserOperation 接口中增加方法:public void addUser(User user);
在 User.xml 中配置
程序代码
< !--执行增加操作的SQL语句。id和parameterType
分别与IUserOperation接口中的addUser方法的名字和
参数类型一致。以#{name}的形式引用Student参数
的name属性,MyBatis将使用反射读取Student参数
的此属性。#{name}中name大小写敏感。引用其他
的gender等属性与此一致。seGeneratedKeys设置
为"true"表明要MyBatis获取由数据库自动生成的主
键;keyProperty="id"指定把获取到的主键值注入
到Student的id属性-->
id="addUser" parameterType="User"
useGeneratedKeys="true" keyProperty="id">
insert into user(userName,userAge,userAddress)
values(#{userName},#{userAge},#{userAddress})
然后在 Test 中写测试方法:
程序代码
/**
* 测试增加,增加后,必须提交事务,否则不会写入到数据库.
*/
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 更新数据
方法类似,先在 IUserOperation 中增加方法:public void updateUser(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("原来是魔都的浦东创新园区");
userOperation.updateUser(user);
session.commit();
} finally {
session.close();
}
}
用mybatis 删除数据
同理,IUserOperation 增加方法:public void deleteUser(int id);
配置User.xml
程序代码
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
delete>
然后在Test类中写测试方法:
程序代码
/**
* 删除数据,删除一定要 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();
}
}
这样,所有增删改查都完成了,注意在增加,更改,删除的时候要调用session.commit(),这样才会真正对数据库进行操作,否则是没有提交的。
到此为止,简单的单表操作,应该都会了,接下来的时间了,我会讲多表联合查询,以及结果集的选取。
mybatis实战教程(mybatis in action)之四:实现关联数据的查询
有了前面几章的基础,对一些简单的应用是可以处理的,但在实际项目中,经常是关联表的查询,比如最常见到的多对一,一对多等。这些查询是如何处理的呢,这一讲就讲这个问题。我们首先创建一个Article 这个表,并初始化数据.
程序代码
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;
-- ----------------------------
-- 添加几条测试数据
-- ----------------------------
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');
你应该发现了,这几个文章对应的userid都是1,所以需要用户表user里面有id=1的数据。可以修改成满足自己条件的数据.按照orm的规则,表已经创建了,那么肯定需要一个对象与之对应,所以我们增加一个 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类型。
多对一的实现
场景:在读取某个用户发表的所有文章。当然还是需要在User.xml 里面配置 select 语句, 但重点是这个 select 的resultMap 对应什么样的数据呢。这是重点,这里要引入 association 看定义如下:
程序代码
< !-- User 联合文章进行查询 方法之一的配置 (多对一的方式) -->
id="resultUserArticleList" type="Article">
<id property="id" column="aid" />
<result property="title" column="title" />
<result property="content" column="content" />
property="user" javaType="User">
<id property="id" column="id" />
<result property="userName" column="userName" />
<result property="userAddress" column="userAddress" />
< 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 对应的映射结合起来看,就明白了。用association 来得到关联的用户,这是多对一的情况,因为所有的文章都是同一个用户的。
还有另外一种处理方式,可以复用我们前面已经定义好的 resultMap ,前面我们定义过一个 resultListUser ,看这第二种方法如何实现:
程序代码
"User" id="resultListUser">
<id column="id" property="id" />
<result column="userName" property="userName" />
<result column="userAge" property="userAge" />
<result column="userAddress" property="userAddress" />
-- User 联合文章进行查询 方法之二的配置 (多对一的方式) -->
id="resultUserArticleList-2" type="Article">
<id property="id" column="aid" />
<result property="title" column="title" />
<result property="content" column="content" />
property="user" javaType="User" resultMap="resultListUser" />
将 association 中对应的映射独立抽取出来,可以达到复用的目的。
在 IUserOperation 接口中,加入 select 对应的id 名称相同的方法:
public List getUserArticles(int id);
好了,现在在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();
}
}
然后运行就可以测试。
与spring3集成
在前面讲到纯粹用mybatis 连接数据库,然后 进行增删改查,以及多表联合查询的的例子,但实际项目中,通常会用 spring 这个沾合剂来管理 datasource 等。充分利用spring 基于接口的编程,以及aop ,ioc 带来的方便。用spring 来管理 mybatis 与管理hibernate 有很多类似的地方。今天的重点就是数据源管理以及 bean的配置。
程序代码
< !--本示例采用DBCP连接池,应预先把DBCP的jar包复制到工程的lib目录下。 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="password"/>
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="config/Configuration.xml"/>
bean>
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
<property name="mapperInterface" value="com.yihaomen.mybatis.inter.IUserOperation" />
bean>
这里面的重点就是 org.mybatis.spring.SqlSessionFactoryBean 与 org.mybatis.spring.mapper.MapperFactoryBean[b] 实现了 spring 的接口,并产生对象。详细可以查看 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的用户查询,根据数据库中的情况,可以改成你自己的.
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());
}
}
}
运行即可得到相应的结果.
与Spring MVC 的集成
前面讲到了mybatis与spring 的集成。但这个时候,所有的工程还不是web工程,虽然我一直是创建的web 工程。今天将直接用mybatis与Spring mvc 的方式集成起来。主要有以下几个方面的配置
1、web.xml 配置 spring dispatchservlet ,比如为:mvc-dispatcher
程序代码 程序代码
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath*:config/applicationContext.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
<listener>
<listener-class>
org.springframework.web.context.ContextCleanupListenerlistener-class>
listener>
<servlet>
<servlet-name>mvc-dispatcherservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcherservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
2、在web.xml 同目录下配置 mvc-dispatcher-servlet.xml 文件,这个文件名前面部分必须与你在web.xml里面配置的DispatcherServlet 的servlet名字对应.其内容为:
程序代码
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.yihaomen.controller" />
<mvc:annotation-driven />
<mvc:resources mapping="/static/**" location="/WEB-INF/static/"/>
<mvc:default-servlet-handler/>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/value>
property>
<property name="suffix">
<value>.jspvalue>
property>
bean>
< /beans>
3、在源码目录 config 目录下配置 spring 配置文件 applicationContext.xml
程序代码
< !--本示例采用DBCP连接池,应预先把DBCP的jar包复制到工程的lib目录下。 -->
<context:property-placeholder location="classpath:/config/database.properties" />
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://127.0.0.1:3306/mybatis?characterEncoding=utf8"
p:username="root" p:password="password"
p:maxActive="10" p:maxIdle="10">
bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:config/Configuration.xml" />
<property name="mapperLocations" value="classpath*:com/yihaomen/mapper/*.xml" />
bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yihaomen.inter" />
bean>
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、页面文件:
< c:forEach items="${articles}" var="item">
${item.id }--${item.title }--${item.content }
forEach>
实现mybatis分页
上面已经讲到了mybatis与spring MVC的集成,并且做了一个列表展示,显示出所有article 列表,但没有用到分页,在实际的项目中,分页是肯定需要的。而且是物理分页,不是内存分页。对于物理分页方案,不同的数据库,有不同的实现方法,对于mysql 来说 就是利用 limit offset,pagesize 方式来实现的。oracle 是通过rownum 来实现的,如果你熟悉相关数据库的操作,是一样的很好扩展,本文以mysql 为例子来讲述.
实现mybatis 物理分页,一个最简单的方式是,是在你的mapper的SQL语句中直接写类似如下方式 :
程序代码
请注意这里的 parameterType 是你传入的参数类,或者map ,里面包含了offset,pagesize ,和其他你需要的参数,用这种方式,肯定可以实现分页。这是简单的一种方式。但更通用的一种方式是用 mybatis 插件的方式.
准备工作,在mysql数据库中创建一个用户表,用来展示分页用。
建表语句
CREATE DATABASE learning;
USE learning;
CREATE TABLE t_user (
USER_ID int(11) NOT NULL AUTO_INCREMENT,
USER_NAME char(30) NOT NULL,
USER_PASSWORD char(10) NOT NULL,
USER_EMAIL char(30) NOT NULL,
PRIMARY KEY (USER_ID),
KEY IDX_NAME (USER_NAME)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8
插入N条数据
INSERT INTO t_user (USER_ID, USER_NAME, USER_PASSWORD, USER_EMAIL) VALUES (1, 'KJ', 'abc', '[email protected]');
INSERT INTO t_user (USER_ID, USER_NAME, USER_PASSWORD, USER_EMAIL) VALUES (2, 'KJ2', '123', '[email protected]');
1、用maven管理项目工程,在pom.xml中引入jar包
<dependency>
<groupId>com.github.pagehelpergroupId>
<artifactId>pagehelperartifactId>
<version>4.0.0version>
dependency>
2、mybatis-config.xml中添加插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" value="mysql"/>
<property name="offsetAsPageNum" value="true"/>
<property name="rowBoundsWithCount" value="true"/>
<property name="pageSizeZero" value="true"/>
<property name="reasonable" value="false"/>
<property name="params" value="pageNum=start;pageSize=limit;"/>
plugin>
plugins>
这样子就引入进来了,接下来就是来开始分页功能的实现
3、mapper文件中添加如下一个方法:
<resultMap id="BaseResultMap" type="com.lin.domain.User">
<id column="USER_ID" property="userId" jdbcType="INTEGER" />
<result column="USER_NAME" property="userName" jdbcType="CHAR" />
<result column="USER_PASSWORD" property="userPassword" jdbcType="CHAR" />
<result column="USER_EMAIL" property="userEmail" jdbcType="CHAR" />
resultMap>
<select id="selectUserByUserName" parameterType="java.lang.String" resultMap="BaseResultMap">
SELECT *
FROM t_user
WHERE 1 = 1
<if test="userName != null and userName !=''">
AND USER_NAME = #{userName,jdbcType=VARCHAR}
if>
ORDER BY USER_ID
select>
4、然后就是dao类
/**
*
* @author KJ
* @since 2016年8月18日
* @param userName
* @return
*/
List selectUserByUserName(@Param("userName") String userName);
这里一定的记得加@Param(“userName”)
接下来就可以在service层中添加分页查询的的接口了
5、接口类
/**
*
* @author KJ
* @since 2016年8月18日
* @param userName 查询条件,可为空
* @param pageNo 查询条件,可为空,默认取1
* @param pageSize 查询条件,可为空,默认取10
* @return
*/
PagedResult queryByPage(String userName,Integer pageNo,Integer pageSize);
6、实现类
public PagedResult<User> queryByPage(String userName,Integer pageNo,Integer pageSize ) {
pageNo = pageNo == null?1:pageNo;
pageSize = pageSize == null?10:pageSize;
PageHelper.startPage(pageNo,pageSize); //startPage是告诉拦截器说我要开始分页了。分页参数是这两个。
return BeanUtil.toPagedResult(userDao.selectUserByUserName(userName));
}
这里就可以直接在返回里头使用了PageHelper,这里userDao.selectUserByUserName(userName)的返回是一个list
其中,PagedResult是我自己封装的一个分页结果类
package com.lin.util;
import java.util.List;
import com.lin.dto.BaseEntity;
/**
* 功能概要:
*
* @author KJ
* @since 2016年8月18日
*/
public class PagedResult extends BaseEntity {
/*serialVersionUID*/
private static final long serialVersionUID = 1L;
private List dataList;//数据
private long pageNo;//当前页
private long pageSize;//条数
private long total;//总条数
private long pages;//总页面数目
public List getDataList() {
return dataList;
}
public void setDataList(List dataList) {
this.dataList = dataList;
}
public long getPageNo() {
return pageNo;
}
public void setPageNo(long pageNo) {
this.pageNo = pageNo;
}
public long getPageSize() {
return pageSize;
}
public void setPageSize(long pageSize) {
this.pageSize = pageSize;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public long getPages() {
return pages;
}
public void setPages(long pages) {
this.pages = pages;
}
}
这是它的基类
package com.lin.dto;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* 类说明:bean基类
*
*
* 详细描述:
*
* @author KJ
* @since 2016年8月18日
*/
public abstract class BaseEntity implements Serializable{
private static final long serialVersionUID = 1L;
private static Map,PropertyInfo[]> class2Props = new HashMap,PropertyInfo[]>(128);
@Override
public String toString() {
PropertyInfo[] props = class2Props.get(this.getClass());
if( props == null ){
props = getProps(this.getClass());
}
StringBuilder builder = new StringBuilder(1024);
boolean isFirst = true;
for (int i = 0, n = props.length; i < n; i++) {
try {
PropertyInfo propInfo = props[i];
Object value = propInfo.getMethod.invoke(this, new Object[0]);
if (isFirst)
isFirst = false;
else
builder.append(",");
builder.append(propInfo.propName);
builder.append(":");
if (value instanceof String)
builder.append("\"");
builder.append(value);
if (value instanceof String)
builder.append("\"");
} catch (Exception e) {
// ignore
}
}
return "{" + builder.toString() + "}";
}
private static PropertyInfo[] getProps(Class extends BaseEntity> clazz) {
PropertyInfo[] props;
Method[] allMethods = clazz.getMethods();
List propList = new ArrayList();
for (int i = 0, n = allMethods.length; i < n; i++) {
try {
Method method = allMethods[i];
if ((method.getModifiers() & Modifier.PUBLIC) == 1
&& method.getDeclaringClass() != Object.class
&& (method.getParameterTypes() == null || method
.getParameterTypes().length == 0)) {
String methodName = method.getName();
if (methodName.startsWith("get") || methodName.startsWith("is") ) {
PropertyInfo propInfo = new PropertyInfo();
propInfo.getMethod = method;
if (methodName.startsWith("get")) {
propInfo.propName = methodName.substring(3, 4).toLowerCase()
+ methodName.substring(4);
} else if (methodName.startsWith("is")) {
propInfo.propName = methodName.substring(2, 3).toLowerCase()
+ methodName.substring(3);
}
propList.add(propInfo);
}
}
}catch(Exception e){
}
}
props = new PropertyInfo[propList.size()];
propList.toArray(props);
class2Props.put(clazz, props);
return props;
}
static class PropertyInfo{
Method getMethod;
String propName;
}
}
BeanUtil是一个将PageHelper返回的list转成pageResult的工具
package com.lin.util;
import java.util.List;
import com.github.pagehelper.Page;
import com.lin.util.PagedResult;
/**
* 功能概要:
*
* @author KJ
* @since 2016年8月18日
*/
public class BeanUtil {
public static PagedResult toPagedResult(List datas) {
PagedResult result = new PagedResult();
if (datas instanceof Page) {
Page page = (Page) datas;
result.setPageNo(page.getPageNum());
result.setPageSize(page.getPageSize());
result.setDataList(page.getResult());
result.setTotal(page.getTotal());
result.setPages(page.getPages());
} else {
result.setPageNo(1);
result.setPageSize(datas.size());
result.setDataList(datas);
result.setTotal(datas.size());
}
return result;
}
}
7、这样就好了,可以跑单元测试了
/**
* 分页测试
* @author KJ
* @since 2016年8月18日
*/
@Test
public void queryByPage(){
PagedResult pagedResult = userService.queryByPage(null,1,10);//null表示查全部
logger.debug("查找结果" + pagedResult);
}
上面是分页插件的使用方法,前台展示详情请看我的下一篇博文。
mybatis 动态sql语句
mybatis 的动态sql语句是基于OGNL表达式的。可以方便的在 sql 语句中实现某些逻辑. 总体说来mybatis 动态SQL 语句主要有以下几类:
下面分别介绍这几种处理方式
1. mybaits if 语句处理
程序代码
<select id="dynamicIfTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 1 = 1
<if test="title != null">
and title = #{title}
if>
<if test="content != null">
and content = #{content}
if>
<if test="owner != null">
and owner = #{owner}
if>
select>
这条语句的意思非常简单,如果你提供了title参数,那么就要满足title=#{title},同样如果你提供了Content和Owner的时候,它们也需要满足相应的条件,之后就是返回满足这些条件的所有Blog,这是非常有用的一个功能,以往我们使用其他类型框架或者直接使用JDBC的时候, 如果我们要达到同样的选择效果的时候,我们就需要拼SQL语句,这是极其麻烦的,比起来,上述的动态SQL就要简单多了
2.choose (when,otherwize) ,相当于java 语言中的 switch ,与 jstl 中的choose 很类似
程序代码
<select id="dyamicChooseTest" parameterType="Blog" resultType="Blog">
select * from t_blog where 1 = 1
<when test="title != null">
and title = #{title}
when>
<when test="content != null">
and content = #{content}
when>
and owner = "owner1"
select>
when元素表示当when中的条件满足的时候就输出其中的内容,跟JAVA中的switch效果差不多的是按照条件的顺序,当when中有条件满足的时候,就会跳出choose,即所有的when和otherwise条件中,只有一个会输出,当所有的我很条件都不满足的时候就输出otherwise中的内容。所以上述语句的意思非常简单, 当title!=null的时候就输出and titlte = #{title},不再往下判断条件,当title为空且content!=null的时候就输出and content = #{content},当所有条件都不满足的时候就输出otherwise中的内容。
3.trim (对包含的内容加上 prefix,或者 suffix 等,前缀,后缀)
程序代码
<select id="dynamicTrimTest" parameterType="Blog" resultType="Blog">
select * from t_blog
"where" prefixOverrides="and |or">
<if test="title != null">
title = #{title}
if>
<if test="content != null">
and content = #{content}
if>
<if test="owner != null">
or owner = #{owner}
if>
trim元素的主要功能是可以在自己包含的内容前加上某些前缀,也可以在其后加上某些后缀,与之对应的属性是prefix和suffix;可以把包含内容的首部某些内容覆盖,即忽略,也可以把尾部的某些内容覆盖,对应的属性是prefixOverrides和suffixOverrides;正因为trim有这样的功能,所以我们也可以非常简单的利用trim来代替where元素的功能
4.where (主要是用来简化sql语句中where条件判断的,能智能的处理 and or 条件
程序代码
<select id="dynamicWhereTest" parameterType="Blog" resultType="Blog">
select * from t_blog
<where>
<if test="title != null">
title = #{title}
if>
<if test="content != null">
and content = #{content}
if>
<if test="owner != null">
and owner = #{owner}
if>
where>
select>
where元素的作用是会在写入where元素的地方输出一个where,另外一个好处是你不需要考虑where元素里面的条件输出是什么样子的,MyBatis会智能的帮你处理,如果所有的条件都不满足那么MyBatis就会查出所有的记录,如果输出后是and 开头的,MyBatis会把第一个and忽略,当然如果是or开头的,MyBatis也会把它忽略;此外,在where元素中你不需要考虑空格的问题,MyBatis会智能的帮你加上。像上述例子中,如果title=null, 而content != null,那么输出的整个语句会是select * from t_blog where content = #{content},而不是select * from t_blog where and content = #{content},因为MyBatis会智能的把首个and 或 or 给忽略。
5.set (主要用于更新时)
程序代码
id="dynamicSetTest" parameterType="Blog">
update t_blog
<set>
<if test="title != null">
title = #{title},
if>
<if test="content != null">
content = #{content},
if>
<if test="owner != null">
owner = #{owner}
if>
set>
where id = #{id}
set元素主要是用在更新操作的时候,它的主要功能和where元素其实是差不多的,主要是在包含的语句前输出一个set,然后如果包含的语句是以逗号结束的话将会把该逗号忽略,如果set包含的内容为空的话则会出错。有了set元素我们就可以动态的更新那些修改了的字段
6.foreach (在实现 mybatis in 语句查询时特别有用)
foreach的主要用在构建in条件中,它可以在SQL语句中进行迭代一个集合。foreach元素的属性主要有item,index,collection,open,separator,close。item表示集合中每一个元素进行迭代时的别名,index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,open表示该语句以什么开始,separator表示在每次进行迭代之间以什么符号作为分隔符,close表示以什么结束,在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况下,该属性的值是不一样的,主要有一下3种情况:
如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map,实际上如果你在传入参数的时候,在MyBatis里面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key
1、单参数List的类型
程序代码
<select id="dynamicForeachTest" resultType="Blog">
select * from t_blog where id in
<foreach collection="list" index="index" item="item" open="(" separator="," close=")">
#{item}
foreach>
select>
上述collection的值为list,对应的Mapper是这样的
程序代码
public List<Blog> dynamicForeachTest(List<Integer> ids);
测试代码
@Test
public void dynamicForeachTest() {
SqlSession session = Util.getSqlSessionFactory().openSession();
BlogMapper blogMapper = session.getMapper(BlogMapper.class);
List ids = new ArrayList();
ids.add(1);
ids.add(3);
ids.add(6);
List blogs = blogMapper.dynamicForeachTest(ids);
for (Blog blog : blogs)
System.out.println(blog);
session.close();
}
2、数组类型的参数
程序代码
<select id="dynamicForeach2Test" resultType="Blog">
select * from t_blog where id in
<foreach collection="array" index="index" item="item" open="(" separator="," close=")">
#{item}
foreach>
select>
对应mapper
程序代码
public List dynamicForeach2Test(int[] ids);
3、 Map 类型的参数
程序代码
<select id="dynamicForeach3Test" resultType="Blog">
select * from t_blog where title like "%"#{title}"%" and id in
<foreach collection="ids" index="index" item="item" open="(" separator="," close=")">
#{item}
foreach>
select>
mapper 应该是这样的接口:
程序代码
public List<Blog> dynamicForeach3Test(Map<String, Object> params);
通过以上方法,就能完成一般的mybatis 的 动态SQL 语句.最常用的就是 if where foreach这几个,一定要重点掌握.
mybatis 代码生成工具的使用
mybatis 应用程序,需要大量的配置文件,对于一个成百上千的数据库表来说,完全手工配置,这是一个很恐怖的工作量. 所以mybatis 也有像hibernate一样的逆向工程生成插件,下面介绍下详细过程:首先用eclipse install一下这个插件http://mybatis.googlecode.com/svn/sub-projects/generator/trunk/eclipse/UpdateSite/
安装后将generator.xml放入项目中
<generatorConfiguration>
<classPathEntry location="E:\eclipse\workspace\UserInfoManage\WebContent\WEB-INF\lib\mysql-connector-java-5.1.30.jar" />
<context id="DB2Tables" targetRuntime="MyBatis3">
<commentGenerator>
<property name="suppressAllComments" value="false" />
commentGenerator>
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/ssmdb"
userId="root"
password="root">
jdbcConnection>
<javaTypeResolver >
<property name="forceBigDecimals" value="false" />
javaTypeResolver>
<javaModelGenerator targetPackage="org.xin.entity" targetProject="bill">
<property name="enableSubPackages" value="true" />
<property name="trimStrings" value="true" />
javaModelGenerator>
<sqlMapGenerator targetPackage="org.xin.mapper" targetProject="bill"> <property name="enableSubPackages" value="false" /> sqlMapGenerator>
<javaClientGenerator type="XMLMAPPER" targetPackage="org.xin.mapper.xml" targetProject="bill"> <property name="enableSubPackages" value="true" /> javaClientGenerator>
<table schema="ssmdb" tableName="user_t" domainObjectName="UserEntity" />
context>
generatorConfiguration>
然后鼠标右键这个xml,可以找到 Generate MyBatis/iBATIS Artifacts,点击运行Generate MyBatis/iBATIS Artifacts即可自动生成dao、mapper.xml、domain,瞬间减少大量工作。