相当于关注微信公众号,公众号推送消息
可以一次执行多个命令,本质是一组命令的集合。一个事务中的 所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。
WATCH 用来监视一些 key,一旦这些 key 在事务执行组装之前被改变,则取消事务的执行。
使用watch的情况下在事务组装之后更改key的值是可以的
执行exec之前若出现错误,所有语句都不执行
错误的语句不执行,其他语句照样执行
双十一去购物的时候使用同一张银行卡去付款
10000
一个请求想给金额减8000
一个请求想给金额减5000
一个请求想给金额减1000
解决方案
悲观锁
select * from biao where 1=1 for update;
悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,
每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,
这样别人想拿这个数据就会block直到它拿到锁。
传统的关系型数据库里边就用到了很多这种锁机制,
比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
12306抢票
乐观锁(Optimistic Lock), 顾名思义,就是很乐观,
每次去拿数据的时候都认为别人不会修改,所以不会上锁,
但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,
可以使用版本号等机制。乐观锁适用于多读的应用类型,
这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。
redis.clients
jedis
3.2.0
junit5新特性
@BeforeEach 完成每一个方法前要做的事
@BeforeAll 完成每所有方法前要做的事
@BeforeEach 和 @BeforeAll 是 JUnit 5 中的两个测试生命周期注解,用于在执行测试方法之前执行一些准备工作。
@BeforeEach 注解表示被注解的方法将在每个测试方法执行之前执行。它通常用于设置一些测试数据或对象的初始状态,以确保每个测试方法都从相同的起点开始执行。
@BeforeAll 注解表示被注解的方法将在所有测试方法执行之前执行一次。它通常用于初始化一些共享资源或执行一些耗时较长的准备工作,以避免重复的初始化操作。
这两个注解都可以用于测试类中的方法,但有一些区别:
需要注意的是,@BeforeAll 方法必须是静态方法,而 @BeforeEach 方法可以是静态或实例方法。
使用这两个注解可以帮助我们在测试前进行一些准备工作,提高测试的可靠性和可维护性。
在pom文件中引入依赖
org.springframework.boot
spring-boot-starter-parent
2.7.10
创建一个启动类
@SpringBootApplication
@MapperScan("com.aaa.mapper")
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class);
}
}
org.springframework.boot
spring-boot-starter-data-redis
//io流 加快读取速度
org.apache.commons
commons-pool2
2.6.0
redis.clients
jedis
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
/**
* 连接池的设置
*
* @return
*/
@Bean
public JedisPoolConfig getJedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
return jedisPoolConfig;
}
/**
* RedisTemplate
* @param factory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();
RedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
/**
* 缓存处理
* @param factory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
使用工具类redisTemplate.opsForValue()操作 ops(operations)
@Cacheable
注解在类上,则每一个方法都开启缓存,都存放到数据库中
在方法上 则就在方法中用
再次刷新 直接在redis中获取数据,无需在mysql中找了
java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=…) with your test
报错,需要把test放在同包下