zoukankan      html  css  js  c++  java
  • spring-data-redis 在spring boot中的使用

      项目中需要用到redis,主要用来作为缓存,redis的客户端有两种实现方式,一是可以直接调用jedis来实现,二是可以使用spring data redis,通过spring的封装来调用。应该使用哪一个呢?基于当前版本spring data redis 1.0.1和jedis 2.0.0,分析如下: 

    Spring Data Redis 1.0.1 优点 

    1.对具体redis客户端做了封装,客户端可在jedis,jredis,rjc等Java客户端中做出选择和切换 

    2.用template对调用做了封装,省去了建立连接,释放连接等繁琐代码。 

    3.对对象的序列化也可自由选择工具。 

    4.提供对spring cache的支持,可用注解实现Cache —— 但是无法设定缓存失效时间。 

    Jedis 2.0.0优点 

    1.可用到Jedis本身提供的更多的特性,比如sharded,比如Masater/Slaver。 

    2.Jedis经过我们之前项目的使用,对其稳定性有验证。 

    1.在Maven中添加依赖

     1  <properties>
     2                        <spring.data.redis.version>1.6.0.RELEASE</spring.data.redis.version>
     3     <jedis.version>2.9.0</jedis.version>
     4 </properties>
     5 <dependencies>
     6 <dependency>
     7             <groupId>org.springframework.data</groupId>
     8             <artifactId>spring-data-redis</artifactId>
     9             <version>${spring.data.redis.version}</version>
    10         </dependency>
    11         <dependency>
    12             <groupId>redis.clients</groupId>
    13             <artifactId>jedis</artifactId>
    14             <version>${jedis.version}</version>
    15         </dependency>
    16 </dependencies>    
    View Code

    2. 配置文件

      1 import java.util.HashMap;
      2 import java.util.Map;
      3 
      4 import org.springframework.beans.factory.annotation.Qualifier;
      5 import org.springframework.beans.factory.annotation.Value;
      6 import org.springframework.cache.annotation.CachingConfigurerSupport;
      7 import org.springframework.cache.annotation.EnableCaching;
      8 import org.springframework.context.annotation.Bean;
      9 import org.springframework.context.annotation.Configuration;
     10 import org.springframework.context.annotation.DependsOn;
     11 import org.springframework.core.env.MapPropertySource;
     12 import org.springframework.data.redis.connection.RedisClusterConfiguration;
     13 import org.springframework.data.redis.connection.RedisConnectionFactory;
     14 import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
     15 import org.springframework.data.redis.core.RedisTemplate;
     16 import org.springframework.data.redis.core.StringRedisTemplate;
     17 import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
     18 import org.springframework.data.redis.serializer.StringRedisSerializer;
     19 
     20 import com.gta.train.platform.common.util.SpringContextHolder;
     21 
     22 import redis.clients.jedis.JedisPoolConfig;
     23 
     24 @Configuration
     25 @EnableCaching
     26 public class RedisClusterConfig extends CachingConfigurerSupport {
     27 
     28     private JedisPoolConfig poolConfig(int maxIdle, int maxTotal, long maxWaitMillis, boolean testOnBorrow,
     29             boolean testOnReturn) {
     30         JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
     31         jedisPoolConfig.setMaxIdle(maxIdle);
     32         jedisPoolConfig.setMaxTotal(maxTotal);
     33         jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
     34         jedisPoolConfig.setTestOnBorrow(testOnBorrow);
     35         jedisPoolConfig.setTestOnReturn(testOnReturn);
     36         return jedisPoolConfig;
     37     }
     38 
     39     private RedisClusterConfiguration redisCluterConfig(String clusterNodes, Long timeout, int redirects,
     40             String password) {
     41         Map<String, Object> source = new HashMap<String, Object>();
     42         source.put("spring.redis.cluster.nodes", clusterNodes);
     43         // source.put("spring.redis.cluster.timeout", timeout);
     44         // source.put("spring.redis.cluster.max-redirects", redirects);
     45         return new RedisClusterConfiguration(new MapPropertySource("RedisClusterConfiguration", source));
     46     }
     47 
     48     @Bean(name = "redisConnectionFactory")
     49     public JedisConnectionFactory redisConnectionFactory(@Value("${spring.redis.cluster.maxIdle}") int maxIdle,
     50             @Value("${spring.redis.cluster.maxTotal}") int maxTotal,
     51             @Value("${spring.redis.cluster.maxWaitMillis}") long maxWaitMillis,
     52             @Value("${spring.redis.cluster.testOnBorrow}") boolean testOnBorrow,
     53             @Value("${spring.redis.cluster.testOnReturn}") boolean testOnReturn,
     54             @Value("${spring.redis.cluster.nodes}") String clusterNodes,
     55             @Value("${spring.redis.cluster.timeout}") Long timeout,
     56             @Value("${spring.redis.cluster.max-redirects}") int redirects,
     57             @Value("${spring.redis.cluster.password}") String password) {
     58         JedisConnectionFactory connectionFactory = new JedisConnectionFactory(
     59                 redisCluterConfig(clusterNodes, timeout, redirects, password),
     60                 poolConfig(maxIdle, maxTotal, maxWaitMillis, testOnBorrow, testOnReturn));
     61         connectionFactory.setPassword(password);
     62         return connectionFactory;
     63     }
     64 
     65     @Bean(name = "stringRedisTemplate")
     66     public StringRedisTemplate stringRedisTemplate() {
     67         StringRedisTemplate template = new StringRedisTemplate();
     68         JedisConnectionFactory jedisConnectionFactory = SpringContextHolder.getBean("redisConnectionFactory");
     69         template.setConnectionFactory(jedisConnectionFactory);
     70         return template;
     71     }
     72 
     73     @SuppressWarnings("rawtypes")
     74     @Bean(name = "redisTemplate")
     75     @DependsOn("redisConnectionFactory")
     76     public RedisTemplate redisTemplate(JedisConnectionFactory redisConnectionFactory) {
     77         RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
     78     //    JedisConnectionFactory jedisConnectionFactory = SpringContextHolder.getBean("redisConnectionFactory");
     79         template.setConnectionFactory(redisConnectionFactory);
     80         template.setKeySerializer(new StringRedisSerializer());
     81         template.setValueSerializer(new JdkSerializationRedisSerializer());
     82         template.setHashKeySerializer(new StringRedisSerializer());
     83         template.setHashValueSerializer(new JdkSerializationRedisSerializer());
     84         return template;
     85     }
     86     
     87     @Bean(name = "shiroRedisConnectionFactory")
     88     public JedisConnectionFactory shiroRedisConnectionFactory(@Value("${spring.redis.cluster.maxIdle}") int maxIdle,
     89             @Value("${spring.redis.cluster.maxTotal}") int maxTotal,
     90             @Value("${spring.redis.cluster.maxWaitMillis}") long maxWaitMillis,
     91             @Value("${spring.redis.cluster.testOnBorrow}") boolean testOnBorrow,
     92             @Value("${spring.redis.cluster.testOnReturn}") boolean testOnReturn,
     93             @Value("${spring.redis.cluster.nodes}") String clusterNodes,
     94             @Value("${spring.redis.cluster.timeout}") Long timeout,
     95             @Value("${spring.redis.cluster.max-redirects}") int redirects,
     96             @Value("${spring.redis.cluster.password}") String password) {
     97         JedisConnectionFactory connectionFactory = new JedisConnectionFactory(
     98                 redisCluterConfig(clusterNodes, timeout, redirects, password),
     99                 poolConfig(maxIdle, maxTotal, maxWaitMillis, testOnBorrow, testOnReturn));
    100         connectionFactory.setPassword(password);
    101         return connectionFactory;
    102     }
    103     
    104     
    105     
    106     /**
    107      * @description 
    108      * @author wbh
    109      * @date 2018年11月12日 下午3:45:29
    110      * @param shiroRedisConnectionFactory
    111      * @return
    112      * RedisTemplate
    113      */
    114     @SuppressWarnings("rawtypes")
    115     @Bean(name = "shiroRedisTemplate")
    116     @DependsOn("shiroRedisConnectionFactory")
    117     public RedisTemplate shiroRedisTemplate(@Qualifier("shiroRedisConnectionFactory")JedisConnectionFactory shiroRedisConnectionFactory) {
    118         RedisTemplate<byte[], Object>  template = new RedisTemplate<byte[], Object>();
    119     //    JedisConnectionFactory jedisConnectionFactory = SpringContextHolder.getBean("redisConnectionFactory");
    120         template.setConnectionFactory(shiroRedisConnectionFactory);
    121         //template.setKeySerializer(new StringRedisSerializer());
    122         //template.setValueSerializer(  new RedisObjectSerializer());
    123         template.setDefaultSerializer(new JdkSerializationRedisSerializer());
    124         //template.setHashKeySerializer(new StringRedisSerializer());
    125         //template.setHashValueSerializer(new JdkSerializationRedisSerializer());
    126         return template;
    127     }
    128 }
    View Code

    application-dev.properties对配置的重写

     1 ######################################redis-start##################################
     2 #redis-clusteru914du7f6e
     3 #spring.redis.cluster.nodes=10.1.129.64:6401,10.1.129.64:6402,10.1.129.64:6403,10.1.129.64:6404,10.1.129.64:6405,10.1.129.64:6406
     4 #redis-clusteru914du7f6e
     5 spring.redis.cluster.nodes=10.10.130.150:1501,10.10.130.150:1502,10.10.130.150:1503,10.10.130.150:1504,10.10.130.150:1505,10.10.130.150:1506
     6 spring.redis.cluster.timeout=2000
     7 spring.redis.cluster.max-redirects=100
     8 spring.redis.cluster.password=123456
     9 spring.redis.cluster.maxIdle=200
    10 spring.redis.cluster.maxTotal=1000
    11 spring.redis.cluster.maxWaitMillis=2000
    12 spring.redis.cluster.testOnBorrow=true
    13 spring.redis.cluster.testOnReturn=true
    14 
    15 
    16 ######################################redis-end#####################################
    View Code

    3.静态方法

      1 import java.util.ArrayList;
      2 import java.util.List;
      3 import java.util.Map;
      4 import java.util.Set;
      5 import java.util.concurrent.TimeUnit;
      6 
      7 import com.gta.train.platform.fs.vo.qts.IndexInfo;
      8 import com.gta.train.platform.fs.vo.qts.StockA;
      9 import org.springframework.data.redis.core.HashOperations;
     10 import org.springframework.data.redis.core.ListOperations;
     11 import org.springframework.data.redis.core.RedisTemplate;
     12 import org.springframework.data.redis.core.StringRedisTemplate;
     13 
     14 import com.gta.train.platform.common.util.SpringContextHolder;
     15 
     16 import com.gta.train.platform.common.util.StringUtils;
     17 
     18 public class JedisClusterUtil {
     19     private static StringRedisTemplate stringRedisTemplate = SpringContextHolder.getBean("stringRedisTemplate");
     20     private static RedisTemplate<String, Object> redisTemplate = SpringContextHolder.getBean("redisTemplate");
     21 
     22     private JedisClusterUtil() {
     23     }
     24 
     25     /**
     26      * @description 根据键值取redis缓存中的数据
     27      * @date 2017年6月27日 下午4:02:07
     28      * @param key
     29      * @return
     30      * @return String
     31      */
     32     public static final String get(String key) {
     33         if (StringUtils.isNullOrEmpty(key)) {
     34             return null;
     35         }
     36         return stringRedisTemplate.opsForValue().get(key);
     37     }
     38     
     39     /**
     40      * @description 根据键值从redis中获取对象
     41      * @date 2018年6月1日 上午10:52:23
     42      * @param key
     43      * @return
     44      * @return Object
     45      */
     46     public static final Object getObject(String key) {
     47         if (StringUtils.isNullOrEmpty(key)) {
     48             return null;
     49         }
     50         return redisTemplate.opsForValue().get(key);
     51     }
     52 
     53     /**
     54      * @description 往redis服务器中,写数据
     55      * @author fengya
     56      * @date 2017年6月27日 下午4:04:12
     57      * @param key
     58      * @param value
     59      * @return void
     60      */
     61     public static final void set(String key, String value) {
     62         stringRedisTemplate.opsForValue().set(key, value);
     63     }
     64     
     65     /**
     66      * @description 往redis中设置对象,对象必须进行序列化
     67      * @date 2018年6月1日 上午10:28:41
     68      * @param key
     69      * @param value
     70      * @return void
     71      */
     72     public static final void set(String key, Object value) {
     73         redisTemplate.opsForValue().set(key, value);
     74     }
     75 
     76     /**
     77      * @description 对缓存中的键key进行设置有效期限
     78      * @date 2017年6月29日 下午4:00:01
     79      * @param key
     80      * @param seconds
     81      *            必须大于0
     82      * @return void
     83      */
     84     public static final void expire(String key, long seconds) {
     85         if (seconds > 0) {
     86             stringRedisTemplate.expire(key, seconds, TimeUnit.SECONDS);
     87         }
     88     }
     89 
     90     /**
     91      * @description 写缓存数据,并规定过期时间
     92      * @date 2017年6月27日 下午4:07:02
     93      * @param key
     94      * @param value
     95      * @param seconds
     96      *            过期时间,单位:秒
     97      * @return void
     98      */
     99     public static final void set(String key, String value, long seconds) {
    100         stringRedisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS);
    101     }
    102     
    103     /**
    104      * @description 判断redis缓存中是否存在键为key的数据
    105      * @date 2017年6月29日 下午3:56:32
    106      * @param key
    107      * @return
    108      * @return boolean
    109      */
    110     public static final boolean exists(String key) {
    111         String value = get(key);
    112         if (StringUtils.isNullOrEmpty(value)) {
    113             return false;
    114         }
    115         return true;
    116     }
    117 
    118     /**
    119      * @description 删除一个key
    120      * @date 2017年6月27日 下午5:02:56
    121      * @param key
    122      * @return void
    123      */
    124     public static final void del(String... keys) {
    125         for (String key : keys) {
    126             stringRedisTemplate.delete(key);
    127         }
    128     }
    129     
    130     /**
    131      * @description 从redis缓存中,删除对象
    132      * @date 2018年6月1日 上午11:09:08
    133      * @param keys
    134      * @return void
    135      */
    136     public static final void delObject(String... keys) {
    137         for (String key : keys) {
    138             redisTemplate.delete(key);
    139         }
    140     }
    141 
    142     /**
    143      * @description 往缓存中添加一个list数据
    144      * @date 2017年8月10日 下午2:10:24
    145      * @param key
    146      * @param dataList
    147      * @return
    148      * @return ListOperations<String,Object>
    149      */
    150     public static final ListOperations<String, Object> setCacheList(String key, List<Object> dataList) {
    151         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
    152         if (null != dataList) {
    153             listOperation.rightPushAll(key, dataList);
    154         }
    155         return listOperation;
    156     }
    157 
    158     /**
    159      * @description 读取缓存集合中所有的数据信息
    160      * @date 2017年8月10日 下午4:10:37
    161      * @param key
    162      * @return
    163      * @return List<Object>
    164      */
    165     public static final List<Object> getCacheList(String key) {
    166         return redisTemplate.opsForList().range(key, 0, -1);
    167     }
    168 
    169     /**
    170      * @description 根据键值获得该键对应的集合数据,并对所有的记录数据进行出栈
    171      * @date 2017年8月10日 下午2:18:02
    172      * @param key
    173      * @return
    174      * @return List<Object>
    175      */
    176     public static final List<Object> listPopAll(String key) {
    177         List<Object> dataList = new ArrayList<Object>();
    178         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
    179         Long size = listOperation.size(key);
    180         for (int i = 0; i < size; i++) {
    181             dataList.add(listOperation.leftPop(key));
    182         }
    183         return dataList;
    184     }
    185 
    186     /**
    187      * @description 对缓存集合中的元素按照下标位置进行出栈操作
    188      * @date 2017年8月10日 下午4:07:44
    189      * @param key
    190      * @param start
    191      *            下标开始位置
    192      * @param end
    193      *            下标结束位置 ,-1代表最后一个元素下标
    194      * @return
    195      * @return List<Object>
    196      */
    197     public static final List<Object> listPopRange(String key, int start, long end) {
    198         List<Object> dataList = new ArrayList<Object>();
    199         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
    200         long size = listOperation.size(key);
    201         end = end > size ? size : end;
    202         for (int i = start; i < end; i++) {
    203             dataList.add(listOperation.leftPop(key));
    204         }
    205         return dataList;
    206     }
    207 
    208     /**
    209      * @description 获得缓存键值为Key集合中的下标范围内的集合数据
    210      * @date 2017年8月10日 下午2:19:26
    211      * @param key
    212      * @param start
    213      * @param end
    214      * @return
    215      * @return List<Object>
    216      */
    217     public static final List<Object> range(String key, long start, long end) {
    218         ListOperations<String, Object> listOperation = redisTemplate.opsForList();
    219         return listOperation.range(key, start, end);
    220     }
    221 
    222     /**
    223      * @description 获得缓存中集合的长度
    224      * @date 2017年8月10日 下午2:21:51
    225      * @param key
    226      * @return
    227      * @return Long
    228      */
    229     public static final Long listSize(String key) {
    230         return redisTemplate.opsForList().size(key);
    231     }
    232 
    233     /**
    234      * @description 在集合指定下标内进行数据覆盖
    235      * @date 2017年8月10日 下午2:22:58
    236      * @param key
    237      * @param index
    238      * @param obj
    239      * @return void
    240      */
    241     public static final void listSet(String key, int index, Object obj) {
    242         redisTemplate.opsForList().set(key, index, obj);
    243     }
    244 
    245     /**
    246      * @description 向集合缓存的头部插入记录
    247      * @date 2017年8月10日 下午2:24:10
    248      * @param key
    249      * @param obj
    250      * @return
    251      * @return long
    252      */
    253     public static final long leftPush(String key, Object obj) {
    254         return redisTemplate.opsForList().leftPush(key, obj);
    255     }
    256 
    257     /**
    258      * @description 向集合缓存的尾部插入记录
    259      * @date 2017年8月10日 下午2:25:31
    260      * @param key
    261      * @param obj
    262      * @return
    263      * @return long
    264      */
    265     public static final long rightPush(String key, Object obj) {
    266         return redisTemplate.opsForList().rightPush(key, obj);
    267     }
    268 
    269     /**
    270      * @description 缓存集合中的数据,只保留start到end位置的元素
    271      * @date 2017年8月10日 下午2:27:05
    272      * @param key
    273      * @param start
    274      *            记录的开始位置(0表示第一条记录)
    275      * @param end
    276      *            记录的结束位置(如果为-1则表示最后一个,-2,-3以此类推)
    277      * @return void
    278      */
    279     public static final void trim(String key, int start, int end) {
    280         redisTemplate.opsForList().trim(key, start, end);
    281     }
    282 
    283     /**
    284      * @description 删除缓存集合中指定位置的元素
    285      * @date 2017年8月10日 下午2:28:55
    286      * @param key
    287      * @param i
    288      *            要删除的数量,如果为负数则从List的尾部检查并删除符合的记录
    289      * @param obj
    290      *            要匹配的值
    291      * @return
    292      * @return long 删除后的List中的记录数
    293      */
    294     public static final long remove(String key, long i, Object obj) {
    295         return redisTemplate.opsForList().remove(key, i, obj);
    296     }
    297 
    298     /**
    299      * @description 在缓存中存储set集合,
    300      * @date 2017年8月10日 下午4:53:06
    301      * @param key
    302      * @param dataSet
    303      * @return
    304      * @return void
    305      */
    306     public static final void setCacheSet(String key, Set<Object> dataSet) {
    307         redisTemplate.opsForSet().add(key, dataSet.toArray());
    308     }
    309     
    310     /**
    311      * @description 得到集合中所有的元素
    312      * @date 2017年8月10日 下午5:10:35
    313      * @param key
    314      * @return
    315      * @return Set<Object>
    316      */
    317     public static final Set<Object> getCacheSet(String key) {
    318         return redisTemplate.opsForSet().members(key);
    319     }
    320     
    321     /**
    322      * @description 对缓存中的集合进行出栈操作
    323      * @date 2017年8月10日 下午5:13:29
    324      * @param key
    325      * @return
    326      * @return Object
    327      */
    328     public static final Object setPop(String key) {
    329         return redisTemplate.opsForSet().pop(key);
    330     }
    331     
    332     /**
    333      * @description 对缓存中的集合元素进行删除操作
    334      * @date 2017年8月10日 下午5:14:36
    335      * @param key
    336      * @param values 待删除的元素集合
    337      * @return
    338      * @return long 删除元素的个数
    339      */
    340     public static final long setPop(String key,Object...values) {
    341         return redisTemplate.opsForSet().remove(key, values);
    342     }
    343     
    344     /**
    345      * @description 往缓存写入map数据
    346      * @date 2017年8月10日 下午5:17:48
    347      * @param key
    348      * @param dataMap
    349      * @return void
    350      */
    351     public static final void setCacheMap(String key,Map<String, Object> dataMap) {
    352         redisTemplate.opsForHash().putAll(key, dataMap);
    353     }
    354     
    355     /**
    356      * @description 根据键值从缓存中取map数据
    357      * @date 2017年8月10日 下午5:20:40
    358      * @param key
    359      * @return
    360      * @return Map<Object,Object>
    361      */
    362     public static final Map<Object, Object> getCacheMap(String key) {
    363         return redisTemplate.opsForHash().entries(key);
    364     }
    365     
    366     /**
    367      * @description 从缓存中取根据Map中的键取值对象
    368      * @date 2017年8月10日 下午5:23:11
    369      * @param key
    370      * @param mapKey
    371      * @return
    372      * @return Object
    373      */
    374     public static final Object getMapValue(String key,String mapKey) {
    375         return redisTemplate.opsForHash().get(key, mapKey);
    376     }
    377     
    378     /**
    379      * @description 往缓存Map中,添加一组元素
    380      * @date 2017年8月10日 下午5:25:11
    381      * @param key 缓存中对应的键
    382      * @param mapKey map中的键
    383      * @param mapValue map中的值
    384      * @return void
    385      */
    386     public static final void mapPush(String key,String mapKey,Object mapValue) {
    387         redisTemplate.opsForHash().put(key, mapKey, mapValue);
    388     }
    389     
    390     /**
    391      * @description 从缓存中对应键的key中的map中,根据map中的键进行删除该键对应的元素
    392      * @date 2017年8月10日 下午5:29:53
    393      * @param key 缓存中的键
    394      * @param mapKey map中的键
    395      * @return void
    396      */
    397     public static final void deleteMapByMapKey(String key,String mapKey) {
    398         redisTemplate.opsForHash().delete(key, mapKey);
    399     }
    400 
    401     /**
    402      * @description 往缓存写入map数据
    403      * @date 2017年8月10日 下午5:17:48
    404      * @param key
    405      * @param dataMap
    406      * @return void
    407      */
    408     public static final void setMap(String key,Map<String, String> dataMap) {
    409         redisTemplate.opsForHash().putAll(key, dataMap);
    410     }
    411 
    412     public static final Map<String, String> getMap(String key) {
    413         HashOperations<String, String, String> hps = redisTemplate.opsForHash();
    414         return hps.entries(key);
    415     }
    416 
    417     public static final void setIndexMap(String key,Map<String, IndexInfo> dataMap) {
    418         redisTemplate.opsForHash().putAll(key, dataMap);
    419     }
    420 
    421     public static final Map<String, IndexInfo> getIndexMap(String key) {
    422         HashOperations<String, String, IndexInfo> hps = redisTemplate.opsForHash();
    423         return hps.entries(key);
    424     }
    425 
    426 }
    View Code

    4.具体使用

    1 JedisClusterUtil.set("lkjlkjjklasdf", "11111111111");
    2 System.out.println(JedisClusterUtil.get("lkjlkjjklasdf"));
    3 
    4 SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    5 byte[] bkey = getByteKey("c0233b04e18a11e8984cd4ae52b618b7");
    6 shiroRedisTemplate.opsForValue().set(bkey,info);
    7 Object o=shiroRedisTemplate.opsForValue().get(bkey);
    8 System.out.println(o);
    View Code
  • 相关阅读:
    USACO Section 2.2 Subset Sums
    九度 1399 名侦探柯南
    九度 1416 猴子吃坚果
    pch文件的使用(原作者太逗了)
    线程同步
    extern "c"
    进程与线程
    排序算法代码汇总
    Linux Shell 常用命令与目录分区的学习总结 (开始学习linux)
    堆和栈
  • 原文地址:https://www.cnblogs.com/songStar/p/11016115.html
Copyright © 2011-2022 走看看