1.什么是mybatis?
MyBatis 是支持定制 化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手工设置参数以及抽取结果集。 MyBatis 使用简单的 XML 或注解来配置和映射基本体,将接口和 Java 的 POJOs(Plain Old Java Objects, 普通的 Java对象)映射成数据库中的记录。
2.mybatis的原理:
MyBatis应用程序根据XML配置文件创建SqlSessionFactory,SqlSessionFactory在根据配置,配置来源于两个地方,一处是配置文件,一处是Java代码的注解,获取一个SqlSession。SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例直接运行映射的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。
3.mybatis的优点:
1、简单易学
mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现
2、解除sql与程序代码的耦合
通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性
3.提供映射标签,支持对象与数据库的orm字段关系映射
4.提供xml标签,支持编写动态sql。
4.mybatis的缺点:
1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。
4、二级缓存机制不佳
5.mybatis的一级缓存和二级缓存:
缓存的作用:使用缓存, 我们可以避免频繁的与数据库进行交互, 尤其是在查询越多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。
mybatis 也提供了对缓存的支持, 分为一级缓存和二级缓存。 但是在默认的情况下, 只开启一级缓存(一级缓存是对同一个 SqlSession 而言的)。
一级缓存:
同一个 SqlSession 对象, 在参数和 SQL 完全一样的情况先, 只执行一次 SQL 语句(如果缓存没有过期)。
@Test
public void oneSqlSession() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 执行第一次查询
List<Student> students = studentMapper.selectAll();
for (int i = 0; i < students.size(); i++) {
System.out.println(students.get(i));
}
System.out.println("=============开始同一个 Sqlsession 的第二次查询============");
// 同一个 sqlSession 进行第二次查询
List<Student> stus = studentMapper.selectAll();
Assert.assertEquals(students, stus);
for (int i = 0; i < stus.size(); i++) {
System.out.println("stus:" + stus.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
在以上的代码中, 进行了两次查询, 使用相同的 SqlSession, 结果如下
在日志和输出中:
第一次查询发送了 SQL 语句, 后返回了结果;
第二次查询没有发送 SQL 语句, 直接从内存中获取了结果。
1.2 不同的 SqlSession:
@Test
public void differSqlSession() {
SqlSession sqlSession = null;
SqlSession sqlSession2 = null;
try {
sqlSession = sqlSessionFactory.openSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 执行第一次查询
List<Student> students = studentMapper.selectAll();
for (int i = 0; i < students.size(); i++) {
System.out.println(students.get(i));
}
System.out.println("=============开始不同 Sqlsession 的第二次查询============");
// 从新创建一个 sqlSession2 进行第二次查询
sqlSession2 = sqlSessionFactory.openSession();
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
List<Student> stus = studentMapper2.selectAll();
// 不相等
Assert.assertNotEquals(students, stus);
for (int i = 0; i < stus.size(); i++) {
System.out.println("stus:" + stus.get(i));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
if (sqlSession2 != null) {
sqlSession2.close();
}
}
}
在代码中, 分别使用 sqlSession 和 sqlSession2 进行了相同的查询。
其结果如下:
从日志中可以看到两次查询都分别从数据库中取出了数据。 虽然结果相同, 但两个是不同的对象。
1.3 刷新缓存
刷新缓存是清空这个 SqlSession 的所有缓存, 不单单是某个键
@Test
public void sameSqlSessionNoCache() {
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
// 执行第一次查询
Student student = studentMapper.selectByPrimaryKey(1);
System.out.println("=============开始同一个 Sqlsession 的第二次查询============");
// 同一个 sqlSession 进行第二次查询
Student stu = studentMapper.selectByPrimaryKey(1);
Assert.assertEquals(student, stu);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (sqlSession != null) {
sqlSession.close();
}
}
}
二级缓存:
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。