Mybatis复习使用

Mybatis复习使用

1.1 简介以及我们为什么要使用:

  • mybatis是一款优秀的持久层框架
    • 持久层:即数据持久化,持久化就是将程序的数据从持久状态和瞬时状态转化的过程;
    • 持久状态就是将数据放在数据库中,或者文件io中,但是放在文件中特别耗性能;
    • 瞬时状态就是放在内存中,断电即失去;
    • 他支持定制化sql,避免了jdbc的代码,帮助我们开发更加的高效

为什么要持久化?
1,因为放在内存中的话断电即失去,
2,有一些对象必须要存贮起来不能被丢掉
3,内存太贵了

持久层
controller,service,dao。。。

  1. 他们都是帮助我们完成持久化的代码块
  2. 界限十分明显

为什么要学习mybatis

  1. 方便
  2. 传统的jdbc代码复杂,简化框架
  3. sql和代码分离,提高了可维护性
  4. 提供对象关系映射标签。
  5. 支持动态编写sql
  6. 使用人多

创建工程

  1. 根据mybatis中文开发文档创建mybatis-config.xml
  2. 导入maven依赖
  3. 配置jdbc

每个基于mybatis的应用都是以sqlsessionfactory实例为核心创建的,运用到的是工厂设计模式sqlSessionFactory的实例可以通过sqlSessionFactoryBuilder获得
目的是从工厂中获得Session

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
来自mybatis中文文档中
使用mbatis必须获取SqlSessionFactory对象。

编写usermapper,创建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.kui.dao.Usermapper">
    <select id="selectAllUser" resultType="com.kui.pojo.User">
        select * from mybatis.user where id = 1
    </select>
</mapper>
  • namespace 指向接口位置
  • id 指向接口中的方法
  • resultType指向返回类型
  • parameterType 方法参数类型
    添加mybatis-config配置文件
<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.cj.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8&amp;useSSL=false&amp;serverTimezone=UTC&amp;"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/kui/dao/usermapper.xml"/>
    </mappers>
</configuration>

在进行mappers配置的时候路径以 / 划分

最后执行成功

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。
SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。
SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。 下面的示例就是一个确保 SqlSession 关闭的标准模式:

在测试增删改的时候必须要提交事务否则插入不进去数据;

测试用例流程:

  1. 创建得到sqlSessionFactory并且返回sqlSession的对象
  2. 创建mybatis-config。xml配置
  3. 创建pojo对象
  4. 编写mapper
  5. 测试

1.2mybatis可以适应配置多种环境

但是sqlSessionFactory运行环境只能选择一种回顾以前我们用到过层c3p0,dbcp,druid数据源池连接用完可以回收
pooled和unpooled区别就是有没有连接池的概念

  • mybatis默认的事务管理器就是jdbc 连接池pooled

1.3配置别名

别名的意思就是去掉类名前缀简化开发。
有3种方式一种是自定义别名另一种是包扫描

自定义

 <typeAliases>
        <typeAlias type="com.kui.pojo.User" alias="user">	</typeAlias>
    </typeAliases>

包扫描

    <typeAliases>
        <package name="com.kui.pojo"/>
    </typeAliases>

添加注解


import org.apache.ibatis.type.Alias;

@Alias("user")

mybatis中
基本数据类型也有别名
在这里插入图片描述
意思就是如果你需要返回int数据类型,在resultType中就要配置_int否则则返回包装数据类型Integer

1.4Setting配置

翻了下官方文档经常用的
在这里插入图片描述

在这里插入图片描述
这三个偶尔用先放在这里

完整的配置如下

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

1.5映射器Mappers

映射器配置共有四种方法:

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

使用时应当注意
使用 class 配置的时候需要xml文件与mapper放在同一个包下否则会报错
如果使用resource就不会出现这种问题
第二种配置基本不用

1.6作用域scope和生命周期

SqlSessionFactoryBuilder

  • 当他创建完sqlSessionFactory后就不需要他了
  • 他是个局部变量

sqlSessionFactory

  • 他是一个工厂,可以把它想象成为一个数据库和连接池 他一旦被创建就没有理由去丢弃他在运行期间
  • 因此它的最佳作用域是应用作用域
  • 最佳的使用模式就是单例模式或静态单例模式

sqlSession

  • 可以把他理解为连接连接池的一个请求,每个线程都应有自己的sqlSession实例
  • 用完后需要关闭
  • sqlSession的实例是线程不安全的最佳作用域应当是请求或方法作用域

如果使用不好会导致严重的并发问题

1.8解决属性名和字段名不一致的问题

  1. 可以使用sql语句 AS 比如
select name as na  from User where id=1

但是这样做意义不大

  1. 使用ResultMap
  <resultMap id="userResult" type="User">
        <result property="id" column="id"></result>  <!--column数据库中的字段,property类中的属性-->
        <result property="name" column="name"></result>
        <result property="pwd" column="pwd"></result>
    </resultMap>
    <select id="selectAllUser" resultType="User" resultMap="userResult">
        select * from mybatis.user
    </select>

当然我们也可以只添加你需要修改的映射;

但是这些还远远不够面对更复杂的类型

2:日志功能

2.1:日志工厂

在这里插入图片描述需要掌握log4j和STDOUT_LOGGING
具体需要是用哪个在设置中设定

STDOUT_LOGGING

  <settings>
        <setting name="logImpl " value="STDOUT_LOGGING"/>
    </settings>

运行程序:
在这里插入图片描述配置成功 注意在复制粘贴文档的时候会有空格要去掉否则报错

LOG4J
配置这个需要导包
修改setting
创建log4j.properties
要记住info debug

3 分页

回忆一下sql语句

select * from user limit 1,2

每页查询两个数据

select * from user limit 1,4

或者使用分页插件懂得其中的原理还是limit

4 使用注解开发

@Select("select * from user")
 List<User> getUserList2();
 配置映射mapper
 使用注解开发的时候参数多的情况下一定要加上@Param(值)
 因为在sql查询的时候  @Param中的值绑定的是#{}值,必须要对应

使用注解开发会注定提交事务

原理 底层是动态代理和反射机制
缺点:别名无法配置
@Param中的值对应的Sql中引用的值

4.1#{}和${}区别

  1. #{}可以防止SQL注入
  2. #{}相当于加上“”来解析

5 mybatis 执行流程

  1. resources获取全局配置文件
  2. 实例化sqlSessionFactoryBuider构造器
  3. 解析文件流 XMLconfigBuilder
  4. 读取Configuration
  5. SqlSessionFactory实例化
  6. transcational事务执行
  7. excutor执行器创建
  8. 创建sqlSession
  9. 执行crud如果出现错误 则回滚至6事务执行
  10. 查看是否执行成功否则回滚事务
  11. 提交事务
  12. 关闭sqlSession

6 lombok

  1. 通过plugin添加
  2. 导入jar包
  3. @Data 帮我们添加无参构造 getandset方法 重写equals,hashcode,tostring方法
  4. @@AllArgsConstructor 添加有参构造 当添加时@Data中的无参构造就会消失需要手动添加无参构造或手动添加

7 一对多,多对一处理

创建表

create table teacher(
id int primary key ,
name varchar(20) default null
)engine=innodb charset=utf8;
insert into student values(1,"张三",1),(2,"张4",2),(3,"张5",1);
insert into teacher values(1,"张三"),(2,"张4"),(3,"张5");
alter table student add constraint foreign key(tid) references teacher(id)
create table student(
id int primary key ,
name varchar(20) default null,
tid int not null
)

在这里插入图片描述

7.1 一对多
两种查询方法
1联表

<select id="getTeacher" parameterType="_int" resultType="teacher" resultMap="getTeacherMap">
    select t.id tid,t.name tname,s.name sname,s.id sid from student s,teacher t
    where
    s.tid=t.id and t.id=#{tid}
</select>
<resultMap id="getTeacherMap" type="teacher">
    <result property="id" column="tid"></result>
    <result property="name" column="tname"></result>
    <collection property="students" ofType="student">
        <result property="name" column="sname"></result>
        <result property="id" column="sid"></result>
    </collection>
</resultMap>

嵌套

<select id="getTeacherSon"  resultMap="TeacherSon">
    select * from teacher where id=#{id}
</select>
<resultMap id="TeacherSon" type="teacher">
   <collection property="students" column="id" javaType="ArrayList" ofType="student" select="getStudentBYtid"></collection>
</resultMap>
<select id="getStudentBYtid" resultType="student">
    select * from student where tid=#{id}
</select>

7.2 多对一
查询学生的所有信息和对应老师的信息
有两种方法

1.联表查询
首先编写sql

select * from student s,teacher t where s.tid=t.id
<select id="getStudentAndTeacher2" resultMap="TeacherMap">
    select s.id sid,s.name sname,t.name tname,t.id tid from student s,teacher t where s.tid=t.id
</select>
<resultMap id="TeacherMap" type="Student">
    <result column="sid" property="id"></result>
    <result column="sname" property="name"></result>
    <association property="teacher" javaType="teacher">
        <result column="tname" property="name"></result>
        <result column="tid" property="id"></result>
    </association>

</resultMap>

第二种嵌套查询

 <resultMap id="StudentResult" type="student">
     <association property="teacher" javaType="teacher" column="tid" select="getTeacher"/>
 </resultMap>
<select id="getStudentAndTeacher" resultMap="StudentResult">
    select * from student
</select>
 <select id="getTeacher" resultType="teacher">
     select * from teacher where id=#{sad}
 </select>

总结
association :多对一查询
collection:1对多
javaType:指定实体类属性的类型
ofType:指定泛型类型

尽量保证sql的可读性

8.动态Sql

动态sql就是根据不同的条件生产成不同的语句提高代码的可复用性
if

<select id="queryArticles" resultType="article" parameterType="map">
    select * from article where 1=1
    <if test="name!=null">
        and name=#{name}
    </if>
    <if test="title!=null">
        and title=#{title}
    </if>
</select>

是个判断条件很简单

choose

<select id="queryChoose" resultType="article" parameterType="map">
    select * from article where 1=1
    <choose>
        <when test="name!=null">
            and name=#{name}
        </when>
        <when test="title!=null">
            and title=#{title}
        </when>
        <otherwise>
            and id=1
        </otherwise>
    </choose>
</select>

when,set,trim,where

<update id="updateArticle" parameterType="map" >
    update article
    <set>
        <if test="name!=null">name=#{name},</if>
        <if test="title!=null">title=#{title}</if>
    </set>
       where id=#{id}
</update>

where下的语句如果都为false
则会自动消失
set会帮我们删除逗号除了第一个逗号

sql片段
有的时候我们需要提取sql的公共部分,他可以帮我们实现代码复用
举例子:
在mapper中提取sql

<sql id="if-title-name">
    <if test="name!=null">name=#{name},</if>
    <if test="title!=null">title=#{title}</if>
</sql>

在执行操作时引入include标签

<update id="updateArticle" parameterType="map" >
    update article
    <set>
        <include refid="if-title-name"/>
    </set>
       where id=#{id}
</update>

Foreach
select * from article where 1=1 and (id=1 or id=2 or id=3)
应用于这样的场景

9 mybatis缓存

mybatis默认定制了一级缓存和二级缓存

  1. 默认情况下他会开启一级缓存(sqlSession级别的缓存,也就是本地缓存),意思也就是当sqlSession
    调用close方法结束后,缓存也就失效了

  2. 二级缓存是基于nameSpace级别的缓存,需要手动配置开启

  3. 为了提高可扩展性,mybatis定义了接口Cache我们可以实现cache接口来实现自定义二级缓存

mybatis官方文档中是这样描述的
在这里插入图片描述
默认策略是lru

在这里插入图片描述
缓存失效的情况:
注意增删改可能会改变原来的数据所以会刷新缓存致使缓存失效
手动清理缓存:
sqlSession。clearCache
查询不同的东西
使用不同的mapper

一级缓存用处通常是用户经常刷新界面

二级缓存:
配置setting
cacheEnabled =true
添加标签就是这么简单
当然我们也可以添加一些属性

<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。可用的清除策略有:
LRU – 最近最少使用:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
的清除策略是 LRU。

作用域为Mapper当中
工作机制

  • 当一条会话查询到数据默认保存在一级缓存中;
  • 会话关闭这个会话的一级缓存就没了,但我们开启了二级缓存,数据就会存在二级缓存中
  • 新的会话来时可以从二级缓存中查出
  • 不同的mapper查询出的数据放在自己的缓存中类似于Map

当然我们在Select语句中也可以配置不使用缓存useCache=false
使用二级缓存要实现pojo类序列化接口

缓存原理

当sqlSession查询到数据后会将数据存到一级缓存中,且作用域只在当前会话sqlSession中,当sqlSession会话关闭后缓存会提交到二级缓存Mapper作用域中。
第一次查询首先看二级缓存有没有数据再看一级缓存,如果都没有则查询数据库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值