1.初识Mybatis
1.引入相关jar包
<!--Mybatis依赖包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--mysql驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
2.搭建数据库
3.编写Mybatis全局配置文件
<?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 default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/kuang/dao/userMapper.xml"/>
</mappers>
</configuration>
4.创建实体类和mapper接口
5.编写mapper.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">
<mapper namespace="dao.EmployeeMapper">
<select id="getEmpById" resultType="bean.Employee">
select id,last_name lastName,gender,email from tbl_employee where id = #{id}
</select>
</mapper>
6.测试
//1.读取mybatis配置文件,获取SqlSessionFactory对象
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession实例,能直接执行已经映射的sql语句
SqlSession openSession = sqlSessionFactory.openSession();
//3.获取接口的实现类对象
//Mybatis会为接口自动创建一个代理对象,代理对象去执行增删改查
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
//下面再通过代理对象mapper进行增删改查
Employee employee = mapper.getEmpById(1);
//记得手动关闭openSession
openSession.close();
可能会出现静态资源过滤问题
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
2.Mybatis全局配置文件
configuration 配置:下面的这些配置要完全按照顺序配置,否则会报错
-
properties 属性
引入外部资源,如数据库连接的基本信息
<properties resource="dbconfig.properties"></properties>
-
settings 设置
<settings> <!--开启驼峰命名法--> <setting name="mapUnderscoreToCamelCase" value="true"/> <!--懒加载,需要用到哪个表的值再去加载而不是一起加载--> <setting name="lazyLoadingEnabled" value="true"/> <!--入侵式加载--> <setting name="aggressiveLazyLoading" value="false"/> </settings>
-
typeAliases 别名处理器
可以为指定的java类型取一个别名
<typeAliases> <typeAlias type="bean.Department" alias="dept"/> </typeAliases>
也可以为一整个包取别名,别名就是简单类名小写。
<typeAliases> <package name="com.atguigu.bean"/> </typeAliases>
还可以在实体类上使用@Alias注解
@Alias("dept") public class Department {}
-
typeHandlers 类型处理器
-
objectFactory 对象工厂
-
plugins 插件
-
environments 环境
- environment 环境变量
- transactionManager 事务管理器
- dataSource 数据源
<environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments>
- environment 环境变量
-
databaseIdProvider 数据库厂商标识
-
mappers 映射器
1.使用映射器接口实现类的完全限定类名
需要配置文件名称和接口名称一致,并且位于同一目录下<mappers> <mapper class="org.mybatis.builder.AuthorMapper"/> </mappers>
2.使用相对于类路径的资源引用
<mappers> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers>
3.使用使用完全限定资源定位符(URL)
<mappers> <mapper url="file:///var/mappers/AuthorMapper.xml"/> </mappers>
4.将包内的映射器接口实现全部注册为映射器
但是需要配置文件名称和接口名称一致,并且位于同一目录下<mappers> <package name="org.mybatis.builder"/> </mappers>
3.mapper映射文件
namespace
- namespace的命名必须跟某个接口同名
- 接口中的方法与映射文件中sql语句id应该一一对应
<?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">
<mapper namespace="com.kuang.mapper.UserMapper">
</mapper>
使用不同的数据库操作语句时,应使用不同的映射语句标签
select – 映射查询语句
-
id即为mapper接口中的方法名
-
parameterType:参数类型
可以不传,MyBatis会根据TypeHandler自动推断
-
必须设置接收类型即resultType或者resultMap,前者为实体类的类型,后者为自定义的类型
resultType
<select id="getDeptById" resultType="bean.Department"> select id,dept_name departmentName from tbl_dept where id=#{id} </select>
resultMap
<resultMap type="bean.Employee" id="MySimpleEmp"> <!--指定主键列的封装规则 column:指定哪一列 property:指定对应的javaBean的属性 --> <id column="id" property="id"/> <result column="last_name" property="lastName"/> <!--其他不指定的列会自动封装,但,建议,我们只要写resultMap就把全部的映射规则都写上--> <result column="email" property="email"/> <result column="gender" property="gender"/> </resultMap>
<select id="getEmpById" resultMap="MySimpleEmp"> select * from tbl_employee where id=#{id} </select>
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
sql –抽取可重用语句块
resultMap – 自定义结果集映射
-
多对一:association
<!--按查询结果嵌套处理--> <resultMap id="StudentTeacher2" type="Student"> <id property="id" column="sid"/> <result property="name" column="sname"/> <!--关联对象property 关联对象在Student实体类中的属性--> <association property="teacher" javaType="Teacher"> <result property="name" column="tname"/> </association> </resultMap> <select id="getStudents2" resultMap="StudentTeacher2" > select s.id sid, s.name sname , t.name tname from student s,teacher t where s.tid = t.id </select>
<!--按查询嵌套处理 : 略-->
-
一对多:collection
<!--按查询结果嵌套处理--> <resultMap id="TeacherStudent" type="Teacher"> <result property="name" column="tname"/> <collection property="students" ofType="Student"> <result property="id" column="sid" /> <result property="name" column="sname" /> <result property="tid" column="tid" /> </collection> </resultMap> <select id="getTeacher" resultMap="TeacherStudent"> select s.id sid, s.name sname , t.name tname, t.id tid from student s,teacher t where s.tid = t.id and t.id=#{id} </select>
<!--按查询嵌套处理 : 略-->
JavaType和ofType都是用来指定对象类型的
- JavaType是用来指定pojo中属性的类型
- ofType指定的是映射到list集合属性中pojo的类型
cache –命名空间的二级缓存配置
cache-ref – 其他命名空间缓存配置的引用
4.动态sql
if
<select id="queryBlogIf" parameterType="map" resultType="blog">
select * from blog where 1=1
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</select>
choose (when, otherwise)
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>
where
where元素只会在子元素返回任何内容的情况下才插入 “where” 子句。而且,若子句的开头为 “and” 或 “or”,where元素也会将它们去除。
<select id="findActiveBlogLike" resultType="Blog">
SELECT * FROM BLOG
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
</select>
set
set 元素会动态地在行首插入set关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
<update id="updateAuthorIfNecessary">
update Author
<set>
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</set>
where id=#{id}
</update>
trim
模拟where: prefixOverrides属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)
会移除所有 prefixOverrides属性中指定的内容,并且插入 prefix*属性中指定的内容
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</trim>
模拟set:覆盖了后缀值设置,并且自定义了前缀值
<trim prefix="SET" suffixOverrides=",">
<if test="username != null">username=#{username},</if>
<if test="password != null">password=#{password},</if>
<if test="email != null">email=#{email},</if>
<if test="bio != null">bio=#{bio}</if>
</trim>
foreach
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog where 1=1
<where>
<!--
collection:指定输入对象中的集合属性
item:每次遍历生成的对象
open:开始遍历时的拼接字符串
close:结束时拼接的字符串
separator:遍历对象之间需要拼接的字符串
select * from blog where 1=1 and (id=1 or id=2 or id=3)
-->
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id=#{id}
</foreach>
</where>
</select>
5.缓存
Mybatis缓存
- Mybatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
- MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
- 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
一级缓存失效的四种情况
-
sqlSession不同:结论:每个sqlSession中的缓存相互独立
-
sqlSession相同,查询条件不同:结论:当前缓存中,不存在这个数据
-
sqlSession相同,两次查询之间执行了增删改操作!结论:因为增删改操作可能会对当前数据产生影响
-
sqlSession相同,手动清除一级缓存
session.clearCache();//手动清除缓存
二级缓存
- 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
- 工作机制
- 一个会话(sqlSession)查询一条数据,这个数据就会被放在当前会话的一级缓存中
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
- 新的会话查询信息,就可以从二级缓存中获取内容
- 不同的mapper查出的数据会放在自己对应的缓存(map)中
使用二级缓存
1.在mybatis全局配置文件中开启全局缓存
<setting name="cacheEnabled" value="true"/>
2.在mapper映射文件中配置使用二级缓存
<cache/>
3.所有的实体类要实现序列化接口
public class Department implements Serializable {}