一、MyBatis概述
1.1框架
在文献中看到的framework被翻译为框架
Java常用框架:
SSM三大框架: Spring+SpringMVC+MyBatis
SpringBoot
SpringCloud等等。
框架其实就是对通用代码的封装,提前写好一些接口和类,我们可以在写项目的时候直接写入这些
接口和类(引入框架),基于这些写好的接口和类进行开发,可以大大提高开发效率。
框架一般以jar包的形式存在。(Jar包中有class文件以及各种配置文件等)
SSM三大框架的学习顺序:
方式一:MyBatis、Spring、SpringMVC(建议)
方式二:Spring、MyBatis、SpringMVC
1.2三层架构
表现层(UI):直接跟前端打交互(一是接收前端ajax请求,二是返回json数据给前端)
业务逻辑层(BLL):一是处理表现层转发过来的前端请求(也就是具体业务),二是将从持久层
获
取的数据返回到表现层。
数据访问层(DAL):直接操作数据库完成CRUD,并将获得的数据返回到上一层(也就是业务逻
辑
层)。
Java持久层框架:
MyBatis
Hibernate(实现了JPA规范)
JOOQ
Guzz
Spring Data(实现了JPA规则)
ActiveJDBC
…
1.3 JDBC不足
示列代码1:
示列代码2:
// …
// sql语句写死在java程序中
String sql = “insert into
t_user(id,idCard,username,password,birth,gender,email,city,street,zipcode,ph
one,grade) values(?,?,?,?,?,?,?,?,?,?,?,?)”;
PreparedStatement ps = conn.prepareStatement(sql);
// 繁琐的赋值:思考一下,这种有规律的代码能不能通过反射机制来做自动化。
ps.setString(1, “1”);
ps.setString(2, “123456789”);
ps.setString(3, “zhangsan”);
ps.setString(4, “123456”);
ps.setString(5, “1980-10-11”);
ps.setString(6, “男”);
ps.setString(7, “zhangsan@126.com”);
ps.setString(8, “郑州”);
ps.setString(9, “郑州管城回族区二河大街”);
ps.setString(10, “1000000”);
ps.setString(11, “16398574152”);
ps.setString(12, “A”);
// 执行SQL
int count = ps.executeUpdate();
// …
/ …
// sql语句写死在java程序中
String sql = “select
id,idCard,username,password,birth,gender,email,city,street,zipcode,phone,grade
from t_user”;
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
List userList = new ArrayList<>();
// 思考以下循环中的所有代码是否可以使用反射进自动化封装。
while(rs.next()){
// 获取数据
String id = rs.getString(“id”);
String idCard = rs.getString(“idCard”);
String username = rs.getString(“username”);
String password = rs.getString(“password”);
String birth = rs.getString(“birth”);
String gender = rs.getString(“gender”);
String email = rs.getString(“email”);
String city = rs.getString(“city”);
String street = rs.getString(“street”);
String zipcode = rs.getString(“zipcode”);
JDBC不足:
SQL语句写死在Java程序中,不灵活。改SQL的话就要改Java代码。违背开闭原则OCP。
给?传值是繁琐的。能不能自动化???
将结果集封装成Java对象是繁琐的。能不能自动化???
1.4了解MyBatis
MyBatis本质上就是对JDBC的封装,通过MyBatist完成CRUD
MyBatis在三层架构中负责持久化层,属于持久化层框架
MyBatis的发展历程
MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁
移到了google code,并且改名为MyBatis。2013年11月迁移到Github。
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久
层框架包括SQL Maps(SQL映射)和Data Access Objects(DAOs)。
打开mybatis代码可以看到它的包结构中包含:ibatis
ORM:对象关系映射
O(Object):Java虚拟机中的Java对象
R(Relational):关系型数据库
M(Mapping):将Java虚拟机中的Java对象映射到数据库表中一行记录,或是将数据库表中一行
记录映射成Java虚拟机中的一个Java对象。
Mybatis是一个半自动化的ORM,因为SQL语句是自己编写的。
也有全自动的,比如Hibernate就是全自动的,它调用方法,会自动生成SQL语句。
String phone = rs.getString(“phone”);
String grade = rs.getString(“grade”);
// 创建对象
User user = new User();
// 给对象属性赋值
user.setId(id);
user.setIdCard(idCard);
user.setUsername(username);
user.setPassword(password);
user.setBirth(birth);
user.setGender(gender);
user.setEmail(email);
user.setCity(city);
user.setStreet(street);
user.setZipcode(zipcode);
user.setPhone(phone);
user.setGrade(grade);
// 添加到集合
userList.add(user);
}
// …
ORM图示
MyBatis属于半自动化ORM框架。
Hibernate属于全自动化的ORM框架。
MyBatis框架特点:
支持定制化 SQL、存储过程、基本映射以及高级映射
避免了几乎所有的 JDBC 代码中手动设置参数以及获取结果集
支持XML开发,也支持注解式开发。(mybatis大部分是采用XML方式开发)
将接口和 Java的对象映射成数据库中的记录
体积小好学:两个jar包,两个XML配置文件。
完全做到sql解耦合。
提供了基本映射标签。
提供了映射标签。
提供了XML标签,支持动态SQL的编写。
…
二、MyBatis入门程序
只要你会JDBC,MyBatis就可以学。
2.1版本
软件版本:
IntelliJ IDEA:2022.1.4
Navicat for MySQL:16.0.14
MySQL数据库:8.0.30
组件版本:
MySQL驱动:8.0.30
MyBatis:3.5.10
JDK:Java17
JUnit:4.13.2
Logback:1.2.11
2.2Mybatis下载
从github下载,地址:https://github.com/mybatis/mybatis-3
将框架以及框架的源码都下载下来,下载框架后解压,打开mybatis目录
通过以上解压可以看到,框架一般都是以jar包的形式存在。我们的mybatis课程使用maven,所
以这个jar我们不需要。
官方手册需要。
2.3 MyBatis入门程序开发步骤
写代码前准备:
准备数据库表:汽车表t_car,字段包括:
创建表的SQL脚本:
数据展示如下:
2.2 加载mybatis的五个步骤
- 配置Maven环境,打包方式设置为jar,加载MyBatis,MySQL
CREATE TABLEt_car
(
id
BIGINT(20) NOT NULL AUTO_INCREMENT,
car_num
VARCHAR(255) DEFAULT NULL,
brand
VARCHAR(255) DEFAULT NULL,
guide_price
DECIMAL(10,0) DEFAULT NULL,
produce_time
CHAR(10) DEFAULT NULL,
car_type
VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (id
)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (165, ‘6666’, ‘丰田霸道’, 32.00, ‘2020-11-11’, ‘燃油车’);
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (166, ‘1202’, ‘大众速腾’, 30.00, ‘2020-11-11’, ‘燃油车’);
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (167, ‘1203’, ‘奔驰GLC’, 5.00, ‘2010-12-03’, ‘燃油车’);
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (168, ‘1204’, ‘奥迪Q7’, 3.00, ‘2009-10-11’, ‘燃油车’);
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (169, ‘1205’, ‘朗逸’, 4.00, ‘2001-10-11’, ‘新能源’);
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (171, ‘1207’, ‘奥迪A6’, 30.00, ‘2000-01-02’, ‘燃油车’);
INSERT INTOt_car
(id
,car_num
,brand
,guide_price
,produce_time
,
car_type
) VALUES (172, ‘6666’, ‘丰田霸道’, 32.00, ‘2020-11-11’, ‘燃油车’);
jar - 新建,编辑mybatis-config.xml文件(放入resources文件夹)
注意1:mybatis核心配置文件的文件名不一定是mybatis-config.xml,可以是其它名字。
注意2:mybatis核心配置文件存放的位置也可以随意。这里选择放在resources根下,相当于放到了类
的
根路径下。 - 新建,配置xxxMapper.xml文件
用or来删除
CarMapper.xml
2. 批量插入
/**
- 通过foreach完成批量删除
- @param ids
- @return
/
int deleteBatchByForeach2(@Param(“ids”) Long[] ids);
delete from t_car where
id = #{id}
@Test
public void testDeleteBatchByForeach2(){
CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.cla
ss);
int count = mapper.deleteBatchByForeach2(new Long[]{40L, 41L, 42L});
System.out.println(“删除了几条记录:” + count);
SqlSessionUtil.openSession().commit();
}
insert into t_car values
(null,#{car.carNum},#{car.brand},#{car.guidePrice},#
{car.produceTime},#{car.carType})
int insertMatch(@Param(“cars”) List cars);
@Test
public void testInsertBatchByForeach(){
CarMapper mapper = SqlSessionUtil.openSession().getMapper(CarMapper.class);
Car car1 = new Car(null, “2001”, “兰博基尼”, 100.0, “1998-10-11”, “燃油车”);
Car car2 = new Car(null, “2001”, “兰博基尼”, 100.0, “1998-10-11”, “燃油车”);
Car car3 = new Car(null, “2001”, “兰博基尼”, 100.0, “1998-10-11”, “燃油车”);
List cars = Arrays.asList(car1, car2, car3);
int count = mapper.insertBatchByForeach(cars);
System.out.println(“插入了几条记录” + count);
SqlSessionUtil.openSession().commit();
}
9.7 sql标签与include标签
sql标签用来声明sql片段
include标签用来将声明的sql片段包含到某个sql语句当中
十、MyBatis的高级映射及延迟加载
10.1 数据库表的准备
准备数据库表:一个班级对应多个学生。班级表:t_clazz。学生表:t_stu
Student
Claszz
id,
car_num as carNum,
brand,
guide_price as guidePrice,
produce_time as produceTime,
car_type as carType
select from t_car
/* - 学生类
- @author
- @version 1.0
- @since 1.0
*/
public class Student {
private Integer sid;
private String sname;
//…
}
创建mapper接口:StudentMapper、ClazzMapper
创建mapper映射文件:StudentMapper.xml、ClazzMapper.xml
10.2 多对一映射
判断哪个是主表的方法:哪个在前
比如多对一就是多在前,多个学生对应一个班级,此时学生就是主表
多对一如何在jvm里解释
将学生类中添加班级类即可
left join左连接,把左边的全部查出来,右边有的则匹配,没有则为null
记得要在表后面跟上代称,如t_stu s
查询结果:
问题:根据ID查询学生信息,并返回班级信息
- 第一种方式(级连属性映射)
/**
- 班级类
*/
public class Clazz {
private Integer cid;
private String cname;
//…
}
select s.sid,s.sname,c.cid,c.cname
from t_stu s left join t_clazz c on s.cid=c.cid
where s.sid = 1
2.第二种方式(Association)
将resultMap中的类设置为Association(即另一个类)
- 第三种方式(分步查询)
两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载)
第一处:association中select位置填写sqlId。sqlId=namespace+id。其中column属性作为这条子sql
语
句的条件。
select s.sid,s.sname,s.cid,c.cname from t_stu s left join t_clazz c on
s.cid=c.cid where s.sid = #{sid}
public class StudentMapperTest {
@Test
public void testSelectBySid(){
StudentMapper mapper =
SqlSessionUtil.openSession().getMapper(StudentMapper.class);
Student student = mapper.selectBySid(1);
System.out.println(student);
}
}
1.第一种方式(collection方式)
在select中增加collection标签,表示集合
2. 第二种方式(分步式加载)
二级缓存的失效:只要两次查询之间出现了增删改操作。二级缓存就会失效。【一级缓存也会失效】
- eviction:指定从缓存中移除某个对象的淘汰算法。默认采用LRU策略。
LRU:Least Recently Used。最近最少使用。优先淘汰在间隔时间内使频率最低的对
象。(其
实还有这种淘汰算法LFU,最不常用。)
FIFO:First In First Out。一种先进先出的数据缓存器。先进入二级缓存的对象最先被淘汰。
SOFT:软引用。淘汰软引用指向的对象。具体算法和JVM的垃圾回收算法有关。
WEAK:弱引用。淘汰弱引用指向的对象。具体算法和JVM的垃圾回收算法有关。 - flushInterval:
二级缓存的刷新时间间隔。单位毫秒。如果没有设置。就代表不刷新缓存,只要内存足够大,一直
会向二级缓存中缓存数据。除非执行了增删改。 - readOnly:
true:多条相同的sql语句执行之后返回的对象是共享的同一个。性能好。但是多线程并发可能
会存在安全问题。
false:多条相同的sql语句执行之后返回的对象是副本,调用了clone方法。性能一般。但安全。 - size:
设置二级缓存中最多可存储的java对象数量。默认值1024。
11.6 集成Ehcache
集成EhCache是为了代替mybatis自带的二级缓存。一级缓存是无法替代的。
mybatis对外提供了接,也可以集成第三方的缓存组件。例如EhCache、Memcache等。都可以。
EhCache是Java写的。Memcache是C语言写的。所以mybatis集成EhCache较为常见,按照以下步骤操
作,就可以完成集成:
第一步:引入mybatis整合ehcache的依赖。