自用Mybatis笔记

4 篇文章 0 订阅
2 篇文章 0 订阅

1、什么是框架?

​ 它是我们软件开发中的一套解决方案,不同的框架解决的是不同的问题。

​ 使用框架的好处:

​ 框架封装了很多细节,是开发者可以使用极简的方式实现功能。大大提升开发效率。

2、三层架构

​ 表现层:适用于展示数据

​ 业务层:事处理业务需求

​ 持久层:是和数据库交互的

3、持久层技术解决方案

JDBC技术:

​ Connection

​ PreparedStatement

​ ResultSet

Spring的JDBCTemplate:

​ Spring中对JDBC的简单封装

Apache的JDBCUtils:

​ 它和Spring的JDBCTemplate很像,也是对JDBC的简单封装

以上这些都不是框架

​ JDBC是规范

​ Spring的JDBCTemplate和Apache的DBUtils都只是工具类

4、MyBatis的概述

​ MyBatis是一个持久层框架,用Java语言编写

​ 它封装了JDBC操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建链接等繁杂过程

​ 他使用了ORM思想实现了结果集的封装

ORM: Object Relational Mapping 对象关系映

​ 简单的说:

​ 就是把数据库表和实体类及实体类的属性对应起来

​ 让我们可以操作实体类就实现操作数据库表

​ user User

​ id UserID

​ user_name userName

今天我们需要做到

​ 实体类中的属性和数据库表的字段名称保持一致

​ user User

​ id id

​ user_name user_name

5、MyBatis的入门

mybatis的环境搭建

​ 第一步:创建maven工程并导入坐标

​ 第二步:创建实体类和dao的接口

​ 第三步:创建MyBatis的主配置文件SqlMapConfig.xml

​ 第四步:创建映射配置文件IUserDao.xml

环境搭建的注意事项

​ 第一个:创建IUserDao.xml和创建IUserDao.java时,名称是为了和我们之前的只是保持一致。

​ 在MyBatis中它把持九层的操作接口名称和映射文件也叫做:Mapper

​ 所以,IUserDao和IUserMapper是一样的

​ 第二个:在idea创建目录时,它和包是不一样的

​ 包在创建时:com.xin.dao是三级结构

​ 目录在创建时:com.xin.dao是一级结构

​ 第三个:mybatis的映射配置文件位置必须和dao接口的包结构相同

​ 第四个:映射配置文件的mapper标签Namespace属性的取值必须是dao接口的全限定类名

​ 第五个:映射配置文件的操作配置(select),id属性的取值必须dao接口是方法名

当我们遵从了第三、四、五点之后,我们在开发中就无需再写dao的实现类

mybatis的入门案例

//1、读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2、创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3、使用工厂产生SqlSession对象
SqlSession session = factory.openSession();
//4、使用SqlSession创建dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5、使用代理对象执行方法
List<User> users = userDao.findAll();
for (User user : users){
    System.out.println(user);
}
//6、释放资源
session.close();
in.close();

注意事项:不要忘记再映射配置中告知mybatis要封装的实体类中

配置的方式:指定实体类的全限定类名

mybatis基于注解的入门案例

把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定sql语句

​ 同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名

明确:

​ 我们在实际开发中都是越简便越好,所以都是采用不写dao实现类的方式

​ 不管使用xml还是注解配置

​ 但是MyBatis它是支持写dao实现类的

代码解析:

读取路径(一般不使用绝对路径和相对路径):

​ 第一个:使用类加载器,他只能读取类路径的配置文件

​ 第二个:使用ServletContext对象的getRealPath()

创建工厂mybatis使用了构建者模式,builder就是构建者,优势:把对象的创建细节隐藏,使使用者直接调用方法即可拿到对象

生产SqlSession使用了工厂模式,优势:解耦(降低类之间的依赖关系)

创建Dao接口实现类使用了代理模式,优势:不修改源码的基础上对已有方法增强

6、自定义MyBatis的分析:

​ mybatis在使用代理dao的方式实现增删改查是做什么事呢?

​ 只有两件事:

​ 第一:创建代理对象

​ 第二:在代理对象中调用selectList

​ 自定义MyBatis能通过入门案例看到类

​ class Resources

​ class SqlSessionFactoryBuilder

​ interface SqlSessionFactory

​ interface SqlSession

链接数据库的信息,有了他们就能创建Connection对象

<!--配置连接数据库的基本信息-->
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>

映射的配置文件信息

<mappers>
    <mapper resource="com/xin/dao/IUserDao.xml"></mapper>
</mappers>

执行的SQL语句,就可以获取PreparedStatement和封装实体类的全限定类名

<select id="findAll" resultType="com.xin.domain.User">
    select * from user;
</select>

读取配置文件:用到的技术就是解析xml的技术

此处用到的就是***dom4j解析xml技术***

selectList方法
1、根据配置文件的信息创建Connection对象
	注册驱动,获取链接
2、获取预处理对象PreparedStatement
	此时需要SQL语句
	connection.prepareStatement(sql);
3、执行查询
	Resultset resultset = preparedStatement.excuteQuery();
4、遍历结果集用于封装
    List<E> list = new ArrayList();
	while(resultSet.next()){
		E element = (E)Class.forName(配置的权限的类名).newInstance();
        进行封装,把每个rs的内容都添加到element中
         我们的实体类属性和表中的列名是一致的。于是我们就可以把表的类名看成实体类的属性名
         就是可以使用反射的方式来根据名称获取每个属性,并赋值(此处使用反射封装)
        把element加入到list中
        list.add(element);
	}
5、返回list
    return list;

要想让该selectList方法执行,我们需要给方法提供两个信息

​ 1、连接信息

2、映射信息

两个部分:

第一:执行的SQL语句

第二:封装结果的实体类全限定类名

合起来定义为一个对象Mapper

Mapper的对象:String sql和String domainClassPath

sql为findAll方法的sql语句

domainClassPath为全限定类名

//4、使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);

根据dao接口的字节码创建dao的代理对象

public <T> T getMapper(Class<T> daoInterfaceClass){
	/**
		类加载器:他使用的和被代理对象是相同的类加载器
		代理对象要实现的接口:和被代理对象实现相同的接口
		如何代理:他就是增强的方法,我们需要自己来提供
				此处就是一个InvocationHandle的接口,我们需要写一个该接口的实现类
				在实现类中调用selectList方法
	*/
	Proxy.newProxyInstance(类加载器,代理对象要实现的接口字节码数组,如何代理)
}

第一步:SqlSessionFactoryBuilder接收SqlMapConfig.xml文件流,构建出SqlSessionFactory对象

第二步:SqlSessionFactory读取SqlMapConfig.xml中链接数据库和mapper的映射信息。用来生产出真正操作数据库的SqlSession对象。

第三步:

​ SqlSession对象有两大作用:

​ 1、生成接口代理对象

​ 2、定义通用的增删改查方法

​ 注:无论哪个分支,除了链接数据库信息,还需要得到sql语句

第四步:

​ 作用一:在在SqlSessionImpl对象的getMapper方法中分两步来实现。

​ 1、先用SqlSessionFactory读取数据库链接信息创建Connection对象

​ 2、通过jdk代理模式创建出代理对象作为getMapper方法返回值,这里主要工作是在创建代理对象是第三个参数处理类里面得到sql语句。执行对应CRUD操作。

​ 作用二:在SqlSessionImpl对象中提供selectList()方法,【当然,实际mybatis框架中还有selectOne,insert等方法】这些方法内也分两步

​ 1、用SqlSessionFactory读取数据库链接信息创建Connection对象

​ 2、直接得到sql语句,使用JDBC的Connection对象进行相应的CRUD操作

第五步:

​ 封装结果集:无论使用分支一生成代理对象,还是直接用分支二提供CRUD方法,我们都需要对返回的数据库结果集进行封装,变成Java对象返回给调用者。所以我们还必须要知道调用者所需要的返回类型

7、OGNL表达式

Object Graphhic Navigation Language

对象 图 导航 语言

他是通过对象的取值方法来获取数据。在写法上把get省略了。

比如:获取用户的名称

类中的写法:user.getUserName();
OGNL表达式写法:user.username

mybatis中为什么能直接写username,而不用user.呢?

因为在paramentType中已经提供了属性所属的类,所以此时不需要写对象名

8、mybatis中的连接池以及事务控制

1、连接池

​ 我们在实际开发中都会使用连接池

​ 因为他可以减少我们获取连接所消耗的时间。

​ 连接池就是用于存储的一个容器

​ 容器其实就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一连接

​ 该集合还必须实现队列的特性:先进先出

2、mybatis中的连接池

​ mybatis中的连接池提供了3种方式配置:

​ 配置的位置:

​ 主配置文件:

​ 主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式

​ type属性的取值:

​ POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现

​ UNPOOLED采用传统的获取连接的方式,虽然也实现了javax.sql.DataSource接口,但是并没有使用池的思想

​ JNDI 采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的

​ 注意:如果不是web或者maven的war工程,是不能使用的

​ 我们所使用的是tomcat服务器,采用连接池就是dbcp连接池。

3、mybatis的事务

​ 什么是事务?

​ 事务的四大特性ACID

​ 不考虑隔离性会产生的3个问题

​ 解决办法:四种隔离级别

​ 它是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚

4、mybatis中的多表查询

​ 表之间的关系有几种:

​ 一对多

​ 多对一

​ 一对一

​ 多对多

举例:

​ 用户和订单就是一对多

​ 订单和用户就是多对一

​ 一个用户可以下多个订单

​ 多个订单属于同一个用户

​ 任何身份证号就是一对一

​ 一个人只能有一个身份证号

​ 一个身份证号只能属于一个人

​ 学生和老师之间就是多对多

​ 一个学生可以被多个老师教

​ 一个老师可以教多个学生

特例:

​ 如果拿出每一个订单,他都只能属于一个用户。

​ 所以mybatis就把多对一看成了一对一

mybatis中的多表查询

​ 事例:用户和高糊

​ 一个用户可以有多个账户

​ 一个账户只能属于一个用户(多个账户也可以属于一个用户)

步骤:

​ 1、简历两张表:用户表、账户表

​ 让在用户表和账户表之间具备一对多的关系:需要使用外键在账户中添加

​ 2、简历两个实体类:用户实体类和账户实体类

​ 让用户和账户的实体类能体现出来一对多的关系

​ 3、简历两个配置文件

​ 用户的配置文件

​ 账户的配置文件

​ 4、实现配置

​ 当我们查询用户时,可以同时得到用户下面所包含的账户信息

​ 当我们查询账户时,可以同时得到账户的所属用户信息

事例:用户和角色

​ 一个用户有多个角色

​ 一个角色赋予多个用户

步骤:

​ 1、简历两张表:用户表、角色表

​ 让在用户表和角色表之间具备多对多的关系:需要使用中间表,中间表中包含各自的主键

​ ,在中间表中是外键

​ 2、简历两个实体类:用户实体类和角色实体类

​ 让用户和角色的实体类能体现出来多对多的关系

​ 各自包含对方一个集合引用

​ 3、简历两个配置文件

​ 用户的配置文件

​ 角色的配置文件

​ 4、实现配置

​ 当我们查询用户时,可以同时得到用户下面所包含的角色信息

​ 当我们查询角色时,可以同时得到角色的所赋予用户信息

补充:

*1、JNDI

Java Naming and Directory Interface: java命名和目录接口是SUN公司提供的一种标准的Java命名系统接口

9、mybatis中的延迟加载

问题:

​ 在一对多中,当我们有一个用户有一百个账户

​ 在查询用户的时候,要不要把关联的账户查出来?

​ 在查询账户的时候,要不要把关联的用户查出来?

​ 在查询用户时,用户下的账户信息应该是,什么时候使用,什么时候查询的?

​ 在查询账户是,账户的所属信息应该是随着账户查询时一起查询出来。

什么是延迟加载

​ 在真正是用数据时才发起查询,不用的时候不查询。按需查询(懒查询)

什么是立即加载

​ 不管用不用,只要一调用,马上发起查询。

对应的四中表关系中:一对多,多对一,一对一,多对多

​ 一对多,多对多:通常情况下我们都是采用延迟加载。

​ 多对一,一对一:通常情况下我们都是采用立即加载。

<!--配置参数-->
<settings>
    <!--开启mybatis支持延迟加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

10、mybatis中的缓存

什么是缓存

​ 存在于内存的临时数据

为什么使用缓存

​ 减少和数据库的交互次数,提高执行效率

什么样的数据能使用缓存,什么样的数据不能使用缓存

​ 适用于缓存:

​ 经常查询并且不改变的

​ 数据的正确与否对最终结果影响不大的

​ 不适用于缓存

​ 经常改变的数据

​ 数据的正确与否对最终结果影响很大的

​ 例如:商品的库存,银行的汇率,股市的牌价

MyBatis中的一级缓存和二级缓存

​ 一级缓存:它指的是MyBatis中SqlSession对象的缓存

​ 当我们执行查询之后,查询结果会同时存入到SqlSession为我们提供的一块区域中,

​ 该区域的结构有一个Map。当我们再次查询同样的数据,mybatis会先去sqlsession中查询是否有, 有的话直接拿出来。

​ 当SqlSession对象消失时,mybatis的一级缓存也就消失了。

​ 二级缓存:它指的是MyBatis中SqlSesscionFactory对象的缓存。由同一个SqlSessionFactory对象创建的 SqlSesssion共享其缓存。

​ 二级缓存的使用步骤:

​ 第一步:让mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)

​ 第二步:让当前映射文件支持二级缓存(在IUserDAO.xml中配置)

​ 第三部:让当前操作支持二级缓存(在select标签中配置)

​ 二级缓存中存放的是数据,而不是对象

{“id”, "username":"老王", "address":"北京"}

11、mybatis的注解开发

@Insert:实现新增

@Update:实现更新

@Delete:实现删除

@Select:实现查询

@Result:实现结果集封装

@Results:可以与@Result一起使用,封装多个结果集

@ResultMap:实现引用@Results定义的封装

@One:实现一对一结果集封装

@Many:实现一对多结果集封装

@SelectProvider: 实现动态SQL映射

@CacheNamespace:实现注解二级缓存的使用

环境搭建

pom.xml导入的依赖

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13</version>
        <scope>test</scope>
    </dependency>
</dependencies>

SqlMapConfig.xml

<?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="jdbcConfig.properties"></properties>
    <!--配置别名-->
    <typeAliases>
        <package name="com.xin.domain"/>
    </typeAliases>
    <!--配置环境-->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入带有注解的dao接口所在位置-->
    <mappers>
        <package name="com.xin.dao"/>
    </mappers>
</configuration>

log4j.properties

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

单表CRUD操作(代理DAO方式)

多表查询

缓存的配置

SqlMapConfig.xml

<!-- 配置二级缓存 --> 
<settings> 
    <!-- 开启二级缓存的支持 -->
    <setting name="cacheEnabled" value="true"/> 
</settings>

在持久层接口使用注解配置二级缓存

/**
  *@author xin
  */
@CacheNamespace(blocking=true)//mybatis 基于注解方式实现配置二级缓存
public interface IUserDao {}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值