Spring boot Mybatis面试题
一、JDBC存在的问题
1.1 JDBC存在的问题
- 硬编码问题:数据库的驱动名、数据库的URL、数据库的用户名、数据的密码等存在硬编码
解决方案:将数据库驱动名、数据库URL、数据库用户名、密码配置在xml|properties
- sql语句存在硬编码、占位符索引存在硬编码、占位符值存在硬编码
解决方案:sql语句写在xml文件、占位符的索引自动分配、占位符的值可以根据索引进行自动绑定。
*查询结果的列名存在硬编码、对象需要自己创建、对象的属性需要自己赋值、需要手工将对象添加至列名。
解决方案:查询结果的列名可以配置在xml文件中、对象可以自动创建、对象的属性值可以自动绑定、对象自动添加到列表中去。
二、Mybatis
2.1 Mybatis是什么
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
2.2 工作原理
- 全局配置文件配置了数据源,事务等mybatis运行环境
- SqlSessionFactory创建SqlSession对象
- SqlSession提供了操作数据库的方法
- Excutor执行器·,真正负责处理数据库操作
- MappedStatement 封装输入参数类型,封装输出结果类型,sql语句
- DB数据库
2.3 #{}和${}的区别
#{}相当于占位符 | ${}相当于字符串拼接符 |
---|---|
#{}解决了sql注入 | ${}存在sql注入 |
${}在动态解析的时候,会将我们传入的参数当做String字符串填充到我们的语句中
#{} 在动态解析的时候,会解析成一个参数标记符。
#{}将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
2.4 xml中特殊字符处理
三、缓存机制
3.1 目的
缓存目的是为了减少对数据库的访问次数,提升数据库的执行效率。
mybatis缓存机制包括:1.一级缓存 2.二级缓存
3.2 一级缓存
一级缓存也叫sqlSession级别的缓存 ,也就是在同一个sqlSession内执行两次多次相同结果的查询语句,只会在第一次时发出sql查询数据库的数据,然后之后每次从一级缓存中查询数据返回。
3.2 清除一级缓存
- 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前SqlSession缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
- 当一个SqlSession结束后那么他里面的一级缓存也就不存在了
3.3 二级缓存
二级缓存是mapper级别的缓存,也就是同一个namespace的mappe.xml,当多个SqlSession使用同一个Mapper操作数据库的时候,得到的数据会缓存在同一个二级缓存区域
3.4 清除二级缓存
- 如果SqlSession执行了DML操作(insert、update、delete),并commit了,那么mybatis就会清空当前mapper缓存中的所有缓存数据,这样可以保证缓存中的存的数据永远和数据库中一致,避免出现脏读
3.5 使用缓存过程
- 当一个sqlseesion执行了一次select后,在关闭此session的时候,会将查询结果缓存到二级缓存
- 当另一个sqlsession执行select时,首先会在他自己的一级缓存中找,如果没找到,就回去二级缓存中找,找到了就返回,就不用去数据库了,从而减少了数据库压力提高了性能
3.6 验证一级缓存
四、面试题
参考:https://www.cnblogs.com/aishangJava/p/10526957.html
五、Spring Boot整合mybatis
5.1 需要的依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
5.2 数据库配置
spring:
datasource:
password: 123
username: root
url: jdbc:mysql://localhost:3306/stus
5.3 编写department类
public class Department {
private Integer id;
private String departmentName;
public Department() {
}
public Department(Integer id, String departmentName) {
this.id = id;
this.departmentName = departmentName;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
}
5.4 mapper类
@Mapper
public interface DepartmentMapper {
@Select("select * from department where id = #{id}")
public Department Select();
@Delete("delete form department where id = #{id}")
public void delete();
@Update("update department set departmentName=#{departmentName} where id=#{id}")
public void update();
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
public void insert(Department department);
}
5.5 Controller测试
@Controller
@ResponseBody
public class departmentController {
@Autowired
DepartmentMapper mapper;
@GetMapping("/dept/{id}")
public Department getDepartment(@PathVariable("id") Integer id){
return mapper.Select();
}
@GetMapping("/dept")
public Department insert(Department department){
mapper.insert(department);
return department;
}
}
5.5 总结
- 从url获取如id参数,配置是:
GetMapping("/dept/{id}")
不需要加#号
- insert语句,表名称后面一定要加入插入的属性名
insert into department(departmentName) values(#{departmentName})
- 如果要得到自增的主键的值,需要在mapper中加入如下的注解,useGeneratedKeys 为true代表使用自增的主键的值,keyProperty 告诉哪个属性是主键
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into department(departmentName) values(#{departmentName})")
public void insert(Department department);
- 今天出错的原因是GetMapping(“/dept/{id}”),id前加了#,自动创建数据库的配置未注释。