Mybatis 重点
1、概述及地位
官网:http://www.mybatis.org/mybatis-3/zh/index.html
1.1 框架
一个半成品的项目,我们使用该项目,进行二次开发,能够提高开发效率
2.1 是一个 ORM 框架
对象关系映射
数据库表名 JavaBean类名
字段名(列名) 属性名
记录(行) 对象
2.3 角色:Dao层
与 数据库进行 交互,封装的是 JDBC 的实现
2、基于配置文件开发
1、开发环境搭建
1. 新建maven 打包方式jar
2. 导入依赖
3. 配置文件
主配置文件 SqlMapConfig.xml 配置mybatis所需要的环境
Sql映射文件 接口名.xml 管理sql语句
1、XML文件必须跟接口在同一个目录中
2、XML文件中 mapper节点的namespace属性的值必须是 接口的全限定类名
3、select标签的 id属性的值为 接口的方法名
4、resultType 值为 接口方法的返回值,若返回集合,则指定集合中元素的全类名
5、paramterType 值为 接口方法的形参类型。该参数可以省略不写
4. 编写与数据库表对应的 JavaBean
5. 编写 dao 接口
6. 建立 dao接口与Sql映射文件的关系
7. 测试
备注:可参考官方文档(别死记硬背)
2、核心配置文件
现在掌握,将来了解(学会 Spring后),整合 Spring 后,可以是一个空文件,甚至没有
3、sql 映射文件
精通:常用标签、属性
标签:mapper、select、insert、update、delete、resultMap、sql、include、cache、selectKey
select 标签
查询所有
查询单个
模糊查询
查询返回单行单列,返回一个值
insert 标签
子标签:selectKey
select LAST_INSERT_ID()
insert into user (username,address) values (#{username},#{address})
INSERT INTO USER (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
select UUID()
insert into user_info (id,username) values (#{id},#{username})
修改和删除
update user set username=#{username},address=#{address},sex=#{sex},
birthday=#{birthday} where id=#{id}
delete from user where id = #{id}
select :
需求:查询的结果集列名 跟 属性名 不一致的情况下,我们需要进行映射
第一种方式:可以把 查询结果集的列名 取 别名(跟 javabean 属性名一致)
第二种方式 :使用 resultMap 自定义结果集映射
手动指定 主键列名 与 普通列名 跟 javabean 属性进行一一映射
(就算结果集列名跟属性名一致,推荐也是进行映射)
sql 的子节点:if、where、foreach、trim、set、choose、when、otherwise
属性:namespace、id、resultType、resultMap、parameterType
备注:可以参看逆向工程生成的文件
4、输入映射 (参数封装)parameterType
简单参数(8大基本数据类型或其包装类型,还有 String 类型)
#{key} key随意,一般key与形参名称一致
pojo #{key} key名必须与 pojo 的属性名一致,具体参看 增删改配置
包装 pojo(QueryVo) 参数名必须与 包装 pojo 的属性一致(可以使用 . 的形式访问其属性)
#{user.username} 该 user 是 queryVo 的一个属性, username 是 user 的一个属性
上述ONGL表达式获取到的是 QueryVo中的user中的 username 的值
例如:
class QueryVo{
private User user;
//省略 getter/setter 方法
}
@param注解 多个参数前,使用@param("name") 修饰形参,在 xml 中使用 #{name} 映射绑定形参
例如:
5、输出映射(结果封装)
resultType:底层是 resultMap
简单类型:int、double、String 等,直接返回 类型全类名 或者 别名
譬如:int、java.lang.String 等
pojo:可以是全类名,也可以是别名。推荐使用全类名:包名.类名
譬如:com.itheima.domain.User
List 集合:是集合中元素的具体类型,格式同 pojo
map集合:java.util.map 或者 map
resultMap
查询结果集与映射pojo属性不一致时,可以使用resultMap指定结果集列名与pojo的属性名进行手动映射
后期还可以映射关联关系
一对一:association
一对多:collection
6、动态sql
if、where、foreach、sql片段
if 、 where
foreach
INSERT INTO USER (username,birthday,sex,address) VALUES
(#{user.username},#{user.birthday},#{user.sex},#{user.address})
trim
set
UPDATE USER
username = #{username},
birthday = #{birthday},
sex = #{sex},
address = #{address},
id = #{id}
sql 片段
username,birthday,sex,address
INSERT INTO USER (
) VALUES
(#{user.username},#{user.birthday},#{user.sex},#{user.address})
7、关联关系
根据具体业务需要分析表与表之间的关系(实体与实体之间的关系)
使用 resultMap 进行映射。
一对一(多对一):association
javaType:指定具体关联的属性类型
一对多:collection
ofType:指定具体关联的集合中元素的类型
多对多映射:collection,在 mybatis 中其实也是看成 一对多
需要借助 中间表
userid roleid 联合主键
1 1
2 1
1 2
8、延迟加载(懒加载)
在关联查询的基础上才可能出现延迟加载(发送两条或两条以上的SQL)
多对一(一对一)或者一对多 都可以使用懒加载
AccountPlusMapper.java
/**
* @author 黑马程序员
* @Company http://www.ithiema.com
*/
public interface AccountPlusMapper {
/**
* 查询帐户关联用户信息
* @return
*/
List findAll();
/**
* 根据用户id查询账户列表
* @param id
* @return
*/
List findByUid(Integer uid);
}
UserPlusMapper.java
/**
* 也是操作 User类的持久化接口
* @author ghy
*/
public interface UserPlusMapper {
/**
* 根据 id 查询用户
* @param id
* @return
*/
User findById(Integer id);
/**
* 更新
* 没有返回值
* @param user
*/
void update(User user);
}
一对一 UserPlusMapper.xml
查询 账户时,关联查询用户信息(用户信息实现延迟加载)
需要在全局配置文件中配置延迟加载
一对多 UserPlusMapper.xml
UPDATE USER SET username = #{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id = #{id}
9、缓存
/**
* 测试一级缓存
* 注意:只有两次相同查询操作才会有缓存.
* 1.二级缓存是 SqlSession 级别,也就是只有同一个 SqlSession 才具备相同的缓存。一级缓存存放的数据是 对象的副本
* 2.一级缓存默认开启,程序员无法关闭。一级缓存的介质通常是内存
*
* 3.当 SqlSession 对象执行以上方法时,缓存失效
* close
* clearCache
* commit
* 增删改方法,不管是否提交事务
*/
@Test
public void testFirstLevelCache(){
User u1 = userPlusMapper.findById(88);
System.out.println(u1);
//session.commit();
User user = new User();
user.setId(87);
user.setUsername("87改一下");
userPlusMapper.update(user);
User u2 = userPlusMapper.findById(88);
System.out.println(u2);
System.out.println(u1 == u2);
}
/**
* 测试二级缓存
* 注意:在 SqlSession 关闭之后,数据才会保存到二级缓存中
* 1.二级缓存是 SqlSessionFactory 级别,由同一个 SqlSessionFactory 生产的 SqlSession 共享一个二级缓存。
* 二级缓存存放的数据是 散装数据
* 2.二级缓存默认开启(3.4.5版本,之前的版本默认是有关闭的),程序员可以手动开启。二级缓存的介质可以是内存或者硬盘
* 3.二级缓存使用步骤
* 3.1 要缓存的类必须实现 Serializable 接口
* 3.2 全局配置文件中开启
* 3.3 在要使用二级缓存的 Mapper.xml文件中 使用
*
* 当用户发送查询需求时,查询操作是怎么执行的?
*/
@Test
public void testSecondLevelCache(){
SqlSession session1 = sqlSessionFactory.openSession();
UserPlusMapper userPlusMapper1 = session1.getMapper(UserPlusMapper.class);
User user1 = userPlusMapper1.findById(79);
session1.close();
SqlSession session2 = sqlSessionFactory.openSession();
UserPlusMapper userPlusMapper2 = session2.getMapper(UserPlusMapper.class);
User user2 = userPlusMapper2.findById(79);
session2.close();
System.out.println(user1 == user2); // false
}
[图片上传失败...(image-a8f13e-1569651548520)]
面试题:
一级缓存跟二级缓存的区别?
3、基于注解开发
- @Insert:实现新增
- @Update:实现更新
- @Delete:实现删除
- @Select:实现查询
- @Result:实现结果集封装
- @Results:可以与@Result 一起使用,封装多个结果集 (等同于 xml 中的 ResultMap)
- @ResultMap:实现引用@Results 定义的封装
- @One:实现一对一结果集封装
- @Many:实现一对多结果集封装
- @SelectProvider: 实现动态 SQL 映射
- @CacheNamespace:实现注解二级缓存的使用
一对一
/**
* 查询所有账户,并且获取每个账户所属的用户信息
* @return
*/
@Select("select * from account")
@Results(id="accountMap",value = {
@Result(id=true,column = "id",property = "id"),
@Result(column = "uid",property = "uid"),
@Result(column = "money",property = "money"),
@Result(property = "user",column = "uid",
one=@One(select="com.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
})
List findAll();
一对多
/**
* @Results 等同于 Sql映射文件(mapper.xml) 中 resultMap 节点
* id : 唯一标识,以便其他@Select注解标记的方法引用结果集
* 等同于 Sql映射文件(mapper.xml) 中 resultMap 节点中的 id属性
* value : 指定如何映射结果集
* @Result
* id : 代表映射是否是主键 true:是 false:不是 (默认值)
*
* @ResultMap 表示引用 其他 @Results的 id属性的值
* @return
*/
@Select("select * from user")
@Results(id="userMap",value={
@Result(id=true,column = "id",property = "userId"),
@Result(column = "username",property = "userName"),
@Result(column = "address",property = "userAddress"),
@Result(column = "sex",property = "userSex"),
@Result(column = "birthday",property = "userBirthday"),
@Result(property = "accounts",column = "id",
many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
List findAll();
4、逆向工程(Mybatis官方提供的)
概念:就是由 数据库表 生成 pojo,mapper接口,mapper.xml (只能生成单表CRUD)
eclipse : 需要一个普通的Java项目。
idea : 需要一个Maven项目。
我们要做的:
1、改数据库的连接信息
2、改包名
3、指定要逆向生成的表名与类名
tb_user (表名) ---- TbUser (默认的类名) ---- User (自定义类名)
4、右键 run ---- eclispe
双击运行插件 ---- idea