Java学习笔记-Day74 MyBatis 框架(一)
一、MyBatis 框架介绍
1、简介
MyBatis 是持久层框架、轻量级框架、半自动的ORM框架,用于数据库的访问。它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
官方文档:https://mybatis.org/mybatis-3/zh/index.html
2、MyBatis的全局配置文件
MyBatis的全局配置文件(mybatis-config.xml文件)中包含了对 MyBatis 系统的核心设置,包含获取数据库连接实例的数据源(DataSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)。
操作过程:从MyBatis的全局配置文件中构建 SqlSessionFactory对象,这个对象可以创建SQLSession对象,再通过SQLSession对象获取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>
<!-- 获取数据库连接实例的数据源 -->
<properties resource="db.properties"></properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件的地址 -->
<mappers>
<mapper resource="com/etc/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
- db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=Asia/Shanghai
username=root
password=root
3、SqlSessionFactory(工厂)
SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此 SqlSessionFactory 的最佳作用域是应用作用域。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
4、SqlSession(核心对象)
每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理作用域中,比如 Servlet 架构中的 HttpSession。
SqlSession接口的实现类是DefaultSqlSession类。通过SqlSession对象获取Dao层某个接口的实例(底层是通过动态代理实现的)。
5、映射文件
MyBatis 的真正强大在于它的映射语句,也是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 就是针对 SQL 构建的,并且比普通的方法做的更好。
SQL 映射文件有很少的几个顶级元素(按照它们应该被定义的顺序):
(1)cache – 给定命名空间的缓存配置。
(2)cache-ref – 其他命名空间缓存配置的引用。
(3)resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象。
(4)parameterMap – 已废弃!老式风格的参数映射。内联参数是首选,这个元素可能在将来被移除,这里不会记录。
(5)sql – 可被其他语句引用的可重用语句块。
(6)insert – 映射插入语句
(7)update – 映射更新语句
(8)delete – 映射删除语句
(9)select – 映射查询语句
- BlogMapper.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.etc.mybatis.dao.BlogMapper">
<!-- id="selectBlog" 是一个接口中的方法名叫做selectBlog
resultType="Blog" 是这个方法的返回值类型,这里请写完整地包名
#{id} 代表传递过来的参数
-->
<!-- 查询 -->
<select id="selectBlog" resultType="com.etc.mybatis.entity.Blog">
select * from blog where id = #{id}
</select>
<!-- 查询 -->
<select id="selectBlogs" resultType="com.etc.mybatis.entity.Blog">
select * from blog
</select>
<!-- 插入 -->
<insert id="insertBlog">
insert into blog (id,title,content) values (#{id},#{title},#{content})
</insert>
<!-- 修改 -->
<update id="updateBlog">
update blog set title=#{title},content=#{content} where id=#{id}
</update>
<!-- 修改 -->
<update id="updateBlogs">
update blog set title=#{title},content=#{content} where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteBlog">
delete from blog where id=#{id}
</delete>
</mapper>
二、操作步骤
1、映射文件实现操作
(1)加入 mybatis.jar 和 mysql-connector-java.jar 这两个jar包到java项目中。
(2)在src目录下创建Mybatis的全局配置文件mybatis-config.xml(包含数据库连接信息和映射文件地址)和db.properties配置文件。
- 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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- 映射文件的地址 -->
<mappers>
<mapper resource="com/etc/mybatis/example/BlogMapper.xml"/>
</mappers>
</configuration>
- db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=Asia/Shanghai
username=root
password=root
(3)创建对应的数据库表,根据表结构创建实体类,并创建Dao层的接口。
package com.etc.mybatis.entity;
public class Blog {
private int id;
private String title;
private String content;
public Blog(int id, String title, String content) {
super();
this.id = id;
this.title = title;
this.content = content;
}
public Blog() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Blog [id=" + id + ", title=" + title + ", content=" + content + "]";
}
}
package com.etc.mybatis.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.etc.mybatis.entity.Blog;
public interface BlogMapper {
// 通过id查询Blog数据
public Blog selectBlog(int id);
// 通过查询Blog的所有数据
public List<Blog> selectBlogs();
// 插入操作
public boolean insertBlog(Blog blog);
// 修改操作(使用Blog类)
public boolean updateBlog(Blog blog);
// 修改操作(多个参数可以使用@Param注解)
public boolean updateBlogs(@Param("id") int id,@Param("title") String title,@Param("content") String content);
// 删除操作
public boolean deleteBlog(int id);
}
(4)创建映射文件BlogMapper.xml,并编写sql语句。
<?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.etc.mybatis.dao.BlogMapper">
<!-- id="selectBlog" 是一个接口中的方法名叫做selectBlog
resultType="Blog" 是这个方法的返回值类型,这里请写完整地包名
#{id}占位符 代表传递过来的参数
-->
<!-- 查询 -->
<select id="selectBlog" resultType="com.etc.mybatis.entity.Blog">
select * from blog where id = #{id}
</select>
<!-- 查询 -->
<select id="selectBlogs" resultType="com.etc.mybatis.entity.Blog">
select * from blog
</select>
<!-- 插入 -->
<insert id="insertBlog">
insert into blog (id,title,content) values (#{id},#{title},#{content})
</insert>
<!-- 修改 -->
<update id="updateBlog">
update blog set title=#{title},content=#{content} where id=#{id}
</update>
<!-- 修改 -->
<update id="updateBlogs">
update blog set title=#{title},content=#{content} where id=#{id}
</update>
<!-- 删除 -->
<delete id="deleteBlog">
delete from blog where id=#{id}
</delete>
</mapper>
(5)编写测试类,创建sqlSessionFactory对象,通过sqlSessionFactory对象得到SqlSession对象,通过SqlSession对象得到Mapper实例,调用Mapper实例的方法来完成查询、修改、增加或删除操作。查询操作不用手动提交事务,增加、删除、修改都需要手动提交事务。
- 查询操作的测试类
public class TestMybaitsSelect {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(1);
System.out.println(blog);
}
}
- 修改操作的测试类
public class TestMybaitsUpdate {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog b = new Blog(12, "jack", "jack");
boolean flag = mapper.updateBlog(b);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
- 增加操作的测试类
public class TestMybaitsInsert {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog b = new Blog(12, "tom", "tomaandjerry");
boolean flag = mapper.insertBlog(b);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
- 删除操作的测试类
public class TestMybaitsDelete {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
boolean flag = mapper.deleteBlog(12);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
2、映射器注解实现操作
因为最初设计时,MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,而且 映射语句也是定义在 XML 中的。而到了 MyBatis3,有新的可用的选择了。MyBatis3 构建在基于全面而且强大的Java 配置 API 之上。这个配置 API 是基于 XML 的 MyBatis 配置的基础,也是新的基于注解配置的基础。注解提供了一种简单的方式来实现简单映射语句,而 不会引入大量的开销。
操作步骤:
(1)加入 mybatis.jar 和 mysql-connector-java.jar 这两个jar包到java项目中。
(2)在src目录下创建Mybatis的全局配置文件mybatis-config.xml(包含数据库连接信息和映射文件地址)和db.properties配置文件。
- 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>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<!-- Mapper接口的位置 -->
<mappers>
<mapper class="com.etc.mybatis.example.BlogMapper"/>
</mappers>
</configuration>
- db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatisdb?serverTimezone=Asia/Shanghai
username=root
password=root
(3)创建对应的数据库表,根据表结构创建实体类。创建Dao层的接口,并在接口添加映射器注解。
package com.etc.mybatis.entity;
public class Blog {
private int id;
private String title;
private String content;
public Blog(int id, String title, String content) {
super();
this.id = id;
this.title = title;
this.content = content;
}
public Blog() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "Blog [id=" + id + ", title=" + title + ", content=" + content + "]";
}
}
public interface BlogMapper {
@Select(value="select * from blog where id = #{id}")
public Blog selectBlog(int id);
@Select(value="select * from blog")
public List<Blog> selectBlogs();
@Insert(value="insert into blog (id,title,content) values (#{id},#{title},#{content})")
public void insertBlog(Blog blog);
@Update(value="update blog set title=#{title},content=#{content} where id=#{id}")
public void updateBlog(Blog blog);
@Update(value="update blog set title=#{title},content=#{content} where id=#{id}")
public void updateBlogs(@Param("id") int id,@Param("title") String title,@Param("content") String content);
@Delete(value="delete from blog where id=#{id}")
public void deleteBlog(int id);
}
(4)编写测试类,创建sqlSessionFactory对象,通过sqlSessionFactory对象得到SqlSession对象,通过SqlSession对象得到Mapper实例,调用Mapper实例的方法来完成查询、修改、增加或删除操作。查询操作不用手动提交事务,增加、删除、修改都需要手动提交事务。
- 查询操作的测试类
public class TestMybaitsSelect {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(1);
System.out.println(blog);
}
}
- 修改操作的测试类
public class TestMybaitsUpdate {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog b = new Blog(12, "jack", "jack");
boolean flag = mapper.updateBlog(b);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
- 增加操作的测试类
public class TestMybaitsInsert {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog b = new Blog(12, "tom", "tomaandjerry");
boolean flag = mapper.insertBlog(b);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
- 删除操作的测试类
public class TestMybaitsDelete {
public static void main(String[] args) throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
BlogMapper mapper = session.getMapper(BlogMapper.class);
boolean flag = mapper.deleteBlog(12);
// 手动提交事务
session.commit();
session.close();
inputStream.close();
System.out.println("flag="+flag);
}
}
三、ResultMap
如果实体类的属性和表的列名不一致的话,使用resultMap来处理,可以通过映射文件或者注解来实现。resultMap和resultType只能使用一个。
(1)映射文件实现
<?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.etc.mybatis.dao.BlogMapper">
<!-- resultMap="blogResultMap" 引用的是自定义的resultMap -->
<select id="selectBlog" resultMap="blogResultMap">
select * from blog where blogid = #{id}
</select>
<!-- 自定义的resultMap: (1)解决了实体类属性和表结构不一致 (2)表关联查询,实体关系(1:N 1:1 M:N) -->
<resultMap id="blogResultMap" type="com.etc.mybatis.entity.Blog" >
<!-- id:主属性和列对应设置 ,property="id" 类中的属性,column="blogid" 表中的列名 -->
<id property="id" column="blogid"/>
<!-- result:其他列和属性配置 ,property="title"是类中的属性,column="blogtitle"是表中的列名 -->
<result property="title" column="blogtitle"/>
<result property="content" column="blogcontent"/>
</resultMap>
</mapper>
(2)注解实现
public interface BlogMapper {
@Select(value="select * from blog where blogid = #{id}")
@Results(id = "blogResultMap", value = {
@Result(property="id", column="blogid", id=true),
@Result(property="title", column = "blogtitle"),
@Result(property="content", column="blogcontent") })
public Blog selectBlog(int id);
}