MyBatis
MyBatis是一款优秀的持久层框架
MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的过程
MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和Java的实体类映射成数据库中的记录
什么是持久化
持久化是将程序数据在持久状态和瞬时状态间转换的机制
把内存中的对象保存到数据库,XML或者磁盘当中。例如JDBC机制和文件
什么是持久层
完成持久化工作的代码块,Dao层。我们的架构当中,应该有一个相对独立的逻辑层面,专注于数据持久化逻辑的实现
MyBatis使用的流程
- 搭建数据库
- maven配置
- 配置myBatis-config
- myBatis工具类
public class Mybatis{
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();
}
}
- 构建实体类
- 编写Mapper接口
- 配置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="com.yzh.dao.UserMapper">
<select id="selectUser" resultType="com.yzh.pojo.User">
select * from user
</select>
</mapper>
- 编写测试类然后运行
配置文件可配置内容包括
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
自动映射
ResultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来。
实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap 能够代替实现同等功能的长达数千行的代码。
ResultMap 的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系就行了。
手动映射
<select id="selectUserById" resultMap="UserMap">
select name,pwd from user where id = #{id}
</select>
手动映射实现ResultMap
<resultMap id="UserMap" type="User">
<!-- id为主键 -->
<id column="id" property="id"/>
<!-- column是数据库表的列名 , property是对应实体类的属性名 -->
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
mysql的日志实现
在测试sql时,使用日志输出sql的话能够帮助我们更快找出问题所在
我们可以使用Log4j进行日志的输出
//日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
//控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
注解开发
sql注解主要分为:
- @select()
- @insert()
- @update()
- @delete()
- @one
- @many
例如select
//查询全部用户
@Select("select id,name,pwd password from user")
public List<User> getAllUser();
增删改要处理事务
动态sql
如果需要写复杂的 SQL 语句,往往需要拼接,而拼接 SQL ,稍微不注意,由于引号,空格等缺失可能都会导致错误。这就要使用 mybatis 动态SQL,通过 if, choose, when, otherwise, trim, where, set, foreach等标签,可组合成非常灵活的SQL语句,从而在提高 SQL 语句的准确性的同时,也大大提高了开发人员的效率。
if语句
<select id="queryIf" parameterType="map" resultType="User">
select * from user where
<if test="xxx != null">
and xxx = #{xxx}
</if>
</select>
where语句
<select id="queryIf" parameterType="map" resultType="User">
select * from user
<where>
<if test="xxx != null">
xxx= #{xxx}
</if>
</where>
</select>
set语句
<!--注意set是用的逗号隔开-->
<update id="update" parameterType="map">
update user
<set>
<if test="xxx!= null">
xxx = #{xxx},
</if>
</set>
where id= #{id};
</update>
choose语句
<select id="queryChoose" parameterType="map" resultType="user">
select * from user
<where>
<choose>
<when test="xxx != null">
xxx = #{xxx }
</when>
<otherwise>
and xxx = #{xxx}
</otherwise>
</choose>
</where>
</select>
引用sql语句
例如引用上一个的例子
<select id="queryIf" parameterType="map" resultType="user">
select * from user
<where>
<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace -->
<include refid="queryChoose"></include>
<!-- 在这里还可以引用其他的 sql 片段 -->
</where>
</select>
Foreach语句
<select id="queryForeach" parameterType="map" resultType="user">
select * from user
<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>
缓存
- 缓存就是存在内存中的临时数据
- 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。
使用缓存的原因
减少和数据库的交互次数,减少系统开销,提高系统效率。
MyBatis缓存
分为一级缓存和二级缓存
一级缓存也叫本地缓存:
- 与数据库同一次会话期间查询到的数据会放在本地缓存中。
- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
@Test
public void testQueryUserById(){
SqlSession session = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
User user2 = mapper.queryUserById(1);
session.close();
}//第二次没有进行数据库查询
一级缓存失效的四种情况
- sqlSession不同
@Test
public void testQueryUserById(){
SqlSession session = MybatisUtils.getSession();
SqlSession session2 = MybatisUtils.getSession();
UserMapper mapper = session.getMapper(UserMapper.class);
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
User user2 = mapper2.queryUserById(1);
session.close();
session2.close();
}
每个sqlSession中的缓存相互独立
- sqlSession相同,查询条件不同
- sql相同,两次查询间进行了增删改操作
- sqlSession相同,手动清除一级缓存
二级缓存
- 二级缓存也叫全局缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;新的会话查询信息,就可以从二级缓存中获取内容;不同的mapper查出的数据会放在自己对应的缓存(map)中;