mybatis的概述
mybatis是一个持久层框架,用java编写的。
它封装了jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程
它使用了ORM思想实现了结果集的封装。
ORM 是什么意思:
Object Relational Mappging 对象关系映射
简单的说:
就是把数据库表和实体类及实体类的属性对应起来
让我们可以操作实体类就实现操作数据库表。
user User
id userId
user_name userName
<!-- 根据 id 查询 -->
<select id="findById" resultType="com.XXX.User" parameterType="int">
select * from user where id = #{uid}
</select>
细节:
resultType 属性:
用于指定结果集的类型。
parameterType 属性:
用于指定传入参数的类型。 因为我们要传入的是一个类的对象,所以类型就写类的全名称。
sql 语句中使用#{}字符:
它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据,具体的数据是由#{}里面的内容决定的。
#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。它用的是 ognl 表达式。
ognl 表达式:
它是 apache 提供的一种表达式语言,全称是: Object Graphic Navigation Language 对象图导航语言 它是按照一定的语法格式来获取数据的。 语法格式就是使用 #{对象.对象}的方式。
#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用
getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,这个对象由框架帮我们创建了,默认对象名称是类名小写,所以可以省略 user. 而直接写 username。
操作完增删改操作后一定要提交事务:session.commit();来实现事务提交。
#{}与${}的区别:
#{}表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换, #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类 型值,#{}括号中可以是 value 或其它名称。
${}表示拼接 sql 串
通过${}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, ${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。
Mybatis 与 JDBC 编程的比较(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 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类
型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。
typeAliases(类型别名)
在 SqlMapConfig.xml 中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.XXX.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.XXX.domain"/>
<package name="其它包"/>
</typeAliases>
mappers(映射器)
1、使用相对于类路径的资源
如:<mapper resource="com/itheima/dao/IUserDao.xml" />
2、使用 mapper 接口类路径
如:<mapper class="com.itheima.dao.UserDao"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
3、注册指定包下的所有 mapper 接口
如:<package name="cn.itcast.mybatis.mapper"/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
动态 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>
注意:<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
<where>
<!-- 根据用户信息查询 -->
<select id="findByUser" resultType="user" parameterType="user"><include refid="defaultSql"></include><where><if test="username!=null and username != '' ">and username like #{username}</if><if test="address != null">and address like #{address}</if></where></select>
<foreach>
<select id="findInIds" resultType="user" parameterType="queryvo"><!-- select * from user where id in (1,2,3,4,5); --><include refid="defaultSql"></include><where><if test="ids != null and ids.size() > 0"><foreach collection="ids" open="id in ( " close=")" item="uid"separator=",">#{uid}</foreach></if></where></select>SQL 语句:select 字段 from user where id in (?)<foreach>标签用于遍历集合,它的属性:collection:代表要遍历的集合元素,注意编写时不要写#{}open:代表语句的开始部分close:代表结束部分
sql片段:
<!-- 抽取重复的语句代码片段 --><sql id="defaultSql">select * from user</sql><!-- 配置查询所有操作 --><select id="findAll" resultType="user"><include refid="defaultSql"></include></select>
一对一:
<!-- 建立对应关系 --><resultMap type="account" id="accountMap"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/><!-- 它是用于指定从表方的引用实体属性的 --><association property="user" javaType="user"><id column="id" property="id"/><result column="username" property="username"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/><result column="address" property="address"/></association></resultMap>
一对多:
<resultMap type="user" id="userMap"><id column="id" property="id"></id><result column="username" property="username"/><result column="address" property="address"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/><!-- collection 是用于建立一对多中集合属性的对应关系ofType 用于指定集合元素的数据类型--><collection property="accounts" ofType="account"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/></collection>
</resultMap>
多对多:
<!--定义 role 表的 ResultMap--><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><collection property="users" ofType="user"><id column="id" property="id"></id><result column="username" property="username"></result><result column="address" property="address"></result><result column="sex" property="sex"></result><result column="birthday" property="birthday"></result></collection></resultMap>
mybatis的延迟加载:
延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速
度要快。
坏处:
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗
时间,所以可能造成用户等待时间变长,造成用户体验下降。
开启延迟加载的配置:
<settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/></settings>
使用 assocation 实现延迟加载
<!-- 建立对应关系 --><resultMap type="account" id="accountMap"><id column="aid" property="id"/><result column="uid" property="uid"/><result column="money" property="money"/><!-- 它是用于指定从表方的引用实体属性的 --><association property="user" javaType="user"select="com.xxx.dao.IUserDao.findById"column="uid">< /association></resultMap><select id="findAll" resultMap="accountMap">select * from account</select>select: 填写我们要调用的 select 映射的 idcolumn : 填写我们要传递给 select 映射的参数
使用 Collection 实现延迟加载
<resultMap type="user" id="userMap"><id column="id" property="id"></id><result column="username" property="username"/><result column="address" property="address"/><result column="sex" property="sex"/><result column="birthday" property="birthday"/><!-- collection 是用于建立一对多中集合属性的对应关系ofType 用于指定集合元素的数据类型select 是用于指定查询账户的唯一标识(账户的 dao 全限定类名加上方法名称)column 是用于指定使用哪个字段的值作为条件查询--><collection property="accounts" ofType="account"select="com.xxx.dao.IAccountDao.findByUid"column="id"></collection></resultMap><!-- 配置查询所有操作 --><select id="findAll" resultMap="userMap">select * from user</select><collection>标签:主要用于加载关联的集合对象select 属性:用于指定查询 account 列表的 sql 语句,所以填写的是该 sql 映射的 idcolumn 属性:用于指定 select 属性的 sql 语句的参数来源,上面的参数来自于 user 的 id 列,所以就写成 id 这一个字段名了
Mybatis 一级缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在.一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加方法时,就会清空一级缓存。
,
第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查询用户信息。得到用户信息,将用户信息存储到一级缓存中。如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存中获取用户信息。
Mybatis 二级缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个
SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。
<settings><!-- 开启二级缓存的支持 --><setting name="cacheEnabled" value="true"/></settings>因为 cacheEnabled 的取值默认就为 true,所以这一步可以省略不配置。为 true 代表开启二级缓存;为false 代表不开启二级缓存。
<mapper namespace="com.xxx.dao.IUserDao"><!-- 开启二级缓存的支持 --><cache></cache></mapper>
<!-- 根据 id 查询 --><select id="findById" resultType="user" parameterType="int" useCache="true">select * from user where id = #{uid}</select>将 UserDao.xml 映射文件中的<select>标签中设置 useCache=”true”代表当前这个 statement 要使用二级缓存,如果不使用二级缓存可以设置为 false。注意:针对每次查询都需要最新的数据 sql,要设置成 useCache=false,禁用二级缓存。
使用 Mybatis 注解:
/*** 查询所有用户* @return*/@Select("select * from user")@Results(id="userMap",value= {@Result(id=true,column="id",property="userId"),@Result(column="username",property="userName"),@Result(column="sex",property="userSex"),@Result(column="address",property="userAddress"),@Result(column="birthday",property="userBirthday")})List<User> findAll();
@Results 注解代替的是标签<resultMap>该注解中可以使用单个@Result 注解,也可以使用@Result 集合@Results({@Result(),@Result()})或@Results(@Result())@Resutl 注解代替了 <id>标签和<result>标签@Result 中 属性介绍:id 是否是主键字段column 数据库的列名property 需要装配的属性名one 需要使用的@One 注解(@Result(one=@One)()))many 需要使用的@Many 注解(@Result(many=@many)()))@One 注解(一对一)代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。@One 注解属性介绍:select 指定用来多表查询的 sqlmapperfetchType 会覆盖全局的配置参数 lazyLoadingEnabled。。使用格式:@Result(column=" ",property="",one=@One(select=""))@Many 注解(多对一)代替了<Collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。注意:聚集元素用来处理“一对多”的关系。需要指定映射的 Java 实体类的属性,属性的 javaType(一般为 ArrayList)但是注解中可以不定义;使用格式:@Result(property="",column="",many=@Many(select=""))