- Mybatis是一个持久层的框架、也是一个半自动的ORM(object relational mapping)框架
核心配置文件
properties属性
可以创建一个properties文件,将驱动、url、用户名和密码存放在其中
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql:///数据库的名称
db.username=用户名
db.password=密码
好处:我们切换数据的时候只需要更改properties文件中的配置即可
核心配置文件引用properties的方法
<properties resource="db.properties">
typeAliases类型别名的设置
当我们正常使用映射文件的时候,要求resultType必须要写全名称,若我们在核心配置文件中设置别名,就可以简写
<!--当映射文件中出现person就表示是com.jiale.beans.Person的对象-->
<typeAliases>
<typeAlias type="com.jiale.beans.Person" alias="Person">
</typeAliases>
注意:别名可以忽略大小写
若项目中的别名有很多,需要配置很多的别名,可以通过package的方式来配置
<!--表示当前包下的所有实体类都配置了别名,别名的名称是类名-->
<typeAliases>
<package name="com.jiale.beans">
</typeAliases>
environments 环境配置
配置数据库中的连接环境
<!--在配置的多个环境中,默认使用哪一个-->
<environments default="development">
<!--单个环境的唯一标识,和default中的必须写一样的-->
<environment id="development">
<!--事务管理,当前的连接是否使用事务-->
<transactionManager type="JDBC"/>
<!--dateSource数据源 连接数据库的基础设置-->
<dateSource type="POOLED">
<property name="driver" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</dateSource>
</environment>
</environments>
- transcationManager配置事务管理,目前可以配置两个参数
- JDBC:使用jdbc的事务管理,也意味着开启了事务
- MANAGED:不使用事务,mybatis不使用事务,适合mybatis和其他框架、插件配合使用,其他框架来做事务管理
- dateSource 数据源属性 type属性
- POOLED:直接使用jdbc的连接池,但是使用连接池的概念,插件连接后,将连接放入到容器中来使用
- UNPOOLED:不使用连接池的概念,每次访问都是新建一个连接
- JNDI:使用第三方的连接池 c3p0 dbcp
添加映射文件
<mappers>
<mapper resource="PersnMapper.xml">
</mappers>
plugings分页插件的使用
- 添加依赖
- 核心配置文件中添加设置
<!--配置第三方的插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>
- 正常查询的时候添加分页设置
//添加分页设置
PageHelper.startPage(2,4);//当前的页数为2,每页的条数为4
- 可以使用分页提供的工具类
pageNum:当前的页数 pageSize:每页的条数 size:当前页的条数 prePage:上一页的页码
nextPage:下一页的页码 isFirstPage:是不是第一页 isLastPage:是不是最后一页 total:数据的总条数
类的映射文件
namespace命名空间
<mapper namespace="">
增删改查的sql标签
<insert id="addPerson" parameterType="com.jiale.beans.Person">
insert into person (name,sex,age) values(#{name},#{sex},#{age})
</insert>
<select id="getPerById" parameterType="int" resultType="com.jiale.beans.Person">
select * from person where id=#{id}
</select >
- 每个增删改查都有一个id,作为当前sql语句的唯一标识
- parameterType:表示当前sql传入的参数,如果传入的参数是对象,必须要写全名称
- resultType:只能在select标签中使用,表示查询后返回的结果去映射的那个对象,如果返回的是多个数据,mybatis会自动封装为list集合,我们需要配置的是list集合的泛型类型
ResultMap的使用
使用前提:创建的对象和数据库表不能自动映射(对象的属性和数据库中的名称不一样),可以通过手动的方法来实现
<!--自定义映射结果集 id的唯一标识 type 将结果映射到那个类中-->
<resultMap id="baseUser" type="User">
<!--配置标签有两个id和result,效果是一样的-->
<!--每个标签中都可以设置property对象的属性和column数据库的列-->
<id property="id" column="id"/>
<result property="name" column="uname"/>
<result property="age" column="uage"/>
</resultMap>
<!--使用resultMap,必须是使用手动映射-->
<select id="getPerById" parameterType="int" resultType="baseUser">
select * from person where id=#{id}
</select >
数据添加后返回主键selectKey
<insert id="addPerson" parameterType="com.jiale.beans.Person">
<!--在添加语句后执行对应的查询,将查询的结果赋值到id中-->
<selectKey order="AFTER" keyProperty="id" resultType="int">
SELECT LAST_INSERT_ID()
</selectKey >
insert into person (name,sex,age) values(#{name},#{sex},#{age})
</insert>
sql片段
类似于java中的封装,将重复出现的sql语句封装到sql片段中,在标签内进行调用
<!--添加一个sql片段将重复的SQL进行封装-->
<sql id="selectColumn">
select id,name,sex,age from person
</sql>
<!--调用-->
<include refid="selectColumn">
Mybatis的动态sql
if where标签
- if:if条件如果成立,sql就执行,如果使用多个使用and和or连接
- where:判断where标签内是否有sql语句,有就添加,没有就不添加,可去掉sql最前面的and或or
select * from person
<where>
<if test="name != null and name != ''">
and name like concat("%",concat(#{name},"%"))
</if>
<if test="sex!= null and sex!= ''">
and sex = #{sex}
</if>
<if test="hobby != null and hobby != ''">
and hobby= #{hobby}
</if>
</where>
choose标签
- 一套判断,该判断里面只有一个判断是正确的
select * from person
<choose>
<when test="name != null and name != ''">
where name like concat("%",concat(#{name},"%"))
</when>
<when test="sex!= null and sex!= ''">
where sex = #{sex}
</when>
<when test="hobby != null and hobby != ''">
where hobby= #{hobby}
</when>
<otherwise>
where age = 28
</otherwise>
</choose>
set标签
- 自动在标签的sql语句前面添加set,自动去掉后面的
update person
<set>
<if test="name != null and name != ''">
and name like concat("%",concat(#{name},"%"))
</if>
<if test="sex!= null and sex!= ''">
and sex = #{sex}
</if>
<if test="hobby != null and hobby != ''">
and hobby= #{hobby}
</if>
</set>
<where>
<if test="id != null and id != ''">
and id= #{id}
</if>
</where>
- 使用set标签的优点:避免了传递对象没有属性,在数据库中将对应的参数修改为null的情况
trim标签
去掉SQL语句的前后空格,还有个特殊的属性
- prefix:添加前缀 suffix:添加后缀 prefixOverrides:去掉前缀 suffixOverrides:去掉后缀
select * from person
<trim prefix="where" prefixOverrides="and">
<where>
<if test="name != null and name != ''">
and name like concat("%",concat(#{name},"%"))
</if>
<if test="sex!= null and sex!= ''">
and sex = #{sex}
</if>
<if test="hobby != null and hobby != ''">
and hobby= #{hobby}
</if>
</where>
foreach标签
遍历标签,如果传递的数据是个数组或者集合,才会使用遍历标签
标签的属性:
- collection:需要遍历的集合 item:表示迭代后每个对象的名称 open:在遍历开始前sql语句前面添加的内容
- close:在遍历开始后sql语句前面添加的内容 separator:在遍历的过程中每次遍历中间添加的内容
insert into person (name,sex,age)
<foreach collection="list" item="per" open="values(" close=")" separator="),(">
#{per.name},#{per.sex},#{per.age}
</foreach>
Mybatis的延迟加载
- 延迟加载的概述
只能在嵌套循环里面使用,延迟加载也叫懒加载、按需加载
在数据使用的情况下去加载数据,不使用就不加载,mybatis默认是关闭的,在正常使用中,如果加载的数据是大量的数据,加载的时候就会发生延迟,降低用户的使用体验,延迟加载根据具体的使用情况来决定是否使用 - 延迟加载的实现
(1)导入依赖cglib
(2)局部延迟加载:fetchType=“lazy”
局部延迟加载的配置:必须在所有的association和collection标签中添加fetchType,如果不添加就没有延迟加载,会将所有的数据都查询
(3)全局延迟加载
在核心配置文件中设置
<settings>
<!--开启全局的延迟加载-->
<setting name="lazyLodingEnabled" value="true"/>
<!--将读取任意属性就加载所有数据关闭-->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
全局延迟加载的配置简单,但是不能精确的定义延迟加载具体的使用
mybatis的缓存机制
- 查询的时候,同一个查询执行多次,浪费数据库的资源,在mybatis中可以使用查询缓存,查询的结果放入内存中,下一次查询直接获取
- 如果要使用缓存,需要将对象做序列化的操作
一级缓存
sqlsession级别的缓存,默认是开启的
缓存的数据什么时候清理?
- 关闭sqlsession的时候
- 执行对应的删改语句
二级缓存
- sqlsessionFactory级别的缓存,sqlsessionFactory在项目运行的时候创建,在项目关闭的时候销毁。二级缓存是默认关闭的。二级缓存是分块的,根据命名空间区分的。
- 开启二级缓存,实体类必须序列化们没有序列化会报异常
implements Serializeable
在核心配置文件的settings里面设置
<!--开启二级缓存-->
<setting name="cacheEnabled" value="true">
在映射文件中配置
<!--开启当前映射文件的二级缓存-->
<cache/>
二级缓存是一般项目优化最常用的一种
Mybatis的核心API介绍
Resources
- 作用:读取一个文件将文件转化为字节流文件
//读取核心配置文件,转化为一个流对象
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactoryBuilder
- 作用:将读取到的流对象创建一个sqlsession工厂
//创建一个sqlsession工厂
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
SqlSessionFactroy
- 作用:生产sqlsession对象
//生产sqlsession对象
SqlSession sqlSession = factory.openSession();
SqlSession
- 作用:可以调用五个方法来操作数据库insert update delete selectOne selectList
int i = sqlSession.insert("namespace.方法",p);
在执行增删改方法的时候使用commit方法,提交事务
还可以调用一个close方法 关闭sqlsesion
基于接口代理方式实现开发
优点:调用方法的入参都是由自己定义的,返回值类型包括是否增删改查的方法都是自己判断的
- 接口的开发规则
- 在映射文件中,namespace必须是接口的全名称
- 接口中的方法名必须和映射文件中标签的id一致
- 接口中的方法对应的入参必须和映射文件中标签中的parameterType一致
- 接口中的方法对应的返回值必须要和映射文件标签中的resultType类型一样(如果返回的是集合,映射文件配置的是泛型的类型,接口要配置list - 配置calss实现接口的开发
- 接口必须和映射文件的名字一样
- 接口必须和映射文件在同一个目录下,在resouces中创建和接口同名的文件夹来存放。
<mappers>
<!--通过calss来配置-->
<mapper calss="con.jiale.mapper.Test"/>
</mappers>
<mappers>
<!--表示该包下的所有接口都配置了calss-->
<package name="con.jiale.mapper"/>
</mappers>
Mybatis的多表联合查询
关联查询
一次性将所有表的数据都查询出来
多对一查询
在dog类中添加一个person 表示多对一的关系
映射文件的配置
<mapper namespace="com,jiale.mapper.DogMapper">
<!--自定义结果集 需要将person的数据进行匹配-->
<resultMap id="baseDog" type="Dog">
<id property="did" column="did"/>
<result property="dname" column="dname"/>
<result property="color" column="color"/>
<!--专门设置多对一的标签 association-->
<association property="per" javaType="Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
</association>
</resultMap>
一对多查询
在person中添加一个List集合,表示所有的dog
映射文件的配置
<mapper namespace="com,jiale.mapper.DogMapper">
<!--自定义结果集 需要将person的数据进行匹配-->
<resultMap id="basePerson" type="Person">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="sex" column="sex"/>
<result property="age" column="age"/>
<!--专门设置一对多的标签 collection ofType:集合泛型的类型-->
<collection property="dogs" javaType="Dog">
<id property="did" column="did"/>
<result property="dname" column="dname"/>
<result property="color" column="color"/>
</collection>
</resultMap>
多对多查询
- 创建学生类有List集合,表示一个学生对应多个中间表的课程
- 创建课程类有LIst集合,表示每个课程对应多个中间表的学生
- 创建中间表有学生和课程
映射文件的配置
<!--自定义结果集 学生类型-->
<resultMap id="baseStudent" type="Student">
<id property="sid" column="sid"/>
<result property="sname" column="sname"/>
<result property="ssex" column="ssex"/>
<result property="sage" column="sage"/>
<!--配置学生和中间表的一对多关系-->
<collection property="sc" javaType="Dog">
<id property="scid" column="scid"/>
<result property="score" column="score"/>
</collection>
<!--配置中间表和课程之间的关系-->
<association property="co" javaType="Course">
<id property="cid" column="cid"/>
<result property="cname" column="cname"/>
<result property="ctime" column="ctime"/>
</association>
</resultMap>
嵌套查询
多对一查询
根据颜色查询Dog,并根据id查询Person
<!--自定义结果集-->
<resultMap id="baseDog" type="Dog">
<id property="did" column="did"/>
<!--设置多对一的关联关系 column:将第一次查询结果的某个列的值放入第二次查询中-->
<!--select:查询person表要找的方法-->
<association property="per" javaType="Person" column="pid" select="findPerById">
</resultMap>
<!--根据颜色查询Dog-->
<select id="findDogByColor" parameterType="String" resultMap="baseDog">
select * from dog where color = #{color}
</select >
<!--根据pid查询person-->
<select id="findPerById" parameterType="int" resultType="Person">
select * from person where id= #{pid}
</select >
一对多
根据id查询person,再根据pid查询对应的dog
<!--自定义结果集-->
<resultMap id="basePerson" type="Person">
<!--设置一对多的关联关系-->
<collection property="dogs" javaType="Dog" column="id" select="findDogByPid">
</resultMap>
<!--根据id查询person-->
<select id="findPerById" parameterType="int" resultMap="basePerson">
select * from person where id= #{pid}
</select >
<!--根据pid查询dog-->
<select id="findDogById" parameterType="int" resultType="Dog">
select * from dog where pid= #{id}
</select >
多对多
查询大于某个课时时间的课程
<!--自定义课程结果集-->
<resultMap id="baseCourse" type="Course">
<id property="cid" column="cid">
<!--设置一对多的关联关系-->
<collection property="sc" javaType="SC" column="cid" select="findDogByPid">
</resultMap>
<!--根据课时查询课程-->
<select id="findCourseByTime" parameterType="int" resultMap="baseCourse">
select * from course where ctime > #{time}
</select >
<!--自定义课程结果集-->
<resultMap id="baseSC" type="SC">
<!--设置多对一的关联关系-->
<association property="st" javaType="Student" column="sid" select="findStudentBySid">
</resultMap>
<!--根据课程的cid查询中间表的方法-->
<select id="findSCByCid" parameterType="int" resultMap="baseSC">
select * from student_course where cid= #{cid}
</select >
<!--根据sid查询学生的方法-->
<select id="findStudentBySid" parameterType="int" resultType="Student">
select * from student where sid= #{sid}
</select >
Mybatis的注解
常用的注解
- @insert @delete @update @select :curd
- @results:和resultMap一样,自定义结果集 @result:在results下面使用,做列和属性的映射
- @one :配置多对一映射 @many:配置一对多映射
@Insert("insert into person (name,sex,age) values (#{name},#{sex},#{age})")
//多对一
@Select("select * from dog where did = #{did}")
@Results({
@Result(property = "did",column="did"),
@Result(property = "person",javaType="Person.calss"column="pid"),
one = @One(select = "findPerById")
})
Dog findDogByDid(Integer did);
//一对多
@Select("select * from person where id= #{id}")
@Results({
@Result(property = "id",column="id"),
@Result(property = "dogs",javaType="List.calss"column="id"),
many= @Many(select = "findDogByPid")
})
Dog findPerById(Integer id);