Mybatis学习笔记
1、搭建环境
1.1 搭建数据库
以个人为例,在WampServer中的MySQL创建mybatis数据库,同时创建mybatis表
1.2 创建Maven项目(模块)
1.3 导入依赖
在pom.xml的dependencies中加入以下代码。
如果在父项目的pom.xml中添加以下依赖,那么在子项目中即可使用,无需再次添加。
是否需要将依赖写在父项目或者子项目中,视情况而定。
mysql
mysql-connector-java
8.0.19
org.mybatis
mybatis
3.5.6
junit
junit
4.13
1.4 添加核心配置文件
在模块中的resource文件夹下添加mybatis-config.xml,并写入以下代码
<?xml version="1.0" encoding="UTF8" ?>
- url、username、password视情况修改
- 对于每一个新创建的mapper的xml文件,都需要在mappers标签下进行注册,格式如上所示。
- 为了避免引用错误,尽量将Mapper文件写在Resource文件夹下
2、SqlSession工具类创建
- 这个工具类主要用于对SqlSessionFactory的初始化配置
package mybatis;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class Utils {
private static SqlSessionFactory sqlSessionFactory;
// 初始化Mybatis配置
static {
try {
String resource = "mybatis-config.xml"; // 配置文件名,可更改
InputStream inputStream = Resources.getResourceAsStream( resource );
sqlSessionFactory = new SqlSessionFactoryBuilder().build( inputStream );
} catch ( IOException e ) {
e.printStackTrace();
}
}
public static SqlSession getSqlSession() {
return sqlSessionFactory.openSession();
}
}
3、创建实体类
- 实体类根据需求创建
- 一般包含的元素与数据库表中的字段一一对应。
package pojo;
public class User {
private int id;
private String name;
public User() {
}
public User( int id, String name ) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
3、编写接口
- 根据业务需求,编写所需要的业务方法
package mybatis;
import org.apache.ibatis.annotations.Param;
import pojo.User;
import java.util.List;
public interface userMapper {
List< User > getUserList();
void insertUser( @Param( "user" ) User user );
void deleteUser( int id );
void updateUser( @Param("id") int id, @Param("name") String name );
}
4、编写接口Mapper.xml
-
这个xml文件的作用于接口实现类的作用相同,只是Mybatis将JDBC代码省略,我们只需写出相应的sql语句即可
-
namespace里面放的是接口名(全限定名)
-
每个标签里面的 id 对应 方法名
-
resultType可以放实体名(全限定名)和String等类型
-
Mapper写完之后记得在配置文件 config.xml 中注册
-
参数类型需要在接口方法参数中通过注解@param来进行配置
<?xml version="1.0" encoding="UTF-8" ?>
insert into user(id, user) values(#{user.id}, #{user.name})
delete from user where id = #{id}
update user SET user = #{name} WHERE id = #{id}
5、获取接口实现类
- 在业务层需要与数据库交互时,可通过以下代码来获取DAO实现类
SqlSession sqlSession = Utils.getSqlSession();
userMapper userMapper = sqlSession.getMapper( userMapper.class );
userMapper.deleteUser( 3 );
sqlSession.commit();
sqlSession.close();
// Mybatis CRUD操作
public class MybatisTest {
@Test
public void test() {
// 在try的括号中开启sqlSession,无需管理流的关闭
// 语句块结束之后,能够自动关闭sqlSession
try ( SqlSession sqlSession = Utils.getSqlSession() ) {
// sqlSession.getMapper(接口名.class)
// 在配置文件xml中实现接口,得到实现类
userMapper userMapper = sqlSession.getMapper( userMapper.class );
// select
List< User > userList = userMapper.getUserList();
for ( User user : userList ) {
System.out.println( user );
}
// insert
userMapper.insertUser( new User( 3, "杨鑫" ) );
// update
userMapper.updateUser( 3, "林耀博" );
// delete
userMapper.deleteUser( 3 );
// select 不需要commit
// insert、delete、update 事务操作需要commit
sqlSession.commit();
}
}
}
6、CRUD
6.1 select
Map map = new HashMap();
map.put("key1","value1");
map.put("key2","value2");
mapper.getUserList(map);
6.2 insert
insert into user(id, user) values(#{user.id}, #{user.name})
6.3 update
update user set user = #{name} where id = #{id}
6.4 delete
delete from user where id = #{id}
6.5 模糊查询SQL
select * from user where name like "%"#{name}"%"
select * from user where name like concat('%',#{name},'%')
7、配置优化
7.1 属性优化
- 通过配置文件properties存储相关信息
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false
username=root
password=
- 在核心配置文件mybatis-config.xml中添加内容
- 通过${key}获取配置文件中对应的value值
7.2 别名优化
7.2.1 typeAlias
- 在核心配置文件mybatis-config.xml中添加字段 typeAliases
- 存在的意义是减少类全限定名的冗余
- 在底下的所有Mapper中均可使用这些别名
7.2.2 package
- 也可以指定一个包名,Mybatis会在包名下面搜索需要的Java Bean
7.2.3 注解@Alias (最方便)
- 也可以通过注解@Alias(" "),在实体类的上方声明
- 无需通过typeAliases标签配置
@Alias("User")
public class User {
private int id;
private String name;
/*
* todo
*/
}
8、设置
9、分页
9.1 SQL Limit分页
select * from user limit 0,3; //从第0(1)条记录开始,选取3条
9.2 RowBounds分页
RowBounds rowBounds = new RowBounds(0,3);
//第一个参数要写全限定名,指向某一个Mapper接口中的某一个方法
List list = sqlSession.selectList("mybatis.userMapper.getUserList", null, rowbounds);
9.3 PageHelper分页插件
-
文档地址
https://pagehelper.github.io/docs/howtouse/
9.3.1 使用步骤
- 导入Maven依赖
com.github.pagehelper
pagehelper
4.2.0
- 在mybatis-config.xml中添加默认plugin配置(添加在environment上面)
9.3.2 使用范例
@Test
public void searchUserByParam()
{
int pageIndex = 2; //获取第2页的数据
int pageSize = 10; //每页10条数据
String orderBy = "create_time ASC"; //排序
//分页信息
//PageHelper.startPage只会在接下来最近的一条查询语句中生效
//且必须接的是select语句,不能是增删改语句,否则失效
PageHelper.startPage(pageIndex, pageSize, orderBy);
//查询条件参数类
UserSearchParam userSearchParam = new UserSearchParam();
//userSearchParam.setUserName("pan_junbiao的博客"); //查询条件1
//userSearchParam.setProvince("广东省"); //查询条件2
//执行分页查询
//userMapper.searchUserList()返回类型为 Page 然后转化为 PageInfo
PageInfo userInfoPage = new PageInfo(userMapper.searchUserList(userSearchParam));
//打印用户列表
List userInfoList = userInfoPage.getList();
userInfoList.stream().forEach(System.out::println);
//打印分页信息
System.out.println("当前页码:第" + userInfoPage.getPageNum() + "页");
System.out.println("分页大小:每页" + userInfoPage.getPageSize() + "条");
System.out.println("数据总数:共" + userInfoPage.getTotal() + "条");
System.out.println("总页数:共" + userInfoPage.getPages() + "页");
}
10、多对一
public class student {
int id;
String name;
Teacher teacher;
}
10.1 按照查询嵌套处理(子查询)
10.2 按照结果嵌套处理(联表查询)
11、一对多
public class Teacher {
int id;
String name;
List students;
}
11.1 按照查询嵌套处理(子查询)
11.2 按照结果嵌套处理(联表查询)
12、动态SQL
12.1 IF
12.2 choose、when、otherwise(类似switch)
12.3 where
- where元素只会在至少有一个子元素的条件返回SQL子句的情况下才去插入WHERE"子句。
- 而且,若语句的开头为AND"或'OR'"where元素也会将它们去除。
12.4 set
- set元素会动态前置SET关键字,同时也会删掉多余的逗号
update Author
username=#{username},
password=#{password},
email=#{email},
bio=#{bio}
where id=#{fid}
12.5 trim
| 属性 | 描述 |
|---|---|
| prefix | 给sql语句拼接的前缀 |
| suffix | 给sql语句拼接的后缀 |
| prefixOverrides | 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND" |
| suffixOverrides | 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定 |
示例:
12.6 SQL片段
- 使用sql标签抽取公共的部分
- 在需要的地方使用include标签引用即可
title = #{title}
and author = #{author}
12.7 foreach
HashMap map = new HashMap();
ArrayList ids = new ArrayList();
ids.add(1);
map.put( "ids",ids ) ;
List blogs = mapper.queryBlogForeach( map );
for (Blog blog : blogs) {
system.out.print1n(blog);
}
- collection的对应:
- map的key为ids,value为id列表
- id列表变量名为ids,select标签的parameterType为java.util.List
13、缓存
- MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
- MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
- 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)。
- 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
- 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存。
13.1 一级缓存
- 一级缓存也叫本地缓存:
- 默认情况开启一级缓存。
- 与数据库同一次会话期间(SqlSession)查询到的数据会放在本地缓存中。
- 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库;
13.2 二级缓存
-
二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存。
-
基于namespace级别的缓存,一个名称空间(Mapper接口),对应一个二级缓存。
-
工作机制:
- 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中;
- 如果当前会话关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中。
- 新的会话查询信息,就可以从二级缓存中获取内容;
- 不同的mapper查出的数据会放在自己对应的缓存(map)中;
-
使用步骤:
- 在mybatis-config.xml中开启全局缓存
- 在需要使用二级缓存的Mapper中开启
? 也可以自定义参数
小结:
-
只要开启了二级缓存,在同一个Mapper下就有效。
-
所有的数据都会先放在一级缓存中。
-
只有当会话提交,或者关闭的时候,才会提交到二级缓存中!
-
缓存查询顺序:
- 二级缓存
- 一级缓存
- 数据库查询
14、注意事项
14.1 xml文件资源导出失败时
- 在pom.xml添加以下代码
- 这样写在java文件夹下的配置文件和Mapper.xml都能导出了
src/main/resources
**/*.properties
**/*.xml
true
src/main/java
**/*.properties
**/*.xml
true
14.2 resource,路径要用 / 分开 ,不要用 .
14.3 实体类属性名和数据库字段名不一致的问题
- 方案一:SQL语句中,对应字段起别名 as xxx
- 方案二:resultMap
数据库:id user
实体类:id name
第二个字段没有对应
15、SpringBoot+Mybatis
import org.apache.ibatis.annotations.*;
import springboot.bean.Department;
//Mapper接口通过@Autowired注入
@Mapper //告诉mybatis这是一个操作数据库的mapper
public interface DepartmentMapper {
@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);
@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);
@Options(useGeneratedKeys = true,keyProperty = "id") //使用自动生成主键,keyProperty = "id"表示id为封装主键
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}