MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架。
MyBatis封装了JDBC,并提供对象映射。他减少了几乎所有JDBC的代码和手动配置,只需要进行简单的XML或注解配置,就能灵活地完成数据库操作。
MyBatis与spring组合使用可以发挥出更加强大的作用。
MyBatis有两种使用方法:通过xml配置文件配置,或通过java注解配置。实际项目开发中,可以灵活地在两种方式间切换使用。这篇文章主要介绍xml的配置方式。
这里用一个简单的案例来演示如何使用MyBatis。
本项目环境:JDK1.8 , mybatis3.3.0,mysql。
新建java项目,导入mybatis及mysql JDBC的jar包(如需使用日志等功能还需导入其他包).如图:
在数据库中创建一张book表,有id,书名,价格三个字段,并插入几条测试数据:
在java项目中创建与数据库对应的bean类:
public class Book {
private int id;
private String bookName;
private double price;
//省略相应的GetSet、toString、构造方法、
}
到这里,准备工作就做完了。MyBatis的任务就是从数据库中查询出我们需要的数据,并映射给bean类。或反过来将bean类insert/update/delete到数据库中。
配置mybatis:
mybatis-config是mybatis的基础配置文件,需要配置jdbc连接方式,引用所有mapper文件。
工程下新建一个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>
<!-- settings元素下是一些高级选项,可以改变mybatis运行中的行为。非必须 -->
<settings>
<!-- 开启数据库中下划线命名字段对java类中驼峰命名的映射关系。如:book_name与bookName互相映射 -->
<setting name="mapUnderscoreToCamelCase" value="true" />
</settings>
<!-- 给长字符串起一个别称。非必须 -->
<typeAliases>
<typeAlias alias="book" type="com.lxy.beans.Book" />
</typeAliases>
<!-- 数据库连接环境。这里使用的是mysql的jdbc,事务管理及连接池也是用jdbc。 -->
<!-- 这部分可由spring管理 -->
<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://localhost/myschool" />
<property name="username" value="root" />
<property name="password" value="111112" />
</dataSource>
</environment>
</environments>
<!-- mappers中列出所有定义的mapper文件 -->
<mappers>
<mapper resource="com/lxy/mappers/BookMapper.xml" />
</mappers>
</configuration>
创建mapper文件
一个mapper文件通常与一个bean类对应,里面定义了数据表与javabean类的映射关系,以及要执行的sql语句。
其中id为方法标识,用于调用方法;resultType标识了返回值类型;parameterType标识了入参类型。
这里创建一个BookMapper.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.lxy.mappers.BookMapper">
<!-- 简单查询方法 -->
<select id="selectAll" resultType="book">
select * from book;
</select>
<!-- 新增方法 -->
<insert id="insertBook" parameterType="book">
insert book (book_name,price) values(#{bookName},#{price});
</insert>
</mapper>
测试方法
package com.lxy.test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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.lxy.beans.Book;
public class UserTest {
public static void main(String[] args) throws IOException {
// SqlSessionFactory的作用域应为整个应用的生命周期。可以使用单例实现,但通常通过spring的依赖注入实现
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// SqlSession的作用域应在线程内。给每个request重新开启一个session。
// sqlsession有selectOne,selectList,insert,update,delete,commit,rollback等方法
SqlSession session = factory.openSession();
try {
Book b = new Book("java进阶", 36.7d);
session.insert("com.lxy.mappers.BookMapper.insertBook", b);
session.commit();
List<Book> lst = session.selectList("com.lxy.mappers.BookMapper.selectAll");
for (Book book : lst) {
System.out.println(book);
}
} finally {
// 每次会话结束后关闭session
session.close();
}
}
}
至此,就完成了Mybatis的基本查询及新增功能。
resultMap
mapper文件中的resultType标识了方法返回的类型,它会将数据库查询出的字段自动映射到对应名称的bean类中。
retultType可以应对大多数简单查询的情况。但如果查询情况变得复杂,比如多表联查,就需要使用resultMap来对字段进行手动映射了。
来看个例子:
现在我们将刚才的书本表稍微改造一下,关联上作者表的信息:
相应的bean类也进行改造:
public class Book {
private int id;
private String bookName;
private double price;
private Author author;
@Override
public String toString() {
return "Book [id=" + id + ", bookName=" + bookName + ", price=" + price+ ", author_name=" + author.getAuthorName() + "]";
}
//...省略getset方法
}
public class Author {
private int id;
private String authorName;
//...省略getset方法
}
Author的信息作为属性保存在Book类中。此时要查询出book和Author信息并映射到Book类中,该怎么实现呢?
首先在mapper中编写sql语句:
<!-- 复杂查询 -->
<select id="selectBookInfo" resultMap="BookMap">
select
b.id as book_id,
book_name,
price,
a.id as author_id,
author_name
from book b left join author a on b.author_id=author_id
where b.id = #{id}
</select>
然后手工映射BookMap:
<resultMap type="Book" id="BookMap">
<id property="id" column="book_id" />
<result property="bookName" column="book_name" />
<result property="price" column="price" />
<association property="author" javaType="Author">
<id property="id" column="author_id" />
<result property="authorName" column="author_name" />
</association>
</resultMap>
id – 一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能
result – 注入到字段或 JavaBean 属性的普通结果
association – 一个复杂的类型关联;许多结果将包成这种类型
column – 数据库表中的字段名
这样就配置完成了。写个测试方法测试一下
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 com.lxy.beans.Book;
public class UserTest {
public static void main(String[] args) throws IOException {
// SqlSessionFactory的作用域应为整个应用的生命周期。可以使用单例实现,但通常通过spring的依赖注入实现
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
// SqlSession的作用域应在线程内。给每个request重新开启一个session。
// sqlsession有selectOne,selectList,insert,update,delete,commit,rollback等方法
SqlSession session = factory.openSession();
try {
Book book = session.selectOne("com.lxy.mappers.BookMapper.selectBookInfo",5);
System.out.println(book);
} finally {
// 每次会话结束后关闭session
session.close();
}
}
}
输出结果: