Spring Boot进阶系列四
这边文章主要实战如何使用Mybatis以及整合Redis缓存,数据第一次读取从数据库,后续的访问则从缓存中读取数据。
1.0 Mybatis
MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。
MyBatis并不是一套完整的ORM数据库连接框架,目前大多数互联网公司首选的数据库连接方式,不会对应用程序或者数据库的现有设计强加任何影响。 SQL写在xml里,便于统一管理和优化。解除SQL与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。SQL和代码的分离,提高了可维护性。
它的优点也正是缺点,编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。 SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
1.1使用 MyBatis 官方提供的 Spring Boot 整合包实现。
1.1.1. pom.xml里面添加mybatis jar包。
<!-- springboot,mybatis 整合包 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
1.1.2 配置数据库连接
在 application.properties 中添加:
# Data source configuration
spring.datasource.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=user-name
spring.datasource.password=******
# mybatis 配置
mybatis.config-location=classpath:mybatis/mybatis-config.xml
mybatis.mapper-locations=classpath:mybatis/mapper/*.xml
1.1.3 在 src/main/resources 下创建 mybatis 文件夹,并在 mybatis 文件夹中创建 "mybatis-config.xml" 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 获取数据库自增主键值 -->
<setting name="useGeneratedKeys" value="true"/>
<!-- 使用列别名替换列名,默认为 true -->
<setting name="useColumnLabel" value="true"/>
<!-- 开启驼峰命名转换:Table(create_time) => Entity(createTime) -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
1.1.4 示例表依然使用系列一中的book表
CREATE TABLE `book` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`Name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`Category` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`Price` decimal(18,2) NOT NULL,
`Publish_Date` date NOT NULL,
`Poster` varchar(45) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8
1.1.5 实体模型如下
public class Book implements Serializable {
private static final long serialVersionUID = -8471725336062010735L;
private Integer id;
private String name;
private String category;
private Double price;
private Date publish_date;
private String poster;
} // 省略getter,setter方法
1.1.6 Mapper接口
@Mapper
public interface BookMapper {
public void insert(Book book);
public Book getById(Integer id);
public void deleteById(Integer id);
public void update(Book book);
}
1.1.7添加bookMapper.xml
mybatis 文件夹下创建一个 mapper文件夹,里边存放 Mpper 接口对应的 mapper 映射文件。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.example.demo.store.BookMapper"> <insert id="insert" parameterType="com.example.demo.model.Book"> insert into demo.book(Name,Category,Price,Publish_Date,Poster) values(#{name},#{category},#{price},curdate(),'NA') </insert>
<select id="getById" parameterType="java.lang.Integer" resultType="com.example.demo.model.Book"> SELECT * FROM demo.book where Id = #{id} </select> <update id="update" parameterType="com.example.demo.model.Book"> update demo.book set Name = #{name},Price = #{price}, Category = #{category} where Id = #{id} </update> <delete id="deleteById" parameterType="java.lang.Integer"> delete from demo.book where Id = #{id} </delete> </mapper>
2.0 使用Redis做缓存
redis是一个高性能的key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。 可以对这些类型运行原子操作,例如附加到字符串 ; 递增哈希值 ; 将元素推送到列表中 ; 计算集合交集, 并集和差异 ; 或者在排序集中获得排名最高的成员。
为了实现其出色的性能,Redis使用 内存数据集。根据使用情况,可以通过每隔一段时间将数据集转储到磁盘或通过将每个命令附加到日志来保留它。如果仅仅需要功能丰富的网络内存缓存,则可以选择禁用持久性。
Redis还支持简单的设置,就可以实现主从异步复制,具有非常快速的非阻塞第一次同步,自动重新连接以及在网络分割上的部分重新同步。
2.1 集成Redis到Springboot应用程序
磁盘读写速度远低于内存读写速度,那么当数据量增大时,如果一直去连接数据库增删改查,那么压力之大可想而知。适时地引入缓存,直接从缓存中读取无疑是改善性能的很重要的手段。
2.1.1 pom.xml中添加redis jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2.1.2 在 application.properties 中添加配置信息
#Cache type is redis
spring.cache.type=redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0
# Cache expire time
spring.cache.redis.time-to-live=120000
2.1.3 加入一层服务,在com.example.demo.service package中,新建BookService.java
@CacheConfig(cacheNames="book")
@Service
public class BookService {
@Autowired
private BookMapper bookMapper;
@CachePut(key = "#book.id")
public void save(Book book) {
System.out.println("Save name =" + book.getName() + " data...");
this.bookMapper.insert(book);
}
@CachePut(key = "#book.id")
public void update(Book book) {
System.out.println("Update id = " + book.getId() + " data...");
this.bookMapper.update(book);
}
@Cacheable(key = "#id")
public Book getBookById(Integer id) {
System.out.println("No data in cache, fetch data from db server. Id is : " + id);
Book book = bookMapper.getById(id);
return book;
}
@CacheEvict(key = "#id")
public void delete(Integer id) {
System.out.println("Delete id=" + id + " data from db server...");
bookMapper.deleteById(id);
}
}
2.1.4 添加Controller
@Controller
@RequestMapping("book")
@ResponseBody
public class BookController {
@Autowired
private BookService bookServie;
@RequestMapping("save")
public void save(Book book) {
this.bookServie.save(book);
}
@RequestMapping("update")
public void update(Book book) {
this.bookServie.update(book);
}
@RequestMapping("get/{id}")
public Book get(@PathVariable("id") Integer id) {
Book book = this.bookServie.getBookById(id);
return book;
}
@RequestMapping("delete/{id}")
public void delete(@PathVariable("id") Integer id) {
this.bookServie.delete(id);
}
}
2.1.5 开启缓存注解
@EnableCaching @SpringBootApplication public class ProductApp1Application { public static void main(String[] args) { SpringApplication.run(ProductApp1Application.class, args); } }
2.1.6 测试,
浏览器上输入,http://localhost:8080/book/get/58
只有第一次会访问数据库,
No data in cache, fetch data from db server. Id is : 58
2019-09-01 17:36:36.559 DEBUG 21364 --- [nio-8080-exec-7] c.example.demo.store.BookMapper.getById : ==> Preparing: SELECT * FROM demo.book where Id = ?
2019-09-01 17:36:36.847 DEBUG 21364 --- [nio-8080-exec-7] c.example.demo.store.BookMapper.getById : ==> Parameters: 58(Integer)
2019-09-01 17:36:36.874 DEBUG 21364 --- [nio-8080-exec-7] c.example.demo.store.BookMapper.getById : <== Total: 1
后续发送请求则直接从缓存中读取数据,此时已经没有任何日志输出了。