如果有大量相同的请求查询数据库,则数据库需要执行多次重复的sql,那么并发压力高,查询效率低. 如果引入缓存机制,则可以极大的提升用户的查询的效率。
缓存介于服务器和数据库之间,其为了减轻数据库查询压力,提供服务器更高效的反馈速度出现。
@Test
public void testCache(){
SqlSession sqlSession = sqlSessionFactory.openSession();
EmpMapper userMapper = sqlSession.getMapper(EmpMapper.class);
List<Emp> userList1 = userMapper.findAll();
List<Emp> userList2 = userMapper.findAll();
List<Emp> userList3 = userMapper.findAll();
sqlSession.close();
}
我们利用同一个SqlSession,执行多次数据库操作后,可以在控制台输出观察看,虽然执行了3次方法,但是sql只执行一次此时缓存就是生效的。要注意的时,使用缓存时,数据模型类要实现序列号接口。
注意事项: sqlSession关闭之后,二级缓存才能生效
//测试二级缓存
@Test
public void testCache2(){
SqlSession sqlSession1 = sqlSessionFactory.openSession();
EmpMapper empMapper = sqlSession1.getMapper(EmpMapper.class);
List<Emp> list1 = empMapper.findAll();
sqlSession1.close(); //sqlSession使用之后必须关闭.否则二级缓存不生效.
//利用同一个SqlSessionFactory 创建不同的SqlSession
SqlSession sqlSession2 = sqlSessionFactory.openSession();
EmpMapper empMapper2 = sqlSession2.getMapper(EmpMapper.class);
List<Emp> list2 = empMapper2.findAll();
sqlSession2.close();
}
如果需要使用一级/二级缓存,则POJO对象必须实现序列化接口. 否则数据不可以被缓存.
图解序列化规则:
在俩次查询中,相当于调用了俩次线程,线程A查询到的JAVA对象,线程B并不认识,这时就需要序列号排列字节信息,使线程B可以认识线程A查询到的JAVA对象,从而使线程B可以去使用。
说明: 在新项目中添加依赖信息,可以直接赋值demo3中的pom内容
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
<exclusions>
<exclusion>
<groupId>org.junit.vintagegroupId>
<artifactId>junit-vintage-engineartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.0version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
dependencies>
这里要注意的是,mybatis.mappers
是层级目录的结构,不是其名字中包含一个.
,而是代表层级目录的意思。
SpringBoot整合Mybatis中,不再使用之前的mybatis-config.xml
文件,而是使用springboot.yml
配置文件。
#配置端口号
server:
port: 8090
#管理数据源
spring:
datasource:
#高版本驱动使用
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
#设定用户名和密码
username: root
password: root
#SpringBoot整合Mybatis
mybatis:
#指定别名包
type-aliases-package: com.study.pojo
#扫描指定路径下的映射文件
mapper-locations: classpath:/mybatis/mappers/*.xml
#开启驼峰映射
configuration:
map-underscore-to-camel-case: true
1. 通过@Mapper注解 管理对象
@Mapper //将Mapper接口交给Spring容器管理.
public interface UserMapper {
List<User> findAll();
}
2. 通过包扫描的方式,管理mapper接口 编辑主启动类, 指定包扫描路径
@SpringBootApplication
//按照指定的包路径,扫描mapper的接口管理对象
@MapperScan("com.study.mapper")
public class SpringbootSsmApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSsmApplication.class, args);
}
}
3. 编辑数据模型类
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private Integer id;
private String name;
private Integer age;
private String sex;
}
1. 编辑测试类
@SpringBootTest
class SpringbootSsmApplicationTests {
@Autowired //注入指定的对象
private UserMapper userMapper; //IDEA 编译提示 不影响执行
/**
* 测试SpringBoot整合Mybatis
*/
@Test
public void testFindAll(){
List<User> userList = userMapper.findAll();
System.out.println(userList);
}
}
2. 编辑UserMapper.xml文件
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.study.mapper.UserMapper">
<select id="findAll" resultType="User">
select * from demo_user
select>
mapper>
特点:
特点:
1.不管被代理者是否有接口,都可以为其创建代理对象.
2. 代理对象是目标对象的子类. 继承关系.
结论:
1.Spring中如果有接口,默认使用JDK代理方式,如果没有接口,则默认使用CGLIB代理方式.
2.Spring5以后,自身接口对象创建代理对象时,使用cglib
我们在mapper类中添加的@Mapper注解,就可以很好的解决这个报错;
但是当项目并没有在mapper类中添加@Mapper注解,而是在主启动类上添加包扫描路径时,因为包扫描只有在主启动类启动时才会生效,所以会导致在项目启动前报此警告错误,这时只需要按照下图设置即可取消:
用户访问URL: http://localhost:8090/findAll
返回值: List 的JSON串.
用户访问时,首先会调用SpringMVC控制的Controller层代码,Controller层注入被Spring框架管理的Service层代码,Service层需要注入Mybatis管理的Mapper层代码,其统一被SpringBoot管理,共同构成SpringBoot框架。
@RestController //@ResponseBody 将list集合转化为json
public class UserController {
@Autowired
private UserService userService;
/**
* URL: http://localhost:8090/findAll
* 参数: 无
* 返回值: List
*/
@RequestMapping("/findAll")
public List<User> findAll(){
return userService.findAll();
}
}
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserMapper userMapper;
@Override
public List<User> findAll() {
return userMapper.findAll();
}
}
public interface UserMapper {
List<User> findAll();
}
<mapper namespace="com.jt.mapper.UserMapper">
<!--必须配置别名包-->
<select id="findAll" resultType="User">
select * from demo_user
</select>
</mapper>
打开浏览器搜索http://localhost:8090/findAll
根据Id查询数据库
URL: http://localhost:8090/findUserById?id=1
返回值: User对象
/**
* 需求: http://localhost:8090/findUserById?id=1
* 参数接收: id=1
* 返回值: User对象
*/
@RequestMapping("/findUserById")
public User findUserById(Integer id){
return userService.findUserById(id);
}
@Override
public User findUserById(Integer id) {
return userMapper.findUserById(id);
}
User findUserById(Integer id);
编辑UserMapper.xml文件:
<select id="findUserById" resultType="User">
select * from demo_user where id = #{id}
select>
或者也可以使用注解的方式进行查询,但是要注意,注解和映射文件只能二选一,不能同时使用:
@Select("select * from demo_user where id = #{id}")
User findUserById(Integer id);
根据age与sex查询数据库
URL: http://localhost:8090/findUserByAs?age=18&sex=女
返回值: List集合封装.
/*
*URL:http://localhost:8090/findUserByAs?age=18&sex=女
* 参数:age=18/sex=女
* 返回值:List<集合>
* 参数的接收:如果是多个参数,并且与属性名称一致,可以使用对象接收
*
*/
@RequestMapping("/findUserByAs")
public List<User> findUserByAs(User user){
return userService.findUserByAs(user);
}
List<User> findUserByAs(User user);
@Override
public List<User> findUserByAs(User user){
return userMapper.findUserByAs(user);
}
@Select("select * from demo_user where age = #{age} and sex = #{sex}")
List<User> findUserByAs(User user);
说明:要求修改id=1的数据,将name=“黑熊精” age=3000 sex=男,要求使用restFul的结构实现参数传递
常规get请求:http://localhost:8090/updateById?id=1&name=黑熊精&age=3000&sex=男
Restful请求路径:http://localhost:8090/updateById?1/黑熊精/3000/男
/*
*URL:http://localhost:8090/updateById/1/黑熊精/3000/男
* 参数:4个
* 返回值:修改成功
* restFul结构 参数分析 {属性名称}
* 参数接收:
* 1:单个参数使用@PathVariable Integer id接收
* 2:多个参数接收 使用对象mvc自动提供的功能
*/
@RequestMapping("/updateById/{id}/{name}/{age}/{sex}")
public String updateById(User user){
userService.updateById(user);
return "用户修改成功";
}
//spring整合mybatis之后,事务自动提交.
@Override
public void updateById(User user) {
userMapper.updateById(user);
}
@Update("update demo_user set name=#{name},age=#{age},sex =#{sex} where id=#{id}")
void updateById(User user);
编辑UserController
/*
*URL:http://localhost:8090/findUserByLike?name=乔
* 参数:乔
* 返回值: 返回list集合
* restFul结构 参数分析 {属性名称}
*/
@RequestMapping("/findUserByLike")
public List<User> findUserByLike(String name){
return userService.findUserByLike(name);
}
编辑UserService
List<User> findUserByLike(String name);
@Override
public List<User> findUserByLike(String name) {
return userMapper.findUserByLile(name);
}
编辑UserMapper
@Select("select * from demo_user where name like \"%\"#{name}\"%\"")
List<User> findUserByLile(String name);
编辑UserController
/*
* 批量查询
* http://localhost:8090/findUserByIds?ids=1,3,5,7
* 返回list集合
* 参数:ids=1,3,5,7
* 返回值:List
* 知识点:MVC中参数,号分割的规则,应该使用数组接收mvc的规则
* */
@RequestMapping("/findUserByIds")
public List<User> findUserByIds(Integer[] ids){
return userService.findUserByIds(ids);
}
编辑UserService
List<User> findUserByIds(Integer[] ids);
@Override
public List<User> findUserByIds(Integer[] ids) {
return userMapper.findUserByIds(ids);
}
编辑UserMapper
List<User> findUserByIds(Integer[] ids);
== 因为多个查询,所以查询语句需要写到UserMapper.xml中==
<select id="findUserByIds" resultType="User">
select * from demo_user where id in (
<foreach collection="array" separator="," item="id">
#{id}
foreach>
)
select>
编辑UserController
/*
*实现用户新增
* http://localhost:8090/saveUser/悟空/8000/男
* 返回成功的提示即可
* 返回值:String
* */
@RequestMapping("/saveUser/{name}/{age}/{sex}")
public String saveUser (User user){
userService.saveUser(user);
return "新增入库成功";
}
编辑UserService
void saveUser(User user);
@Override
public void saveUser(User user) {
userMapper.saveUser(user);
}
编辑UserMapper
@Insert("insert into demo_user (id,name,age,sex) values(null,#{name},#{age},#{sex} )")
void saveUser(User user);
}
}