今天是2021-2-7
一。redis
1.学会使用了springboot整合redis操作hash结构的各种api,写为了一个工具类
@Component
public class RedisUtils {
@Autowired
private RedisTemplate<String,Object> redisTemplate;
/**
* 查看指定key是否存在
* @param key
* @return
*/
public Boolean existsKey(String key){
return redisTemplate.hasKey(key);
}
/**
* 判断hash中是否存在指定key
* @param key
* @return
*/
public Boolean hExists(String key){
return redisTemplate.opsForHash().hasKey(RedisEnum.NEWS.getName(),key);
}
/**
* 一次添加整个实体集合
* @param key
* @param map
* @param <T>
*/
public <T> void hPutAll(String key,Map<String,T> map){
redisTemplate.opsForHash().putAll(key,map);
}
/**
* 得到存储的所有hash数据
* @param key
* @return
*/
public <T> List<T> hGetAll(String key){
return redisTemplate.execute(new RedisCallback<List<T>>(){
//需要使用序列化时的序列化器,以达到一致
RedisSerializer serializer=redisTemplate.getHashValueSerializer();
@Override
public List<T> doInRedis(RedisConnection connection) throws DataAccessException {
List<byte[]> bytes=connection.hVals(key.getBytes());
List<T> list=new ArrayList<>();
for (byte[] b :bytes) {
list.add((T) serializer.deserialize(b));
}
return list;
}
});
}
/**
* 修改或更新后调用该方法
*/
public void hSet(String key,String field,Object value){
redisTemplate.opsForHash().put(key,field,value);
}
/**
* 删除后调用该方法
* @param key
* @param field
*/
public void hDel(String key,String field){
redisTemplate.opsForHash().delete(key,field);
}
public void delKey(String key){
redisTemplate.delete(key);
}
/**
* 得到hash中的一条数据
* @param key
* @param field
* @return
*/
public Object hGet(String key,String field){
return redisTemplate.opsForHash().get(key,field);
}
2.批量操作之execute()与executePipelined
2.1 execute可以在一次redis连接中批量执行多个操作,并以list的形式最终返回多个操作的值,减少连接创建和销毁消耗的资源,但这个方法不支持事务操作。
2.2 executePipelined是一次redis连接中在“管道”内批量执行多个操作,支持事务。但重写的回调函数必须返回空值,因为executePipelined内部其实还是调用了execute,在execute内部开启管道执行操作,外部回调函数的返回值会被管道执行的结果覆盖。
public List<Object> executePipelined(final SessionCallback<?> session, final RedisSerializer<?> resultSerializer) {
Assert.isTrue(initialized, "template not initialized; call afterPropertiesSet() before using it");
Assert.notNull(session, "Callback object must not be null");
RedisConnectionFactory factory = getConnectionFactory();
// bind connection
RedisConnectionUtils.bindConnection(factory, enableTransactionSupport);
try {
return execute(new RedisCallback<List<Object>>() {
public List<Object> doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
boolean pipelinedClosed = false;
try {
Object result = executeSession(session);
if (result != null) {
throw new InvalidDataAccessApiUsageException(
"Callback cannot return a non-null value as it gets overwritten by the pipeline");
}
List<Object> closePipeline = connection.closePipeline();
pipelinedClosed = true;
return deserializeMixedResults(closePipeline, resultSerializer, hashKeySerializer, hashValueSerializer);
} finally {
if (!pipelinedClosed) {
connection.closePipeline();
}
}
}
});
} finally {
RedisConnectionUtils.unbindConnection(factory);
}
}
3.doInRedis中的redis操作不会立刻执行
3.1所有redis操作会在connection.closePipeline()之后一并提交到redis并执行,这是pipeline方式的优势,相较传统的单次操作性能提升非常多。
4.序列化器默认是JdkSerializationRedisSerializer
4.1Jackson2JsonRedisSerializer,使用该序列化器需要指定目标类的类型:xxx.class,无法全局使用,多种情况可能要定义多个。且序列化带泛型的数据时,会以map的结构进行存储,反序列化是不能将map解析成对象。如果要序列化带泛型的数据,先将数据转为json字符串,再存入字符串;反序列化后再将字符串转为泛型数据即可。
4.2 GenericJackson2JsonRedisSerializer,操作object类型,可直接反序列化带泛型的数据。因为使用GenericJackson2JsonRedisSerializer序列化时,会保存序列化的对象的包名和类名,反序列化时以这个作为标示就可以反序列化成指定的对象。但占用内存会比Jackson2JsonRedisSerializer要多,效率稍低。
@Bean
public RedisTemplate<String, Object> redisTemplate( RedisConnectionFactory redisConnectionFactory)throws UnknownHostException {
RedisTemplate<String, Object> redisTemplate=new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用 GenericFastJsonRedisSerializer 替换默认序列化
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
// 设置key和value的序列化规则
redisTemplate.setKeySerializer(new GenericToStringSerializer<>(Object.class));
redisTemplate.setValueSerializer(genericJackson2JsonRedisSerializer);
// 设置hashKey和hashValue的序列化规则
redisTemplate.setHashKeySerializer(new GenericToStringSerializer<>(Object.class));
redisTemplate.setHashValueSerializer(genericJackson2JsonRedisSerializer);
// 设置支持事务
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
二。mybatis
insert插入数据后,redis添加的对象自增id为空,解决:
在insert标签加属性,是否使用 useGeneratedKeys 开关为true,keyProperty对应的就是要返回的字段名称
<insert id="insertSelective" parameterType="cn.tencent.eee.aaa.dao.model.User" useGeneratedKeys="true" keyProperty="id">
</insert>
三。js
修改或新增后,需要判断某个字段的值是否与其他记录的同一字段值相同,解决:
1.为目标字段添加onblur事件,获取并失去焦点后发送ajax请求判断
2.禁用其他需要的输入框的输入:$("#xxx").prop("disabled",true);
即可
改为false即可启用
四。springboot
需要在项目启动时同步更新redis的缓存,解决:
@Component
@Order(1)
public class MyApplicationRunner implements CommandLineRunner {
@Autowired
private NewsService service;
//同步数据库的数据到redis
@Override
public void run(String... args) throws Exception {
service.addNewsToRedis();
}