MyBatis笔记(二)

简介: MyBatis笔记

8.分布查询的优点


  • 分布查询的优点是可以实现延迟加载
  • 延迟加载可以避免在分步查询中执行所有的SQL语句,节省资源,实现按需加载
  • 需要在核心配置文件中添加如下的配置信息
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>


  • lazyLoadingEnabled表示全局的延迟加载开关,true表示所有关联对象都会延迟加载,false表示关闭
  • aggressiveLazyLoading表示是否加载该对象的所有属性,如果开启则任何方法的调用会加载这个对象的所有属性,如果关闭则是按需加载
  • 由于这个配置是在核心配置文件中设定的,所以所有的分步查询都会实现延迟加载,而如果某个查询不需要延迟加载,可以在collection标签或者association标签中的fetchType属性设置是否使用延迟加载,属性值lazy表示延迟加载,属性值eager表示立即加载


9.动态SQL


  • if标签
  • if标签通过test属性给出判断的条件,如果条件成立,则将执行标签内的SQL语句
  • 范例
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp where
    <if test="empName != null and empName != ''">
        emp_name = #{empName}
    </if>
    <if test="age != null and age != ''">
        and age = #{age}
    </if>
    <if test="gender != null and gender != ''">
        and gender = #{gender}
    </if>
</select>


  • where标签
  • 考虑if标签中的范例出现的一种情况:当第一个if标签条件不成立而第二个条件成立时,拼接成的SQL语句中where后面连着的是and,会造成SQL语句语法错误,而where标签可以解决这个问题
  • 范例
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <where>
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </where>
</select>
  • where标签只会在子标签返回任何内容的情况下才插入WHERE子句。而且,若子句的开头有多余的and或者or,where标签也会将它们去除,但是子句末尾的and或者or不能去除
  • trim标签
  • trim标签用于去掉或添加标签中的内容
  • trim标签常用属性
  1. prefix:在trim标签中的内容的前面添加某些内容
  2. prefixOverrides:在trim标签中的内容的前面去掉某些内容
  3. suffix:在trim标签中的内容的后面添加某些内容
  4. suffixOverrides:在trim标签中的内容的后面去掉某些内容
  • 用trim实现where标签范例相同的功能
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <trim prefix="where" prefixOverrides="and">
        <if test="empName != null and empName != ''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age != ''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </trim>
</select>
  • choose、when、otherwise标签
  • 这三个标签是组合使用的,用于在多条件中选择一个条件,类似Java中的if...else if...else...语句
  • 范例
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp where gender = #{gender}
    <choose>
        <when test="empName != null and empName != ''">
            and emp_name = #{empName}
        </when>
        <when test="age != null and age != ''">
            and age = #{age}
        </when>
    </choose>
</select>


  • 当某个when标签的条件满足时将对应的SQL语句返回,如果都不满足并且有otherwise标签时,才会返回otherwise标签中的SQL语句
  • foreach标签
  • foreach标签允许指定一个集合或数组,并且对这个集合或数组进行遍历
  • foreach标签可以用的属性有
  1. collection:指定需要遍历的集合或数组
  2. item:当前遍历到的元素
  3. index:当前遍历到的元素的序号
  4. 当遍历的集合是Map类型时,index表示键,item表示值
  5. open:指定遍历开始前添加的字符串
  6. close:指定遍历开始后添加的字符串
  7. separator:指定每次遍历之间的分隔符
  • collection属性值注意事项
  • 如果遍历的是List时,属性值为list
  • 如果遍历的是数组时,属性值为array
  • 如果遍历的是Map时,属性值可以是map.keys()map.values()map.entrySet()
  • 除此之外,还可以在映射方法的参数中使用@Param()注解自定义collection属性值
  • 批量添加数据
<insert id="addMoreEmp">
    insert into t_emp values
    <foreach collection="list" separator="," item="emp">
        (null,#{emp.empName},#{emp.age},#{emp.gender},null)
    </foreach>
</insert>


  • 批量删除数据
<delete id="deleteMoreEmp">
    delete from t_emp where emp_id in
    <foreach collection="array" item="empId" separator="," open="(" close=")">
        #{empId}
    </foreach>
</delete>
  • sql标签
  • 用于记录一段通用的SQL语句片段,在需要用到该SQL语句片段的地方中通过include标签将该SQL语句片段插入
  • sql标签通过id属性唯一标识一个SQL语句片段,include标签通过refid属性指定使用某个SQL片段
  • 范例
<sql id="item">
    emp_id,emp_name,age,gender,dept_id
</sql>
<select id="getEmpByEmpId" resultType="Emp">
 select <include refid="item"></include>
    from t_emp
    where emp_id = #{empId}
</select>



四.核心配置文件


1.文件结构


  • 核心配置文件命名建议是mybatis-config.xml,无强制要求
  • 核心配置文件主要用于配置连接数据库的环境以及MyBatis的全局配置信息
  • 核心配置文件存放的位置是maven工程下的src/main/resources目录下
  • 简易结构如下,核心配置文件的标签不止这几个
<?xml version="1.0" encoding="UTF-8" ?>
<!--DTD约束-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--
    1.environments配置数据库的环境,环境可以有多个
        2.default属性指定使用的环境
    -->
    <environments default="development">
        <!--
            1.environment配置具体某个数据库的环境
            2.id属性唯一标识这个环境
        -->
        <environment id="development">
            <!--
                1.transactionManager设置事务管理方式
                2.type属性取值有“JDBC|MANAGED”
                3.JDBC指当前环境中使用的是JDBC中原生的事务管理方式,事务的提交或回滚需要手动处理
                4.MANAGED指被管理,例如Spring中
            -->
            <transactionManager type="JDBC"/>
            <!--
                1.dataSource配置数据源
                2.取值有"POOLED|UNPOOLED|JNDI"
                3.POOLED表示使用数据库连接池缓存数据库连接
                4.UNPOOLED:表示不使用数据库连接池
                5.JNDI表示使用上下文中的数据源
            -->
            <dataSource type="POOLED">
                <!--设置链接数据库的驱动-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!--设置连接数据库的地址-->
                <property name="url" value="jdbc:mysql://localhost:3306/ssm"/>
                <!--设置连接数据库的用户名-->
                <property name="username" value="root"/>
                <!--设置连接数据库的密码-->
                <property name="password" value="lxq"/>
            </dataSource>
        </environment>
    </environments>
    <!--mappers用于引入映射的配置文件-->
    <mappers>
        <!--mapper用于指定某个映射文件,resource属性指定文件路径-->
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>

   


2.核心配置文件详解


(1)标签顺序


  • 核心配置文件中configuration标签下的子标签要按照一定的顺序书写
  • properties => settings => typeAliases => typeHandlers => objectFactory => objectWrapperFactory => reflectorFactory =>  plugins => environments => databaseIdProvider => mappers


(2)标签详解


  • <properties>标签
  • 用于引入某个properties配置文件,是一个单标签
  • resource属性指定配置文件
  • 范例

<properties resource="jdbc.properties" />


  • <typeAliases>标签
  • 用于为某个类的全类名设置别名,子标签是<typeAlias>
  • 一个子标签对应设置一个类的别名
  • 子标签下有type和alias两个属性,type指定需要设置别名的类的全类名,alias指定别名
  • 如果只设置了type属性,那么默认的别名就是它的类名(不是全类名)而且不区分大小写
  • 如果想要设置某个包下所有类的别名,可以使用<package>标签,用name属性指定包名
  • 范例
<typeAliases>
    <typeAlias type="com.lxq.pojo.User" alias="User"></typeAlias>
    <package name="com.lxq.pojo"></package>
</typeAliases>


  • MyBatis中内建了一些类型的别名,常见的有

Java类型

别名

int

_int或_integer

Integer

int或integer

String

string

List

list

Map

map

  • <property>标签
  • 用于配置连接数据库时用到的各种属性,是一个单标签
  • 该标签有两个属性,一个是name指定属性名,另一个是value指定属性值
  • 如果不使用<properties>标签引入相关配置文件时,使用方式如下

<property name="driver" value="com.mysql.jdbc.Driver" />


  • 如果使用<properties>标签引入相关的配置文件时,value属性可以写成如下形式

<property name="driver" value="${jdbc.driver}" />

其中配置文件的内容是

注意:这里使用jdbc.driver来给键命名是因为核心配置文件中可能会引入其他的配置文件,如果使用driver来命名键的话有可能会跟其他配置文件中的键同名而产生冲突

  • <mappers>标签
  • 该标签用于引入映射文件
  • 每个映射文件使用子标签<mapper>来表示,该子标签是一个单标签
  • 子标签<mapper>使用属性resource来指定需要引入的映射文件
  • 如果想要将某个包下所有的映射文件都引入,可以使用<package>标签,使用name属性来指定需要引入的包
  • 范例
<mappers>
    <mapper resource="mappers/UserMapper.xml" />
    <package name="com.lxq.mapper" />
</mappers>

注意:使用包的形式引入映射文件需要满足两个条件,1.mapper接口所在的包和映射文件所在的包要一致;2.mapper接口名和映射文件名要相同


五.相关API


1.Resources


  • Resources类由MyBatis提供用于获取来自核心配置文件的输入流
  • 相关方法是:InputStream getResourceAsStream(String filepath),注意这是一个静态方法


2.SqlSessionFactoryBuilder


  • SqlSessionFactoryBuilder类由MyBatis提供用于获取SqlSessionFactory的实例对象
  • 相关方法是:SqlSessionFactory build(InputStream is),该方法通过一个输入流返回了SqlSessionFactory对象


3.SqlSessionFactory


  • SqlSessionFactory类由MyBatis提供用于获取SqlSession对象,每个基于MyBatis的应用都是以一个SqlSessionFactory的实例为核心的
  • 相关方法:SqlSession openSession()SqlSession openSession(boolean autoCommit),这两个方法都用于获取SqlSession对象,如果使用有参数的可以指定是否自动提交事务,没有指定参数的默认是不自动提交事务


4.SqlSession


  • SqlSession类由MyBatis提供用于执行SQL、管理事务、接口代理
  • 常用方法

方法

说明

void commit()

提交事务

void rollback()

回滚事务

T getMapper(Class<T> aClass)

获取指定接口的代理实现类

void close()

释放资源

  • 除了以上常用方法外,SqlSession还有很多有关数据库增删改查的方法,但是这些方法繁琐而且不符合类型安全,所以使用getMapper()方法来获取一个Mapper接口的代理实现类来执行映射语句是个比较方便的做法


5.最佳实践


  • SqlSessionFactoryBuilder
    这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。因此 SqlSessionFactoryBuilder 实例的最佳范围是方法范围(也就是局部方法变量)。你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但是最好还是不要让其一直存在以保证所有的 XML 解析资源开放给更重要的事情
  • SqlSessionFactory
    SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由对它进行清除或重建。使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏味道(bad smell)”。因此  SqlSessionFactory 的最佳范围是应用范围。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式
  • SqlSession
    每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的范围是请求或方法范围。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也绝不能将 SqlSession 实例的引用放在任何类型的管理范围中,比如 Serlvet 架构中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的范围中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭
  • 工具类
public class SqlSessionUtil {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }
}


六.缓存


1.一级缓存


  • 一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问,一级缓存是默认开启的
  • 一级缓存失效的四种情况:
  • 使用另一个SqlSession
  • 同一个SqlSession但是查询条件不同
  • 同一个SqlSession但是两次查询中间执行了任何一次增删改操作
  • 同一个SqlSession但是两次查询中间手动清空了缓存,手动清空缓存的方法是调用SqlSession的clearCache()方法


2.二级缓存


  • 二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存,此后若再次执行相同的查询语句,结果就会从缓存中获取
  • 二级缓存开启的条件:
  • 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
  • 在映射文件中设置标签<cache/>
  • 二级缓存必须在SqlSession关闭或提交之后有效
  • 查询的数据所转换的实体类类型必须实现序列化的接口
  • 二级缓存失效的情况:两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
  • <cache/>可以设置的一些属性:
  • eviction属性:缓存回收策略,默认的是 LRU
  1. LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象
  2. FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们
  3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象
  4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象
  • flushInterval属性:刷新间隔,单位是毫秒,默认情况下不设置也就是没有刷新间隔,缓存仅仅调用语句时刷新
  • size属性:引用数目,正整数代表缓存最多可以存储多少个对象,太大容易导致内存溢出
  • readOnly属性:只读, 取值是true/false
  1. true:只读缓存,会给所有调用者返回缓存对象的相同实例,因此这些对象不能被修改,这提供了很重要的性能优势
  2. false:读写缓存,会返回缓存对象的拷贝(通过序列化),这会慢一些,但是安全,因此默认是false


3.缓存的查询顺序


  • 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
  • 如果二级缓存没有命中,再查询一级缓存
  • 如果一级缓存也没有命中,则查询数据库
  • 注意SqlSession关闭之后,一级缓存中的数据才会写入二级缓存
目录
相关文章
|
7月前
|
SQL 缓存 Java
框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性
本文详细解构了MyBatis的工作机制,包括解析配置、创建连接、执行SQL、结果封装和关闭连接等步骤。文章还介绍了MyBatis的五大核心功能特性:支持动态SQL、缓存机制(一级和二级缓存)、插件扩展、延迟加载和SQL注解,帮助读者深入了解其高效灵活的设计理念。
|
Java 数据库连接 数据库
Mybatis逆向工程笔记小结
Mybatis逆向工程笔记小结
|
SQL Java 数据库连接
【Java笔记+踩坑】MyBatisPlus基础
MyBatisPlus简介、标准数据层开发CRUD、业务层继承IService、ServiceImpl、条件查询、LambdaQueryWrapper、id生成策略、逻辑删除、乐观锁@Version、代码生成器、ActiveRecord
【Java笔记+踩坑】MyBatisPlus基础
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
SQL Java 关系型数据库
MyBatis-Plus全套笔记三
MyBatis-Plus全套笔记三
122 1
|
SQL Java 数据库连接
MyBatis-Plus全套笔记二
MyBatis-Plus全套笔记二
134 1
|
Java 关系型数据库 数据库连接
MyBatis-Plus全套笔记一
MyBatis-Plus全套笔记一
399 1
|
SQL Java 数据库连接
[推荐] MyBatis框架初学笔记-为之后拾遗
[推荐] MyBatis框架初学笔记-为之后拾遗
106 0
|
SQL 存储 缓存
MyBatis 学习心得笔记
MyBatis 学习心得笔记
222 0