Mybatis

1:简介

1.1:什么是mybatis
  • MyBatis 是一款优秀的持久层框架,
  • 它支持自定义 SQL、存储过程以及高级映射。
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
1.2:持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化。
1.3:持久层

Dao层、service层、controller层

  • 完成持久化工作的代码块
  • 层是界限十分明显的
1.4::为什么需要mybatis
  • 保住程序员将数据存入数据库中
  • 方便
  • 传统的jdbc代码太复杂

2:第一个mybatis程序

思路:搭建环境-导入mybatis-编写代码-测试

2.1:搭建环境
  1. 搭建数据库
  2. 新建项目项目
    1. 新建普通的maven项目
    2. 删除src目录—当做父工程
    3. 导入maven依赖(mysql、junit、mybatis)
2.2:创建模块
  • 编写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核心配置文件-->
    <configuration>
        
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=true&amp;userUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        
        <!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
        <mappers>
            <mapper resource="com/chen/dao/UserDao.xml"/>
        </mappers>
        
        <settings>
            <setting name="lazyLoadingEnabled" value="true"/>
            <setting name="logImpl" value="STDOUT_LOGGING"/>
        </settings>
    
    <!--    配置插件-->
        <plugins>
            <plugin interceptor="com.github.pagehelper.PageInterceptor">
            </plugin>
        </plugins>
    </configuration>
    
  • 编写mybatis工具类

package com.chen.utils;

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;

/**
 * @Author CYXing
 * @Date 2021/9/30 15:28
 * @Version 1.0
 */

//sqlSessionFactory
public class mybatisUtil {

    private static SqlSessionFactory sqlSessionFactory;
    static {
        //第一步:获取SqlSessionFactory对象
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //获取SQLSession对象
    public static SqlSession sqlSession(){
        return sqlSessionFactory.openSession();
    }

}
2.3:编写代码
  • 实体类

    @Data
    public class User {
        private int id;
        private int age;
        private String name;
    }
    
  • Dao接口

    public interface UserDao {
        List<User> getUserList();
    }
    
  • 接口实现类

    <?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.chen.dao.UserDao">
    <select id="getUserList" resultType="com.chen.pojo.User">
        select * from user
    </select>
    </mapper>
    
2.4:测试

注意点:

org.apache.ibatis.binding.BindingException: Type interface com.chen.dao.UserDao is not known to the MapperRegistry.

MapperRegistry是什么?

核心配置文件中注册mapper

<!--    每一个Mapper.xml都需要在mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/chen/dao/UserDao.xml"/>
    </mappers>
测试:

可能遇到的问题:

  1. 配置文件没有注册
  2. 绑定接口错误
  3. 方法名不对
  4. 返回类型不对
  5. Maven导出资源问题

3:CRUD

3.1:namespace:

namespace中的包名要与接口名一致

3.2:select、insert、delete、update

选择,查询语句

  • id:就是对应的namespace中的方法名
  • resultType:sql语句执行的返回值,
  • paramType:参数类型!

编写接口

编写对应的mapper语句

3.3:万能Map:

假设实体类或者数据库中的表,字段或者参数过多,我们应当使用Map!

4:配置解析

1:核心配置文件
  • mybatis-config.xml

  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)
2:环境配置(environments)

事务管理器:JDBC(默认)、MANAGED

MyBatis 可以配置成适应多种环境

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

连接数据库的数据源有:dbcp、c3p0、druid、jdbc等

连接池:POOLED|UNPOOLED|JNDI

3:属性(properties)

在这里插入图片描述

我们可以通过properties属性实现引用

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。

db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useSSL=true&userUnicode=true&characterEncoding=UTF-8
username=root
password=123456

在核心配置文件中引入

<properties resource="db.properties"/>
4:类型别名(typeAliases)
<!--    给实体类起别名-->
    方式一
    <typeAliases>
        <typeAlias type="com.chen.pojo.User" alias="user"/>
    </typeAliases>
    
   方式二
    <typeAliases>
    	<package name="com.chen.pojo"/>
    </typeAliases>
5:设置
6:其他设置
7:映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件

method01:

    <mappers>
        <mapper resource="com/chen/dao/UserMapper.xml"/>
    </mappers>

method02:使用class文件绑定注册

    <mappers>
        <mapper class="com.chen.dao.UserMapper"/>
    </mappers>

注意点:

  • 接口和他的Mapper配置文件必须同名!
  • 接口和他的Mapper配置文件必须在同一个包下!

method03:使用扫描包进行注入绑定

    <mappers>
        <package name="com.chen.dao"/>
    </mappers>

注意点:

  • 接口和他的Mapper配置文件必须同名!
  • 接口和他的Mapper配置文件必须在同一个包下!
8:生命周期

在这里插入图片描述

生命周期和作用域至关重要,因为错误使用会导致严重的并发问题

SQLSessionFactoryBuilder:
  • 一旦创建SQLSessionFactory,就不需要了就不需要它了
  • 最佳作用域为局部变量
SQLSessionFactory:
  • 数据库连接池
  • 一旦创建在运行期间一直存在,没有任何理由丢弃它或者重新创建
  • 最佳作用域为全局变量
  • 最简单的就是使用单例模式或者静态单例模式
sqlSession:
  • 连接到连接池的一个请求
  • 最佳作用域是方法作用域
  • 用完之后赶紧关闭

5:解决属性名跟字段名不一致的问题

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

问题:

当实体类与指定数据表对应时,实体类中的属性名与字段名不匹配时会出现赋值为空的情况!

解决方法:
  • 给数据库查询字段起别名
  • resultMap
5.1:resultMap

结果集映射

6:日志

日志工厂

如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手

曾经:sout、debug

现在:日志工厂

​ logImpl:指定mybatis所用日志的具体实现,未指定时将自动查找

  • SLF4J

  • LOG4J(掌握)
  • LOG4J2

  • JDK_LOGGING

  • COMMONS_LOGGING

  • STDOUT_LOGGING(掌握)
  • NO_LOGGING

在mybatis中具体使用哪个日志实现,在设置中实现

6.1:STDOUT_LOGGING标准日志输出

在这里插入图片描述

6.2:Log4j

什么是log4j?

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 我们也可以控制每一条日志的输出格式
  • 定义每一条日志信息的级别
  • 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
  1. 先导入log4j包

    dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  2. log4j.properties

  3. 配置log4j为日志的实现

  4. 直接运行

简单应用
  1. 在要是用的log4j的类中,导入包
    在这里插入图片描述

​ 2:日志对象,参数为当前类的class

​ 3:日志级别

7:分页

思考:为什么要分页?
  • 减少数据的处理量
7.1:使用limit分页
select * from user limit startIndex,pagesize
使用mybatis实现分页,核心SQL
  1. 接口

        //分页查询
        List<User> getUserByLimit(Map<String,Object> map);
    
  2. mapper.xml

    <select id="getUserByLimit" parameterType="map" resultType="user">
            select *
            from user
            limit #{startIndex},#{pageSize}
        </select>
    
  3. 测试

7.2:RowBounds分页

不适用sql实现分页

  1. 接口

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qS5xIOTG-1646898584826)(C:\Users\19828\AppData\Roaming\Typora\typora-user-images\image-20211009162219914.png)]

  1. 测试
7.3:分页插件
pageHelper:https://pagehelper.github.io/

8:使用注解开发

8.1:面向接口编程
8.2:使用注解开发
  1. 注解在接口上实现

        @Select("select * from user")
        List<User> getUser();
    
  2. 在核心配置文件中绑定接口

    <!--    绑定接口-->
        <mappers>
            <mapper class="com.chen.dao.UserMapper"/>
        </mappers>
    

底层原理:动态代理

8.3:CRUD

我们可以在工具类出创建的时候实现自动提交事务!

在这里插入图片描述

关于@Param()注解
  • 基本类型的参数或者String类型需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型可以忽略
  • sql中引用的就是param中的参数名

9:Lombok

步骤:

  • 在idea中安装lombok插件

  • 在项目中导入lombok依赖

  • @Data:无参构造、get、set、toString、equals、hascode
    @AllArgsConstructor
    @NoArgsConstructor
    

10: 多对一处理

多对一:

  • 多个学生对应一个老师
  • 对于学生而言:多对一 关联
  • 对于老师而言:一对多 集合
测试环境搭建:
  1. 导入lombok
  2. 新建实体类Teacher、Student
  3. 建立Mapper接口
  4. 建立Mapper.XML文件
  5. 在核心配置文件中绑定注册我们的Mapper接口
  6. 测试查询能否成功!
多对一:
按照查询嵌套处理:
按照结果嵌套处理:
一对多:
实例:按照结果嵌套处理:

*变换前:*主要依靠多条sql语句获取到所需要的的信息

	<select id="selectLevel1" resultMap="BaseResultMap">
		select t1.`code` business_type_code, t1.`name` business_type_name
		from pile_business_type t1
		<where>
			t1.is_deleted='N'
		</where>
		order by t1.`code`
	</select>

	<select id="selectChildrenByBusiness" resultMap="Children">
		select  t2.`code`, t2.`name`
		from pile_report_type t2
		<where>
			t2.business_type_code=#{businessTypeCode,jdbcType=VARCHAR}
			and t2.is_deleted = 'N'
			and  (t2.parent_code is null or t2.parent_code='')
		</where>
		order by t2.`code`
	</select>

变换后:主要依赖resultMap中的collection一次性获取所需的信息

减少的sql语句的使用相对来说提高了性能!

《方式一》
<resultMap id="test" type="com.jandar.pile.yw.entity.PileBusinessType">
		<result property="code" column="business_type_code"/>
		<result property="name" column="business_type_name"/>
<!--		复杂属性 我们需要单独处理 
						多对一:		对象:association   ==》javaType=“” 指定属性类型
						一对多:		集合:collection	   ==》 ofType=“”  获取集合中泛型信息
-->
		<collection property="children" ofType="com.jandar.pile.yw.entity.PileReportType">
			<result property="code" column="code"/>
			<result property="name" column="name"/>
		</collection>
	</resultMap>

<select id="selectLevel1" resultMap="test">
		select t1.`code` business_type_code, t1.`name` business_type_name,t2.`code` code, t2.`name` name
		from pile_business_type t1, pile_report_type t2
		<where>
		t1.code=t2.business_type_code
		and t1.is_deleted='N'
		and t2.is_deleted='N'
		and (t2.parent_code is null or t2.parent_code='')
		</where>
		order by t1.`code`, t2.`code`
	</select>
    
    《方式二》
    
小结:
  1. 关联:association–【多对一】
  2. 集合:collection–【一对多】
  3. javaType & ofType
    1. javaType用来指定实体类中属性的类型
    2. ofType用来指定映射到List或者集合中的pojo,泛型中的约束类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段问题
  • 如果问题不好排查可以使用日志

高频面试:

  • mysql引擎
  • innoDB底层原理
  • 索引
  • 索引优化

12:动态sql

什么是动态sql:指根据不同的条件生成不同的sql语句

if

set

choose

when

sql片段

有时候,我们可能将一些公共的部分抽取出来,方便适用

使用sql标签抽取公共部分
<sql id="Base_Column_List">
   id, unique_id, report_time, user_id, report_user_name, report_user_phone, report_address,
   report_content, report_obj, report_pic_names, report_video_names, report_pic_urls, report_video_urls,
   report_province, report_city, report_street, report_code, anonymous, status, read_status,
   report_update_time, download_status,name
 </sql>
 
 在需要使用的地方用Include标签引用
 <include refid="Base_Column_List"/>

foreach

在这里插入图片描述
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VnQJD2CI-1646898584827)(C:\Users\19828\AppData\Roaming\Typora\typora-user-images\image-20211011162238042.png)]

13:缓存

13.1:简介

在这里插入图片描述

查询:连接数据库,耗资源!
    一次查询的结果,给他暂存在一个可以直接取到的地方 ==》内存:缓存
 我们再次查询相同数据的时候,直接走缓存,就不用走数据库了
  1. 什么是缓存{cache}?
    • 内存中的临时数据
    • 用户在缓存中查找数据,不用从磁盘查询数据,从而提高效率,解决高并发系统的性能问题
  2. 为什么使用缓存?
    • 减少和数据库的交互次数,减少系统开销
  3. 什么样的数据能缓存?
    • 经常查询并且不经常改变的数据【可以使用缓存】
13.2:mybatis缓存
  • mybatis包含非常强大的查询缓存特性,他可以非常方便的定制和配置缓存

  • 默认两级缓存:一级缓存和二级缓存

    • 默认情况下,只有一级缓存开启

    • 二级缓存需要手动开启和配置,基于namespace级别的缓存

    • 为了提高扩展性mybatis定义了接口Cache

13.3:一级缓存
  • 一级缓存也叫本地缓存:sqlsession
    • 与数据库同一次会话期间查询到的数据会放在本地缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

测试步骤:

  1. 开启日志
  2. 测试在一个session中查询两次相同的记录
  3. 查看输入值输出

在这里插入图片描述

缓存失效的情况:

  1. 查询不同的数据

  2. 增删改操作,可能会改变原来的数据

  3. 查询不同的Maper.xml

  4. 手动清理缓存

    //手动清理缓存
    sqlSession.clearCache();
    

小结:一级缓存默认开启,只在一次sqlsession中有效,也就是拿到连接到关闭这个区间

一级缓存相当于一个map。

13.4:二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace几倍的缓存,一个名称空间,对应一个二级缓存
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果关闭当前会话,一级缓存就没了;如果有二级缓存,当会话关闭时,一级缓存的数据会被保存到二级缓存中
    • 新的会话查询信息,就可以从二级缓存中获取
    • 不同的mapper查询结果会放在不同的缓存中

步骤

  1. 开启全局缓存

    <!--        显示的开启全局缓存-->
     <setting name="cacheEnable" value="true"/>
    
  2. 在要是用二级缓存的Mapper中开启

    <!--    在当期Mapper.xml中使用二级缓存-->
    <cache eviction="FIFO" flushInterval="60000" readOnly="true" size="512"/>
    
  3. 测试

    1. 问题:我们需要将实体类序列化!否则就会报错

      q:Caused by: java.io.NotSerializableException: com.chen.pojo.User

      a:public class User implements Serializable 
      

    小结:

    • 只要开启了二级缓存,在同一个mapper下就有效
    • 所有的数据都会先放在一级缓存中
    • 当会话结束时才会提交到二级缓存中
13.5:缓存原理:

在这里插入图片描述

13.6:自定义缓存:ehcache

Ehcache是一种广泛使用的开源java分布式缓存。主要面向通用缓存
要在程序中使用ehcache,先导入依赖。

redis数据库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值