简介
mybatis是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
MyBatis工作原理
1.读取配置文件,配置文件配置的是数据库连接的信息
2.加载映射文件(Mapper) 文件里面配置了sql语句
3.构建会话工厂
4.构造会话对象 由会话工厂创建SqlSession对象,该对象包含了执行SQL的所有方法
5.根据sqlSession创建dao(指的是查询的一个接口)接口的代理对像 通过代理对象执行(自己定义的)增删改查方法
MyBatis的核心对象
1.SqlSessionFactory对象线程安全,一旦被创建在整个执行期间都会存在.主要作用就是构建SqlSession,SqlSessionFactory对象是通过
SqlSessionFactoryBuilder读取xml配置文件配置创建的.
2.SqlSession他是应用程序与持久层之间执行交互操作的一个单线程对象,主要作用执行持久化操作,线程不安全使用范围最好在一个方法
或一次请求中,不可以放到一个类的静态字段,使用完后及时关闭.
映射文件的主要元素(xml)
<resultMap id="userMap" type="user" > ----id唯一标识 -----type 表示是封装到哪个实体类 这里是Account类
<id property="id" column="id"></id> -----id表示哪一列是主键
<result property="username" column="username"></result>property是实体类Account类的字段 column是数据库字段
一对一 在pojo中 将一方的对象作为另一方的属性
<association property="user" javaType="user"><!--property表示封装哪个对象,colum表示通过那个字段封装-->
<id property="id" column="id"></id>-----id表示哪一列是主键
<result column="username" property="username"></result>property是实体类Account类的字段 column是数据库字段
</association >
一对多 将多的一方的封装为List<多的一方> 作为一的一方pojo的属性
<collection>
.............
</collection>
</resultMap>
xml方式 映射文件中的属性和sql注入问题
--resultType 属性: 用于指定结果集的类型。
--parameterType 属性 用于指定传入参数的类型。如果为我们要传入的是一个类的对象,所以类型就写类的全
名称。
--如果插入数据时某个字段自增 可以使用keyProperty接收主键返回值,id指的是自增字段
keyProperty="id" useGeneratedKeys="true" 设置主键自僧
模糊查询时 不直接在sql语句中使用% 而是在方法中拼接%
--sql 语句中使用#{}字符: 它代表占位符,相当于原来
jdbc 部分所学的,都是用于执行语句时替换实际的数
据。 具体的数据是由#{}里面的内容决定的。
#{}中内容的写法: 由于数据类型是基本类型,所以此处可以随意写。
--sql语句拼接时不建议使用${} 会引起sql注入, 建议使用 #{} 表示一个占位符号
例如 :模糊查询 select * from user where username like '%${value}%'
正确写法 select * from user where username like concat( '%' ,#{value} ,'%') 使用concat()函数拼接
开启注解 不再写xml
使用注解 不再使用resource而使用class
配置文件
<mappers>
<mapper class="dao.IUserDao"/>
</mappers>
Mybatis 与 JDBC 编程的比较
1.数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。 解决: 在 SqlMapConfig.xml 中配置数据链接池,使用连接池管理数据库链接。
2.Sql 语句写在代码中造成代码不易维护,实际应用 sql 变化的可能较大,sql 变动需要改变 java 代码。 解决: 将 Sql 语句配置在 XXXXmapper.xml 文件中与 java 代码分离。
3.向sql语句传参数麻烦,因为sql语句的where 条件不一定,可能多也可能少,占位符需要和参数对应。 解决: Mybatis自动将 java 对象映射至 sql 语句,通过 statement 中的 parameterType 定义输入参数的 类型。
4.对结果集解析麻烦,sql 变化导致解析代码变化,且解析前需要遍历,如果能将数据库记录封装成 pojo 对 象解析比较方便。 解决: Mybatis自动将 sql执行结果映射至 java 对象,通过statement中的resultType 定义输出结果的 类型
实体类和数据库字段不一致
resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称
动态sql
----<if> 判断语句,用于单条件分支判断 例如
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username!=null and username != '' ">
and username like #{username}
</if>
<if test="address != null">
and address like #{address}
</if>
</select>
----<choose><when><otherwise> 相当于javaz中swit-ch...case...default语句.
例如
select * from user where 1=1
<choose>
<when test="username!=null and username !='' " >
and username like concat('%',#{username},'%')
</when>
<when>.........</when>
<otherwise>
and phone is not null
</otherwise>
</choose>
----为了简化上面 where 1=1 的条件拼装,我们可以采用<where>标签来简化开发。
------SQL 语句:实现 select * from user WHERE id in (41,42,43); 这样的功能
<foreach>标签用于遍历集合,它的属性:
collection:代表要遍历的集合元素,注意编写时不要写#{}
open:代表语句的开始部分
close:代表结束部分
item:代表遍历集合的每个元素,生成的变量名
sperator:代表分隔符
-------<bind> 模糊查询拼接%
关联映射
一对一
<!-- 一对一-->
<mapper namespace="dao.IAccuntDao">
<!--定义封装account和user两个表-->
<resultMap id="Map" type="account"> <!--type 表示是封装到哪个实体类 这里是Account类-->
<id property="ID" column="AID"></id><!--property是实体类Account类的字段 column是数据库字段-->
<result property="UID" column="UID"></result>
<result property="MONEY" column="MONEY"></result>
<!--一对一关系映射,封装user内容-->
<association property="user" javaType="user"><!--property表示封装哪个对象,colum表示通过那个字段封装-->
<id property="id" column="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</association>
</resultMap>
<!--查询所有账户 同时包含用户名和地址信息 那么包含两张表一个是user表一个是account表-->
<select id="findAllAccount" resultMap="Map">
SELECT u.*,a.ID as aid,a.MONEY from account a, user u WHERE a.UID = u.id;
</select>
</mapper>
一对多
在 多的一方添加一的一方的主键作为外键<collection>标签
用户---订单
<!-- 1对多 -->
<mapper namespace="dao.IUserDao">
<!--定义user的map-->
<resultMap id="userMap" type="user">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="birthday" column="birthday"></result>
<result property="sex" column="sex"></result>
<result property="address" column="address"></result>
<!--配置list集合映射-->
<collection property="accounts" ofType="account"><!--accounts 是User类里面的字段-->
<id column="aid" property="ID"></id>
<result column="UID" property="UID"></result>
<result column="MONEY" property="MONEY"></result>
</collection>
</resultMap>
<!-- 配置查询所有操作( //查询所有用户 同时获取到用户下所有账户信息 一对多)-->
<select id="findAll" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid
</select>
<!-- 根据用户id查询用户(一)对应的账户(多)信息 -->
<select id="findById" parameterType="Integer" resultMap="userMap">
select u.*,a.id as aid ,a.uid,a.money from user u ,account a where u.id =a.uid and u.id=#{id};
</select>
</mapper>
多对多 产生中间表,引入两张表的主键作为外键
订单------商品
<!-- 多对多 -->
<mapper namespace="dao.IRoleDao">
<!--定义roleMap 因为使用了map所以实体类 Role类的字段可以和数据库字段不一致-->
<resultMap id="roleMap" type="role">
<id property="roleId" column="rid"></id>
<result property="roleName" column="ROLE_NAME"></result>
<result property="roleDesc" column="ROLE_DESC"></result>
<!--封装user-->
<collection property="users" ofType="user">
<id column="id" property="id"></id>
<result column="username" property="username"></result>
<result column="birthday" property="birthday"></result>
<result column="sex" property="sex"></result>
<result column="address" property="address"></result>
</collection>
</resultMap>
<!--查询所有-->
<select id="findAll" resultMap="roleMap">
/*-- 左外连接(多对多 需要中间表)*/
select u.*,r.ID as rid,r.ROLE_NAME,r.ROLE_DESC from role r left outer join user_role ur on r.ID=ur.RID
left outer join user u on u.id = ur.UID;
</select>
</mapper>
延迟加载sql缓存
-----一级缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。
关闭SqlSession .close 再创建缓存消失
一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除. commit(),close()等方法时,
就会清空一级缓存
---------二级缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession
去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession
可以共用二级缓存,二级缓存是跨 SqlSession 的。
注解开发
@Results 注解 代替的是标签<resultMap>
@Result 中 属性介绍: id 是否是主键字段 column
数据库的列名 property 需要装配的属性名 one 需
要使用的@One 注解(@Result(one=@One)
())) many 需要使用的@Many 注解(@Result(many=@many)()))
@One 注解(一对一) 代替了<assocation>标签,
是多表查询的关键,在注解中用来指定子查询返回单一
对象。 @One 注解属性介绍: select 指定用来多表查询的 sqlmapper
@Many 注解(多对一) 代替了<Collection>标
签,是是多表查询的关键,在注解中用来指定子查询返
回对象集合。 注意:聚集元素用来处理“一对多”的
关系。需要指定映射的 Java 实体类的属性,属性的 ja
vaType (一般为 ArrayList