全局配置文件
全局配置文件结构
properties属性
-
可在外部配置(db.properties),且可动态替换,亦可在子元素property中配置
- 内部配置:
- 外部配置
settings 设置
-
改变mybatis的运行时行为
<settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <setting name="defaultFetchSize" value="100"/> <setting name="safeRowBoundsEnabled" value="false"/> <setting name="mapUnderscoreToCamelCase" value="false"/> <!--配置本地缓存即基于sqlSession的一级缓存--> <!-- 有SESSION和STATEMENT两个可选项--> <!--SESSION 缓存会话执行的所有查询 --> <!--STATEMENT对相同的sqlSession的不同调用不会共享数据 --> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </settings>
typeAliases 别名处理
typeHandlers 类型处理器
数据库字段类型转化为pojo中的java类型,还是反之转换,都会用类型处理器进行转换
<typeHandlers>
<typeHandler hander="..."></typeHandler>
</typeHandlers>
plugins 插件机制
environments
<environments default="mysql_first">
<!-- 连接环境信息,取一个任意唯一的名字 -->
<environment id="mysql_first">
<!-- mybatis使用jdbc事务管理方式 -->
<transactionManager type="jdbc" />
<!-- mybatis使用连接池方式来获取连接 -->
<dataSource type="pooled">
<!-- 配置与数据库交互的4个必要属性 -->
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
解释:
- 实际开发中我们使用 Spring 管理数据源,并进行事务控制的配置来覆盖上述配置
mapper 映射器
<mappers>
<mapper resource="StudentMapper.xml"/>
<mapper resource="CardMapper.xml"/>
<mapper resource="GradeMapper.xml"/>
</mappers>
- resource是引入类路径下的映射文件,也就是resource目录下
映射文件
文件标签元素
CRUD
其他博文有介绍
主键生成方式和获取主键值
1.主键生成策略
- mysql支持主键自增
- Oracle不支持
- 在建库的时候就设置主键自增?
mysql也可以使用UUID
<!-- mysql的uuid生成主键 -->
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="BEFORE" resultType="string">
select uuid()
</selectKey>
INSERT INTO USER(id,username,birthday,sex,address) VALUES(#{id},#{username},#{birthday},#{sex},#{address})
</insert>
-
若数据库不支持主键自动生成,例如Oracle,可以通过子元素
selectKey
设置id<!-- oracle 在执行insert之前执行select 序列.nextval() from dual取出序列最大值,将值设置到user对象 的id属性 --> <insert id="insertUser" parameterType="cn.itcast.mybatis.po.User"> <selectKey keyProperty="id" order="BEFORE" resultType="int"> select 序列.nextval() from dual </selectKey> INSERT INTO USER(id,username,birthday,sex,address) VALUES( 序列.nextval(),#{username},#{birthday},#{sex},#{address}) </insert>
2.主键返回
方式一
如果我们一般插入数据的话,如果我们想要知道刚刚插入的数据的主键是多少,我们可以通过以下的方式来获取
解决思路:
- 通过LAST_INSERT_ID()获取刚插入记录的自增主键值,在insert语句执行后,执行select LAST_INSERT_ID()就可以获取自增主键。
- 以下方式必须在建数据库的时候通过auto_increment,设置主键自增,然后通过以下方式获得插入后的主键值。
mysql:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User">
<selectKey keyProperty="id" order="AFTER" resultType="int">
select LAST_INSERT_ID()
</selectKey>
INSERT INTO USER(username,birthday,sex,address) VALUES(#{username},#{birthday},#{sex},#{address})
</insert>
// 直接用原来的对象就能获取到主键
SqlSession sqlSession= MybatisUtil.getSqlSession();
GradeMapper gradeMapper= sqlSession.getMapper(Mapper.GradeMapper.class);
Grade grade =new Grade();
grade.setName("陈ll伟班");
gradeMapper.insertGrade(grade);
System.out.println(grade.getId());
sqlSession.commit();
注意一定要手动提交事务不然数据库中看不到数据
方式二
<!--若数据库支持主键自增可以设置useGeneratedKeys="true" ,然后把keyProperty设置到目标属性上。-->
<insert id="insertGrade" parameterType="Domin.Grade" useGeneratedKeys="true" keyProperty="id">
insert into Grade(g_name) values (#{name})
</insert>
占位符
在Mybatis中,有两种占位符
#{}
解析传递进来的参数数据${}
对传递进来的参数原样拼接在SQL中
Mybatis注解开发代替映射文件
缓存机制
一级缓存
又称本地缓存local cache ,属于sqlSession级别
第一次发出一个查询sql,sql查询结果写入sqlsession的一级缓存中,缓存使用的数据结构是一个map<key,value>
- key:hashcode+sql+sql输入参数+输出参数(sql的唯一标识)
- value:用户信息
同一个sqlsession再次发出相同的sql,就从缓存中取走数据。如果两次中间出现commit操作(修改、添加、删除),本sqlsession中的一级缓存区域全部清空,下次再去缓存中查询不到所以要从数据库查询,从数据库查询到再写入缓存
Mybatis一级缓存值得注意的地方:
- Mybatis默认就是支持一级缓存的,并不需要我们配置.
- mybatis和spring整合后进行mapper代理开发,不支持一级缓存,mybatis和spring整合,spring按照mapper的模板去生成mapper代理对象,模板中在最后统一关闭sqlsession。
一级缓存失效的几种情况
二级缓存
二级缓存的范围是mapper级别(mapper同一个namespace),mapper以命名空间为单位创建缓存数据结构,结构是map<key、value>
查询结果映射的pojo序列化
mybatis二级缓存需要将查询结果映射的pojo实现 java.io.serializable接口,如果不实现则抛出异常:
org.apache.ibatis.cache.CacheException: Error serializing object. Cause: java.io.NotSerializableException: cn.itcast.mybatis.po.User
二级缓存可以将内存的数据写到磁盘,存在对象的序列化和反序列化,所以要实现java.io.serializable接口。
如果结果映射的pojo中还包括了pojo,都要实现java.io.serializable接口。
禁用二级缓存
对于变化频率较高的sql,需要禁用二级缓存:
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
缓存相关属性设置
有的同学到这里可能会有一个疑问:为什么缓存我们都是在查询语句中配置??而使用增删改的时候,缓存默认就会被清空【刷新了】???
缓存其实就是为我们的查询服务的,对于增删改而言,如果我们的缓存保存了增删改后的数据,那么再次读取时就会读到脏数据了!所以增删改默认flushCache=true ,每次操作完,刷新缓存。
二级缓存相关属性
eviction=“FIFO”:缓存回收策略:
LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认的是 LRU。
flushInterval:刷新间隔,单位毫秒 默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新
size:引用数目,正整数 代表缓存最多可以存储多少个对象,太大容易导致内存溢出
readOnly:只读,true/false
true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被 修改。这提供了很重要的性能优势。
false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全, 因此默认是 false。
二级缓存使用步骤
-
全局配置文件中开启二级缓存
<setting name="cacheEnabled" value="true"/>
-
二级缓存的范围是mapper级别的,因此我们的Mapper如果要使用二级缓存,还需要在对应的映射文件中配置…
<cache/>
-
POJO 需要实现 Serializable 接口
Mybatis 逆向工程
MyBatis Generator: 简称 MBG,是一个专门为 MyBatis 框架使用者定制的代码生成器,
可以快速的根据表生成对应的映射文件,接口,以及 bean 类。支持基本的增删改查,
以及 QBC 风格的条件查询。但是表连接、存储过程等这些复杂 sql 的定义需要我们手
工编写 。
官方文档地址
http://www.mybatis.org/generator/
官方工程地址
https://github.com/mybatis/generator/releases
整合第三方缓存
尚硅谷pdf
3Y:
https://segmentfault.com/a/1190000013680313
PageHelper分页插件
使用步骤
1.导入jar包或者依赖
导入相关包 pagehelper和 jsqlparser
2.全局配置文件中配置分页插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"> </plugin>
</plugins>
3.使用PageHelper的方法
Page
Page<Object> page = PageHelper.startPage(9,1)
PageInfo
在查询完数据后,使用 PageInfo 对象封装查询结果,可以获取更详细的分页信息以及
可以完成分页逻辑
2.全局配置文件中配置分页插件
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"> </plugin>
</plugins>
3.使用PageHelper的方法
Page
Page<Object> page = PageHelper.startPage(9,1)
[外链图片转存中…(img-GpQiTaJR-1607520318782)]
PageInfo
在查询完数据后,使用 PageInfo 对象封装查询结果,可以获取更详细的分页信息以及
可以完成分页逻辑
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1Syj5aiW-1607520318783)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201112171839559.png)]