Mybatis配置文件、生命周期、关联、动态SQL和缓存

1. 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 resource="db.properties" />

    <settings>
        <!--默认的日志工厂  stdout_logging-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
        <!--是否开启驼峰命名自动映射-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--全局开启缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    <typeAliases>
        <!--起别名的三种方式
   1. typeAliases指定实体类 pojo
   2. typeAliases指定实体类的包名
   3. 在实体类上使用@Alias("author")注解
   -->
        <package name="com.mingde.pojo"/>
    </typeAliases>
    <environments default="development"><!--环境配置 SqlSessionFactory实例只能选择一个环境-->
        <environment id="development">
            <transactionManager type="JDBC" /><!--事务管理器 type="[JDBC|MANAGED]")-->
            <dataSource type="POOLED">
                <!--数据源-->
                <property name="driver" value="${driver}" /><!--三种内建的数据源类型  type="[UNPOOLED|POOLED|JNDI]-->
                <property name="url" value="${url}" />
                <property name="username" value="${username}" />
                <property name="password" value="${password}" />
            </dataSource>
        </environment>
    </environments>
    <!--3种映射器
    1. 推荐使用的resource
    2. class 注意 1. 接口和他的Mapper配置文件相同 2. 接口和他的Mapper配置文件必须在同一个包下
    3. packet 扫描包进行注解绑定   注意点和第二种映射器相同。
    -->
    <mappers>
        <mapper class="com.mingde.mapper.UserMapper"/>
    </mappers>
</configuration>
1. environments
  • 配置Mybatis的多套运行环境,将SQL映射到多个不同的数据上,必须指定一个为默认的运行环境。

  • environment位environments的子标签。

  • transactionManager的二种事务管理器

    1. JDBC:直接使用了JDBC的提交和回滚设施,它依赖从数据源获得连接来管理事务的作用域;
    2. MANAGED:这个配置几乎没有做什么。
  • dataSource三种的数据源类型

    1. UNPOOLED: 这个数据源的实现会每次请求时打开和关闭连接。

    2. POOLED:实现利用了“池”的概念将JDBC连接对象组织起来,避免了创建新的连接实例时的所必须的初始化和认证时间。

    3. JNDI:为了能在如EJB或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的数据源引用。

2. 映射器(mappers)
  1. 使用相对域类路径的资源引用
<mappers>
	<mapper resource="org/mybatis/builder/AuthorMapper.xml" />    
<mappers>
  1. 使用映射器接口实现类的完全限定类名
<mappers>
	<mapper class="org.mybatis.builder/AuthorMapper" />
</mappers>
  1. 使用完全限定资源定位符(URL) 不推荐

  2. 将包内的映射器接口实现全部注册为映射器

   <mappers>
   	<package name="org.mybatis.builder" />
   </mappers>
3. 起别名的三种方式
  1. typeAliases标签里中的typeAlias指定实体类pojo
  2. typeAliases标签里中的package指定实体类的包名
  3. 在实体上使用注解@Alias(“xxx”)

2. 作用域(Scope)和生命周期

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;

/**
 * 1. SqlSessionFactoryBuilder 这个类可以被实例化、使用和丢弃,一旦创建SqlSessionFactory就不需要它了,最佳作用域是方法作用域(局部方法变量)
 * 2. SqlSessionFactory 一旦创建任何时候都存在,最佳作用域应用作用域
 * 3. SqlSession 线程不安全不能共享 最佳作用域请求和方法作用域
 * */
public class MybatisConfig {
    static SqlSessionFactory build;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream resourceAsStream = Resources.getResourceAsStream(resource);
            build = new SqlSessionFactoryBuilder().build(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession() {
        return build.openSession(true);
    }
}
1. SqlSessionFactoryBuilder

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

2. SqlSessionFactory

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

3. SqlSession

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

3. 三种分页方式

#语法
SELECT * FROM table LIMIT stratIndex,pageSize

SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15  

#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:   
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.  

#如果只给定一个参数,它表示返回最大的记录行数目:   
SELECT * FROM table LIMIT 5; //检索前 5 个记录行  

#换句话说,LIMIT n 等价于 LIMIT 0,n。 
1. Mybatis中的xml文件拼接SQL语句
<select id="selectUser" parameterType="map" resultType="user">
  select * from user limit #{startIndex},#{pageSize}
</select>
2.RowBounds分页

查找出所有信息再进行分页。

@Test
public void testUserByRowBounds() {
   SqlSession session = MybatisUtils.getSession();

   int currentPage = 2;  //第几页
   int pageSize = 2;  //每页显示几个
   RowBounds rowBounds = new RowBounds((currentPage-1)*pageSize,pageSize);

   //通过session.**方法进行传递rowBounds,[此种方式现在已经不推荐使用了]
   List<User> users = session.selectList("com.kuang.mapper.UserMapper.getUserByRowBounds", null, rowBounds);

   for (User user: users){
       System.out.println(user);
  }
   session.close();
}
3. PageHelper

官方文档:https://pagehelper.github.io/

4. 关联

  • 关联的嵌套Select查询
<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>
  • 关联嵌套结果查询
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>

5. 集合

  • 集合的嵌套 Select 查询
  <resultMap id="blogResult" type="Blog">
    <collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
  </resultMap>
  
  <select id="selectBlog" resultMap="blogResult">
    SELECT * FROM BLOG WHERE ID = #{id}
  </select>
  
  <select id="selectPostsForBlog" resultType="Post">
    SELECT * FROM POST WHERE BLOG_ID = #{id}
  </select>
  • 集合的嵌套结果映射
<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <result property="body" column="post_body"/>
  </collection>
</resultMap>

6. 动态SQL

  • if:提供了可选的查找文本功能;
<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>
  • choose、when、otherwise相当于Java中的switch
<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
  <choose>
    <when test="title != null">
      AND title like #{title}
    </when>
    <when test="author != null and author.name != null">
      AND author_name like #{author.name}
    </when>
    <otherwise>
      AND featured = 1
    </otherwise>
  </choose>
</select>
  • trim:可以用来实现where和set元素的功能。prefixOverrides 属性会忽略通过管道符分隔的文本序列;
  • where:元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
  • set:set 元素可以用于动态包含需要更新的列;
  • foreach:对集合进行遍历
<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>

7. 缓存

1、什么是缓存 [ Cache ]?

  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

2、为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

3、什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据。
1. 一级缓存

一级缓存也叫本地缓存:

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
2. 二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;

  • 工作机制

    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
    • 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
    • 新的会话查询信息,就可以从二级缓存中获取内容;
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中;

https://mp.weixin.qq.com/mp/homepage?__biz=Mzg2NTAzMTExNg==&hid=3&sn=456dc4d66f0726730757e319ffdaa23e&scene=18#wechat_redirect

https://mybatis.org/mybatis-3/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值