0. 重点
- 配置MyBatis环境
- CRUD操作
1.使用xml配置文件
2.使用注解- 利用Lombok插件简化对象实例的基本操作,e.g.,getter/setter/…
- 查询结果处理:一对多、多对一
- 动态SQL:类似多态,可以根据输入的不同条件,生成对应的SQL语句
1. 简介
1.1什么是MyBatis?
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
1.2怎么获取MyBatis?
Maven获取
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
Github
中文文档:https://mybatis.org/mybatis-3/zh/index.html
1.3什么是持久层?
数据持久化
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
内存:断电即失
数据库(jdbc) / IO文件持久化
为什么需要持久化?
断电即失:有一些对象不能丢失
1.4持久层
完成持久化工作的代码块
层界限明显
1.5为什么需要MyBatis?
辅助程序员将数据存入数据库
传统的JDBC代码太复杂。简化,框架,自动化。
2. 第一个MyBatis程序
思路: 搭建环境 -> 导入MyBatis -> 编写代码 -> 测试
2.1 搭建环境
搭建数据库
2.2 搭建Maven项目
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
2.3 MyBatis配置
https://mybatis.org/mybatis-3/zh/getting-started.html
3.CRUD
基本步骤:
- 创建接口
- 实现接口
a) 利用xml配置文件
b) 利用注解 - 测试
3.1 查找
UserMapper.java
// 根據ID查詢用戶 定义接口
User getUserByID(int id);
UserMapper.xml
// 实现接口
<select id="getUserByID" parameterType="int" resultType="com.kuang.pojo.User">
select * from mybatis.user where id = #{id}
</select>
UserDaoTest.java
@Test
public void getUserByID(){
/***
* 使用try創建sqlSession實例,避免了關閉操作
*/
try(SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserByID(1);
System.out.println(user);
}
}
3.2 插入
// 增删改需要提交事务
@Test
public void addUser(){
try (SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int res = userMapper.addUser(new User(4,"李四","123456"));
if (res > 0){
System.out.println("插入成功!");
}
// 提交事务
// 没有这行,不能提交数据库
sqlSession.commit();
}
}
3.3修改
3.4删除
注:增删改需要提交事务!!!!
3.5 Map
如果数据库的表中字段太多,可以考虑用map处理。因为,每次new一个新的对象,需要对每个字段赋值,而使用map,根据key-value与数据库对应字段对应起来。
3.6 模糊查询
-
Java代码执行的时候,传递通配符:%
-
在Sql拼接中使用通配符。(推荐)
<select id="likeUser" resultType="com.kuang.pojo.User">
select * from mybatis.user where name like "%"#{value}"%"
</select>
4. 配置解析
4.1 核心配置文件
• properties(属性)
• settings(设置)
• typeAliases(类型别名)
• typeHandlers(类型处理器)
• objectFactory(对象工厂)
• plugins(插件)
• environments(环境配置)
environment(环境变量)
- transactionManager(事务管理器)
- dataSource(数据源)
• databaseIdProvider(数据库厂商标识)
• mappers(映射器)
4.2 环境配置(environments)
尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
事务管理器(transactionManager)
在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]"):
• JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
• MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。
默认:JDBC
数据源(dataSource)
有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
默认:POOLED
4.3属性(properties)
1.编写配置文件
<!-- <property name="driver" value="com.mysql.cj.jdbc.Driver"/>-->
<!-- <property name="url" value="jdbc:mysql://192.168.56.10:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8"/>-->
<!-- <property name="username" value="root"/>-->
<!-- <property name="password" value="root"/>-->
2.在核心配置文件引入
<properties resource="db.properties">
<!-- 外部配置优先级更高 /-->
<property name="password" value="root"/>
3.直接引入外部文件
# db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://192.168.56.10:3306/mybatis?userSSL=true&useUnicode=true&characterEncoding=UTF-8
username=root
password=root
如果字段相同,外部文件优先级更高!!!
4.4 类型别名(typeAliases)
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
Way1:
<!--给实体类起别名-->
<typeAliases>
<typeAlias type="com.kuang.pojo.User" alias="User"/>
</typeAliases>
Way2:
<!--指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean-->
<!--在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。不区分大小写-->
<typeAliases>
<package name="com.kuang.pojo"/>
</typeAliases>
对于方法2,加注解时,类名失效;
注2.方法一,适用于方法类少的情况;方法二,适用于方法类多的情况。
4.5映射器(mappers)
注册绑定编写的Mapper文件
四种方法:官网
方法1:
<!-- 使用相对于类路径的资源引用 -->
<!--每一个Mapper.XML都需要在此注册-->
<mappers>
<mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>
方法2:
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
<mapper class="com.kuang.dao.StudentMapper"/>
<mapper class="com.kuang.dao.TeacherMapper"/>
</mappers>
方法3:
<!-- 将包内的映射器接口实现全部注册为映射器 -->
对于方法2和方法3:
注意点:
- 接口与他的Mapper配置文件必须同名
- 接口与他的Mapper配置文件必须在同一个包下。
4.6 作用域(Scope)和生命周期
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoryBuilder
一旦创建了 SqlSessionFactory,就不再需要它了。
SqlSessionFactory
一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
类似数据库连接池。类比线程池
SqlSession
每个线程都应该有它自己的 SqlSession 实例。类比线程
用完之后需要及时关闭,避免资源浪费
5. 属性名与字段名不一致
Eg 属性名password 字段名:pwd
利用resultMap建立属性名与字段名的对应关系。
<resultMap id="userMap" type="User">
<result column="id" property="id"></result>
<result column="name" property="name"/>
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserByID" parameterType="int" resultMap="userMap">
select * from mybatis.user where id = #{id}
</select>
5.1 resultMap
是MyBatis 中最重要最强大的元素
参考:官网
6. 日志
官网
mybatis-config.xml
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
结果:
6.1日志工厂:
<configuration>
<settings>
...
<setting name="logImpl" value="LOG4J"/>
...
</settings>
</configuration>
利用日志信息,调试、排错。
7. 分页
7.1 利用数据库提供的Limit实现分页查询
两个参数:startIndex和pageSize
7.2 利用Java中RowBounds实现分页(早期,不推荐)
注:前者是物理分页,后者是逻辑分页!!!
逻辑分页:先查出所有数据,然后显示指定的范围。
8. 使用注解开发
8.1 面向接口编程
8.2 使用注解开发
注解在接口上实现:
@Select("select * from user")
List<User> getUsers();
注册:
<mappers>
<mapper class="com.kuang.dao.UserMapper"/>
</mappers>
测试:
@Test
public void getUserByID(){
/***
* 使用try創建sqlSession實例,避免了關閉操作
*/
// SqlSession sqlSession1 = MybatisUtils.getSqlSession(); alt+enter 代码补全
try(SqlSession sqlSession = MybatisUtils.getSqlSession()){
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.getUsers();
// System.out.println(users);
for (User user : users) {
System.out.println(user);
}
}
}
结果:
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心。MyBatis建议使用xml文件配置,而非注解。
注解:
本质:反射
底层:动态代理
8.3 CRUD
// 查找所有用户
@Select("select * from user")
List<User> getUsers();
// 按id查找用户
@Select("select * from user where id = #{id}")
User getUserByID(@Param("id") int id);
// 增删改,与此类似。
// 在创建工具类的时候自动提交事务!!!
sqlSessionFactory.openSession(true);
// 不设置autoCommit,默认为false
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
public SqlSession openSession(boolean autoCommit) {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, autoCommit);
}
9.Lombok
9.1.安装插件:
9.2.导入Jar包:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
9.3.在实体类上加注解:
import lombok.Data;
@Data
public class User {
private int id;
private String name;
private String password;
}
9.4.原始与Lombok比较
插件,避免了重复性工作,比如,为每个属性构造getter setter方法。
原始操作:
Lombok注解:
Lombok常用的注解:
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @NoArgsConstructor
@Data
可以自定义与Lombok同时使用。并非对立。
10.查询
10.1多对一情况
问题:多个学生对应一个老师,查询每个学生信息,及其对应的老师。
普通SQL语句:
利用Mybatis
首先给出直接复制SQL语句,得到的结果:
并没有查到对应老师的信息。
原因:resultType=”Student”
返回值与此类型不匹配。
为了匹配SQL返回值类型与自定义类型,MyBatis提供两种方法:
方法1:嵌套查询
<!--
思路:
1.查询所有的学生信息
2.根据查询出来的学生的tid,寻找对应的老师,子查询
-->
<select id="getStudent" resultMap="StuTea">
select * from student
</select>
<resultMap id="StuTea" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="Teacher">
select * from teacher where id = #{id}
</select>
利用resultMap保存返回的结果。
方法2:联表查询
<select id="getAllStudent" resultMap="StuTea">
select s.id as sid,s.name as sname,t.name as tname from student s, teacher t where s.tid = t.id
</select>
<resultMap id="StuTea" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="name" column="tname"/>
</association>
</resultMap>
需要指出,这两种方法的结果是一样的。
方法一是查询了teacher的所有信息(id和name),方法二只查询了teacher表的name。
10.2一对多情况
一对多的情况下,一个老师+多个学生(List),即,返回值是一个集合。此时,如何把返回值与实体类进行映射?
返回值映射到对象:
<association property="teacher" javaType="Teacher">
<result property="name" column="tid"/>
</association>
返回值映射到集合:
<collection property="student" ofType="Student">
<result property="name" column="sname"/>
</collection>
也是两种方法。
11. 动态SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。
• if
• choose (when, otherwise)
• trim (where, set)
• foreach
12. 缓存
12.0 基础知识
12.0.1 什么是缓存?
存在内存中的数据
12.0.2 为什么要缓存?
查询重复数据时,不必再查询数据库,直接读取缓存即可。即:减少和数据库的交互次数,减少系统开销,提高系统效率。
12.0.3 什么样的数据使用缓存?
经常查询且不经常改变的数据
12.1一级缓存
默认开启,只在sqlSession中有效,实际相当于局部变量。
12.2二级缓存
默认开启。
开启之后,同一个Mapper里面,每一次查询的结果都可以存在缓存中(引用有最大值)。
所有的数据都先放在一级缓存中,当sqlSession关闭时,才会提交到二级缓存中。