mybatis

本文详述了Mybatis的使用流程,包括配置解析、SqlSessionFactory与SqlSession的生命周期,以及动态SQL和缓存机制。重点介绍了多对一、一对多的映射配置,并探讨了一级缓存和二级缓存的原理及其应用场景。通过实例解析了动态SQL的choose、trim、foreach等标签,同时提到了日志配置和分页策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结:

1、SqlSessionFactoryBuilder(配置文件流)==》SqlSessionFactory ==》SqlSession ==》sqlSession.getMapper(UserDao.class)
2、生命周期
	SqlSessionFactoryBuilder:一旦创建工厂即销毁
	SqlSessionFactory:应用期间一直存在,应用为单例模式
	SqlSession :每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。
3、#{}和${}  #{}是预编译类型prepareStatement 可以有效的防止sql注入
4、多对一 association
     一对多 collection
5、动态sql
6、缓存
	一级缓存:sqlSession级别的缓存
	二级缓存:接口级别的缓存
		只要开启了二级缓存,在同一个mapper下就有效
 		所有数据都会先放在一级缓存中
 		只有当会话提交,或者关闭的时候,才会提交到二级缓存中
基础:
JDBC连接步骤:
	获取驱动 Class.forName("com.mysql.jdbc.Driver")
	获取连接 DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/imooc", "root", "root");
	获取会话 conn.prepareStatement(sql);

Mybatis

mybatis 使用流程

  1. pom.xml文件中导入mybatis依赖
  2. 编写mybatis工具类,读取mybatis-config.xml文件创建SqlSessionFactory和SqlSession对象
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try {
            InputStream is = Resources.getResourceAsStream("");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
  1. 创建mapper接口和mapper.xml文件,mapper接口映射到mapper.xml中
  2. 创建mybatis-config.xml文件,配置数据库,及mapper.xml扫描路径
  3. 业务层编写代码,通过SqlSession对象获得Maper接口对象,调用mapper接口中的方法访问数据库
public class UserServiceImpl implements UserService{
    public List<User> queryAll() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> list = userDao.queryAll();
        sqlSession.close();
        return list;
    }
}

原理总结:

  • 通过SqlSessionFactoryBuilder()读取数据库配置文件mybatis-config.xml
  • 创建SqlSessionFactory对象,通过此对象得到SqlSession对象
  • SqlSession.getMapper(UserMapper.class)得到UserMapper对象
  • 调用UserMapper对象中的方法访问数据库

范围和生命周期

理解我们目前已经讨论过的不同范围和生命周期类是很重要的。 不正确的使用它们会导 致严重的并发问题。

SqlSessionFactoryBuilder

这个类可以被实例化,使用和丢弃。一旦你创建了 SqlSessionFactory 后,这个类就不需 要存在了。 因此 SqlSessionFactoryBuilder 实例的最佳范围是方法范围 (也就是本地方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例, 但是最好的方式是 不需要保持它一直存在来保证所有 XML 解析资源,因为还有更重要的事情要做。

SqlSessionFactory

一旦被创建,SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重 新创建它。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次。 这样的 操作将被视为是非常糟糕的。 因此 SqlSessionFactory 的最佳范围是应用范围。 有很多方法可以做到, 最简单的就是使用单例模式或者静态单例模式

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将 SqlSession 实例的引用放在一个 类的静态字段甚至是实例字段中。 也绝不能将 SqlSession 实例的引用放在任何类型的管理范 围中, 比如 Serlvet 架构中的 HttpSession。 如果你现在正用任意的 Web 框架, 要考虑 SqlSession 放在一个和 HTTP 请求对象相似的范围内。换句话说,基于收到的 HTTP 请求,你可以打开 了一个 SqlSession,然后返回响应,就可以关闭它了。关闭 Session 很重要,你应该确保使 用 finally 块来关闭它。下面的示例就是一个确保 SqlSession 关闭的基本模式:

mybatis-config.xml配置

主要使用配置

  1. properties (引入外部属性配置文件)
  2. settings设置 (设置懒加载和缓存、驼峰)
  3. typeAliases 类型命名
  4. environments 环境 (配置数据驱动类型,数据源)
  5. mappers 映射器 (映射mapper.xml文件)
    详细信息mybatis3中文文档

log4j日志:

  1. 添加log4j的依赖
  2. 在mybatis-config.xml中设置日志未log4j
  3. 在resources目录下添加log4j.properties文件(文件名必须是log4j.properties,mybatis配置文件自动读取该文)
  4. 在properties文件中配置log4j属性

分页:

  1. limit分页
  2. RowBounds分页
  3. 插件分页如pageHelper

关于@Param()注解

  1. 基本类型的参数或者String类型需要加上
  2. 引用类型不用加
  3. 如果只有一个基本类型的话,可以不用加
  4. 我们在sql中引用的参数就是@Param()中

#{}和${}

#{}是预编译类型prepareStatement 可以有效的防止sql注入

Lombok

  • idea中安装lombok插件
  • 添加lombok依赖

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Data 最常用的

@Data 注解可以省去在实体类中添加get、set、toString、hashcode方法
在这里插入图片描述

多对一

resultMap属性中的association属性

第一种方式:结果嵌套

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kayak.service.Student">
    <resultMap id="getStudentAndTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--property代表Student的Teacher属性-->
        <!--column代表Student与Teacher表的关联外键-->
        <!--jdbcType代表查询的类型-->
        <!--select代表调用查询的方法-->
        <association property="teacher" column="tid" jdbcType="Teacher" select="getTeacher"/>
    </resultMap>
    <select id="getStudent" resultMap="getStudentAndTeacher">
            select * from student
    </select>
    <select id="getTeacher" resultType="Teacher">
            select * from teacher
    </select>

</mapper>

第二种方式:查询嵌套(更好理解)

	<resultMap id="getStudentAndTeacher" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" jdbcType="Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>
    <select id="getStudent" resultMap="getStudentAndTeacher">
  		 select s.id as sid,s.name as sname, t.id as tid, t.name as tname t 
  		 from student s,teacher t
    </select>
@Data
public class Student {
    private int id;
    private String name;
    private Teacher teacher;

}
@Data
public class Teacher {
    private int id;
    private String name;
}

一对多

第一种:结果嵌套

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kayak.service.Student">

    <select id="getTeacher" resultMap="TeacherStudent">
            select s.id as sid,s.name as sname, t.id as tid, t.name as tname t 
            from student s,teacher t where t.id = s.id and  t.id = #{id}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--复杂的属性,我们需要单独处理 对象:association 集合:collection
        javaType="" 指定属性的类型
        ofType指定集合中泛型类型
        -->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>
</mapper>

第二种:查询嵌套

<mapper namespace="com.kayak.service.Student">

    <resultMap id="TeacherStudent" type="Teacher">
        <!--column中的id为传参参数-->
        <collection property="students" column="id" ofType="Student" select="getStudent"/>
    </resultMap>
    <select id="getTeacher" resultMap="TeacherStudent">
        select * from teacher t where t.id = #{tid}
    </select>
    <select id="getStudent" resultType="Student">
        select * from student where tid = #{tid}
    </select>
</mapper>
@Data
public class Student {
    private int id;
    private String name;
    private int tid;

}
@Data
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
}

总结:

  1. 多对一 association
  2. 一对多 collection
  3. javaType :用来指定实体类中属性类型
  4. ofType:用来映射collection中泛型类型

动态sql

choose(when otherwise) 类似于if(){}elseif(){} else{},when满足条件之后不会添加剩下的条件
trim(where set)
例子参照mybatis3操作手册

sql片段:
有的时候,我们会将一些功能的部分抽取出来,方便复用!

sql片段
<sql id="sql">
        
</sql>
引用
<include refid=""></include>

foreach
其实就相当于in(1,2,3)

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

where id=1 or id =2 or id =3
(用in会影响查询效率)

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID 
  <foreach item="item" index="index" collection="list"
      open="" separator="or" close="">
       id = #{item}
  </foreach>
</select>

缓存

  1. 一级缓存:sqlSession级别的缓存
  2. 二级缓存:接口级别的缓存

一级缓存

缓存失效

  1. 查询不同的数据
  2. 增删改操作,可能会改变原来的数据,所以肯定要刷新缓存
  3. 查询不同的mapper.xml
  4. 手动清理缓存 sqlsession.clearCache();

一级缓存默认是开启的,只在一次SqlSession中有效,拿到链接到关闭链接的区间段;
一级缓存就相当于一个map

二级缓存

  1. 在mybitis-config.xml中设置缓存开启
  2. 在mapper.xml文件中添加
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.kayak.service.Student">
    <!--开启二级缓存-->
    <cache/>
</mapper>
 <!--可以设置缓存属性-->
<cache
  eviction="FIFO"
  flushInterval="60000"
  size="512"
  readOnly="true"/>

总结:

  1. 只要开启了二级缓存,在同一个mapper下就有效
  2. 所有数据都会先放在一级缓存中
  3. 只有当会话提交,或者关闭的时候,才会提交到二级缓存中

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值