Mybatis入门案例讲解
目 录
- MyBatis概述
- MyBatis下载与安装
- MyBatis的工作原理
- MyBatis的增删改查
- 使用resultMap属性映射查询结果
- 使用Mapper接口执行SQL
MyBatis概述
- MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索。MyBatis可以使用简单的XML或注解来配置和映射基本数据类型,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。
与持久层框架Hibernate对比
-
Hibernate较深度的封装了JDBC,对开发者编写SQL的能力要求不高,只要通过SQL语句操作对象即可完成对数据库持久化的操作。另外Hibernate的可移植性好,如一个项目开始使用的是MySQL数据库,现在决定使用Oracle数据库,由于不同的数据库使用SQL的标准还是有差距的,因此手动修改会存在很大的困难,而使用Hibernate只需改变一下数据库方言即可。使用Hibernate框架,数据库的移植变得非常方便。但是Hibernate也存在诸多的不足,比如在实际开发中会生成很多不必要的SQL语句耗费程序资源,优化起来也不是很方便,且对存储过程的支持也不够强大。
-
Mybatis也是对JDBC的封装,但是封装得没有Hibernate那么深,通过在配置文件中编写SQL语句,可以根据需求定制SQL语句,数据优化起来比Hibernate容易的多。但Mybatis要求程序员编写SQL的能力要比Hibernate高,且可移植性也不是很好。涉及大数据的系统使用Mybatis比较好,因为优化方便。涉及数据量不大且优化要求不高的系统,可以使用Hibernate。
MyBatis下载与安装
- 通过官方网站https://github.com/mybatis/mybatis-3/releases下载MyBatis的最新版本mybatis-3.4.6.zip 。
- 通过CSDN下载 https://download.csdn.net/download/qq_22075913/12842080
- MyBatis压缩包的文件结构
MyBatis的工作原理
- MyBatis框架的执行流程图
使用MyBatis操作数据库时,大致经过以下步骤。
(1) 读取MyBatis配置文件mybatis-config.xml
- mybatis-config.xml是Mybatis的全局配置文件,名称不固定。该文件中配置了数据源、事务等Mybatis运行环境。
(2) 加载映射文件mapper.xml
- mapper.xml是SQL映射文件,该文件中定义了数据库操作的SQL语句,需要在mybatis-config.xml文件中加载。
(3) 创建会话工厂
- 根据Mybatis的配置文件创建会话工厂SqlSessionFactory。
(4) 创建会话
- 通过会话工厂SqlSessionFactory创建SqlSession对象,该对象提供了执行SQL的所有方法。
(5) 通过Executor操作数据库
- Executor是Mybatis的一个核心接口,它与SqlSession绑定在一起,每个SqlSession都有一个新的Executor对象,由Configuration创建。SqlSession内部通过执行器操作数据库,增删改语句通过Executor接口的update方法执行,查询语句通过query方法执行。
(6) 输入参数和输出结果的映射
- 在执行SQL语句前,Executor执行器通过MappedStatement对象,将传入的Java对象映射到SQL语句中。在执行SQL语句后,MappedStatement对象将执行结果映射到Java对象。
MyBatis的增删改查
- 在Java或JavaWeb项目中添加MyBatis必需的核心包,就能对数据表进行增删改查操作了。下面以MySQL数据库eshop中的数据表user_info为例,使用MyBatis实现数据的增删改查。
- 根据用户编号查询用户
实现步骤:
1)新建名为mybatis1的JAVA项目,新建lib文件夹,添加jar包
2)复制Mybatis jar包和Mysql jar包到项目中
3) 创建实体类UserInfo
package com.mybatis.pojo;
public class UserInfo {
private int id;
private String userName;
private String password;
private String realName;
private String sex;
private String address;
private String email;
private String regDate;
private int status;
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 getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getRegDate() {
return regDate;
}
public void setRegDate(String regDate) {
this.regDate = regDate;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
@Override
public String toString() {
return "UserInfo [id=" + id + ", userName=" + userName + ",
password=" + password + ", realName=" + realName+ ", sex=" + sex + ",
address=" + address + ", email=" + email + ",
regDate=" + regDate + ", status="+ status + "]";
}
public UserInfo(int id, String userName, String password, String realName,
String sex, String address, String email,
String regDate, int status) {
this.id = id;
this.userName = userName;
this.password = password;
this.realName = realName;
this.sex = sex;
this.address = address;
this.email = email;
this.regDate = regDate;
this.status = status;
}
public UserInfo() {
}
}
4)创建SQL映射的XML文件
UserInfoMapper.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.mybatis.mapper.UserInfoMapper">
<!-- 根据用户编号查询用户 -->
<select id="findUserInfoById" parameterType="int" resultType="UserInfo">
select *from user_info where id=#{id}
</select>
</mapper>
5)创建属性文件db.properties
# jdbc.driver=com.mysql.jdbc.Driver
jdbc.driver=com.mysql.cj.jdbc.Driver #数据库驱动名
jdbc.url=jdbc:mysql://localhost:3306/eshop?serverTimezone=UTC #数据库Url
jdbc.username=root #数据库用户名
jdbc.password=root #指定用户密码
6)创建Mybatis核心配置文件
mybatis-config.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>
<!-- 加载属性文件 -->
<properties resource="db.properties"></properties>
<!-- 给包中的类注册别名,不用在类名前加包名 -->
<typeAliases>
<package name="com.mybatis.pojo"></package>
</typeAliases>
<!-- 配置环境 -->
<environments default="development">
<environment id="development">
<!-- 使用JDBC事务 -->
<transactionManager type="JDBC"></transactionManager>
<!-- 指定数据源 POOLED数据库连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 引用映射文件 -->
<mappers>
<mapper resource="com/mybatis/mapper/UserInfoMapper.xml"></mapper>
</mappers>
</configuration>
7)创建测试类
package com.mybatis.test;
import static org.junit.jupiter.api.Assertions.*;
import java.io.IOException;
import java.io.InputStream;
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 org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.mybatis.pojo.UserInfo;
public class MybatisTest {
private SqlSessionFactory sqlSessionFactory;
private SqlSession sqlSession;
//初始化方法
@Before
public void init() {
//读取mybatis配置文件
String resource="mybatis-config.xml";
InputStream inputStream;
try {
//得到配置文件流
inputStream=Resources.getResourceAsStream(resource);
//根据配置文件信息,创建会话工厂
sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//通过工厂得到session
sqlSession=sqlSessionFactory.openSession();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//根据id查询用户
@Test
public void testFindById() {
//通过sqlSession执行映射文件中定义的sql并返回结果
UserInfo ui=sqlSession.selectOne("findUserInfoById",1);
System.out.println(ui);
}
@After
public void destroy() {
//提交事务
sqlSession.commit();
//关闭sqlSession
sqlSession.close();
}
}
8)测试结果
9)项目结构如下
10)SQL语句
/*
SQLyog v10.2
MySQL - 5.5.27 : Database - eshop
*********************************************************************
*/
/*!40101 SET NAMES utf8 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`eshop` /*!40100 DEFAULT CHARACTER SET gbk */;
USE `eshop`;
DROP TABLE IF EXISTS `user_info`;
CREATE TABLE `user_info` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`userName` varchar(16) DEFAULT NULL,
`password` varchar(16) DEFAULT NULL,
`realName` varchar(8) DEFAULT NULL,
`sex` varchar(4) DEFAULT NULL,
`address` varchar(255) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`regDate` date DEFAULT NULL,
`status` int(4) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
/*Data for the table `user_info` */
insert into `user_info`(`id`,`userName`,`password`,`realName`,`sex`,`address`,`email`,`regDate`,`status`)
values (1,'tom','123456','汤姆','女','江苏省苏州市吴中区','tom@123.com','2013-07-14',1),
(2,'john','123456','约翰','女','江苏省南京市玄武区','wen@135.com','2013-07-14',1),
(3,'my','123456','my','男','江苏省南京市玄武区','a@135.com','2015-09-16',1),
(4,'sj','123456','sj','男','江苏省南京市玄武区','b@135.com','2015-09-16',1),
(5,'lxf','123456','lxf','男','江苏省南京市玄武区','c@135.com','2015-09-16',1),
(6,'lj','123456','lj','男','江苏省南京市玄武区','a@135.com','2015-09-20',1);
根据用户名模糊查询用户
实现步骤:
1)在映射文件UserInfoMapper.xml中,添加根据用户名模糊查询用户的SQL语句,如下所示
<!-- 根据用户名模糊查询用户 -->
<select id="findUserInfoByName" parameterType="String" resultType="UserInfo">
select *from user_info where userName like
CONCAT(CONCAT('%',#{userName}),'%')
</select>
2)在测试类MybatisTest中,添加一个测试方法testFindByName,代码如下
//根据用户名模糊查询
@Test
public void testFindByName() {
//通过sqlSession执行映射文件中定义的sql并返回结果
List<UserInfo> ulist=sqlSession.selectList("findUserInfoByName","m");
for(UserInfo u:ulist) {
System.out.println(u);
}
}
3)运行测试方法testFindByName,结果如下
添加用户
实现步骤:
1)在映射文件UserInfoMapper.xml中,添加用户的SQL语句,如下所示
<!-- 添加用户 -->
<insert id="addUserInfo" parameterType="UserInfo">
insert into user_info(userName,password) values(#{userName},#{password})
</insert>
2)在测试类MybatisTest中,添加一个测试方法testAddUserInfo,代码如下
//添加用户
@Test
public void testAddUserInfo() {
//创建UserInfo对象
UserInfo userInfo=new UserInfo();
userInfo.setUserName("paul");
userInfo.setPassword("6666");
int result=sqlSession.insert("addUserInfo",userInfo);
if(result>0) {
System.out.println("插入成功");
}else {
System.out.println("插入失败");
}
}
3)运行测试方法testAddUserInfo,结果如下
修改用户
实现步骤:
1)在映射文件UserInfoMapper.xml中,修改用户的SQL语句,如下所示
<!-- 修改用户 -->
<update id="updateUserInfo" parameterType="UserInfo">
update user_info set userName=#{userName},password=#{password} where id=#{id}
</update>
2)在测试类MybatisTest中,添加一个测试方法testAddUserInfo,代码如下
//修改用户
@Test
public void testUpdateUserInfo() {
//加载编号为7的用户
UserInfo ui=sqlSession.selectOne("findUserInfoById", 7);
ui.setUserName("henry");
ui.setPassword("22222");
int result=sqlSession.update("updateUserInfo", ui);
if(result>0) {
System.out.println("更新成功");
}else {
System.out.println("更新失败");
}
}
3)运行测试方法testUpdateUserInfo,结果如下
删除用户
实现步骤:
1)在映射文件UserInfoMapper.xml中,删除用户的SQL语句,如下所示
<!-- 删除用户 -->
<delete id="deleteUserInfo" parameterType="int">
delete from user_info where id=#{id}
</delete>
2)在测试类MybatisTest中,添加一个测试方法testAddUserInfo,代码如下
//删除用户
@Test
public void testDeleteUserInfo() {
//通过sqlSession执行映射文件中定义的sql并返回结果
int result=sqlSession.delete("deleteUserInfo", 7);
if(result>0) {
System.out.println("删除成功");
}else {
System.out.println("删除失败");
}
}
3)运行测试方法testDeleteUserInfo,结果如下
使用resultMap属性映射查询结果
- 在上述示例中,实体类UserInfo中的属性名与数据表user_info中的字段名相同,如果属性名与数据表的字段名不相同,那么就需要使用resultMap属性来进行结果集的映射。
实现步骤:
1)将项目mybatis1复制并命名为mybatis2,再导入eclipse中
2)修改实体类UserInfo.java,将其属性重新命名,使得属性名与数据表user_info的字段名不同
这里修改uid,uname,upass
package com.mybatis.pojo;
public class UserInfo {
private int uid;
private String uname;
private String upass;
private String realName;
private String sex;
private String address;
private String email;
private String regDate;
private int status;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
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 getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getRegDate() {
return regDate;
}
public void setRegDate(String regDate) {
this.regDate = regDate;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
@Override
public String toString() {
return "UserInfo [uid=" + uid + ", uname=" + uname + ", upass=" + upass + ", realName=" + realName + ", sex=" + sex
+ ", address=" + address + ", email=" + email + ", regDate=" + regDate + ", status=" + status + "]";
}
public UserInfo() {
}
}
3)修改映射文件UserInfoMapper.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.mybatis.mapper.UserInfoMapper">
<!-- 根据用户编号查询用户 -->
<select id="findUserInfoById" parameterType="int" resultMap="userInfoMap">
select *from user_info where id=#{id}
</select>
<resultMap type="UserInfo" id="userInfoMap">
<id property="uid" column="id"/>
<result property="uname" column="userName"/>
<result property="upass" column="password"/>
</resultMap>
</mapper>
在 select元素中,通过resultMap属性引用该映射文件中一个id为userInfoMap的 resultMap元素,来完成查询结果的映射。在resultMap元素中,type属性指定映射结果的类型,这里为UserInfo;
4)执行测试类MybatisTest的testFindById方法
结果如下:
使用Mapper接口执行SQL
- 在测试类MybatisTest的测试方法中,通过sqlSession对象调用selectOne、selectList、delete和update等方法。在这些方法中,需要指定映射文件中执行语句的id(如findUserInfoById)。如果id的拼写出现错误,只有到运行时才能发现。为此,MyBatis提供了另一种编程方式,即使用Mapper接口执行SQL,从而避免上述情况的出现,同时也更符合Java面向接口编程的习惯。
使用Mapper接口开发时需要遵循如下规范:
-
映射文件中的namespace与Mapper接口的类路径相同。
-
在Mapper接口中,方法名和映射文件中定义的执行语句的id相同。
-
方法的输入参数类型和映射文件中定义的执行语句的parameterType的类型相同。
-
方法输出参数类型和映射文件中定义的执行语句的resultType的类型相同。
实现步骤:
1)将项目mybatis1复制并命名为mybatis3,再导入eclipse中
2)在com.mybatis.mapper包中,创建接口UserInfoMapper.java,并声明方法,如下所示
package com.mybatis.mapper;
import com.mybatis.pojo.UserInfo;
public interface UserInfoMapper {
UserInfo findUserInfoById(int uid);
}
3)在测试类MybatisTest中,修改测试方法testFindUserInfoById
//根据id查询用户
@Test
public void testFindUserInfoById() {
//通过sqlSession对象的getMapper方法获取UserInfoMapper接口的代理对象
UserInfoMapper mapper=sqlSession.getMapper(UserInfoMapper.class);
//直接调用接口中的方法
UserInfo ui=mapper.findUserInfoById(1);
System.out.println(ui.toString());
}
4)运行测试方法testFindUserInfoById