# MyBatis学习笔记
**Repository Path**: cljloves/notes_mybatis
## Basic Information
- **Project Name**: MyBatis学习笔记
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2019-09-02
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: learn
## README
# MyBatis 学习笔记
## 1. mybatis 入门
### 1.1 mybatis 概述
#### 1.1.1 什么是框架
框架是软件开发中的技术层面上的一套解决方案(高可复用),不同的框架解决不同的问题。
框架封装了很多技术细节,开发者可以使用简单方式实现业务,提高开发效率。
框架本身是商业半成品,只有加上业务,才能成为商业产品。
#### 1.1.2 三层架构
展示层:展示数据
业务层:处理业务需求
持久层:和数据库交互
mybatis 就是一个持久层框架。
#### 1.1.3 持久层技术解决方案
1. JDBC
- Connection
- PreparedStatement
- ResultSet
- **基本步骤:**
1. 加载注册驱动
```java
Class.forName("com.mysql.jdbc.Driver");
```
2. 通过 url 获取 Connection
```java
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?charsetEncoding=utf-8", "root", "password");
```
3. 编写 sql
```java
// ? 表示参数占位符
String sql = "select * from user where username = ?";
```
4. 获取预处理 statement
```java
preparedStatement = connection.preparedStatement(sql);
// 设置参数,sql语句中的参数序号从1开始
preparedStatement.setString(1, "张三");
```
5. 执行并得到结果集
```java
resultSet = preparedStatement.executeQuery();
```
6. 遍历结果集
```java
while (resultSet.next()){
String id = resultSet.getString("id");
String username = resultSet.getString("username");
}
```
7. 释放资源,按顺序释放 resultSet、preparedStatement、connection
2. Spring 的 Jdbctemplate
- 它是对 JDBC 的简易封装
3. Apache 的 DBUtils
- 和 Spring 的 JdbcTemplate 类似,是 JDBC 的简易封装
- **以上这些都不是框架**
- JDBC 是规范
- Spring 的 JdbcTemplate 和 Apache 的 DBUtils 都只是工具类
#### 1.1.4 mybatis 介绍
mybatis 是一个优秀的基于 Java 的持久层框架,内部封装了 jdbc 的诸多操作细节,开发者只需要关注 sql 语句本身,省去了很多样板代码。
它使用了 ORM(Object Relational Mapping)把结果集封装到了实体类。
### 1.2 mybatis 环境搭建
#### 1.2.1 mybatis 环境搭建的基本步骤
1. 首先,我们是使用 maven 搭建项目
2. 导入 mybatis 的 maven 依赖 GAV,至少需要 mybatis 本身和 mysql-connector-java
```xml
org.mybatis
mybatis
x.y.z
mysql
mysql-connector-java
x.y.z
```
3. 创建实体类
```java
package com.test.domain;
import java.io.Serializable;
import java.util.Date;
public class User implements Serializable {
private Integer id;
private String username;
private Date birthday;
private String gender;
private String address;
// 省略了getter和setter没列出来
}
```
4. 创建 dao 接口
```java
package com.test.dao;
import com.test.domain.User;
import java.util.List;
/**
* 用户的持久层接口
*/
public interface IUserDao {
/**
* 查询所有操作
* @return
*/
List findAll();
}
```
5. resources 目录下创建 mybatis 的主配置文件 mybatisConfig.xml
```xml
```
6. 在 resources 目录下创建上述路径中的 mapper 映射配置文件
```xml
```
#### 1.2.2 mybatis 配置注意事项
1. 创建 IUserDao.java 和 IUserDao.xml 时,是照顾以前的编码习惯,所以命名为 Dao。但是 MyBatis 中也把持久层的操作接口和映射文件命名为 Mapper。按开发者的习惯不同,我们都需要知道 Dao 和 Mapper 是代表一个意思。
2. mybatis 的映射配置文件位置必须和 dao 接口的包结构相同。
3. 映射配置文件的 mapper 标签 namespace 属性的值必须是 dao 接口的全限定类名。
4. 映射配置文件的操作配置,其 id 属性的值必须是 dao 接口的方法名。
**按照以上 2. 3. 4.条配置后,开发中就不必去写 dao 的实现类,将由 mybatis 框架动态代理生成代理类供开发者使用。**
### 1.3 mybatis 入门案例
#### 1.3.1 基本操作步骤
```java
//1.读取配置文件
InputStream in = Resources.getResourceAsStream("mybatisConfig.xml");
//2.创建SqlSessionFactory工厂
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(in);
//3.使用工厂生产SqlSession对象
SqlSession session = factory.openSession();
//4.使用SqlSession创建Dao接口的代理对象
IUserDao userDao = session.getMapper(IUserDao.class);
//5.使用代理对象执行方法
List users = userDao.findAll();
for(User user : users){
System.out.println(user);
}
//6.释放资源
session.close();
in.close();
```
要记得在 mapper 配置文件中的操作标签设定 resultType 属性,其值为返回类型的全限定类名。这样才能实现 ORM 操作。
#### 1.3.2 基于注解开发的注意点
- 把 IUserDao.xml 移除(mapper 配置与注解不可共存),在 Dao 接口的方法上使用@select 注解,并指定 sql 语句
- 在 mybatisConfig.xml 中 mapper 标签使用 class 属性,其值为 Dao 接口的全限定类名
### 1.4 mybatis 的基本原理
#### 1.4.1 简易分析
1. 根据主配置文件可以得到**连接信息**,也就能注册驱动,获取 connection。同时也知道了 mapper 配置的位置。
2. 在 mapper 配置文件中可以得到**映射信息**,由 sql 语句可以得到 preparedStatement,从而执行得到 ResultSet,配合 resultType 可以反射操作,最终实现 ORM。
**补充说明:**
Mapper(映射信息对象)中必须包含两个信息:一、是要执行的 sql 语句;二、是方法要返回的类型的全限定类名,好让框架完成 ORM 封装。然后 Mapper 信息被框架加载后,按以下的 key-value 形式保存在内存中。
| string | Mapper |
| :---------------------------: | :----------------------------------: |
| com.test.dao.IUserDao.findAll | Mapper@com.test.dao.IUserDao.findAll |
3. 根据 Dao 接口动态代理创建 Dao 的代理对象
**注意点:**
_ 代理对象使用和被代理对象相同的类加载器
_ 代理对象要实现和被代理对象相同的接口 \* 如何代理:需要实现 InvocationHandler 接口,我们自己提供方法内容,实现去执行对应的 sql。
#### 1.4.2 手写简易 mybatis 框架
1. 分析 1.3.1 中所使用到的几个类
1. Resources,它提供了加载本地配置文件到 InputStream 的方法。
2. Mapper,它是映射信息实体类,只包含两个属性:
```java
private String sql;
private Stirng resultType;//实体类的全限定类名
```
3. Configuration,它是我们简易框架的配置类,包含以下属性:
```java
private String driver;
private Stirng url;
private String username;
private String password;
private Map mappers;//映射信息的map
```
4. XMLConfigLoader,它使用 DOM 解析工具解析主配置文件的输入流,提供返回 Configuration 对象的方法。
5. SqlSessionFactoryBuilder,它通过传入的主配置文件输入流创建 SqlSessionFactory。在这个过程中,它会使用 4 中的类解析主配置文件,生成 Configuration 对象,供 SqlSessionFactory 使用。
6. SqlSessionFactory 及其实现类 DefaultSqlSessionFactory,DefaultSqlSessionFactory 持有一个 Configuration 对象。并且提供一个返回 SqlSession 的 openSession 方法,SqlSession 对象也持有 Configuration。
7. SqlSession 及其实现类 DefaultSqlSession,它使用 Configuration 中的 driver,url,username,password 完成加载驱动,获取 Connection。它还提供获取 Mapper 代理对象的方法和关闭 session 的方法。以下给出获取 Mapper 代理的方法实现:
```java
/**
* 用于创建代理对象
* @param daoInterfaceClass dao的接口字节码
* @param
* @return
*/
@Override
public T getMapper(Class daoInterfaceClass) {
return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),
new Class[]{daoInterfaceClass},new MapperProxy(configuration.getMappers(),connection));
}
```
8. MapperProxy,实现 InvocationHandler 接口,在 invoke 方法中实现查找具体 mapper 并递交给 Exector 执行。
9. Executor,它是 sql 语句的最终执行者。获取 PreparedStatment,执行并获取 ResultSet,以及 ORM 封装进实体类。
2. 总结:以上为简易的 mybatis 基本原理分析。简单的概括就是:**加载配置信息,创建 Mapper 代理对象,实现查询功能。**
## 2. mybatis 基本使用
- mybatis 的默认配置中,是没有开启自动提交的,所以如果在增删改操作后没手动提交,是会自动回滚事务的,即操作失效。只需添加一句:
```java
//提交事务
sqlSession.commit();
```
- JUnit 单元测试的使用技巧:
在我们测试时,如果不采取一定的手段,会在每个@Test 注解的方法中写大量的样板代码,我们可以利用@Before 和@After 两个注解,让 JUnit 为我们自动完成这些操作。
```java
/**
* 测试mybatis的crud操作
*/
public class MybatisTest {
private InputStream in;
private SqlSession sqlSession;
private IUserDao userDao;
@Before//用于在测试方法执行之前执行
public void init()throws Exception{
//1.读取配置文件,生成字节输入流
in = Resources.getResourceAsStream("mybatisConfig.xml");
//2.获取SqlSessionFactory
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
//3.获取SqlSession对象
sqlSession = factory.openSession();
//4.获取dao的代理对象
userDao = sqlSession.getMapper(IUserDao.class);
}
@After//用于在测试方法执行之后执行
public void destroy()throws Exception{
//提交事务
sqlSession.commit();
//6.释放资源
sqlSession.close();
in.close();
}
...
```
### 2.1 mybatis 的单表 crud
#### 2.1.1 增
```java
/**
* 保存用户
* @param user
*/
void saveUser(User user);
```
```xml
select last_insert_id();
insert into user(username,address,sex,birthday)values(#{userName},#{userAddress},#{userSex},#{userBirthday});
```
#### 2.1.2 删
```java
/**
* 根据Id删除用户
* @param userId
*/
void deleteUser(Integer userId);
```
```xml
delete from user where id = #{uid}
```
#### 2.1.3 改
```java
/**
* 更新用户
* @param user
*/
void updateUser(User user);
```
```xml
update user set username=#{userName},address=#{userAddress},sex=#{userAex},birthday=#{userBirthday} where id=#{userId}
```
#### 2.1.4 查
```java
/**
* 根据id查询用户信息
* @param userId
* @return
*/
User findById(Integer userId);
/**
* 根据名称模糊查询用户信息
* @param username
* @return
*/
List findByName(String username);
/**
* 查询总用户数
* @return
*/
int findTotal();
/**
* 根据queryVo中的条件查询用户
* @param vo
* @return
*/
List findUserByVo(QueryVo vo);
```
```java
public class QueryVo {
private User user;
// 省略getter和setter
}
```
```xml
```
### 2.2 mybatis 的参数和返回值
- 当方法只有一个参数且该参数为基本类型或包装类时,mybatis 对 sql 中参数占位符的名字没有具体要求,叫什么都可以。参考 2.1.2 中的示例。
- **OGNL 表达式**
Object Graphic Navigation Language,对象图导航语言。
它通过对象的取值方法获取数据,写法上省略了 get。
例:获取用户名
类方法调用写法:user.getUsername();
OGNL 表达式写法:user.username
mybatis 中可以直接写 username 而不需要加 user.是因为在 parameterType 中已经指定了类,所以不需要写对象名。
- parameterType 可接受的值
- **基本类型与包装类**
- **POJO 对象**
mybatis 使用 ognl 表达式解析对象字段的值,#{}或\${}括号中的值是 pojo 的属性名。
- **POJO 的包装对象**
当需要进行复杂的查询业务时,传入的查询 pojo 对象中还会包含别的 pojo。在上方 2.1.4 的 findUserByVo 有示例。这种由多个对象组成一个对象作为查询条件的方式广泛应用在实际开发中。
- 返回结果集相关说明
- 结果集字段与实体属性能一一对应:
- 一切正常
- 结果集字段与实体属性不能对应上:
- 如果不做处理,就会出现 orm 不能自动映射
- 在 windows 下 mysql 数据库不区分字段大小写,所以做到一些神奇的映射,例:字段 username,属性 userName。但是在 Linux 下 mysql 是严格区分大小写的。
- 所以需要我们把不能一一对应的字段-属性给对应上就能解决问题:
- 方案一、sql 语句中使用 as 更改结果集中的字段名,从而一一对应,进而解决问题。**但是这样做很低效,且不科学**
- 方案二、在 mapper 的 xml 中,增加 resultMap 映射关系配置:
```xml
```
然后在方法配置中,将 resultType 更换成 resultMap:
```xml
```
这样,findByName 方法就能将结果按照 userMap 配置的规则映射到`com.test.domain.User`类对象中了。可以看出的是,该方案需要多解析一道 xml,所以性能肯定较方案一低,但是大大提升了开发效率。
### 2.3 mybatis 的 DAO 编写
mybatis 支持我们自己编写 DAO 实现类,虽然通常我们不这么做。其基本步骤:
1. 读取 mybatis 主配置文件生产输入流
2. 使用 SqlSessionFactoryBuilder 传入主配置输入流,获取 SqlSessionFactory
3. factory.openSession()获取 session
4. 使用 session 对象执行 statement,这里的 statement 是定位具体执行某个方法的声明,例:`com.test.dao.IUserDao.findAll`
5. 然后就可以正常使用,得到结果
6. 最后要记得释放资源
### 2.4 mybatis 配置的细节
- 主配置引用外部 properties 配置文件
- 在 resources 目录添加数据库配置文件 jdbcConfig.properties:
```properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/dbname
jdbc.username=root
jdbc.password=1234
```
- 在 mybatis 主配置文件中:
```xml
```
- 同样的,主配置文件中 Mapper 标签也支持用 resource 属性与 url 属性来引用配置文件,方便我们灵活的配置。
- 配置别名,方便引用实体类
- mybatis 主配置文件中可以添加``标签来配置别名信息,使用``或``标签配置精确到具体某个类或者包路径下所有类的别名。配置了别名可以方便的以大小写不敏感的方式引用。
```xml
```
注意,如果使用 package 标签配置,则实体的别名默认为其类名。
- mappers 标签内使用 package 标签来按包指定 DAO 接口
```xml
```
## 3. mybatis 的深入与多表
### 3.1 mybatis 的连接池
**连接池**就是一个提供可用链接的有限资源容器,它必须是线程安全的,有着队列的 FIFO 特性。感觉上类似于线程池。连接池于系统时就初始化完毕,可以降低获取链接消耗的时间。
mybatis 配置连接池的位置在 mybatis 主配置 xml 中的 environment 标签的``子标签中,可以配置数据源属性`type`,有 3 种类型:
- **POOLED**,采用传统 javax.sql.DataSource 规范,mybatis 有规范的实现类 PooledDataSource,用了池的思想来管理链接。
- **UNPOOLED**,同上也遵循了规范,有实现类 UnpooledDataSource,但是没有用池的思想管理链接,每次都是新建链接。
- **JNDI**,用服务器提供的 JNDI 技术实现,来获取 DataSource 对象,不同服务器能拿到的 DataSource 不一样。**注意**:如果不是 web 或 maven 的 war 工程,是不能使用的。我们常用的 tomcat 服务器,采用的是 dbcp 连接池。
**PooledDataSource**获取链接的核心逻辑:
1. 先去**空闲链接集合**中看看有没有链接可用,没有就进行下一步,否则直接返回集合中的第 0 个
2. 如果无空闲链接,就判断当前活动链接数是否达到限制,否则 new 一个 pooledConnection,扔进**活动连接集合**中
3. 如果已达活动连接数限额,就在**活动连接集合**中拿最老的那个链接处理后返回
我们开发中自然要优先选择**POOLED**类型的数据源使用。
### 3.2 mybatis 的事务控制及涉及的方法
#### 什么是事务?
- 事务(Transaction),是并发控制的基本单位。它是一个操作序列,这些操作要么全部执行完毕,要么都不执行。
#### 事务的四大特性 ACID
- **Atomicity,原子性**。原子性,取其不可分割之意。这说明一个事务是最基本的操作,没有中间过程状态。事务要么执行完毕,要么出错回滚。
- **CONSISTENCY,一致性**。一个事务必须保护执行前后数据的完整性一致。
- **ISOLATION,隔离性**。一个事务的执行过程中,不受到其他事务的影响。
- **DURABILITY,持久性**。一个被完成的事务,其效果应该是持久化的。
#### 不考虑隔离性会产生的 3 个问题
- **脏读**。事务 A 读到了事务 B 未提交的数据。
- **幻读**。事务 A 读到了事务 B 已提交的数据,导致多次查询结果不一致。
- **不可重复读**。事务 A 读到了事务 B 已提交的数据,导致一个事务中的多次查询结果不一致。
#### 事务的四种隔离级别
- **read uncommitted**。事务 A 能读到事务 B 改变但未提交的数据。脏读、幻读、不可重复读都能发生。
- **read committed**。事务 A 能读到事务 B 改变且已提交的数据。避免了脏读,幻读、不可重复读可能发生。
- **repeatable read**。事务 A 执行过程中读到的数据与事务 A 开始执行那一刻的数据保持一致。避免了不可重复读、脏读,幻读可能发生。
- **serializable**。事务串行化执行,不会出现上面 3 个问题。
#### mybatis 中的事务操作
mybatis 的事务通过 sqlSession 对象的 commit 方法和 rollback 方法实现事务的提交与回滚。但最终都是在操作`java.sql.Connection`对象的 commit 与 rollback。
在执行 sqlSessionFactory.openSession 方法时,可以传入参数`true`来激活自动提交。但是我们更推荐手动控制事务的提交与回滚。
### 3.3 mybatis 的动态语句
在 mapper.xml 配置文件中的方法描述里,可以使用``、``、``等标签,实现一些复杂的操作。
- 使用给定的用户信息查找用户(sql 语句中有一个 `where 1=1`):
```xml
```
- 上面的例子还可以替换成``标签的形式,结构会清晰一些:
```xml
```
- 根据传入参数对象中的 ids 集合,查询对象(例子中还使用了``来**复用 sql** 语句):
```xml
select * from user
```
- 由于用到了``和``来抽取复用 sql,就需要注意一点:在``标签中的 sql 语句最好不要加`;`,mapper 的 xml 文件中 sql 语句都不要加`;`是一个良好的实践。
### 3.4 mybatis 的多表查询
#### 表之间的关系
- **一对多**
- **多对一**
- **一对一**
- **多对多**
例子:
- 一个用户可以下多个订单,多个订单属于一个用户。
- 用户->订单:一对多
- 订单->用户:多对一
- 一个人只有一个省份证号,一个身份证号也只对应一个人
- 人-身份证号:一对一
- 一个学生可以被多个老师教,一个老师可以教多个学生
- 学生-老师:多对多
特例:用户-订单关系中,单拿出一个订单看,它只属于一个用户。所以 MyBatis 就把多对一看成了一对一。
#### mybatis 多表示例
##### 用户与账户:一对一,一对多
一个用户可以有多个账户,一个账户只属于一个用户。
- 步骤:
- 建两张表:用户表、账户表
- 让用户表与账户表间有一对多的关系,需要在在账户表中添加用户 id 外键
- 建两个实体类:用户、账户
- 让用户与账户两个实体类能体现一对多关系
- 建两个配置文件
- 用户 mapper.xml
- 账户 mapper.xml
- 实现配置:
- 查询用户时,同时得到其所有的账户信息
- 查询账户时,同时得到其所属用户的信息
- 查询 Account 同时得到 User,一对一实现:
- 在 IAccountDao.xml 的 mapper 配置中:
```xml
```
- 其实有经验的话,大致也能猜出 Account 实体类中的属性了
```java
public class Account implements Serializable {
private Integer id;
private Integer uid;
private Double money;
private User user;
// 省略了setter/getter
}
```
- 查询 User 同时得到 List\,一对多实现:
- IUserDao.xml 配置中:
```xml
```
##### 用户与角色:多对多
一个用户可以有多个角色,一个角色也可以分配给多个用户。
- 步骤:
- 建两张表:用户表、角色表
- 让用户表与账户表间有多对多的关系,需要使用中间表,中间表包含各自的主键,在中间表中是外键。
- 建两个实体类:用户、角色
- 让用户与角色两个实体类能体现多对多关系
- 建两个配置文件
- 用户 mapper.xml
- 角色 mapper.xml
- 实现配置:
- 查询用户时,同时得到其所有的角色信息
- 查询角色时,同时得到其所有的用户信息
- 查询角色带用户
```xml
```
- 查询用户带角色
```xml
```
### 3.5 补充:JNDI
在使用 tomcat 容器部署 war 包服务时,需要使用 JNDI,走的是另一套配置方,交由 tomcat 容器通过 JNDI 来管理我们的数据源等信息,必须经过 tomcat 获取,才能成功拿到数据源。
#### 配置方式
- 在 webapp/META-INF/context.xml 中
```xml
```
- 在 resources 的 mybatis 主配置文件中
```xml
```
## 4. mybatis 的缓存和注解开发
### 4.1 mybatis 中的加载时机(查询的时机)
在多表查询时,如果每次都把关联表的信息全部查出来,会影响性能。
比如在用户与账户的例子中:
- 一个用户有上百的账户,我只是查用户信息,这时我们根本不需要把账户信息一道查出来。但是如果我们后面用到了,也能再去加载出来。
- 查询上述用户的某一个账户时,通常我们又是需要查询用户信息的。
这里就有了两种(通常情况)经典实践场景:
- **一对多、多对多:懒加载**
- **一对一、多对一:急加载**
**懒加载**,在真正使用数据时才发起查询,不使用时不查询,按需加载。
**急加载**,不论是否需要使用,都去查询。
#### mybatis 实现懒加载
讲解技术点时,我们不考虑什么时最佳实践,一对一,一对多的懒加载我们都看看:
- 首先,mybatis 默认是关闭了懒加载的,查看官方文档,我们在主配置文件中配置:
```xml
```
- **一对一**
- 在账户的 mapper 文件中修改
```xml
```
可以看出我们修改了 sql 语句,同时在 resultMap 中将 user 配置了 select 属性,配合 uid 字段就可以调用 IUserDao.findById 查询出来 User 信息。所以我们要去给用户添加 findById 方法。
- 在用户 mapper 文件中:
```xml
```
这样,我们就实现了一对一场景的延迟加载。
- **一对多**
- 在用户 mapper 中
```xml
```
- 在账户 mapper 中
```xml
```
这样,我们就实现了一对多场景的延迟加载。
### 4.2 mybatis 的一级/二级缓存
使用缓存,是为了在不必要的情况,利用空间换时间,大大提升性能。
缓存不是万金油,需要分场景:
- 适用场景:
- 经常查询且数据不经常改变。如:省市区行政区域通用数据。
- 数据正确与否对结果影响不大。
- 不适用场景:
- 改变频繁的数据。
- 对数据正确性要求很高。如:商品库存、银行汇率。
#### mybatis 的一级缓存
它是指 SqlSession 对象的缓存。
它会缓存查询结果的**数据对象**,当我们再次查询相同数据时,mybatis 就会先去看看一级缓存是否有这个数据的对象,有就直接返回。
当调用 SqlSession 对象的修改、添加、删除、commit、close,就会清空一级缓存。
#### mybatis 的二级缓存
它是指 SqlSessionFactory 对象的缓存。由同一个 SqlSessionFactory 对象创建的 SqlSession 对象共享 SqlSessionFactory 对象的二级缓存。
它会缓存查询结果的**纯数据**,当 SqlSession 再次查询相同数据时,mybatis 就会先去看看二级缓存是否有这个数据,有就直接构建成对象返回给 SqlSession。
- 启用步骤
- 主配置中添加配置:
```xml
```
- mapper 中添加标签:
```xml
```
- mapper 的具体方法添加`useCache`属性:
```xml
```
### 4.3 mybatis 的基于注解开发
相较于 xml 配置式的方式,基于注解开发起来更快更爽,但是耦合也更高。
由于注解的方式比较直观,这里就只说几点需要注意的地方。
- 基于注解开发的话,就不能让 mybatis 找到相同 mapper 的 xml 文件,即便你没打算使用 xml 方式,mybatis 在扫描时还是会出现冲突,导致出错。
- 使用@Insert @Update @Select @Delete 4 个注解来实现 CRUD,下面给几个示例找找感觉:
- `@Select("select * from user")`
- `@Insert("insert into user(username,address,sex,birthday)values(#{username},#{address},#{sex},#{birthday})")`
- `@Update("update user set username=#{username},sex=#{sex},birthday=#{birthday},address=#{address} where id=#{id}")`
- `@Delete("delete from user where id=#{id} ")`
- `@Select("select * from user where id=#{id} ")`
- `@Select("select * from user where username like #{username} ")`
- `@Select("select * from user where username like '%${value}%' ")`
- `@Select("select count(*) from user ")`
- 使用`@Results`注解实现 resultMap,解决属性名与字段名不匹配的问题
```java
@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.test.dao.IAccountDao.findAccountByUid",
fetchType = FetchType.LAZY))
})
@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.test.dao.IUserDao.findById",fetchType= FetchType.EAGER))
})
```
而且,在向上面这样定义过 Results 了以后,别的方法也可以方便的通过 id 引用:`@ResultMap("userMap")`
同时,代码中还展示了一对多、多对一,以及懒加载、急加载的配置。
- 开启二级缓存
- 首先,主配置文件中:
```xml
```
- 然后,在 Dao 接口类上加注解:
```java
@CacheNamespace(blocking = true)
public interface IUserDao {
...
}
```
## 更多详细配置,可以查看[官方文档](https://mybatis.org/mybatis-3/zh/index.html)