Mybatis
2021-10-22 11:31:16 13 举报
AI智能生成
复工后
作者其他创作
大纲/内容
几个关键类
mybatis-config.xml
XML配置文件(configuration XML)中包含了对MyBatis系统的核心设置
包含获取数据库连接实例的数据源(dateSource)和决定事务作用域和控制方式的事务管理器(TransactionManager)
SqlSessionFactoreBuilder
概念
- SqlSessionFactoryBuilder通过类名就可以看出这个类的主要作用就是创建一个SqlSessionFactor,通过输入mybatis配置文件的字节流或者字符流,生成XMLConfigBuilder,XMLConfigBuilder创建一个Configuration,Configuration这个类中包含了mybatis的配置的一切信息,mybatis进行的所有操作都需要更据Configuration中的信息来进行
作用域(Scope)和生命周期
可以重用SqlSessionFactoryBuilder来创建多个SqlsessionFactory实例,但是最好还是不要让其一直存在以保证所有的XML解析资源开放给更重要的事情
这个类可以被实例化,使用和丢弃,一旦创建了SqlSessionFactory,就不再需要它了。因此SqlSessionFactoryBuilder实例的最佳作用域是方法作用域(也就是局部方法变量)
SqlSessionFactory接口
概念
sql会话工厂,用于创建SqlSession
作用域和生命周期
SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,在没有任何理由对它进行清除或者重建
最佳作用域是应用作用域。有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式
如何创建
使用XML构建
String resource="org/mybatis/example/mybatis-config.xml"; InputStream inputStream=Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
java代码块构建
SqlSession接口
概念
SqlSession是Mybatis的一个重要接口,定义了数据库的增删改查以及事务管理的常用方法
SqlSession还提供了查找Mapper接口的有关方法
作用域和生命周期
每个线程都应该有他自己的SqlSession实例
SqlSesion的实例不是线程安全的,因此是不能被共享的,所以它的最佳作用域是请求或者方法作用域
每次收到的HTTP请求,就可以打开一个SqlSession,放回一个响应,就关闭它
如何创建
SQLSession session=sqlSessionFactory.openSession(); try{ //do work }finally{ session.close(); }
Mapper接口
概念
承载了实际的业务逻辑。其生命周期比较短,由SqlSession创建,用于将Java对象和实际的SQL语句对应起来
Mapper接口是指程序员自行定义的一个数据操纵接口,类似于通常所说的DAO接口。跟DAO不同的地方在于Mapper接口只需要程序员定义,不需要程序员区实现,MaBatis会自动为Mapper接口创建动态代理对象。Mapper接口的方法通常与Mapper配置文件中的select/insert/update/delete等XML结点存在一一对应关系
实现方式
使用XML配置文件的方式
使用注解方式
直接使用Mybatis提供的API
如何创建
配置文件
<mapper namespace="com.etc.dao.EmployeeDao">
<select id="queryIf" resultType="com.etc.bean.Employee">
select * from employee where 1=1
<if test="eName!=null">
and eName like '%${eName}%'
</if>
<if test="eSex!=null">
and eSex =#{eSex}
</if>
</select>
<select id="queryChoose" resultType="com.etc.bean.Employee">
select * from employee where 1=1
<choose>
<when test="eName!=null">
and eName like '%${eName}%'
</when>
<when test="eSex!=''">
and eSex like '%${eSex}%'
</when>
<otherwise>
order by eid desc
</otherwise>
</choose>
</select>
<select id="queryByTrim" resultType="com.etc.bean.Employee">
select * from employee
<trim prefix="where" prefixOverrides="and|or">
<if test="eName!=null">
and eName like '%${eName}%'
</if>
<if test="eSex!=''">
and eSex like '%${eSex}%'
</if>
<if test="eAddr!=null">
and eAddr like '%${eAddr}%'
</if>
</trim>
</select>
<update id="update" parameterType="com.etc.bean.Employee">
update employee
<set>
<if test="eName!=null">eName=#{eName},</if>
<if test="eSex!=null">eSex=#{eSex},</if>
<if test="eAddr!=null">eAddr=#{eAddr}</if>
</set>
where eid=#{eid}
</update>
<delete id="deleteByList">
delete from employee where eid in
<foreach collection="list" item="eid" open="(" separator="," close=")">
#{eid}
</foreach>
</delete>
<delete id="deleteByArray">
delete from employee where eid in
<foreach collection="array" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
mybatis源码的几个主要部件
SqlSession:作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能;
Executor:MyBatis执行器,是MyBatis调度的核心,负责SQl语句的生成和查询缓存的维护
StatementHandler:封装了JDBC Statement操作,负责对JDBC statement的操作。如设置参数,将Statement结果集转换成List集合
ParameterHandler:负责对用户传递的参数转换成JDBC Statement所需要的参数
ResultSetHandler:负责将JDBC返回的ResultSet结果集对象转换成List类型的集合
TypeHander:负责java数据类型和jdbc数据类型之间的映射和转换
MappedStatement:MappedStatement维护了一条<select|update|delete|insert>节点的封装
SqlSource:负责更据用户传递的parameterObject,动态地生成sql语句,将信息封装到BoundSql对象中,并返回
BoundSQL:表示动态生成的SQL语句以及相应的参数信息
Configuration:Mybatis所有的配置信息都维持在Configuration对象之中
mybatis简介
官网
http://www.mybatis.org/mybatis-3/zh/index.html
什么是Mybatis
Mybatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
Mybatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
MyBatis可以对配置和原生的Map使用简单的XML或注解,将接口和Java的POJO映射成数据库中的数据
安装
<dependency>
<groupId>org.mybatis</groupId>
<artfactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
<groupId>org.mybatis</groupId>
<artfactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
XML映射配置文件
properties
作用
引用propertis文件并读取配置信息,也可以在<propertis/>标签中定义属性
例子
创建一个资源文件jdbc.properties
#驱动 driver
driver=com.mysql.cj.jdbc.Driver
#链接地址
url=jdbc:mysql://localhost:3306/oa
#用户名
username=root
密码
password=root
driver=com.mysql.cj.jdbc.Driver
#链接地址
url=jdbc:mysql://localhost:3306/oa
#用户名
username=root
密码
password=root
mybatis-config.xml中引入
<properties resource="dbconfig.properties"></properties>
也可以在<propertis/>标签中定义属性
使用properties文件里的属性
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
配置的加载顺序
在properties元素体内指定的属性首先被读取
然后根据properties元素中的resource属性读取类路径下属性文件或者更据url属性指定的路径读取属性文件,并覆盖已读取的同名属性
最后读取作为方法参数传递的属性,并覆盖已读取的同名属性
setting
概念
MyBatis中极为重要的调整设置,他们会改变MyBatis的运行时行为
配置方式
<settings>
<!-- //二级缓存开启-->
<setting name="cacheEnabled" value="true"/>
<!-- 延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- //二级缓存开启-->
<setting name="cacheEnabled" value="true"/>
<!-- 延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
常用
cacheEnabled
该配置影响的所有映射器中配置的缓存的全局开关。默认true
lazyLoadingEnabled
延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认false
aggressiveLazyLoading
当开启时,任何方法的调用都会加载该对象的所有属性。否则每个属性会按需加载,默认FALSE
logImpl
指定MyBatis所有日志的具体实现,未指定时将自动查找
mapper
概念
用于引用定义好的映射定义,告诉mybatis去哪里找我们的sql定义配置
引用方式
直接引用xml文件
<mappers>
<mapper resource="mapper/EmployeeMapper.xml"/>
</mappers>
<mapper resource="mapper/EmployeeMapper.xml"/>
</mappers>
通过绝对路径,绝对路径前加
<mappers>
<mapper url="file///D:/workspace/UserMapper.xml"/>
</mappers>
<mapper url="file///D:/workspace/UserMapper.xml"/>
</mappers>
引用mapper接口对象的方式
<mappers>
<mapper resource="com.etc.mapper.UserMapper"/>
</mappers>
<mapper resource="com.etc.mapper.UserMapper"/>
</mappers>
配置环境(environments)
概念
配置成适应多种环境,这种机制有助于将sql映射应用于多种数据库之中
不过要记住:尽管可以配置多个环境,每个SqlSessionFactory实例只能选择其一
使用场景
为了开发设置不同的数据库配置
测试和生产环境数据库不同
有多个数据库和共享相同的模式,既对不同的数据库使用相同的SQl映射
代码
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
mybatis的缓存
概念
①MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis3 中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。
默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行
默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环 依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行
一级缓存
什么是一级缓存,为什么使用一级缓存
①每当我们使用MyBatis开启一次和数据库的会话,MyBatis会创建出一个SqlSession对象表示一次数据库会话。
②在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
③为了解决这个问题,减少资源浪费,MyBatis会在表示会话的SQLSession对象中建立一个简单的缓存,将每次查询到的结果缓存起来,当下次查询的时候,如果判断现有个完全一样的查询,会直接从缓存中将结果取出来,返回给用户,不需要再进行一次查询数据库了。
②在对数据库的一次会话中,我们有可能会反复地执行完全相同的查询语句,如果不采取一些措施的话,每一次查询都会查询一次数据库,而我们在极短的时间内做了完全相同的查询,那么它们的结果极有可能完全相同,由于查询一次数据库的代价很大,这有可能造成很大的资源浪费。
③为了解决这个问题,减少资源浪费,MyBatis会在表示会话的SQLSession对象中建立一个简单的缓存,将每次查询到的结果缓存起来,当下次查询的时候,如果判断现有个完全一样的查询,会直接从缓存中将结果取出来,返回给用户,不需要再进行一次查询数据库了。
一级缓存的生命周期
①a.MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
②b.如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
③c.如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
d.SqlSession中执行了任何一个update操作(update()、delete()、insert()),都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
②b.如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
③c.如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
d.SqlSession中执行了任何一个update操作(update()、delete()、insert()),都会清空PerpetualCache对象的数据,但是该对象可以继续使用;
一级缓存的工作流程
①对于某个查询,根据statementId,params,rowBounds来构建一个key值,根据这个key值去缓存Cache中取出对应的key值存储的缓存结果;
②判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;
③如果命中,则直接将缓存结果返回;
④如果没命中:
1)去数据库中查询数据,得到查询的结果;
2)将key和查询到的结果分别作为key,value对,存储到Cache中;
3)将查询结果返回给用户。
⑤结束
②判断从Cache中根据特定的key值取的数据数据是否为空,即是否命中;
③如果命中,则直接将缓存结果返回;
④如果没命中:
1)去数据库中查询数据,得到查询的结果;
2)将key和查询到的结果分别作为key,value对,存储到Cache中;
3)将查询结果返回给用户。
⑤结束
如何确定CacheKey
1)传入的statementId对于MyBatis而言,你要使用它,必须需要一个statementId,它代表着你将执行什么样的Sql;
2)查询时要求的结果集中的结果范围(结果的范围通过rowBounds.offset和rowBounds.limit表示);
3)这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql())
4)传递给java.sql.Statement要设置的参数值
5)综上所述,CacheKey由以下条件决定:statementId +rowBounds +传递给JDBC的SQL +传递给JDBC的参数值
2)查询时要求的结果集中的结果范围(结果的范围通过rowBounds.offset和rowBounds.limit表示);
3)这次查询所产生的最终要传递给JDBC java.sql.Preparedstatement的Sql语句字符串(boundSql.getSql())
4)传递给java.sql.Statement要设置的参数值
5)综上所述,CacheKey由以下条件决定:statementId +rowBounds +传递给JDBC的SQL +传递给JDBC的参数值
二级缓存
概念
MyBatis的二级缓存是Application级别的缓存,它可以提高对数据库查询的效率,以提高应用的性能。
支持二级缓存的条件
①1.MyBatis支持二级缓存的总开关:全局配置变量参数cacheEnabled=true
②2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效
③3.该select语句的参数useCache=true
④4.对象的类必须实现序列化接口
②2.该select语句所在的Mapper,配置了<cache> 或<cached-ref>节点,并且有效
③3.该select语句的参数useCache=true
④4.对象的类必须实现序列化接口
子主题Cache使用时的注意事项/避免使用二级缓存
(1)注意事项
①只能在【只有单表操作】的表上使用缓存,不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
②在可以保证查询远远大于insert,update,delete操作的情况下使用缓存这一点不需要多说,所有人都应该清楚。记住,这一点需要保证在1的前提下才可以!
(2)避免使用二级缓存
①可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
1)缓存是以namespace为单位的,不同namespace下的操作互不影响。
2)insert,update,delete操作会清空所在namespace下的全部缓存。
3)通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。
①只能在【只有单表操作】的表上使用缓存,不只是要保证这个表在整个系统中只有单表操作,而且和该表有关的全部操作必须全部在一个namespace下。
②在可以保证查询远远大于insert,update,delete操作的情况下使用缓存这一点不需要多说,所有人都应该清楚。记住,这一点需要保证在1的前提下才可以!
(2)避免使用二级缓存
①可能会有很多人不理解这里,二级缓存带来的好处远远比不上他所隐藏的危害。
1)缓存是以namespace为单位的,不同namespace下的操作互不影响。
2)insert,update,delete操作会清空所在namespace下的全部缓存。
3)通常使用MyBatis Generator生成的代码中,都是各个表独立的,每个表都有自己的namespace。
0 条评论
下一页