MyBatis之四_连接池、延迟加载、缓存

一 连接池

1.1 连接池概述

连接池就是用于存储连接的一个容器,用集合对象实现。该集合必须是线程安全的,不能两个线程获取同一个连接。此外,该集合必须实现队列特性,即先进先出。
线程从连接池中获取连接然后访问数据库,访问结束后,将连接还回连接池,而不用断开与数据库的连接。从而减少了访问数据库时获取连接的耗时。

1.2 MyBatis中 的连接池

MyBatis中支持三种连接池的实现方式:POOLED、UNPOOLED、JNDI。主配置文件中dataSource标签的type属性用于指定连接池的实现方式。【与其说是连接池的实现种类,不如说的datasource的种类】

  1. POOLED:采用传统的javax.sql.DataSource规范的连接池,MyBatis中有基于该规范的实现。
  2. UNPOOLED:采用每次直接获取连接的方式,虽然实现javax.sql.Datasource接口,但没有池的思想。
  3. JNDI:采用服务器提供的JNDI技术实现来获取DataSource对象,不同服务器提供的DataSource不同。只能在web或者maven的war工程中使用。tomcat服务器提供的是dbcp连接池。

1.3 配置pooled、unpooled连接池

其实没什么好说的

1.4 配置JNDI连接池

1.4.1 JNDI介绍

JNDI:java命名和目录接口,是SUN公司推出的规范,用于模仿windows系统中的注册表,也就是键值对方式保存和访问值。说的很玄,就是想建立字符串和对象的映射表,通过字符串调用对象。

JNDI要基于Tomcat服务器。Tomcat服务器启动时,会自动创建一些对象,通过为这些对象配置键值对映射,在Java代码中通过键调用Tomcat创建的这些对象。【通过Web应用的配置文件可以让Tomcat在启动时为指定的类创建对象,并配置好键值对映射,然后在Java的配置文件中通过键即可获取对象】
【Java项目中的配置文件在打包后被一起封装到jar包或者war包中了,怎样使用外部的配置文件?】

windows注册表:
在这里插入图片描述
JNDI:键为 directory + name,name可自己指定,directory由服务器决定是固定的。
在这里插入图片描述

1.4.2 JNDI使用

注意:
1.使用JDNI连接池方式时,是由Tomcat服务器创建和维护连接,Java程序调用连接。所以,Java程序必须要以部署到Tomcat服务器的方式运行。
2.单元测试中的方法始终是手动控制的,main程序部署到外部Tomcat服务器上运行时,test内的方法与Tomcat服务器独立的,无法使用Tomcat服务器提供连接池。
3.JSP是由Tomcat服务器调用的,将Java测试代码放到jsp中可以访问Tomcat提供的数据库连接。JSP中如何使用Java代码?直接使用,具体见下文

创建工程:

  1. 创建maven项目,选择webapp骨架;

  2. 创建main/java、main/resources、test、test/java目录;【以上两步是常规的创建maven工程的过程】
    在这里插入图片描述

  3. 在webapp目录下创建META-INF目录,创建context.xml配置文件;【也就是创建web应用的配置信息】

context.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource
        <!-- name为键中可自己指定的部分-->
        name= "jdbc/MyDatasource"
        <!-- type为想要创建的对象所属的类-->
        type="javax.sql.DataSource"
        <!-- auth为对象的创建者,这里Container表示Tomcat-->
        auth="Container"
        <!-- 最大活动连接-->
        maxActive="20"
        <!-- 最大等待时长秒数-->
        maxWait="10000"
        <!-- 最大空闲连接-->
        maxIdle="5"
        <!-- 数据库的四大参数-->
        username="root"
        password="123456"
        driverClassName="XXX"
        url="XXX"
    />
</Context>
Java配置文件(MyBatis主配置文件)

    <!-- 配置环境:默认值可任意-->
    <environments default="mysql">
        <!-- 配置mysql的环境:与上面一致-->
        <environment id="mysql">
            <!-- 配置事务的类型-->
            <transactionManager type=""></transactionManager>
            <!-- 配置数据源:JNDI方式-->
            <dataSource type="JNDI">
                <!-- java:comp/env/是键中固定的路径,由服务器决定-->
                <!-- jdbc/MyDatasource是在context.xml中自定义的-->
                <!-- java:comp/env/jdbc/MyDatasource映射到javax.sql.DataSource对象-->
                <property name="data_source" value="java:comp/env/jdbc/MyDatasource"/>
            </dataSource>
        </environment>
    </environments>
<%@ page import="java.io.InputStream" %>
<%@ page import="org.apache.ibatis.io.Resources" %>
<%@ page import="org.apache.ibatis.session.SqlSessionFactoryBuilder" %>
<%@ page import="org.apache.ibatis.session.SqlSessionFactory" %>
<%@ page import="org.apache.ibatis.session.SqlSession" %>
<%@ page import="dao.IUserDao" %>
<%@ page import="pojo.User" %>
<%@ page import="java.util.List" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello Word</h2>

<%-- 真就直接照搬Java代码,真的就是把Java代码嵌入HML了;JSP中也有导入Java依赖包的操作,而且也能自动导入--%>
<%
    // 1. 读取配置文件
    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    // 2. 创建SqlSessionFactory工厂类:builder模式
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory =builder.build(in);
    // 3. 使用工厂创建SqlSession对象:factory模式
    SqlSession sqlSession = factory.openSession();
    // 4. 使用SqlSession创建DAO接口的代理对象:代理模式,动态代理
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    // 5. 使用代理对象执行SQL方法
    List<User> users = userDao.findAll();
    for(User user:users){
    System.out.println(user);
    }
    // 6. 释放资源
    sqlSession.close();
    in.close();
%>
</body>
</html>

二 延迟加载

略,使用默认策略即可:一对一立即加载,一对多延迟加载

三 缓存

3.1 缓存概述

3.1.1 什么是缓存

存在于内存中的临时数据

3.1.2 为什么使用缓存

查询数据库后将数据保存在内存中,可以减少与数据库的交互次数,提高执行效率

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

特别要考虑:缓存和数据库存在同步的问题,使用缓存就存在不同步的可能性

适用的数据: 经常查询、不经常修改、数据价值小【数据不同步影响不大】
不适用的数据: 不经常查询、经常改变、数据价值大【如:银行汇率】

3.2 MyBatis中的缓存【XML配置实现】

MyBatis中缓存分为一级缓存、二级缓存

3.2.1 一级缓存
  1. 一级缓存指的是SqlSession对象的缓存。执行查询后,查询结果会同时存入到SqlSession对象维护的一块内存区域,该区域结果为Map。
  2. 当再次查询同样的数据时,MyBatis会先在该缓存区域中查找,如果存在直接返回。
  3. 当SqlSession对象消失时,该缓存区域也会消失;SqlSession对象也可以手动清空缓存。
确认和清空缓存:

使用缓存:结果为True,log显示只查询一次
    public static void main(String[] args) throws IOException {
        // 1. 读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2. 创建SqlSessionFactory工厂类:builder模式
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory =builder.build(in);
        // 3. 使用工厂创建SqlSession对象:factory模式
        SqlSession session = factory.openSession();
        // 4. 使用SqlSession创建DAO接口的代理对象:代理模式,动态代理
        IUserDao userDao = session.getMapper(IUserDao.class);
        // 5. 使用代理对象执行SQL方法
        // 第一查询
        List<User> users1 = userDao.findAll();
        // 第二次查询
        List<User> users2 = userDao.findAll();
        // 判断为同一个对象: 输出为True
        System.out.println(users1 == users2);
        // 6. 释放资源
        session.close();
        in.close();
    }

关闭session后:结果为False,log显示查询两次
		...
		SqlSession session1 = factory.openSession();
        IUserDao userDao1 = session.getMapper(IUserDao.class);
        List<User> users1 = userDao.findAll();
        session1.close()
        SqlSession session2 = factory.openSession();
        IUserDao userDao2 = session.getMapper(IUserDao.class);
        List<User> users2 = userDao.findAll();
        System.out.println(users1 == users2);


清空缓存后:结果为False,log显示查询两次
		...
		SqlSession session1 = factory.openSession();
        IUserDao userDao1 = session.getMapper(IUserDao.class);
        List<User> users1 = userDao.findAll();
        session1.clearCache()
        IUserDao userDao2 = session.getMapper(IUserDao.class);
        List<User> users2 = userDao.findAll();
        System.out.println(users1 == users2);
缓存同步:这里很扯蛋啊
当调用SqlSession的修改update、添加insert、删除delete操作,
以及commit、close、clearCache操作时,一级缓存都会清空。
这样的话,怎么还会出现缓存和数据库不同步的情况?

更新后判断:False,log显示查询两次
    public static void main(String[] args) throws IOException {
        // 1. 读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 2. 创建SqlSessionFactory工厂类:builder模式
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory =builder.build(in);
        // 3. 使用工厂创建SqlSession对象:factory模式
        SqlSession session = factory.openSession();
        // 4. 使用SqlSession创建DAO接口的代理对象:代理模式,动态代理
        IUserDao userDao = session.getMapper(IUserDao.class);
        // 5. 使用代理对象执行SQL方法
        // 第一次查询
        User user1 = userDao.findById(10);
        // 更新用户信息
        user1.setName("zs");
        userDao.updateUser(user1);
        // 第二次查询
        User user2 = userDao.findById(10);
        // 判断为同一个对象
        System.out.println(user1 == user2);
        // 6. 释放资源
        session.close();
        in.close();
    }
3.2.2 二级缓存
  1. 二级缓存指的是SqlSessionFactory对象维护的缓存,由同一个SqlSessionFacotry对象创建的SqlSession对象共享同一个二级缓存;
  2. 二级缓存需要手动开启【一级缓存不需要】;先在主配置文件中开启、然后映射配置文件中开启、最后在Sql语句配置中开启(映射配置文件的select标签中);
  3. 二级缓存中保存的不是查询结果封装后的POJO对象,而是查询结果的键值对数据,当新的查询访问二级缓存时,再取出封装;
    在这里插入图片描述
启动二级缓存:

主配置文件:
    <settings>
        <setting name="cacheEnable" value="true"/>
    </settings>

映射配置文件:
    <cache></cache>

select标签:
	<select id="findAll" resultType="pojo.User" useCache="true">
        SELECT * FROM user;
    </select>
二级缓存的效果:False,但log显示只查询了一次
		...
		SqlSession session1 = factory.openSession();
        IUserDao userDao1 = session.getMapper(IUserDao.class);
        List<User> users1 = userDao.findAll();
        session1.close()
        SqlSession session2 = factory.openSession();
        IUserDao userDao2 = session.getMapper(IUserDao.class);
        List<User> users2 = userDao.findAll();
        System.out.println(users1 == users2);

3.3 注解配置实现

使用一级缓存

略,一级缓存默认就是开启的,不需要设置

使用二级缓存

主配置文件:
    <settings>
        <setting name="cacheEnable" value="true"/>
    </settings>

Dao接口:
@CacheNamespace直接作用在类上,blocking属性值设为true,表示开启二级缓存【默认值为false@CacheNamespace(blocking = true)
public interface IUserDao{
	...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值