Mybatis学习小结
一.Mybatis前提知识
1.什么是Mybatis?
优秀的持久层开源框架
MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射
2.什么是持久化层?
负责持久化过程的相对独立的逻辑层面
3.什么是持久化?
将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中
JDBC就是一种持久化机制。文件IO也是一种持久化机制
实现持久化过程大多通过关系数据库来完成
4.Mybatis有什么作用?
避免几乎所有的jdbc代码与和手动参数设置及获取结果集
使用简单的xml配置或注释来配置和映射原生信息,将java实体类(pojo对象)映射成数据库中的记录
5.使用Mybatis有什么好处?
与传统jdbc相比,可以减少很多的重复代码
使用mybatis不会对程序结构设计和数据库设计产生干扰,sql写在xml文件里(支持动态编写sql),便于统一管理和优化
解耦,将业务逻辑和数据访问分离,使系统设计更加清晰,更易于维护
二.简单实现Mybatis
1.搭实验工程与建库
2.导入依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
3.写核心配置文件
在这里插入代码片<?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文件-->
<properties resource="db.properties"/>
<!--log4j日志-->
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<!--以小写字母作为别名-->
<typeAliases>
<package name="pojo"/>
</typeAliases>
<!--核心配置-->
<!--环境配置,连接的数据库,这里使用的是MySQL-->
<environments default="mysql">
<environment id="mysql">
<!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</dataSource>
</environment>
</environments>
<!--配置Mapper文件-->
<!--<mappers>
<!–这是告诉Mybatis区哪找持久化类的映射文件,对于在src下的文件直接写文件名,
如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml–>
<mapper class="dao.UserMapper"/>
</mappers>-->
<mappers>
<!--这是告诉Mybatis区哪找持久化类的映射文件,对于在src下的文件直接写文件名,
如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml-->
<package name="dao"></package>
</mappers>
</configuration>
4.mybatis工具类
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 java.io.IOException;
import java.io.InputStream;
public class MybatisUtils {
private static SqlSessionFactory sqlSessionFactory;
static {
try {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
5.创建实体类
package pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//@Alias()
@Data //lombok注解
@NoArgsConstructor
@AllArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
6.创建Mapper接口
import pojo.User;
import java.util.List;
public interface UserMapper {
List<User> selectUser();
}
7.Mapper.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="dao.UserMapper">
<select id="selectUser" resultType="user">
select * from user
</select>
</mapper>
8.测试
public class MyTest {
@Test
public void selectUser() {
SqlSession session = MybatisUtils.getSession();
//方法一:
//List<User> users = session.selectList("dao.UserMapper.selectUser");
//方法二:
UserMapper mapper = session.getMapper(UserMapper.class);
List<User> users = mapper.selectUser();
for (User user: users){
System.out.println(user);
}
session.close();
}
}
9.可能出现的问题:Maven静态资源过滤问题,在pom文件中加入以下配置
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
<include>**/*.yml</include>
<include>**/*.tld</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
有了MyBatis以后再也不用写原生的JDBC代码了,舒服!
三.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>
<!--引入properties文件-->
<properties resource="db.properties"/>
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
<typeAliases>
<package name="pojo"/>
</typeAliases>
<!--环境配置,连接的数据库,这里使用的是MySQL-->
<environments default="mysql">
<environment id="mysql">
<!--指定事务管理的类型,这里简单使用Java的JDBC的提交和回滚设置-->
<transactionManager type="JDBC"></transactionManager>
<!--dataSource 指连接源配置,POOLED是JDBC连接对象的数据源连接池的实现-->
<dataSource type="POOLED">
<property name="driver" value="${driver}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${username}"></property>
<property name="password" value="${password}"></property>
</dataSource>
</environment>
</environments>
<!--<mappers>
<!–这是告诉Mybatis区哪找持久化类的映射文件,对于在src下的文件直接写文件名,
如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml–>
<mapper class="dao.UserMapper"/>
</mappers>-->
<mappers>
<!--这是告诉Mybatis区哪找持久化类的映射文件,对于在src下的文件直接写文件名,
如果在某包下,则要写明路径,如:com/mybatistest/config/User.xml-->
<package name="dao"></package>
</mappers>
</configuration>
1.environments元素:
- dataSource:
unpooled(每次被请求时打开和关闭连接)
pooled(这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来)
jndi(这个数据源的实现是为了能在如 Spring 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用)
数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等
- transactionManager
JDBC
MANAGER
2.mappers元素
映射器,定义映射SQL语句文件
3.typeAlias优化
指定一个包名,Mybatis会在包名下面搜索需要的JavaBean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名
Alias注解,设置别名
4.settings
四.作用域和生命周期
1.sqlSessionFactoryBuilder
sqlSessionFactoryBuilder用于创建sqlSessionFactory,成功后就失去作用,因此 SqlSessionFactoryBuilder 实例的最佳作用域是【方法作用域】(也就是局部方法变量)
2.sqlSessionFactory
SqlSessionFactory 可以被认为是一个数据库连接池,作用是创建sqlSession对象,一旦创建就要长期保存,直到不在使用mybatis;一般的应用中我们往往希望 SqlSessionFactory 作为一个单例,让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是【应用作用域】
3.sqlSession
SqlSession 就相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务。
所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭;SqlSession 的最佳的作用域是【请求或方法作用域】
五.注解开发
@select
@update
@insert
@delete
本质:jvm动态代理机制
六.执行流程
七.动态SQL
官网描述:
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。
虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。
动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
-------------------------------
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
-------------------------------
1.if
<!--需求1:
根据作者名字和博客名字来查询博客!
如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
select * from blog where title = #{title} and author = #{author}
-->
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog where
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
这样写我们可以看到,如果 author 等于 null,那么查询语句为 select * from user where title=#{title},但是如果title为空呢?那么查询语句为 select * from user where and author=#{author},这是错误的 SQL 语句,如何解决呢?请看下面的 where 语句!
2.where
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
这个“where”标签会知道如果它包含的标签中有返回值的话,它就插入一个‘where’。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉。
3.Set
<!--注意set是用的逗号隔开-->
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author}
</if>
</set>
where id = #{id};
</update>
4.choose
有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
5.sql片段
<sql id="if-title-author">
<if test="title != null">
title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog
<where>
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="if-title-author"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</where>
</select>
注意:
①、最好基于 单表来定义 sql 片段,提高片段的可重用性
②、在 sql 片段中不要包括 where
6.Foreach
需求:我们需要查询 blog 表中 id 分别为1,2,3的博客信息
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from blog where 1=1 and (id=1 or id=2 or id=3)
-->
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
八.分页
一.limit分页
二.RowBounds类分页
@Test
public void getUserByBounds() {
RowBounds rowBounds = new RowBounds(1,2);
List<User> userList = session.selectList("dao.UserMapper.selectUser",null,rowBounds);
}
三.Mybatis的PageHelper插件
1.导入jar包
使用maven的直接添加依赖就好了,这次没有使用maven,导入以下两个jar包。
2.配置分页插件
3.PageHelper.startPage静态方法调用
PageHelper.startPage(request);
//紧跟着的第一个select方法会被分页
List<Country> list = countryMapper.selectIf(1);
//后面的不会被分页,除非再次调用PageHelper.startPage
List<Country> list2 = countryMapper.selectIf(null);
4.PageInfo用法
PageHelper.startPage(pn, 5);
//startPage后面紧跟查询就是一个分页查询。
List<Employee> list = employeeService.selectByList();
//使用PageInfo包装查询后的结果,只需要将PageInfo交给页面就行。
//封装了详细的分页信息,包括我们查询出来的数据userList,传入连续显示的页数5。
PageInfo<Employee> page = new PageInfo<Employee>(list, 5);
PageInfo.class是插件里的类,非常方便的调用,分页再次提高性能
//当前页
private int pageNum;
//每页的数量
private int pageSize;
//当前页的数量
private int size;
//由于startRow和endRow不常用,这里说个具体的用法
//可以在页面中"显示startRow到endRow 共size条数据"
//当前页面第一个元素在数据库中的行号
private int startRow;
//当前页面最后一个元素在数据库中的行号
private int endRow;
//总记录数
private long total;
//总页数
private int pages;
//结果集
private List<T> list;
//前一页
private int prePage;
//下一页
private int nextPage;
//是否为第一页
private boolean isFirstPage;
//是否为最后一页
private boolean isLastPage;
//是否有前一页
private boolean hasPreviousPage;
//是否有下一页
private boolean hasNextPage;
//导航页码数
private int navigatePages;
//所有导航页号
private int[] navigatepageNums;
//导航条上的第一页
private int navigateFirstPage;
//导航条上的最后一页
private int navigateLastPage;
public PageInfo() {
this.isFirstPage = false;
this.isLastPage = false;
this.hasPreviousPage = false;
this.hasNextPage = false;
}
九.缓存
一、mybatis和同是持久层的hibernate一样,都存在着缓存机制,今天来说一下mybatis的缓存机制。
查询缓存来缓存数据,从而达到提高查询性能的要求,以提高我们项目的效率!!
二、mybatis的缓存机制有两级:
1.一级缓存:一级缓存mybatsi已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。(SqlSession级别)
失效的情况:
1.查询条件不同
2.增删改操作
3.查询不同的Mapper.xml,不是同一个Sqlsession对象
4.手动清除缓存(clearCache)
2.二级缓存:二级缓存需要我们手动开启。(全局级别,基于namespace级别的缓存)
特点:
查出的数据都会被默认先放在一级缓存中
只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中
只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据)
第一步在mybatis的全局配置文件中配置Setting属性,设置名为cacheEnabled的属性值为true即可
<settings>
<!--
开启二级缓存,这个全局的配置二级缓存
默认是开启的,但是还是需要写上,防止版本的更新
-->
<setting name="cacheEnabled" value="true"/>
</settings>
第二步:在具体需要二级缓存的mapeer映射文件中开启二级缓存,值需要在相应的映射文件中添加一个cache标签即可
<!-- 开启二级缓存 -->
<cache></cache>