为什么要使用MyBatis?
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
JDBC数据库编程
传统的JDBC数据库编程目前在项目实战中已经几乎绝迹了,原因等我们看一个例子之后稍作分析。这是一个简单的JDBC数据库连接代码例子:
public Student findStudentById(int studId)
{
Student student = null;
Connection conn = null;
try
{
//获得数据库连接
conn = getDatabaseConnection();
String sql = "SELECT * FROM STUDENTS WHERE STUD_ID=?";
//创建 PreparedStatement
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置输入参数
pstmt.setInt(1, studId);
ResultSet rs = pstmt.executeQuery();
//从数据库中取出结果并生成 Java 对象
if(rs.next())
{
student = new Student();
student.setStudId(rs.getInt("stud_id"));
student.setName(rs.getString("name"));
student.setEmail(rs.getString("email"));
student.setDob(rs.getDate("dob"));
}
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
finally
{
//关闭连接
if(conn != null)
{
try
{
conn.close();
}
catch (SQLException e) { }
}
}
return student;
}
public void createStudent(Student student)
{
Connection conn = null;
try
{
//获得数据库连接
conn = getDatabaseConnection();
String sql = "INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB)
VALUES(?,?,?,?)";
//创建 PreparedStatement
PreparedStatement pstmt = conn.prepareStatement(sql);
//设置输入参数
pstmt.setInt(1, student.getStudId());
pstmt.setString(2, student.getName());
pstmt.setString(3, student.getEmail());
pstmt.setDate(4, new
java.sql.Date(student.getDob().getTime()));
pstmt.executeUpdate();
}
catch (SQLException e)
{
throw new RuntimeException(e);
}
finally
{
//关闭连接
if(conn != null)
{
try
{
conn.close();
}
catch (SQLException e) { }
}
}
}
protected Connection getDatabaseConnection() throws SQLException
{
try
{
Class.forName("com.mysql.jdbc.Driver");
return DriverManager.getConnection
("jdbc:mysql://localhost:3306/test", "root", "admin");
}
catch (SQLException e)
{
throw e;
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
可以看出,JDBC编程需要如下几个步骤:
- JDBC连接数据库,注册驱动和数据库信息
- 操作Connection对象,打开Statement对象
- 通过Statement对象操作SQL语句
- 通过ResultSet对象读取数据,再转换为具体的POJO。
- 关闭数据库连接
可以看出JDBC数据库连接的工作量比较大,代码繁杂,有很多的模板代码。像异常的处理、数据库的关闭等都是模式化的处理流程。
Hibernate
Hibernate通过XML文件来与数据库进行交互,可以不需要编写SQL语句,直接使用HQL语句就可以了。
Hibernate屏蔽了SQL,所以只能全表映射,在字段较多的时候效率太低。
MyBatis
MyBatis是一个半自动映射的框架。它需要手动配置POJO、SQL和映射的关系。全表映射的Hibernate只需要配置POJO和映射的关系就可以了。
所以,MyBatis需要三个文件:POJO类,SQL语句,映射关系。
一个简单的MyBatis的例子:
a. 在 SQL Mapper 映射配置文件中配置SQL语句,假定为StudentMapper.xml
INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL,DOB) VALUES(#{studId},#{name},#{email},#{dob})
b. 创建一个StudentMapper接口.
public interface StudentMapper
{
Student findStudentById(Integer id);
void insertStudent(Student student);
}
c. 在JAVA代码中使用MyBatis
SqlSession session = getSqlSessionFactory().openSession();
StudentMapper mapper = session.getMapper(StudentMapper.class);
// Select Student by Id
Student student = mapper.selectStudentById(1);
//To insert a Student record
mapper.insertStudent(student);
从这个小例子可以看出,MyBatis通过Mapper关联Mapper所关联的XML,在XML文件中定义动态的SQL语句。最后在JAVA程序中通过SqlSession来读写数据库。非常简单方便!
MyBatis配置
使用Maven配置MyBatis
新建一个Maven项目,在pom.xml文件中加入依赖。
4.0.0
cn.hwzheng
mybatis
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
1.4.3.RELEASE
org.springframework.boot
spring-boot-starter-web
org.mybatis
mybatis
3.4.1
这里为了方便,我直接使用了SpringBoot来构建应用。SpringBoot已经自带了Tomcat服务器和Spring MVC等功能,提供一站式的解决方案。
MyBatis的基本构成
- SqlSessionFactoryBulider:根据XML配置或者Java配置类来生成SqlSessionFactroy
- SqlSessionFactroy:生成SqlSession的工厂类
- SqlSession:是一个既可以发送SQL去执行并且返回结果又可以获取Mapper的接口。新的MyBatis推荐使用Mapper接口来操作数据库。
- SQL Mapper:由JAVA接口和XML文件(或者注解类)组成,给出相应的SQL映射规则。Mapper负责发送SQL语句去执行,并且返回结果。
配置MyBatis的配置文件
配置MyBatis的配置文件
创建一个配置文件,这里我放在了com/cnc/config包下,文件名为mybatis-config.xml
替换掉数据库驱动、数据库URL、用户名、密码等,即可。
构建SqlSessionFactory
private String resource;
private InputStream inputStream;
private SqlSessionFactory sqlSessionFactory;
private void init() throws Exception{
resource = "com/cnc/config/mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
sqlSessionFactory由mybatis-config.xml
文件中的内容获取。有了sqlSessionFactory,就可以获取SqlSession了。
构建SqlSession
SqlSession的作用类似于公司的前台MM,你委托她做一件事,但是她可能是找她在我们公司的男朋友去办了,而我们并不知道是谁处理了这件事,只知道去找前台MM要结果。SQL语句其实是由内部的Executor接口来处理的。
SqlSession session = sqlSessionFactory.openSession();
try {
Blog blog = session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
} finally {
session.close();
}
其中org.mybatis.example.BlogMapper.selectBlog
是定义在BlogMapper里面的一个方法,使用注解标注。这多少有点让人迷惑,现在更加干净的方法是使用Mapper接口。
Mapper接口
使用Mapper接口来操作数据库是更加推荐的一种方法。在Mapper接口里定义各种SQL方法,用于操作数据库。Mapper接口读取Mapper.xml中的配置,绑定xml中已经定义好的SQL语句。
SqlSession session = sqlSessionFactory.openSession();
try {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
} finally {
session.close();
}
mapper.xml文件内容为:
ResultMap的用法
我们项目中经常遇到数据库的表中的字段名称与POJO的属性名称不同的情况,此时无法自动匹配,但是可以通过配置ResultMap的方式来配置。
比如User的字段名称为id、user_name,hashed_password,通过这个配置,就可以使用跟上面一样的方式来获取数据了。
只需要增加一个resultMap="userResultMap",然后经过userResultMap转换之后返回User对象。
操作实例——基于SpringBoot+MySQL数据库
构建一个Maven项目,结构如图所示。用到的配置文件放到resources/config文件目录下,方便读取。似乎maven项目需要将所有的非JAVA代码放到resource文件夹下,才能正常读取。
pom.xml文件是Maven用于依赖管理的XML文件,这里我使用的是SringBoot+MyBatis3.4.1,所以需要添加这两项的依赖包。
登录:http://spring.io/,找到springboot依赖。
pom.xml内容为:
4.0.0
cn.hwzheng
mybatis
1.0-SNAPSHOT
org.springframework.boot
spring-boot-starter-parent
1.4.3.RELEASE
org.springframework.boot
spring-boot-starter-web
org.mybatis
mybatis
3.4.1
主要是加入MyBatis和SpringBoot的依赖。MyBatis的依赖数据放到dependencies标签下。
这里我使用的是MySQL数据库,MySQL数据库需要事先启动好。MyBatis的数据库配置信息如下:
事先在spring数据库里面配置一个名为USER的表。
配置好了数据库之后,我设计了一个最简单的POJO,叫做User。有三个属性,id、LastName,firstName。对应于数据库中的ID、LASTNAME、FIRSTNAME三个字段。
package com.cnc.beans;
/**
* Created by hwzheng on 2016/12/28.
*/
public class User {
private int id;
private String lastName;
private String firstName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
对应有一个Mapper接口,定义操作数据库的方法。其中SQL方法与Mapper的配置XML文件中的定义绑定。
package com.cnc.mapper;
import com.cnc.beans.User;
/**
* Created by hwzheng on 2016/12/28.
*/
public interface UserMapper {
User selectUser(int id);
int insertUser(User user);
}
Mapper接口必须有一个配置XML文件,绑定Mapper接口中的方法。
insert into USER (ID, FIRSTNAME, LASTNAME) values (#{id}, #{firstName}, #{lastName})
OK,万事俱备,开始使用!
package com.cnc.service;
/**
* Created by hwzheng on 2016/12/28.
*/
import com.cnc.beans.User;
import com.cnc.mapper.UserMapper;
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.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.*;
import org.springframework.stereotype.*;
import org.springframework.web.bind.annotation.*;
import java.io.InputStream;
@Controller
@EnableAutoConfiguration
public class MainController {
private String resource;
private InputStream inputStream;
private SqlSessionFactory sqlSessionFactory;
private void init() throws Exception{
resource = "config/mybatis-config.xml";
inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@RequestMapping("/")
@ResponseBody
String home() {
try {
init();
} catch (Exception e) {
e.printStackTrace();
}
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// User me = mapper.selectUser(1);
User you = new User();
you.setId(2);
you.setFirstName("CHEN");
you.setLastName("SHIJIE");
mapper.insertUser(you);
you = mapper.selectUser(2);
User me = mapper.selectUser(2);
sqlSession.commit();
sqlSession.close();
return "Hello " + me.getLastName() + " " + me.getFirstName() + " " + you.getLastName() + " " + you.getFirstName();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(MainController.class, args);
// MainController controller = new MainController();
// System.out.println(controller.home());
}
}
如果需要最终将结果写入数据库,需要使用session.commit()将结果commit到数据库中。
运行,输入地址栏:http://localhost:8080/
看到结果:
一个最简单的SpringMVC+MyBatis项目就此告成。
结语
本文使用到的仅仅是MyBatis的最基本的功能,MyBatis的许多配置和许多功能都没有涉及到,希望通过接下去的学习可以提高数据库方面的学习,在工作中更好地应用!