SSM中使用redis做中間快取,詳細註釋,程式碼可以執行
1.介紹
在開發中經常遇到大量的重複的,高併發的查詢,此時可以使用redis快取,將結果存入到redis中,當用戶發起查詢請求時,先在redis中查詢結果,沒有命中再去訪問資料庫。這樣可以大大減少資料庫壓力。
2.結構目錄
我的專案可以正常執行,程式碼都會給出來,所以程式碼都是可以跑的
要用到的所有檔案都給出來了,新建一個專案就可以了
config:資料夾是配置檔案,採用了註解的方式,其實和xml差不多,用註解的方式也算是對ssm的理解吧
dao:sql的檔案
model:物件
service:實現
test:main的測試類
log4j:日誌的配置檔案,一定要放在src的根目錄下!!!!!!!
test813SpringRedis這個包也是在src的根目錄下的
3.環境準備
redis服務開啟;
mysql中建立庫:t_role,建立表role,如下
服務開啟;
4.配置檔案
RedisConfig:
package test813SpringRedis.config; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import com.mysql.fabric.xmlrpc.base.Array; import com.sun.org.apache.xalan.internal.xsltc.compiler.Template; import redis.clients.jedis.JedisPoolConfig; /** * @Description * @Author zengzhiqiang * @Date 2018年8月13日 */ @Configuration //EnableCaching 表示 Spring IoC 容器啟動了快取機制 @EnableCaching public class RedisConfig { @Bean(name = "redisTemplate") public RedisTemplate initRedisTemplate(){ JedisPoolConfig poolConfig = new JedisPoolConfig(); //最大空閒數 poolConfig.setMaxIdle(50); //最大連線數 poolConfig.setMaxTotal(100); //最大等待毫秒數 poolConfig.setMaxWaitMillis(20000); //建立 Jedis 連線工廠 JedisConnectionFactory connectionFactory = new JedisConnectionFactory(poolConfig); connectionFactory.setHostName("localhost"); connectionFactory.setPort(6379); //呼叫後初始化方法,沒有它將丟擲異常 connectionFactory.afterPropertiesSet(); //自定 Redis 序列化器 RedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(); RedisSerializer stringRedisSerializer = new StringRedisSerializer(); //定義 RedisTemplate 並設定連線工程 RedisTemplate redisTemplate = new RedisTemplate(); redisTemplate.setConnectionFactory(connectionFactory); //設定序列化器 redisTemplate.setDefaultSerializer(stringRedisSerializer); redisTemplate.setKeySerializer(stringRedisSerializer); redisTemplate.setValueSerializer(jdkSerializationRedisSerializer); redisTemplate.setHashKeySerializer(stringRedisSerializer); redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer); return redisTemplate; } @Bean(name="redisCacheManager") public CacheManager initcCacheManager(@Autowired RedisTemplate redisTemplate){ RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); //設定超時時間為 10 分鐘,單位為秒 cacheManager.setDefaultExpiration(600); //設定快取名稱 List<String> cacheNames = new ArrayList<String>(); cacheNames.add("redisCacheManager"); cacheManager.setCacheNames(cacheNames); return cacheManager; } }
RootConfig:
package test813SpringRedis.config;
import java.util.Properties;
import javax.sql.DataSource;import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
/**
* @Description
* @Author zengzhiqiang
* @Date 2018年8月13日
*/
@Configuration
//定義 Spring 掃描的包
@ComponentScan("test813SpringRedis.*")
//使用事務驅動管理器
@EnableTransactionManagement
//實現介面 TransactionManagementConfigurer ,這樣可以配置註解驅動事務
public class RootConfig implements TransactionManagementConfigurer{
private DataSource dataSource = null;
/**
* 設定日誌
* @Description 這裡有個坑,log4j的配置檔案得放到原始檔加的更目錄下,src下才起作用,放包裡不起作用,找了好久的錯誤
* @Param
* @Return
*/
@Bean(name="PropertiesConfigurer")
public PropertyPlaceholderConfigurer initPropertyPlaceholderConfigurer(){
PropertyPlaceholderConfigurer propertyLog4j = new PropertyPlaceholderConfigurer();
Resource resource = new ClassPathResource("log4j.properties");
propertyLog4j.setLocation(resource);
return propertyLog4j;
}
/**
* 配置資料庫
*/
@Bean(name="dataSource")
public DataSource initDataSource(){
if(dataSource!=null){
return dataSource;
}
Properties props = new Properties();
props.setProperty("driverClassName", "com.mysql.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/t_role");
props.setProperty("username","root");
props.setProperty("password", "123456");
try {
dataSource = BasicDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
/**
* 配置 SqlSessionFactoryBean,這裡引入了spring-mybatis的jar包,是兩個框架的整合
*/
@Bean(name="sqlSessionFactory")
public SqlSessionFactoryBean initSqlSessionFactory(){
SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
sqlSessionFactory.setDataSource(dataSource);
//配置 MyBatis 配置檔案
Resource resource = new ClassPathResource("test813SpringRedis/config/mybatis-config.xml");
sqlSessionFactory.setConfigLocation(resource);
return sqlSessionFactory;
}
/**
* 通過自動掃描,發現 MyBatis Mapper 介面
*/
@Bean
public MapperScannerConfigurer initMapperScannerConfigurer(){
MapperScannerConfigurer msc = new MapperScannerConfigurer();
//掃描包
msc.setBasePackage("test813SpringRedis.*");
msc.setSqlSessionFactoryBeanName("sqlSessionFactory");
//區分註解掃描
msc.setAnnotationClass(Repository.class);
return msc;
}
/**
* 實現介面方法,註冊註解事務 當@Transactonal 使用的時候產生資料庫事務
*/
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(initDataSource());
return transactionManager;
}}
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>
<mappers>
<mapper resource="test813SpringRedis/dao/mapping/RoleMapper.xml" />
</mappers>
</configuration>
當然你也可以把它換成xml的配置形式
註釋很詳細了,程式碼全都在這裡了
5.dao實現
RoleDao:
package test813SpringRedis.dao.mapper;
import java.util.List;
import org.springframework.stereotype.Repository;
import test813SpringRedis.model.Role;
/**
* @Description
* @Author zengzhiqiang
* @Date 2018年8月13日
*/
@Repository
public interface RoleDao {public Role getRole(int id);
public int deleteRole(int id);
public int insertRole(Role role);
public int updateRole(Role role);
public List<Role> findRoles( String name);
}
RoleMapper.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" >
<mapper namespace="test813SpringRedis.dao.mapper.RoleDao">
<insert id = "insertRole" parameterType="test813SpringRedis.model.Role">
insert into role(id,name,note) values(#{id},#{name},#{note})
</insert>
<update id = "updateRole" parameterType="test813SpringRedis.model.Role">
update role set name=#{name},note=#{note} where id = #{id}
</update>
<delete id = "deleteRole">delete from role where id=#{id}
</delete>
<select id = "getRole" resultType="test813SpringRedis.model.Role">select * from role where id =#{id}
</select>
<select id = "findRoles" resultType="test813SpringRedis.model.Role">
select * from role
<where>
<if test="name!= null">
name like concat('%',#{name},'%')
</if>
</where>
</select>
</mapper>
6.物件
package test813SpringRedis.model;
import java.io.Serializable;
/**
* @Description 注意,該類實現了 Serializable 介面,這說明這個類支援序列化,這樣就可以通過 Spring
的序列化器,將其儲存為對應的編碼,快取到 Redis 中,也可以通過 Redis 讀回那些編碼,
反序列化為對應的 Java 物件。
* @Author zengzhiqiang
* @Date 2018年8月13日
*/public class Role implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private int id ;
private String name;
private String note;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;
}public String getNote() {
return note;
}public void setNote(String note) {
this.note = note;
}
}
7.實現
RoleService
package test813SpringRedis.service.inf;
import java.util.List;
import test813SpringRedis.model.Role;
/**
* @Description
* @Author zengzhiqiang
* @Date 2018年8月14日
*/public interface RoleService {
public Role getRole(int id);
public int deleteRole(int id);
public Role insertRole(Role role);
public Role updateRole(Role role);
public List<Role> findRoles(String name);
}
RoleServiceImpl
package test813SpringRedis.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;import test813SpringRedis.dao.mapper.RoleDao;
import test813SpringRedis.model.Role;
import test813SpringRedis.service.inf.RoleService;/**
* @Description
* @Author zengzhiqiang
* @Date 2018年8月14日
*/
@Service
public class RoleServiceImpl implements RoleService{
@Autowired
private RoleDao roleDao ;
/**
* 使用自Cacheable 定義快取策略:先去訪問快取,沒有命中則訪問資料庫
* 通過 value 引用快取管理器,通過 key 定義鍵
* key="'redis_role_'+#id" 這是spring的EL表示式,計算返回一個key,用key訪問redis
*/@Override
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
@Cacheable(value = "redisCacheManager",key="'redis_role_'+#id")
public Role getRole(int id) {
return roleDao.getRole(id);
}/**
* 使用@ CacheEvict 移除快取物件
* 使用在插入資料的地方,則表示儲存到資料庫後,會同期插入 Redis 快取中
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
@CacheEvict(value="redisCacheManager",key="'redis_role_'+#id")
public int deleteRole(int id) {
return roleDao.deleteRole(id);
}/**
* #result.id 寫法就會返回方法返回的角色 id(使用於主鍵資料庫生成,其實這裡我是自己生成的)
*/
@Override
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
@CachePut(value="redisCacheManager",key="'redis_role_'+#result.id")
public Role insertRole(Role role) {
roleDao.insertRole(role);
return role;
}@Override
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
@CachePut(value="redisCacheManager",key="'redis_role_'+#role.id")
public Role updateRole(Role role) {
roleDao.updateRole(role);
return role ;
}/**
* 條件查詢不使用快取策略
*/
@Override
public List<Role> findRoles(String name) {
return roleDao.findRoles(name);
}}
8.測試
package test813SpringRedis.test;
import org.apache.log4j.Logger;
import org.omg.CORBA.PRIVATE_MEMBER;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import test813SpringRedis.config.RedisConfig;
import test813SpringRedis.config.RootConfig;
import test813SpringRedis.model.Role;
import test813SpringRedis.service.inf.RoleService;/**
* @Description
* @Author zengzhiqiang
* @Date 2018年8月14日
*/public class TestMain {
private static Logger log = Logger.getLogger(TestMain.class);
@SuppressWarnings("resource")
public static void main(String[] args) {
log.info("begin....");
//使用註解 Spring IoC 容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(RootConfig.class,RedisConfig.class);
//獲取角色服務類
RoleService roleService = ctx.getBean(RoleService.class);
Role role = new Role();
role.setId(5);
role.setName("role_name_1");
role.setNote("role_note_1");
roleService.insertRole(role);
Role getRole = roleService.getRole(role.getId());
getRole.setNote("role_note_1_update");
roleService.updateRole(getRole);
System.out.println("operation ok");
}
}
9日誌
log4j.properties
log4j.rootLogger = DEBUG,stdout
log4j.logger.org.springframework=DEBUG
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n
10結果
在redis中存在了經過序列化之後的java物件,即是role
看下日誌;
好吧,太多,就不上圖了,
你會發現只是連線了兩次資料庫,分別是插入和更新,所以在查的時候,取得了redis的資料,沒有走資料庫
11注意
我這裡都是引入的jar包的方式,推薦使用maven
主要的東西,當然你spring,mbatis,的jar包都放進去最好了
再多說幾句
那個日誌資訊列印,我是弄了好久才好的,本來都想放棄了的,還是堅持弄出來了。
不要差不多,如果啥子都差不多就行了,那你的人生也就差不多的人生。
君子如玉 -----記錄