MyBatis
1 简介
1.1 什么是MyBatis
- 优秀的持久层框架
- 支持定制化SQL、存储过程以及高级映射
- MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
- MyBatis可以使用简单的XML或注解来配置和映射原生类型、接口和JAVA的POJO为数据库中的记录
- 通过maven或者github获取MyBatis
1.2 持久层
数据持久化,持久化就是将程序中的数据在持久状态和瞬时状态转化的过程
- 内存:断电即失
- 数据库、io文件持久化
为什么持久化
- 内存贵
- 有一些数据不能丢掉
1.3 为什么需要MyBatis
- 帮助开发者将数据存入数据库
- 传统的JDBC代码复杂,简化,自动化
- 解除sql和代码的耦合,是业务逻辑层和数据访问逻辑层分离
- 提供xml标签,支持动态sql
- 提供映射标签,支持对象和数据库的orm字段关系映射
2 第一个MyBatis程序
Type interface com.kuang.dao.UserDao is not known to the MapperRegistry
每一个mapper.xml都需要在核心配置文件中进行注册
2.1 select
- id:namespace中的方法名
- resultType:Sql语句执行的返回值
- parameterType:参数类型
<select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
select * from qing.sys_user where id = #{id};
</select>
2.2 insert
- id:namespace中的方法名
- parameterType:参数类型
<!-- 对象中的属性可以直接取出来-->
<insert id="InsertUser" parameterType="com.kuang.pojo.User" >
insert into qing.sys_user (id,username,password) values(#{id},#{username},#{password});
</insert>
2.3 update
- id:namespace中的方法名
- parameterType:参数类型
<!-- 对象中的属性可以直接取出来-->
<update id="updateUser" parameterType="com.kuang.pojo.User" >
update qing.sys_user set password=#{password},username=#{username} where id=#{id};
</update>
2.4 delete
- id:namespace中的方法名
- parameterType:参数类型
<delete id="delUserById" parameterType="int">
delete from qing.sys_user where id = #{id};
</delete>
2.5 模糊查询
- id:namespace中的方法名
- resultType:Sql语句执行的返回值
- 模糊查询使用通配符%,传参或者拼接sql时使用
3. 配置解析
3.1 核心配置文件
mybatis-config.xml
各种属性可详见 mybatis官网
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
- properties
可以通过该属性来实现引用配置文件,外部文件的优先级高于内部 - typeAliases
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写 - mappers
告诉 MyBatis 到哪里去找映射文件
<!-- 方法1:使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 方法2:使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
使用class文件时注意接口和mapper文件同名且在同一个包下
- 结果集映射resultMap
resultMap是Mybatis中最强大的元素,将数据库的字段和对象的属性进行映射
世界要是这么简单就好了
3.2 日志
数据库操作出现异常,需要排查错误,通过日志进行排查
- STDOUT_LOGGING标准日志
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
- LOG4J
#xml文件中进行配置
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
#导入依赖
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
log4j配置文件
## set log levels ###
log4j.rootLogger = debug , console , file
## 输出到控制台 ###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c]-%m%n
#文件输出相关配置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layou.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
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
#定义静态变量使用
static Logger logger = Logger.getLogger(UserDaoTest.class);
4. 使用注解开发
4.1 面向接口编程
使用面向接口编程的原因是:解耦,可扩展,提高复用,上层不需要管具体的实现,遵守共同的标准;
对于接口深层次的理解是:定义与实现的分离
在接口上直接添加注解,注意基本类型的参数或者String需要加@Param注解,引用类型不需要加
5. 动态SQL
动态SQL:根据不同的条件生成不同的SQL语句
5.1 IF标签
<select id="getUserListIF" parameterType="map" resultType="User">
select * from qing.sys_user where 1=1
<if test="username != null">
and username =#{username}
</if>
<if test="password != null">
and password =#{password}
</if>
</select>
5.2 Where标签
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
<select id="getUserListIF" parameterType="map" resultType="User">
select * from qing.sys_user
<where>
<if test="username != null">
and username =#{username}
</if>
<if test="password != null">
and password =#{password}
</if>
</where>
</select>
5.3 SET标签
<update id="updateUserDS" parameterType="map">
update qing.sys_user
<set>
<if test ="username != null">
username = #{username},
</if>
<if test="password != null">
password = #{password}
</if>
</set>
where id=#{id}
</update>
5.4 SQL片段
为了复用,减少重复
##sql片段
<sql id="iftest">
<if test ="username != null">
username = #{username},
</if>
<if test="password != null">
password = #{password}
</if>
</sql>
##引用sql片段
<include refid="iftest"></include>
5.5 foreach
##动态 SQL 的另一个常见使用场景是对集合进行遍历
<select id="getUserListForeach" parameterType="map" resultType="User">
select * from qing.sys_user
<where>
<foreach collection="ids" item="id" open="(" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
6. 缓存
6.1 什么是缓存
- 将用户经常查询的数据放在缓存中,用户去查询时就不需要从磁盘上查询,从缓存中查询,从而提高查询效率,解决高并发系统的性能问题
6.2 为什么使用缓存
- 减少和数据库的交互次数,较少系统开销,提高效率
6.3 什么样的数据使用缓存
- 经常查询且不改变的数据
6.4 一级缓存
一级缓存也叫本地缓存,与数据库同一次会话sqlSession期间查到的数据会被放在本地缓存中;
如果以后需要获取相同的数据,直接从缓存中取,不会查询数据库。
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存,缓存会失效
缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
手动清理缓存也会导致缓存失效,sqlSession.clearCache();
6.5 二级缓存
二级缓存也叫全局缓存,基于namespace级别的缓存,一个命名空间对应一个二级缓存。
如果当前会话关闭了,会从二级缓存中获取数据。
缓存的顺序:
1.第一次查询先看二级缓存中有没有;
2.第二季看一级缓存中有没有;
3.最后从数据库中查询,然后放在一级缓存中,会话关闭的时候,一级缓存放在二级缓存中