配合此博客 码云仓库地址:https://gitee.com/maoniya/maoni_-mybatis-demo.git
MyBatis官网地址:https://mybatis.org/mybatis-3/zh/configuration.html
maven项目中Mybatis依赖的地址:https://mvnrepository.com/artifact/org.mybatis/mybatis/3.5.4
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.4</version>
</dependency>
什么是mybatis?
-
代替jdbc完成对数据库的操作
-
简化操作流程,将重复的流程进行封装从而实现对数据库的存储过程及高级映射
-
本质:通过简单的xml或注解来配置和映射Java对象到数据库中
核心流程
核⼼流程: https://mybatis.org/mybatis-3/zh/getting-started.html
-
每个基于 MyBatis 的应⽤都是以⼀个 SqlSessionFactory 的实例为核⼼
-
SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得
-
SqlSessionFactoryBuilder 可以从 XML 配置⽂件或⼀个预先配置的 Confifiguration 实例来构
建出 SqlSessionFactory 实例
- ⼯⼚设计模式⾥⾯ 需要获取SqlSession ,⾥⾯提供了在数据库执⾏ SQL 命令所需的所有⽅
法
流程图:
mybatis-config.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>
<!-- environments环境可以配置多个如开发环境,线上环境-->
<environments default="development">
<environment id="development">
<!-- transactionManager 事务管理-->
<transactionManager type="JDBC"/>
<!-- 连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://127.0.0.1:3306/maoni_test2?useUnicode=true&characterEncoding=utf-8&useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<mappers>
<!-- 一张表对应一个mapper文件-->
<mapper resource="mapper/VideoMapper.xml"/>
</mappers>
</configuration>
配置VideoMapper.xml
<?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">
<!--
namespace:名称空间,保持全局唯一,最好是和dao层的java接口一致,可以自动映射接口里的方法
映射sql语句到对应的方法和参数,返回类型
mybatis 使用接口动态代理,所以namespace需要全路径
-->
<mapper namespace="net.maoni.mavenDemo2.dao.VideoMapper">
<!--
statement:sql
id:mapper接口下的方法名
resultType:sql查询的结果集,返回接受的类型
-->
<select id="selectById" resultType="net.maoni.mavenDemo2.domain.Video">
select * from video where id = #{video_id}
</select>
</mapper>
获取参数的值
- 注意 :取java对象的某个值,属性名⼤⼩写要⼀致
#{value} : 推荐使⽤, 是java的名称
${value} : 不推荐使⽤,存在sql注⼊⻛险
什么是sql注入风险?
编写代码 获取 SqlSession,以xml⽅式读取数据库
public class SqlSessionDemo {
public static void main(String[] args) throws IOException {
String resouce ="config/mybatis-config.xml";
//读取配置文件,构建io流
InputStream inputStream = Resources.getResourceAsStream(resouce);
//构建sqlsessionfactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Session
try(SqlSession sqlSession=sqlSessionFactory.openSession()){
VideoMapper videoMapper =sqlSession.getMapper(VideoMapper.class);
Video video = videoMapper.selectById(44);
// System.out.println(video.toString());
List<Video> list = videoMapper.selectList();
for(Video i:list){
System.out.println(i.toString());
}
}
}
}
俩种去读方式 一种是通过xml,一种是通过注解的方式读取
通过注解读取(如果sql简单,没有过多的表关联,则⽤注解相对简单)
public interface VideoMapper {
// 根据视频id查找视频对象
Video selectById(@Param("video_id") int videoId);
//查询全部视频列表
@Select("select * from video")
List<Video> selectList();
}
mybatis的使用流程
-
创建mybatis-confifig.xml 全局的配置⽂件
-
创建XXXMapper.xml配置⽂件
-
创建SqlSessionFactory
-
⽤SqlSessionFactory创建SqlSession对象
-
⽤SqlSession执⾏增删改查CRUD
代码如上图:编写代码 获取 SqlSession,以xml⽅式读取数据库
Mybatis实战参数别名使⽤之查询视频列表
VideoMapper.xml层
<select id="selectPyPointAndTitleLike" resultType="net.maoni.mavenDemo2.domain.Video">
select * from video where point=#{point} and title like concat('%',#{title},'%')
</select>
模糊查询用 concat(),如上图所示
Mapper层
/**
* 根据评分和标题模糊查询
* @param point
* @param title
* @return
*/
List<Video> selectPyPointAndTitleLike(@Param("point") Double point,@Param("title")String title);
实现层
public static void main(String[] args) throws IOException {
String resouce ="config/mybatis-config.xml";
//读取配置文件,构建io流
InputStream inputStream = Resources.getResourceAsStream(resouce);
//构建sqlsessionfactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Session
try(SqlSession sqlSession=sqlSessionFactory.openSession()){
VideoMapper videoMapper =sqlSession.getMapper(VideoMapper.class);
/多参数模糊查询
List<Video> video2 = videoMapper.selectPyPointAndTitleLike(8.7,"HTML");
for(Video i:video2){
System.out.println(i.toString());
}
}
}
}
Mybatis插入语法新增和如何获取自增主键
新增的语法
<insert id="add" parameterType="net.maoni.mavenDemo2.domain.Video">
INSERT INTO `maoni_test2`.`video`(`title`, `summary`, `cover_img`, `price`, `create_time`, `point`)
VALUES
(#{title,jdbcType=VARCHAR}, #{summary,jdbcType=VARCHAR},#{coverImg,jdbcType=VARCHAR}, #{price,jdbcType=INTEGER},
#{createTime,jdbcType=TIMESTAMP}, #{point,jdbcType=DOUBLE});
</insert>
注:{coverImg,jdbcType=VARCHAR}和 #{createTime,jdbcType=TIMESTAMP},因为在配置mybatis-config.xml时加了
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
所以变量名需和domain或者pojo中的保持一致.在Server层的实现类中实现add方法.
//新增一条记录
Video video03=new Video();
video03.setTitle("常熟第一人民医院");
video03.setCoverImg("http://www.baidu.com");
video03.setPoint(9.4);
video03.setCreateTime(new Date());
video03.setPrice(9900);
video03.setSummary("炸u你");
videoMapper.add(video03);
System.out.println("插入成功");
获取自增主键
mapper.xml里:
<insert id="add" parameterType="net.maoni.mavenDemo2.domain.Video"useGeneratedKeys="true" keyProperty="id" keyColumn="id">
INSERT INTO `maoni_test2`.`video`(`title`, `summary`, `cover_img`, `price`, `create_time`, `point`)
VALUES (#{title,jdbcType=VARCHAR}, #{summary,jdbcType=VARCHAR},#{coverImg,jdbcType=VARCHAR}, #{price,jdbcType=INTEGER},
#{createTime,jdbcType=TIMESTAMP}, #{point,jdbcType=DOUBLE});
</insert>
注:如上图插入显示, 在 i n s e r t 标 签 最 后 面 加 入 \textcolor{red}{在insert标签最后面加入} 在insert标签最后面加入 useGeneratedKeys=“true” keyProperty=“id” keyColumn=“id”,在表video中自增主键为id,将其自主映射到java封装的video类里
执行实现类里的方法:
//新增一条记录
Video video03=new Video();
video03.setTitle("常熟第一人民医院");
video03.setCoverImg("http://www.baidu.com");
video03.setPoint(9.4);
video03.setCreateTime(new Date());
video03.setPrice(9900);
video03.setSummary("炸u你");
int rows = videoMapper.add(video03);
System.out.println("插入成功:"+rows);
System.out.println(video03.toString());
结果显示:
如上图:id=51 ,将其主键映射出来
Mybatis实现foreach批量插入语法
语法及标签介绍
-
批量插入多条数据
-
foreach:用于循环拼接的内置标签,常用于批量的新增\in查询,如下是foreach标签内的属性
-
collection:必填,值为要迭代循环的集合类型,情况有多种
- 入参为list类型的时候,collection属性的值为list
- 入参为map类型的时候,collection属性的值为map的key值
-
item:每⼀个元素进⾏迭代时的别名
-
index:索引的属性名,在集合数组情况下值为当前索引值,当迭代对象是map时,这个值是
map的key(没有用到)
-
open:整个循环内容的开头字符串(没有用到)
-
close:整个循环内容的结尾字符串(没有用到)
-
separator: 每次循环的分隔符
-
例子:
在mapper.xml里
<!-- 批量插入数据-->
<insert id="addBatch" parameterType="net.maoni.mavenDemo2.domain.Video">
INSERT INTO `maoni_test2`.`video`(`title`, `summary`, `cover_img`, `price`, `create_time`, `point`)
VALUES <foreach collection="list" item="video" index="index" separator=","> (#{video.title,jdbcType=VARCHAR},
#{video.summary,jdbcType=VARCHAR},#{video.coverImg,jdbcType=VARCHAR}, #{video.price,jdbcType=INTEGER},
#{video.createTime,jdbcType=TIMESTAMP}, #{video.point,jdbcType=DOUBLE})</foreach>
</insert>
注:
- 在批量插入数据时,item的别名一定要有,如:#{video.title,jdbcType=VARCHAR}
- 在插入语句的最后去掉 “;”
在实现类里
/*** 批量插入数据*/
Video video04=new Video();
video04.setTitle("九龙第一人民医院");
video04.setCoverImg("http://www.谷歌.com");
video04.setPoint(8.3);
video04.setCreateTime(new Date());
video04.setPrice(9922);
video04.setSummary("fuck you");
Video video05=new Video();video05.setTitle("广慈第一人民医院");
video05.setCoverImg("http://www.广慈.com");
video05.setPoint(8.7);
video05.setCreateTime(new Date());
video05.setPrice(9933);
video05.setSummary("i love you");
//创建list,将video对象放入list表中开始批量插入'
List<Video> listBatch =new ArrayList<>();
listBatch.add(video04);
listBatch.add(video05);
int rows02 = videoMapper.addBatch(listBatch);
System.out.println(rows02);
System.out.println(listBatch.toString());
结果:
Mybatis实现更新和删除
更新语法
在mapper.xml里
<!-- 更新-->
<update id="updateVideo" parameterType="net.maoni.mavenDemo2.domain.Video">
update video set title=#{title,jdbcType=VARCHAR},summary=#{summary,jdbcType=VARCHAR},cover_img=#{coverImg,jdbcType=VARCHAR},
price=#{price,jdbcType=INTEGER},create_time=#{createTime,jdbcType=TIMESTAMP},point=#{point,jdbcType=DOUBLE} where id =#{id}
</update>
<!-- 删除-->
<delete id="deleteVideo" parameterType="net.maoni.mavenDemo2.domain.Video">
delete from video where id=#{id}
</delete>
实现层里
/*** 更新*/
Video video06 =new Video();
video06.setTitle("上海妇幼医院");
video06.setCoverImg("whwhd.shanghai.com");
video06.setPoint(9.9);
video06.setCreateTime(new Date());
video06.setPrice(963);
video06.setId(165);
int rows03 = videoMapper.updateVideo(video06);
System.out.println(rows03);
/*** 删除*/
Video video07 =new Video();
video07.setId(165);
int rows07 = videoMapper.deleteVideo(video07);
System.out.println(rows07);
动态字段更新(if test标签使用)
-
可以选择性的更新非空字段
-
if test标签介绍
- if 标签可以通过判断传⼊的值来确定查询条件,test 指定⼀个OGNL表达式
- 常⻅写法
//当前字段符合条件才更新这个字段的值 <if test='title != null and id == 87 '> title = #{title}, </if><if test="title !=null"> title = #{title},
当前字段不为空且id值为87的才会更新title字段
例子:
在mapper.xml里
<!-- 动态字段更新-->
<update id="updateVideoSelective" parameterType="net.maoni.mavenDemo2.domain.Video">
update video
-- trim标记更新字段的结尾是以","结尾
-- test 指定⼀个OGNL表达式,test中的属性值为java封装类中的变量名
<trim prefix="set" suffixOverrides=",">
<if test="title !=null">title=#{title,jdbcType=VARCHAR},</if>
<if test="summary !=null">summary=#{summary,jdbcType=VARCHAR},</if>
<if test="coverImg !=null">cover_img=#{coverImg,jdbcType=VARCHAR},</if>
<if test="price !=0">price=#{price,jdbcType=INTEGER},</if>
<if test="createTime !=null">create_time=#{createTime,jdbcType=TIMESTAMP},</if>
<if test="point !=null">point=#{point,jdbcType=DOUBLE},</if>
</trim>
where id =#{id}
</update>
实现类里:
/*** 动态字段更新*/
Video video08 =new Video();
video08.setTitle("上海妇幼医院");
video08.setCoverImg("whwhd.shanghai.com");
video08.setPoint(9.9);
video08.setCreateTime(new Date());
video08.setPrice(963);
video08.setId(46);
int rows08=videoMapper.updateVideoSelective(video08);
System.out.println(rows08);
结果:选择性地更新了数据库中字段对应的数据.
Mybatis实现删除语法和转义字符使用
delete删除语法
- 需求:删除时间大于 and 金额小于
<delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map">
delete from video where create_time <![CDATA[ >= ]]> #{createTime} and price <! [CDATA[ <= ]]> #{price}
</delete>
为什么要转义字符
-
由于MyBatis的sql写在XML⾥⾯, 有些sql的语法符号和xml⾥⾯的冲突
如:大于和小于 <> 与xml格式里的<> 冲突
⼤于等于 <![CDATA[ >= ]]>⼩于等于 <![CDATA[ <= ]]>
在mapper.xml里:
<!--
<![CDATA[ >= ]]> 转义字符 : > 大于
<![CDATA[ <= ]]> 转义字符 : < 小于
-->
<delete id="deleteByCreateTimeAndPrice" parameterType="java.util.Map">
delete from video where create_time <![CDATA[ >= ]]> #{createTime} and price <![CDATA[ <= ]]> #{price}
</delete>
实现类:
/*** 根据创建时间和价格删除
* 时间>createTime
* 价格<price
* 都进行删除
*/
Map<String,Object> map =new HashMap<>();
map.put("createTime","2021-01-11 00:00:00");
map.put("price",10000);
int rows09 = videoMapper.deleteByCreateTimeAndPrice(map);
System.out.println(rows09);
MyBatis3.X配置⽂件mybatis-confifig.xml常⻅属性
mybatis-config.xml常⻅配置
注:核⼼配置⽂件(dom节点顺序要求,不然报错)(记住常用的)
官方文档:https://mybatis.org/mybatis-3/zh/confifiguration.html#
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象⼯⼚)
plugins(插件,少⽤)
environments(环境配置,不配多环境,基本在Spring⾥⾯配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库⼚商标识)
mappers(映射器)
Mybatis的查询类别名typeAlias的使⽤
给类取别名
在mybatis-config.xml里配置
<!-- 给类取个别名,这样在mapper.xml不用输入类的全限定名-->
<typeAliases>
<typeAlias type="net.xdclass.online_class.domain.Video" alias="Video"/>
</typeAliases>
在mapper.xml里
<select id="selectById" resultType="Video">
select * from video where id = #{videoId}
</select>
给包区别名
如果包里存在很多类不需要一个个配置,扫描包即可
在mybatis-config.xml里配置
<typeAliases>
<!-- <typeAlias type="net.maoni.mavenDemo2.domain.Video" alias="Video"/>-->
<package name="net.maoni.mavenDemo2.domain"/>
</typeAliases>
在mapper.xml里
<select id="selectById" resultType="Video">
select * from video where id = #{videoId}
</select>
注:本身就内置很多别名,⽐如Integer、String、List、Map 等
如:
<delete id="deleteByCreateTimeAndPrice" parameterType="Map">
delete from video where create_time <![CDATA[ >= ]]> #{createTime} and price <![CDATA[ <= ]]> #{price}
</delete>
Mybatis里sql片段的使用(高性能sql)
在mapper.xml里标签下的最上方加标签
如:
<sql id="base_video_field">
id,title,summary,cover_img
</sql>
在mapper.xml里标签下的查询方法里
<select id="selectById" resultType="Video">
select <include refid="base_video_field"/> from video where id = #{videoId}
</select>
接下来就是实现类里的事情了
Mybatis下的复杂sql查询
resultMap讲解及简单使用
Mybatis的SQL语句返回结果有两种
- resultType
- 查询出的字段在相应的pojo中必须有和它相同的字段对应,或者基本数据类型
- 适合简单查询
- resultMap
- 需要⾃定义字段,或者多表查询,⼀对多等关系,⽐resultType更强⼤
- 适合复杂查询
resultMap简单使用
在mapper.xml里先配置resultMap的结果集
<resultMap id="VideoResultMap" type="Video">
<!-- id 指定查询列的唯⼀标示 column 数据库字段的名称 property pojo类的名称-->
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="video_title" property="title" jdbcType="VARCHAR"/>
<result column="summary" property="summary" jdbcType="VARCHAR"/>
<result column="cover_img" property="coverImg" jdbcType="VARCHAR"/>
</resultMap>
在配置的下面写上查询方法
<select id="selectBaseFileByIdWithResultMap" resultMap="VideoResultMap">
select id,title as video_title,summary,cover_img from video where id =#{video_id}
</select>
注:
select中的resultMap值对应resultMap标签里的id值,
select标签里的id对应接口里的方法名
ResultMap复杂对象⼀对⼀查询结果映射之association
简述:A表与B表有关联,且B表中有且只有一条数据与A表有关联,在进行B关联A查询时,将A中的数据查询出来的同时也将B表中的数据查询出来
首先在mapper.xml里配置resultMap,然后在resultMap的标签里association映射到需要查询的表中,具体步骤如下
<resultMap id="VideoOrderResultMap" type="VideoOrder">
<id column="id" property="id"/>
<result column="user_id" property="userId" />
<result column="out_trade_no" property="outTradeNo" />
<result column="create_time" property="createTime" />
<result column="state" property="state"/>
<result column="total_fee" property="totalFee"/>
<result column="video_id" property="videoId"/>
<result column="video_title" property="videoTitle"/>
<result column="video_img" property="videoImg"/>
<!-- 关联的是哪个对象 ,对象的类型是什么 -->
<!-- association 配置属性一对一 property 对应videoOrder里面的user属性名 javatype 对应user属性的类型-->
<association property="user" javaType="User">
<id column="user_id" property="id" />
<result column="name" property="name" />
<result column="head_img" property="headImg" />
<result column="create_time" property="createTime" />
<result column="phone" property="phone" />
</association>
</resultMap>
查询的语句
<select id="queryVideoOrderList" resultMap="VideoOrderResultMap">
select
o.id id,
o.user_id ,
o.out_trade_no,
o.create_time,
o.state,
o.total_fee,
o.video_id,
o.video_title,
o.video_img,
u.name,
u.head_img,
u.create_time,
u.phone
from video_order o left join user u on o.user_id =u.id;
</select>
完善接口和实现类
List<VideoOrder> queryVideoOrderList();
List<VideoOrder> videoOrderList =videoOrderMapper.queryVideoOrderList();System.out.println(videoOrderList.toString());
调试debug:
结果集显示查询结果6个,每个结果集里都会包含一个user对象及其查询的数据
ResultMap复杂对象⼀对多查询结果映射之collection
简述:A表与B表有关联,且A表中的某一个字段关联着B表中的多条数据,查询A表的数据时将与其B表中的数据全部查询出
首先在mapper.xml里配置resultMap,然后在resultMap的标签里collection映射到需要查询的表中,具体步骤如下
<resultMap id="UserOrderResultMap" type="User">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="head_img" property="headImg" />
<result column="create_time" property="createTime" />
<result column="phone" property="phone" />
<!-- 如上图所示一样关联的是哪个对象,对象的类型是什么-->
<!-- collection 配置属性一对多 property pojo类中类属性的名称 ofType集合里面的pojo对象 -->
<collection property="videoOrderList" ofType="VideoOrder">
<!-- 配置主键,管理order的唯一标识-->
<id column="order_id" property="id"/>
<result column="user_id" property="userId" />
<result column="out_trade_no" property="outTradeNo" />
<result column="create_time" property="createTime" />
<result column="state" property="state"/>
<result column="total_fee" property="totalFee"/>
<result column="video_id" property="videoId"/>
<result column="video_title" property="videoTitle"/>
<result column="video_img" property="videoImg"/>
</collection>
</resultMap>
查询的语句
<select id="queryUserOrder" resultMap="UserOrderResultMap">
select
u.id,
u.name,
u.head_img,
u.create_time,
u.phone,
o.id order_id,
o.out_trade_no,
o.create_time,
o.state,
o.total_fee,
o.video_id,
o.video_title,
o.video_img
from user u left join video_order o on u.id =o.user_id
</select>
接口和实现类
/** * 查询全部用户的全部订单 */
List<User> queryUserOrder();
/** * resultMap 和 collection测试 * 查询全部用户的全部订单 */
List<User> userList=videoOrderMapper.queryUserOrder();
System.out.println(userList.toString());
查询结果
总结ResultMap的复杂对象查询
-
association 映射的是⼀个pojo类,处理⼀对⼀的关联关系。
-
collection 映射的⼀个集合列表,处理的是⼀对多的关联关系。
-
模板
<!-- column不做限制,可以为任意表的字段,⽽property须为type 定义的pojo属性--> <resultMap id="唯⼀的标识" type="映射的pojo对象"> <id column="表的主键字段,或查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" /> <result column="表的⼀个字段" jdbcType="字段类型" property="映射到pojo对象的⼀个属性"/> <association property="pojo的⼀个对象属性" javaType="pojo关联的pojo对象"> <id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的属性"/> <result column="表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/> </association> <!-- 集合中的property 需要为oftype定义的pojo对象的属性--> <collection property="pojo的集合属性名称" ofType="集合中单个的pojo对象类型"> <id column="集合中pojo对象对应在表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" /> <result column="任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属 性" /> </collection> </resultMap>
Mybatis3.x 中的多级缓存和懒加载
Mybatis3.X ⼀级缓存简述
-
什么是缓存
-
程序经常要调⽤的对象存在内存中,⽅便其使⽤时可以快速调⽤,不必去数据库或者其他持久化
设备中查询,主要就是提⾼性能
-
-
Mybatis⼀级缓存
-
简介:⼀级缓存的作⽤域是SQLSession,同⼀个SqlSession中执⾏相同的SQL查询(相同的
SQL和参数),第⼀次会去查询数据库并写在缓存中,第⼆次会直接从缓存中取
-
基于PerpetualCache 的 HashMap本地缓存
-
默认开启⼀级缓存
-
-
失效策略:当执⾏SQL时候两次查询中间发⽣了增删改的操作,即insert、update、delete等操作
commit后会清空该SQLSession缓存; ⽐如sqlsession关闭,或者清空等
Mybatis3.X ⼆级缓存怎么使用
Mybatis⼆级缓存和配置
Mybatis⼆级缓存
-
简介:Mybatis 二级端口是namespace级别的,多个SqlSession去操作同⼀个namespace下的
Mapper的sql语句,多个SqlSession可以共⽤⼆级缓存,如果两个mapper的namespace相
同,(即使是两个mapper,那么这两个mapper中执⾏sql查询到的数据也将存在相同的⼆级
缓存区域中,但是最后是每个Mapper单独的名称空间)
-
基于PerpetualCache 的 HashMap本地缓存,可⾃定义存储源,如 Ehcache/Redis等
-
默认是没有开启⼆级缓存
-
操作流程:第⼀次调⽤某个namespace下的SQL去查询信息,查询到的信息会存放该
mapper对应的⼆级缓存区域。 第⼆次调⽤同个namespace下的mapper映射⽂件中,相同
的sql去查询信息,会去对应的⼆级缓存内取结果
失效策略
-
执⾏同个namespace下的mapepr映射⽂件中增删改sql,并执⾏了commit操作,会清
空该⼆级缓存
注意:实现⼆级缓存的时候,MyBatis建议返回的POJO是可序列化的, 也就是建议实现
Serializable接⼝
缓存淘汰策略:会使⽤默认的 LRU 算法来收回(最近最少使⽤的)
如何开启某个⼆级缓存 mapper.xml里面配置
eviction:代表的是缓存回收策略,常⻅下⾯两种。
(1) LRU,最近最少使⽤的,⼀处最⻓时间不⽤的对象
(2) FIFO,先进先出,按对象进⼊缓存的顺序来移除他们
flushInterval:刷新间隔时间,单位为毫秒,这⾥配置的是100秒刷新,如果不配置
它,当SQL被执⾏的时候才会去刷新缓存。
size:引⽤数⽬,代表缓存最多可以存储多少个对象,设置过⼤会导致内存溢出
readOnly:只读,缓存数据只能读取⽽不能修改,默认值是false
在mapper.xml里,放在mapper下面
<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>
在mybatis-config.xml里配置全局总开关
<!--这个配置使全局的映射器(⼆级缓存)启⽤或禁⽤缓存,全局总开关,这⾥关闭,mapper中开启了也没⽤-->
<setting name="cacheEnabled" value="true" />
Mybatis⼆级缓存实操
配置好图上显示的俩个二级缓存配置后
String resouce ="config/mybatis-config.xml";
//读取配置文件,构建io流
InputStream inputStream = Resources.getResourceAsStream(resouce);
//构建sqlsessionfactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Session
try {
SqlSession sqlSession1 =sqlSessionFactory.openSession();
VideoMapper videoMapper1=sqlSession1.getMapper(VideoMapper.class);
Video video1=videoMapper1.selectById(44);
System.out.println(video1.toString());
sqlSession1.commit();
SqlSession sqlSession2 =sqlSessionFactory.openSession();
VideoMapper videoMapper2=sqlSession1.getMapper(VideoMapper.class);
Video video2=videoMapper2.selectById(44);
System.out.println(video2.toString());
sqlSession1.commit();
}catch (Exception e){
e.printStackTrace();
}
结果显示如下图:
结果显示,在执行时,只执行了一次sql语句,显示2个结果,说明在执行第二次sql语句时直接在namespace二级缓存空间里查询结果了
如何实现在mapper里某个查询方法不使用二级缓存的功能?
在配置好上诉的俩个配置后在mapper.xml里namespace的标签下select查询的标签里添加useCache标签useCache=“false”
<!-- statement:sql id:mapper接口下的方法名 resultType:sql查询的结果集,返回接受的类型 useCache:规定selectById查询不走二级缓存-->
<select id="selectById" resultType="Video" useCache="false">
select <include refid="base_video_field"/> from video where id = #{videoId}
</select>
执行实现类里的查询方法后结果显示如下图:
出现俩个sql语句,说明该查询方法并未执行二级缓存
⼀级缓存和⼆级缓存使⽤顺序
优先查询⼆级缓存 > 查询⼀级缓存 > 数据库
⾯试题-Mysql的Innodb和MyISAM引擎的区别
mysql常⻅的两种存储引擎的区别
MyISAM不⽀持事务,如果需要事务则改为innodb引擎 更改数据库的表⾥⾯的引擎
我这里使用的是Navicat数据库连接工具,修改表中的引擎
第一步:
第二步:
public static void main(String[] args) throws IOException {
String resouce ="config/mybatis-config.xml";
//读取配置文件,构建io流
InputStream inputStream = Resources.getResourceAsStream(resouce);
//构建sqlsessionfactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取Session
// false:为非自动提交 TRUE:自动提交
SqlSession sqlSession=sqlSessionFactory.openSession(false);
try{
VideoMapper videoMapper = sqlSession.getMapper(VideoMapper.class);
Video video1 =new Video();
video1.setTitle("微服务架构");
videoMapper.add(video1);
int i =1/0;
sqlSession.commit(); // 手动提交
}catch (Exception e){
e.printStackTrace();
sqlSession.rollback(); //事务回滚
}
}
在使用mybatis框架时会遇见的问题
- 在domain层封装数据时与数据库中的字段名出现不匹配的现象如 数据库中字段名带下划线,封装的数据都是驼峰命名,如何将俩个进行映射?
在mybatis-config.xml配置中在标签里添加,且位置必须放在里靠上的位置(原因:在mybatis配置xml里遵循一定的顺序)
<!-- 下划线自动映射驼峰字段-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
-
使用mybatis时在插入的时候,标签使用:parameterType
<insert id="add" parameterType="net.maoni.mavenDemo2.domain.Video"> ''' </insert>
-
在执行插入语句时容易发生的问题?
-
在批量插入数据时,item的别名一定要有,如:#{video.title,jdbcType=VARCHAR}
-
在插入语句的最后去掉 “;”
-
-
在执行删除or添加用到大于小于时>< ,需要用到转义字符
⼤于等于 <![CDATA[ >= ]]> ⼩于等于 <![CDATA[ <= ]]>