1.Mybatis的生命周期
- SqlSessioFactoryBuilder:用于创建SqlSessionFactory,一旦sqlsessionfactory被创建成功就会被回收
-
- sqlsessionfactory:用于创建sqlsession,类似于jdbc的connection对象,而每次应用程序需要访问数据库,都需要创建sqlsession,所以sqlsessionfacttory在整个mybatis生命周期中。(每个数据库对应一个sqlsessionfactory,是单例产生到的)
- sqlsession:生命周期是存在于请求数据库处理事务的过程中,是一个线程不安全的对象(再多线程的情况下,需要特别注意),存活于一个应用的请求和申请,可以执行多条sql保证事务一致性。
- mapper:是一个接口,没有实现类。它的作用是发送sql,返回结果,或修改数据库表,所以它存活于一个sqlsession内,是一个方法级别的东西。当sqlsession被销毁的时候,mapper也会被销毁。
2.什么是mybatis
- mybatis是一款优秀的持久层框架,用于将数据持久化到数据库。(将断电即失的内存数据持久化到数据库中)
- mybatis几乎避免了jdbc代码和手动设置参数以及获取结果集。
- 数据持久化:将数据在持久状态和瞬时状态转化的过程。数据持久化可以有多种:例如持久化到数据库,io文件持久化。
-
- 持久层:
- 为什么需要mybatis
- 方便
- 传统的jdbc代码太复杂。简化。框架。自动化。
3.mybatis搭建的步骤
- 配置mybatis环境
-
创建数据库以及对应的表 -
pom导入mysql,mybatis,junit文件 -
根据对应的表的字段编写pojo基本类。 -
编写mybatis-config.xml配置文件 -
编写接口(在接口中写一个方法,记得写方法的返回值类型) -
编写实现接口的mapper.xml文件:记得写namespace=“接口名”, id:接口的方法名,resultType:接口的饭返回值结果类型。然后就是sql语句 -
将mapper写入mybatis-config.xml配置文件 -
在pom.xml中加入读取.xml的文件
4.sql的增删改查实现
- 第一步要在接口中定义不同的方法来实现增删改查。
- 第二步在mapper.xml文件中创建对应的sql语句以及id=接口中方法名。
5.万能的map
-
map能够简化我们编写代码的时间,如果我们需要在数据库中进行增加数据或者其他操作,当一个对象的属性过多的时候我们创建对象比较麻烦,使用我们可以使用map来简化我们创建对象。Map在mapper.xml的对象简写就是map -
Map传递参数,直接在sql中取出key即可 -
对象传递参数,直接在sql中取出对象的属性即可 -
只有一个基本类型参数的情况下可以不写parameterType,可以直接在sql中取到。 -
mybatis中的模糊查询怎么写?
6.mybatis属性配置以及优化
- 环境配置(environments):
-
mybatis可以配置多个环境不过,每一个SqlSessionFactory实例只能选择一种环境。我们要学会配置多种环境。若要更改环境只需要修改default属性里面的值就可以了。 -
mybatis默认事务管理器就是JDBC,还有一种MANAGER因为太垃圾什么事都没做使用我们不用。默认连接池:POOLED -
属性(properties):在mybatis-config.xml文件中写properties必须写在最前面。也可以在poperties中间写属性以及值。如果有相同的属性则优先使用外部文件的属性。 -
-
mybatis在处理#{}时,会将#{}替换成为?,预编译sql,通过preparedStatement的setxxx的方法进行参数赋值。使用#{}可以有效防止sql注入 -
mybatis在处理#{}时,会直接把${}替换为参数值,存在sql注入的风险 -
#{}比
更
加
安
全
,
但
还
是
提
供
了
{}更加安全,但还是提供了
更加安全,但还是提供了{}这种动态替换参数的方式,是因为有些复杂的sql使用场景通过预编译的方式比较麻烦,且在代码中完全可以做到控制非法参数,有些参数可能是一些常量或字段值。
7.类型别名(typeAliases)
-
类型别名是为java类型设置一个短的名字。 -
存在的意义是为了减少类完全限定名的冗余。
<typeAliases>
<typeAlias type="url" alias="别名"/>
</typeAliases>
```声明别名是顺序的第三个
- 也可以指定一个包名,mybatis会在包名下面搜索需要的java Bean,比如:扫描实体类的包,他的默认别名就为这个类的类名,首字母小写!
```xml
<typeAliases>
<typeAlias name="包的地址"/>
</typeAliases>
在实体类较多的时候,使用第一种方式。
如果实体类十分多,建议使用第二种方式(默认为包中类名不区分大小写建议用小写) 第一种方式可以自定义别名,第二中不行(如需在第二种上自定义别名则需要添加注解,但是加了@Alias(“名”))在resultMap中原来的类名就不能够用了
@Alias("user")
public class User{}
- 8大基本类型的别名在前面加_,其余的类在原来的基础上首字母小写就ok
8.载mybatis-config.xml上对mapper.xml进行绑定
三种方法:
<mappers>
<mapper resource="Iuser.xml"></mapper>
</mappers>
``````xml
<mappers>
<mapper class="类地址"></mapper>
</mappers>
<mappers>
<mapper name="包地址"></mapper>
</mappers>
注意:
- 在使用class或者扫描包进行绑定时,接口和他的mapper配置文件必须同名
- 在使用class或者扫描包进行绑定时,接口和他的mapper配置文件必须在同一个包下!
每一个mapper代表一个业务
9.ResultMap结果集映射
- 当我们的类属性名和数据库表字段名不一致的时候我们查询数据的时候就会显示不正确。这时候我们有两种解决方法:
- 在sql语句中使用别名使得两个名字一致
- 使用ResultMap结果集映射
- idea快速替换快捷键crtl+r
10.日志工厂
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
10.1Log4j
什么是Log4j?
- 我们可以通过Log4j控制日志信息输送的目的地是控制台、文件、GUI组件
- 我们也可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
- 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
11.limit以及RowBounds实现分页
Limit实现分页:
<select id="selectUserList" resultMap="usermap" parameterType="map">
select *from mybatis.user limit
</select>
RowBounds类实现分页:
RowBounds rowBounds = new RowBounds(0,2);
List<Object> objects = sqlsession.selectList("com.southswing.mapper.UserMapper.getUserlist()", null, rowBounds);
12.使用注解进行开发
- 注解在接口上实现
@Select("select * from user")
List<User>getUsers()
- 需要在核心配置文件中绑定接口
<mappers>
<mapper class="mapper接口地址"/>
</mappers>
```3.使用注解进行CRUD操作
关于@Param()注解
- 基本类型的参数或者String类型,需要加上
- 引用类型不需要加
- 如果只有一个基本类型的话,可以忽略,但是建议大家都加上!
- 我们在sql中引用的就是我们这里的@Param("uid")中uid对应的属性
有关mybatis向数据库输入中文数据出现乱码的问题
https://blog.csdn.net/l1509214729/article/details/80781740
#### 14.复杂查询之多对一查询的两种方法
- 第一种方法,先将sql语句写完,然后分别写对应的类属性在sql语句(即是数据库)里面对应的字段。对于对象则通过association来声明。
```xml
<select id="selectStudent2" resultMap="method2">
select s.id sid,s.name sname,t.id tid,t.name tname from teacher t,student s where s.tid=t.id
</select>
<resultMap id="method2" type="com.southswing.pojo.Student">
<result property="id" column="sid"></result>
<result property="name" column="sname"></result>
<association property="teacher" javaType="com.southswing.pojo.Teacher">
<result property="id" column="tid"></result>
<result property="name" column="tname"></result>
</association>
</resultMap>
在接口中构造两个方法分别实现对两个表的查询,然后通过resultMap中的association中的select连接起来即可
<select id="selectStudent3" resultMap="method1">
select * from student
</select>
<resultMap id="method1" type="com.southswing.pojo.Student">
<result property="id" column="id"></result>
<result property="name" column="name"></result>
<association property="teacher" column="tid" javaType="com.southswing.pojo.Teacher" select="getTeacher"></association>
</resultMap>
<select id="getTeacher" resultType="com.southswing.pojo.Teacher">
select *from mybatis.teacher
</select>
15.复杂查询之一对多的两种查询方法
- 方法一:先用sql语句将所有的关联数据查询出来再使用resultMap进行映射。包括collection以及ofType
<select id="selectTeacher" resultMap="method1">
select s.id sid,s.name sname,t.id tid,t.name tname from student s,teacher t where s.tid=t.id and t.id=#{zid}
</select>
<resultMap id="method1" type="com.southswing.Pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="studentList" ofType="com.southswing.Pojo.Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
- 方法二:创建两个接口然后分别编写mapper内容,然后我们就会通过相应的内容进行连接
<select id="selectTeacher2" resultMap="method2">
select t.id tid,t.name tname from mybatis.teacher t where t.id=#{zid}
</select>
<resultMap id="method2" type="com.southswing.Pojo.Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="studentList" javaType="ArrayList" ofType="com.southswing.Pojo.Student" select="selectStudent" column="tid">
</collection>
</resultMap>
<select id="selectStudent" resultType="com.southswing.Pojo.Student">
select * from mybatis.student where tid=#{id}
</select>
```重点:记住传入到第二个select中的数据是通过数据库传递的。
#### 16.动态sql语句
@SuppressWarning("all")镇压警告消去代码下的波浪线
- 从经典数据库列名A_COLUMN到经典java属性名aColumn的类似映射。(有数据库名映射为驼峰命名)
- ```xml
<setting name="mapUnderscoreToCamelCase" value="true"/>
- UUID(生成唯一id的方法是string类型的)
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
```##### 动态sql之IF语句
```xml
<select id="queryBlogIF" parameterType="map" resultType="southswing.Pojo.Blog">
select *from mybatis.blog where 1=1
<if test="title!=null">
and title=#{title}
</if>
</select>
动态sql之choose
<select id="queryBlogChoose" parameterType="map" resultType="southswing.Pojo.Blog">
select * from mybatis.blog
<where>
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="title!=null">
and title=#{title}
</when>
<otherwise>and author=#{author}</otherwise>
</choose>
</where>
</select>
- 通过以及来实现相应的动态查询功能。
- 注意在第二个if或者otherwise后面就需要添加and
动态sql之update
<select id="updateSet" parameterType="map">
update mybatis.blog
<set>
<if test="author!=null">
author=#{author},
</if>
<if test="title!=null">
title=#{title},
</if>
</set>
<where>
id=#{id}
</where>
</select>
- 通过标签来实现的。
- 注意:每个if里面的添加的数据后需要加入一个","。
-
动态sql之trim
<select id="selectTrim" parameterType="map" resultType="southswing.Pojo.Blog">
select *from mybatis.blog
<trim prefix="where" prefixOverrides="and|or">
<if test="title!=null">
and title=#{title}
</if>
</trim>
</select>
```- prefix:前缀
- prefixoverride:去掉第一个and或者是or,当然里面也可以写",",写哪一个就是将多余的那一个去掉。
##### 动态sql之ForEach
```xml
<select id="queryBlogForEach" resultType="southswing.Pojo.Blog" parameterType="map">
select * from mybatis.blog
<where>
<foreach collection="ids" item="id" open="and(" close=")" separator=",">
id=#{id}
</foreach>
</where>
</select>
- foreach就是将map里面一个集合的内容与前面的sql语句按照指定的格式拼接起来。
- collection代表map集合里面的一个泛型为ID的Arraylist集合。item里面为集合中的每一个元素。open:开始端。separator:分隔符。close:结束端。
对应的java代码为:
@Test
public void queryForEach(){
SqlSession sqlSession = Util.getSqlSession();
MapperConfig mapper = sqlSession.getMapper(MapperConfig.class);
HashMap<String, Object> map = new HashMap<>();
ArrayList<Integer> integers = new ArrayList<>();
map.put("ids",integers); for (Blog queryBlogForEach : mapper.queryBlogForEach(map)) {
System.out.println(queryBlogForEach);
}
sqlSession.close();
}
动态sql之sql(关键字)的使用
<select id="queryBlogChoose" parameterType="map" resultType="southswing.Pojo.Blog">
select * from mybatis.blog
<where>
<include refid="sqlzzz"></include>
</where>
</select>
<sql id="sqlzzz" >
<choose>
<when test="id!=null">
id=#{id}
</when>
<when test="title!=null">
and title=#{title}
</when>
<otherwise>and author=#{author}</otherwise>
</choose>
</sql>
- sql就是将一定内容的代码抽象出来,就象定义一个类一样。抽象出来。减少代码冗余。主要通过来进行导入
17.Mybatis缓存
- 什么是缓存?
缓存其实就是内存的一部分。有的数据需要重复的查找或者经常使用我们就可以把他们放在缓存里面。下次再使用可以直接从缓存获取不必去数据区查找。提高了效率,解决了高并发系统的性能问题
- 为什么使用缓存
减少和数据库的交互次数,减少系统开销,提高系统的效率。
17.1mybatis的两种缓存
17.3 二级缓存
-
二级缓存作用域为namespace即整个mapper。由于一级缓存作用域太低了,所以诞生了二级缓存。 -
工作机制
- 一个会话查询一条数据,这个数据就会被放入当前对话的一级缓存中;
- 当前会话关闭了,这个会话对应的一级缓存就没有了;如果此时开启了二级缓存那么数据就会被保存到二级缓存中。
- 新的会话信息就可以从二级缓存中获取内容
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
步骤
- 开启全局缓存(只能开启全局缓存后才能开启二级缓存)虽然全局缓存是默认开启的,但是我们还是需要显示声明。
<setting name="cacheEnable" value="true">
- 在使用二级缓存的时候要开
<cache/>
```当然也可自定义一些参数
3.我们需要将实体类序列化,不然就会报错。
18.mybatis的缓存原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D1NrdlN0-1634712833965)(C:\Users\hct\AppData\Roaming\Typora\typora-user-images\image-20211014091032327.png)]
- 查询顺序:先查询二级缓存->查询一级缓存->查询数据库。(进入下一步是因为上一步的内容没有区域里面找到)
19.Ehcache缓存
-
自定义缓存只需要定义一个类实现cache接口里面的方法就ok了(只不过十分的困难) -
要在程序中使用cache,先要导包!具体去maven仓库查找mybatis-ehcache即可 -
在mapper中指定我们的ehcache缓存的实现
-
ehcache缓存可以自己xml文件进行声明。
mybatis的高频面试题:
|