现在开始Spring+mybatis+redis的整合,一开始我想的是Spring+SpringMVC+Mybatis+redis进行整合,但是慢慢整合着就就感觉前面的会了,后面的肯定也就会了,也就不整合后面的了,如果感觉还是很模糊的话,你可以根据下面的慢慢的来整合你肯定会这么觉的
这篇redis不是用注解的方式操作缓存的,用依赖注入的方式,让redis相当于一个数据库(它原本就是一个key-value库),不像用注解的方式完全不用自己管理,只需有几个工具类,这里需要自己手动写redis的set,get…,添加生命周期和对象转成json字符串也是自己手动解决,当然如果redisDao完善了(命令全了,以后也可以相当于个工具包了)
注解方式请看这:https://blog.csdn.net/weixin_43113679/article/details/90680254
先看看我的目录结构
首先spring-server.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
">
<!-- 包扫描 -->
<context:component-scan base-package="cn.qlq.service"/>
<!-- 下面这俩import,因为是测试,没办法从web.xml里读取,所以只能写这个,等再加上springmvc时就可以直接让web.xml读取全部的xml了,就不用下面这两个import了 -->
<import resource="spring-dao.xml"/>
<import resource="spring-redis.xml"/>
<!--配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置注解的事务驱动 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
spring-dao.xml和它的配置文件conn.properties
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- property-placeholder用于加载一个属性文件 -->
<!-- ignore-unresolvable="true" 必须加上,要不肯定出错,错误应该是没有找到配置文件,如果不加上,它就会只读一个,剩下的不会读按顺序 -->
<context:property-placeholder location="classpath:conn.properties" ignore-unresolvable="true"/>
<!-- c3p0数据库连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
p:driverClass="${jdbc.driver}" p:jdbcUrl="${jdbc.url}"
p:user="${jdbc.username}" p:password="${jdbc.password}"
p:maxPoolSize="100" p:minPoolSize="20"
p:initialPoolSize="20" p:maxIdleTime="200" >
</bean>
<!-- sqlSessionFactory工厂bean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 数据库连接池,ref和上面的数据库连接池的id对应 -->
<property name="dataSource" ref="dataSource" />
<!-- 加载mybatis的全局配置文件 -->
<property name="configLocation" value="classpath:sqlMapConfig.xml" />
</bean>
<!-- 配置MyBatis的高级mapper代理方式 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描包路径,如果需要扫描多个包,中间使用半角逗号隔开 -->
<property name="basePackage" value="cn.qlq.mapper"></property>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
</beans>
conn.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/qbb?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=
sqlMapConfig
<?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>
<!-- MyBatis的全局参数设置,基本用来进行MyBatis的优化处理 -->
<settings>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
<!-- 下面的是延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 是否开启延迟加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 缓冲加载 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<!--肯定要有这个的啦,要不怎么从mybatis中返回自己想要的对象呢-->
<package name="cn.qlq.bean"/>
</typeAliases>
</configuration>
spring-redis.xml和它的配置文件redis.properties
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 连接池配置 -->
<context:component-scan base-package="cn.qlq.Redis"/>
<!--ignore-unresolvable必须写上true,要不配置文件就读不上了,当然,也可以全读,我这为了区分,分开读的-->
<context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true"/>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<!--下面这些可以用配置文件里也可以自己定义,在你,value格式和下一个bean一样-->
<!-- 最大连接数 -->
<property name="maxTotal" value="30" />
<!-- 最大空闲连接数 -->
<property name="maxIdle" value="10" />
<!-- 每次释放连接的最大数目 -->
<property name="numTestsPerEvictionRun" value="1024" />
<!-- 释放连接的扫描间隔(毫秒) -->
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<!-- 连接最小空闲时间 -->
<property name="minEvictableIdleTimeMillis" value="1800000" />
<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
<property name="softMinEvictableIdleTimeMillis" value="10000" />
<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
<property name="maxWaitMillis" value="1500" />
<!-- 在获取连接的时候检查有效性, 默认false -->
<property name="testOnBorrow" value="true" />
<!-- 在空闲时检查有效性, 默认false -->
<property name="testWhileIdle" value="true" />
<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
<property name="blockWhenExhausted" value="false" />
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="host" value="${redis.url}"></constructor-arg>
<constructor-arg name="port" value="${redis.port}"></constructor-arg>
<constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>
</bean>
</beans>
redis.properties
redis.url="ip地址" //自己查自己的
redis.port=6379
redis.pass=
redis.maxIdle=300
redis.maxTotal=30
redis.maxActive=1024
redis.maxWait=10000
redis.testOnBorrow=true
pom.xml
除了SSM中必须有的jar包外下面的也要有
<!--redis必须有的jar包-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.8.10.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!--负责json字符串和javabean对象之间的互转换-->
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
User类
package cn.qlq.bean;
public class User {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
Mapper类(数据库类)
接口
package cn.qlq.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import cn.qlq.bean.User;
public interface UserMapper {
/**
* 获得所有的用户
* */
List<User> getUser()throws Exception;
/**
* 插入一个用户
* */
void insertUser(@Param("user")User user)throws Exception;
/**
* 通过id查询用户
*
* @param id
* @return
*/
User findUserById(@Param("id")int id);
}
mapper.xml
<?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">
<!-- namespace命名空间,作用就是对sql进行分类化管理,理解sql隔离 注意:使用mapper代理方法开发,namespace有特殊重要的作用 -->
<mapper namespace="cn.qlq.mapper.UserMapper">
<select id="getUser" resultType="cn.qlq.bean.User">
select * from book
</select>
<update id="insertUser" parameterType="cn.qlq.bean.User">
INSERT INTO book (id,name) VALUES (#{user.id},#{user.name})
</update>
<select id="findUserById" parameterType="int" resultType="cn.qlq.bean.User">
select * from book where id = #{id}
</select>
</mapper>
缓存类
接口
/**
*
*/
package cn.qlq.Redis;
/**
* @author 作者
* @date 2019年5月21日
*/
public interface RedisDao {
/**
* show 获得缓存中的value
* */
String get(String key) throws Exception;
/**
* show 往缓存中添加value
* */
void set(String key,String value) throws Exception;
/**
* show 获取hash
* */
String hget(String hkey,String key) throws Exception;
/**
* show 插入一个hash
* */
void hset(String hkey,String key,String value)throws Exception;
}
实现类
package cn.qlq.Redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import redis.clients.jedis.JedisPool;
/**
* @author 作者
* @date 2019年5月21日
*/
@Repository("redisDao")
public class RedisDaoImpl implements RedisDao{
@Autowired
private JedisPool jedisPool ;
@Override
public String get(String key) throws Exception {
return jedisPool.getResource().get(key);
}
@Override
public void set(String key,String value) throws Exception {
//获得6小时到9小时的随机时间
int time=(int)(6+Math.random()*(4))*60*60;
//添加键
jedisPool.getResource().set(key, value);
//给键添加生命周期
jedisPool.getResource().expire(key, time);
}
@Override
public String hget(String hkey, String key) throws Exception {
return jedisPool.getResource().hget(hkey, key);
}
@Override
public void hset(String hkey, String key,String value) throws Exception {
int time=(int)(6+Math.random()*(4))*60*60;
jedisPool.getResource().hset(hkey, key,value);
jedisPool.getResource().expire(key, time);
}
}
Server类
接口
package cn.qlq.service;
import java.util.List;
import cn.qlq.bean.User;
public interface UserService {
/**
* show 获取所有的User
* */
List<User> getUser()throws Exception;
/**
* show 插入新的User
* */
void insertUser(User user)throws Exception;
/**
* 通过id查询用户
*
* @param id
* @return
* @throws Exception
*/
User findUserById(int id) throws Exception;
}
实现类
package cn.qlq.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import com.alibaba.fastjson.JSON;
import cn.qlq.Redis.RedisDao;
import cn.qlq.bean.User;
import cn.qlq.mapper.UserMapper;
import cn.qlq.service.UserService;
@Transactional(rollbackFor=Exception.class)
@Service("userService")
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper=null;
@Autowired
private RedisDao redisDao =null;
@Override
public List<User> getUser() throws Exception {
return userMapper.getUser();
}
@Override
public void insertUser(User user) throws Exception {
userMapper.insertUser(user);
String userJson = redisDao.get("user_"+user.getId());
if(StringUtils.isEmpty(userJson)) {
System.out.println("插入缓存");
//因为是缓存中存的是字符串,所以需要转成json字符串
redisDao.set("user_"+user.getId(), JSON.toJSONString(user));
}
//还需要插入数据库中,没写,自己写
}
@Override
public User findUserById(int id) throws Exception {
String userjson = redisDao.get("user_"+id);
User user =null;
//判断缓存中存在对应的id的
if(StringUtils.isEmpty(userjson)) {
//不存在去数据库中取出,再放进缓存
user = userMapper.findUserById(id);
if(user != null) {
redisDao.set("user_"+id, JSON.toJSONString(user));
}else {
//数据库中也不存在就把这个id也存进缓存中标识,防止雪崩或者穿透
}
}else {
//存在就直接把缓存里的json拿出来转换成对象
System.out.println("从缓存拿是数据,不去数据库");
user = JSON.parseObject(userjson,User.class);
}
return user;
}
}
是面关于fastjson的转换字符串和对象不明白的可以参考https://segmentfault.com/a/1190000011212806
测试类
package text;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import cn.qlq.bean.User;
import cn.qlq.service.UserService;
public class ssmTest {
@Autowired
private ApplicationContext ctx = null;
@Autowired
private UserService userService = null;
@Test
public void testGetUsers() throws Exception{
ctx = new ClassPathXmlApplicationContext("spring-service.xml");
userService = ctx.getBean(UserService.class);
List<User> users = userService.getUser();
System.out.println(users);
}
@Test
public void testInsertUser() throws Exception{
ctx = new ClassPathXmlApplicationContext("spring-service.xml");
userService = ctx.getBean(UserService.class);
User user = new User();
user.setId(9);
user.setName("第一个");
userService.insertUser(user);
}
@Test
public void testGetUserById() throws Exception{
ctx = new ClassPathXmlApplicationContext("spring-service.xml");
userService = ctx.getBean(UserService.class);
System.out.println(userService.findUserById(9));
}
}
结果:
第二个Test
第三个Test
没有经过数据库,直接进的缓存拿的数据,完成。