Mybatis

MyBatis 框架概述

mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,
而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。
mybatis 通过 xml 或注解的方式将要执行的各种 statement 配置起来,并通过 java 对象和 statement 中
sql 的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并
返回。
采用 ORM 思想解决了实体和数据库映射的问题,对 jdbc 进行了封装,屏蔽了 jdbc api 底层访问细节,使我
们不用与 jdbc api 打交道,就可以完成对数据库的持久化操作。

<?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>
<!-- 配置 mybatis 的环境 --> <environments default="mysql">
<!-- 配置 mysql 的环境 --> <environment id="mysql">
<!-- 配置事务的类型 --> <transactionManager type="JDBC"></transactionManager>
<!-- 配置连接数据库的信息:用的是数据源(连接池) --> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ee50"/>
<property name="username" value="root"/>
<property name="password" value="1234"/>
</dataSource>
</environment>
</environments>
<!-- 告知 mybatis 映射配置的位置 --> 
<mappers> 
   <mapper resource="com/itheima/dao/IUserDao.xml"/>
</mappers>
</configuration>
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.创建 SqlSessionFactory 的构建者对象
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//3.使用构建者创建工厂对象 SqlSessionFactory
SqlSessionFactory factory = builder.build(in);
//4.使用 SqlSessionFactory 生产 SqlSession 对象
SqlSession session = factory.openSession();
//5.使用 SqlSession 创建 dao 接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//6.使用代理对象执行查询所有方法
List<User> users = userDao.findAll();
for(User user : users) {
System.out.println(user);
}
//7.释放资源
session.close();
in.close();

1、持久层接口和持久层接口的映射配置必须在相同的包下
2、持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
3、SQL 语句的配置标签,,,的 id 属性必须和持久层接口的
方法名相同。

 
     细节:
       resultType 属性:
           用于指定结果集的类型。
      parameterType 属性:
          用于指定传入参数的类型。
          
sql 语句中使用#{}字符: 它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。

#{}中内容的写法:
由于数据类型是基本类型,所以此处可以随意写。
<!-- 保存用户--> <insert id="saveUser" parameterType="com.itheima.domain.User">
insert into user(username,birthday,sex,address) 
values(#{username},#{birthday},#{sex},#{address})
</insert>
细节:
parameterType 属性:
代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。

sql 语句中使用#{}字符: 它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。
具体的数据是由#{}里面的内容决定的。

#{}中内容的写法:
由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。
它用的是 ognl 表达式。

ognl 表达式:
它是 apache 提供的一种表达式语言,全称是:
Object Graphic Navigation Language 对象图导航语言

它是按照一定的语法格式来获取数据的。
语法格式就是使用 #{对象.对象}的方式

#{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用
getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user.
而直接写 username。

在实现增删改时一定要去控制事务的提交
使用:session.commit();来实现事务提交

新增用户 id 的返回值

新增用户后,同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相
当于我们要在新增后将自动增长 auto_increment 的值返回。

<insert id="saveUser" parameterType="USER">
<!-- 配置保存时获取插入的 id --> 
<selectKey keyColumn="id" keyProperty="id" resultType="int">
     select last_insert_id();
</selectKey>
     insert into user(username,birthday,sex,address) 
      values(#{username},#{birthday},#{sex},#{address})
</insert>

我们在配置文件中没有加入%来作为模糊查询的条件,所以在传入字符串实参时,就需要给定模糊查询的标识%。配置文件中的#{username}也只是一个占位符,所以 SQL 语句显示为“?”。

Mybatis_第1张图片

#{}与${}的区别

#{}表示一个占位符号
通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换,
#{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类型值,#{}括号中可以是 value 或其它名称。

$ {}表示拼接 sql 串
通过$ {}可以将 parameterType 传入的内容拼接在 sql 中且不进行 jdbc 类型转换, $ {}可以接收简
单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值,${}括号中只能是 value。

parameterType 配置参数

基 本 类 型 和 String 我 们 可 以 直 接 写 类 型 名 称 , 也 可 以 使 用 包 名 . 类 名 的 方 式 , 例 如 :
java.lang.String。
实体类类型,目前我们只能使用全限定类名。
究其原因,是 mybaits 在加载时已经把常用的数据类型注册了别名,从而我们在使用时可以不写包名,
而我们的是实体类并没有注册别名,所以必须写全限定类名。

传递 pojo 包装对象

开发中通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查
询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
Pojo 类中包含 pojo。
需求:根据用户名查询用户信息,查询条件放到 QueryVo 的 user 属性中。

/**
* 
* 

Title: QueryVo

*

Description: 查询条件对象

*

Company: http://www.itheima.com/

*/
public class QueryVo implements Serializable { private User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
public interface IUserDao {
/**
* 根据 QueryVo 中的条件查询用户
* @param vo
* @return
*/
List<User> findByVo(QueryVo vo);
}
<!-- 根据用户名称模糊查询,参数变成一个 QueryVo 对象了 --> 
<select id="findByVo" resultType="com.itheima.domain.User"
 parameterType="com.itheima.domain.QueryVo">
select * from user where username like #{user.username};
</select>
@Test
public void testFindByQueryVo() {
   QueryVo vo = new QueryVo();
   User user = new User();
   user.setUserName("%王%");
   vo.setUser(user);
List<User> users = userDao.findByVo(vo);
    for(User u : users) {
System.out.println(u);
    } 
}

resultMap 结果类型

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时建立对应关系。从而实现封装。
在 select 标签中使用 resultMap 属性指定引用即可。同时 resultMap 可以实现将查询结果映射为复杂类
型的 pojo,比如在查询结果映射对象中包括 pojo 和 list 实现一对一查询和一对多查询。

<!-- 建立 User 实体和数据库表的对应关系 
   type 属性:指定实体类的全限定类名
   id 属性:给定一个唯一标识,是给查询 select 标签引用用的。
-->
 <resultMap type="com.itheima.domain.User" id="userMap">
 <id column="id" property="userId"/>
 <result column="username" property="userName"/>
 <result column="sex" property="userSex"/>
 <result column="address" property="userAddress"/>
 <result column="birthday" property="userBirthday"/>
</resultMap>

id 标签:用于指定主键字段
result 标签:用于指定非主键字段
column 属性:用于指定数据库列名
property 属性:用于指定实体类属性名称

映射配置

<!-- 配置查询所有操作 --> <select id="findAll" resultMap="userMap">
  select * from user
</select>

SqlMapConfig.xml配置文件

-properties(属性)
  --property
-settings(全局配置参数)
    --setting
-typeAliases(类型别名)
   --typeAliase
   --package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
  --environment(环境子属性对象)
      ---transactionManager(事务管理)
      ---dataSource(数据源)
-mappers(映射器)
   --mapper
   --package

properties(属性)

在使用 properties 标签配置时,我们可以采用两种方式指定属性配置

第一种

 <properties> 
       <property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
       <property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy"/>
       <property name="jdbc.username" value="root"/>
       <property name="jdbc.password" value="1234"/>
</properties>

第二种
在 classpath 下定义 db.properties 文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy
jdbc.username=root
jdbc.password=1234

properties 标签配置
Mybatis_第2张图片
此时我们的 dataSource 标签就变成了引用上面的配置
Mybatis_第3张图片

typeAliases(类型别名)

自定义别名:
Mybatis_第4张图片
※注意:批量命名别名时,默认命名为的别名为类名(不区别大小写)。

mappers(映射器)

< mapper resource=" " />

使用相对于类路径的资源
如:< mapper resource=“com/itheima/dao/IUserDao.xml” />

< mapper class=" " />
使用 mapper 接口类路径
如:< mapper class=“com.itheima.dao.UserDao”/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中

< package name=""/>
注册指定包下的所有 mapper 接口
如:< package name=“cn.itcast.mybatis.mapper”/>
注意:此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

Mybatis 连接池与事务深入

Mybatis 连接池的分类
Mybatis_第5张图片
在这三种数据源中,我们一般采用的是 POOLED 数据源(很多时候我们所说的数据源就是为了更好的管理数据库连接,也就是我们所说的连接池技术)。

Mybatis 中数据源的配置
Mybatis_第6张图片

Mybatis 的动态 SQL 语句

动态 SQL 之标签
我们根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
Mybatis_第7张图片
动态 SQL 之标签
为了简化上面 where 1=1 的条件拼装,我们可以采用标签来简化开发
Mybatis_第8张图片
动态标签之标签
Mybatis_第9张图片
在这里插入图片描述
Mybatis 中简化编写的 SQL 片段
Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的。

定义代码片段
Mybatis_第10张图片
引用代码片段
Mybatis_第11张图片
在这里插入图片描述

Mybatis 多表查询之一对多

1.定义专门的 po 类作为输出类型,其中定义了 sql 查询结果集所有的字段。

2.使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。

Mybatis_第12张图片
一对多查询
Mybatis_第13张图片
Mybatis_第14张图片
Mybatis 多表查询之多对多
Mybatis_第15张图片
Mybatis_第16张图片

Mybatis 延迟加载策略

延迟加载:
就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.
好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速
度要快。
坏处:
因为只有当需要用到数据时,才会进行数据库查询,这样在大批量数据查询时,因为查询工作也要消耗
时间,所以可能造成用户等待时间变长,造成用户体验下降。

使用 assocation 实现延迟加载
Mybatis_第17张图片
< !-- 开启延迟加载的支持 -->
Mybatis_第18张图片
使用 Collection 实现延迟加载
Mybatis_第19张图片

Mybatis 缓存

Mybatis 一级缓存
一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。

一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close()等

第一次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,如果没有,从数据库查
询用户信息。
得到用户信息,将用户信息存储到一级缓存中。
如果 sqlSession 去执行 commit 操作(执行插入、更新、删除),清空 SqlSession 中的一级缓存,这样
做的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户 id 为 1 的用户信息,先去找缓存中是否有 id 为 1 的用户信息,缓存中有,直接从缓存
中获取用户信息

Mybatis 二级缓存
二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个
SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

首先开启 mybatis 的二级缓存。
sqlSession1 去查询用户信息,查询到用户信息会将查询数据存储到二级缓存中

如果 SqlSession3 去执行相同 mapper 映射下 sql,执行 commit 提交,将会清空该 mapper 映射下的二
级缓存区域的数据。

sqlSession2 去查询与 sqlSession1 相同的用户信息,首先会去缓存中找是否存在数据,如果存在直接从
缓存中取出数据。

第一步:在 SqlMapConfig.xml 文件开启二级缓存
Mybatis_第20张图片

第二步:配置相关的 Mapper 映射文件
Mybatis_第21张图片
第三步:配置 statement 上面的 useCache 属性
Mybatis_第22张图片

Mybatis 注解开发

Mybatis_第23张图片
Mybatis_第24张图片
Mybatis_第25张图片
使用注解实现一对多复杂关系映射
Mybatis_第26张图片
基于注解的二级缓存
Mybatis_第27张图片

你可能感兴趣的:(SSM)