redis单点、redis主从、redis哨兵 sentinel,redis集群cluster配置搭建与使用

redis是如今被互联网公司使用最广泛的一个中间件,我们打开GitHub搜索redis,边可以看到,该项目的介绍是这样的:

Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, HyperLogLogs, Bitmaps.

从这句话中,我们可以提取其特性的关键字:

  • in-memory database ,内存数据库
  • support:Strings , lists, sets ,hashes ,hyperloglogs, bitmaps

也就是高性能,支持数据类型多。本文假设你已经了解redis的基本使用,进而讨论redis的单点,高可用,集群。

1 .redis 安装及配置

redis的安装十分简单,打开redis的官网 http://redis.io 。

  1. 下载一个最新版本的安装包,如 redis-version.tar.gz
  2. 解压 tar zxvf redis-version.tar.gz
  3. 执行 make (执行此命令可能会报错,例如确实gcc,一个个解决即可)

如果是 mac 电脑,安装redis将十分简单执行brew install redis即可。

安装好redis之后,我们先不慌使用,先进行一些配置。打开redis.conf文件,我们主要关注以下配置:

port 6379             # 指定端口为 6379,也可自行修改
daemonize yes # 指定后台运行

1.1 redis 单点

安装好redis之后,我们来运行一下。启动redis的命令为 :

redishome/bin/redis-server path/to/redis.config

假设我们没有配置后台运行(即:daemonize no),那么我们会看到如下启动日志:

93825:C 20 Jan 2019 11:43:22.640 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
93825:C 20 Jan 2019 11:43:22.640 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=93825, just started
93825:C 20 Jan 2019 11:43:22.640 # Configuration loaded
93825:S 20 Jan 2019 11:43:22.641 * Increased maximum number of open files to 10032 (it was originally set to 256).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.3 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6380
| `-._ `._ / _.-' | PID: 93825
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

无论是否配置了后台运行,启动成功之后,我们可以新开一个命令行窗口来操作试试。

1.1.2 在命令窗口操作redis

使用命令:telnet localhost 6379 来连接redis,或者你可以直接使用代码来连接测试。连接之后,看到如下信息:

Connected to localhost.
Escape character is '^]'.

我们输入几个命令试试:

set hello world     设置key-value
get hello 获取key值
expire hello 10 设置10秒过期
ttl hello 查看过期时间
del hello 删除key

如此,我们便体验了一把redis,可以说是非常简单了。刚才我们是使用命令行来操作redis的,下面我们来使用代码操作一下redis,以Java为例,我们使用一个开源的 java - redis客户端。

1.1.3 使用jedis客户端操作redis

打开GitHub,搜索redis,进入到项目主页之后,我们可以看到使用方法:

  1. 加入jedis依赖

    <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.0.0</version>
    <type>jar</type>
    <scope>compile</scope>
    </dependency>
  2. 编写代码如下

    Jedis jedis = new Jedis("localhost",6379);
    
    jedis.set("hello", "world");
    
    String value = jedis.get("hello");
    
    System.out.println(value); // get world
    
    jedis.del("hello");
    
    System.out.println(jedis.get("hello"));// get null

1.1.4 使用spring-redis操作

上面jedis操作redis的例子很简单,除了使用jedis之外,还可以使用spring-redis。步骤如下

  1. 配置redis

    <bean id="jedisConnFactory"
    class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
    p:use-pool="true"/> <!-- redis template definition -->
    <bean id="redisTemplate"
    class="org.springframework.data.redis.core.RedisTemplate"
    p:connection-factory-ref="jedisConnFactory"/>
  2. 编写代码

    public class Example {
    
        // inject the actual template
    @Autowired
    private RedisTemplate<String, String> template; // inject the template as ListOperations
    // can also inject as Value, Set, ZSet, and HashOperations
    @Resource(name="redisTemplate")
    private ListOperations<String, String> listOps; public void addLink(String userId, URL url) {
    listOps.leftPush(userId, url.toExternalForm());
    // or use template directly
    redisTemplate.boundListOps(userId).leftPush(url.toExternalForm());
    }
    }

1.2 redis 主从

上面我们启动了一台redis,并对其进行操作。当然这只是实验性的玩玩。假设我们生产环境使用了一台redis,redis挂了怎么办?如果等到运维重启redis,并恢复好数据,可能需要花费很长时间。那么在这期间,我们的服务是不可用的,这应该是不能容忍的。假设我们做了主从,主库挂了之后,运维让从库接管,那么服务可以继续运行,正所谓有备无患。

redis主从配置非常简单,过程如下(ps 演示情况下主从配置在一台电脑上):

  1. 复制两个redis配置文件(启动两个redis,只需要一份redis程序,两个不同的redis配置文件即可)
mkdir redis-master-slave
cp path/to/redis/conf/redis.conf path/to/redis-master-slave master.conf
cp path/to/redis/conf/redis.conf path/to/redis-master-slave slave.conf
  1. 修改配置
## master.conf
port 6379 ## master.conf
port 6380
slaveof 127.0.0.1 6379
  1. 分别启动两个redis
redis-server path/to/redis-master-slave/master.conf
redis-server path/to/redis-master-slave/slave.conf

启动之后,打开两个命令行窗口,分别执行telnet localhost 6379 telnet localhost 6380

然后分别在两个窗口中执行 info 命令,可以看到

# Replication
role:master # Replication
role:slave
master_host:127.0.0.1
master_port:6379

主从配置没问题。

然后在master 窗口执行 set 之后,到slave窗口执行get,可以get到,说明主从同步成功。

这时,我们如果在slave窗口执行 set ,会报错:

-READONLY You can't write against a read only replica.

因为从节点是只读的。

1.3 哨兵sentinel

上面我们介绍了主从,从库作为一个“傀儡”,可以在需要的时候“顶上来”,”接盘“。我们配置的主从是为了”有备无患“,在主redis挂了之后,可以立马切换到从redis上,可能只需要花几分钟的时间,但是仍然是需要人为操作。假设主redis在晚上23点挂了,10分钟之后你接到电话,老板让你赶紧修复,于是你从被窝爬起来整,岂不是很头疼。假如你关机了,又其他人知道服务器密码,那系统岂不是要停机一晚上?太可怕了。

这个时候redis sentinel 就派上用场了。sentinel 通常翻译成哨兵,就是放哨的,这里它就是用来监控主从节点的健康情况。客户端连接redis主从的时候,先连接 sentinel,sentinel会告诉客户端主redis的地址是多少,然后客户端连接上redis并进行后续的操作。当主节点挂掉的时候,客户端就得不到连接了因而报错了,客户端重新想sentinel询问主master的地址,然后客户端得到了[新选举出来的主redis],然后又可以愉快的操作了。

1.3.2 哨兵sentinel配置

为了说明sentinel的用处,我们做个试验。配置3个redis(1主2从),1个哨兵。步骤如下:

mkdir redis-sentinel
cd redis-sentinel
cp redis/path/conf/redis.conf path/to/redis-sentinel/redis01.conf
cp redis/path/conf/redis.conf path/to/redis-sentinel/redis02.conf
cp redis/path/conf/redis.conf path/to/redis-sentinel/redis03.conf
touch sentinel.conf

上我们创建了 3个redis配置文件,1个哨兵配置文件。我们将 redis01设置为master,将redis02,redis03设置为slave。

vim redis01.conf
port 63791 vim redis02.conf
port 63792
slaveof 127.0.0.1 63791 vim redis03.conf
port 63793
slaveof 127.0.0.1 63791 vim sentinel.conf
daemonize yes
port 26379
sentinel monitor mymaster 127.0.0.1 63793 1 # 下面解释含义

上面的主从配置都熟悉,只有哨兵配置 sentinel.conf,需要解释一下:

mymaster        为主节点名字,可以随便取,后面程序里边连接的时候要用到
127.0.0.1 63793 为主节点的 ip,port
1 后面的数字 1 表示选举主节点的时候,投票数。1表示有一个sentinel同意即可升级为master

1.3.3 启动哨兵,使用jedis连接哨兵操作redis

上面我们配置好了redis主从,1主2从,以及1个哨兵。下面我们分别启动redis,并启动哨兵

redis-server path/to/redis-sentinel/redis01.conf
redis-server path/to/redis-sentinel/redis02.conf
redis-server path/to/redis-sentinel/redis03.conf redis-server path/to/redis-sentinel/sentinel.conf --sentinel

启动之后,可以分别连接到 3个redis上,执行info查看主从信息。

1.3.4 编写程序&运行

下面使用程序来连接哨兵,并操作redis。

   public static void main(String[] args) throws Exception{

        Set<String> hosts = new HashSet<>();
hosts.add("127.0.0.1:26379");
//hosts.add("127.0.0.1:36379"); 配置多个哨兵 JedisSentinelPool pool = new JedisSentinelPool("mymaster",hosts);
Jedis jedis = null; for(int i=0 ;i<20;i++){
Thread.sleep(2000); try{ jedis = pool.getResource();
String v = randomString();
jedis.set("hello",v); System.out.println(v+"-->"+jedis.get("hello").equals(v)); }catch (Exception e){
System.out.println(" [ exception happened]" + e);
} } }

程序非常简单,循环运行20次,连接哨兵,将随机字符串 set到redis,get结果。打印信息,异常捕获。

1.3.5模拟主节点宕机情况

运行上面的程序(注意,在实验这个效果的时候,可以将sleep时间加长或者for循环增多,以防程序提前停止,不便看整体效果),然后将主redis关掉,模拟redis挂掉的情况。现在主redis为redis01,端口为63791

redis-cli -p 63791 shutdown

这个时候如果sentinel没有设置后台运行,可以在命令行窗口看到 master切换的情况日志。

# Sentinel ID is fd0634dc9876ec60da65db5ff1e50ebbeefdf5ce
# +monitor master mymaster 127.0.0.1 63791 quorum 1
* +slave slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
# +sdown master mymaster 127.0.0.1 63791
# +odown master mymaster 127.0.0.1 63791 #quorum 1/1
# +new-epoch 1
# +try-failover master mymaster 127.0.0.1 63791
# +vote-for-leader fd0634dc9876ec60da65db5ff1e50ebbeefdf5ce 1
# +elected-leader master mymaster 127.0.0.1 63791
# +failover-state-select-slave master mymaster 127.0.0.1 63791
# +selected-slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
* +failover-state-send-slaveof-noone slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
* +failover-state-wait-promotion slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
# +promoted-slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
# +failover-state-reconf-slaves master mymaster 127.0.0.1 63791
* +slave-reconf-sent slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave-reconf-inprog slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave-reconf-done slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
# +failover-end master mymaster 127.0.0.1 63791
# +switch-master mymaster 127.0.0.1 63791 127.0.0.1 63793
* +slave slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63793
* +slave slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793
# +sdown slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793
# -sdown slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793
* +convert-to-slave slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793

上面的日志较多,仔细找找可以看到下面几行主要的:

初始情况下,1主2从
# +monitor master mymaster 127.0.0.1 63791 quorum 1
* +slave slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
发现主挂了,准备 故障转移
# +try-failover master mymaster 127.0.0.1 63791
将主切换到了 63793 即redis03
# +switch-master mymaster 127.0.0.1 63791 127.0.0.1 63793

这个日志比较晦涩,从代码运行效果看,如下:

14:45:20.675 [main] INFO redis.clients.jedis.JedisSentinelPool - Trying to find master from available Sentinels...
14:45:25.731 [main] DEBUG redis.clients.jedis.JedisSentinelPool - Connecting to Sentinel 192.168.1.106:26379
14:45:25.770 [main] DEBUG redis.clients.jedis.JedisSentinelPool - Found Redis master at 127.0.0.1:63792
14:45:25.771 [main] INFO redis.clients.jedis.JedisSentinelPool - Redis master running at 127.0.0.1:63792, starting Sentinel listeners...
14:45:25.871 [main] INFO redis.clients.jedis.JedisSentinelPool - Created JedisPool to master at 127.0.0.1:63792
ejahaeegig-->true
deeeadejjf-->true
[ exception happened]redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
14:46:02.737 [MasterListener-mymaster-[192.168.1.106:26379]] DEBUG redis.clients.jedis.JedisSentinelPool - Sentinel 192.168.1.106:26379 published: mymaster 127.0.0.1 63792 127.0.0.1 63793.
14:46:02.738 [MasterListener-mymaster-[192.168.1.106:26379]] INFO redis.clients.jedis.JedisSentinelPool - Created JedisPool to master at 127.0.0.1:63793
haiihiihbb-->true
ifgebdcicd-->true
aajhbjagag-->true Process finished with exit code 0

从结果看出

  1. 开始正常操作redis,并设置了两次。
  2. 主redis挂了,jedis得不到连接,报错了JedisConnectionException:Could not get a resource from the pool
  3. 主redis没选好之前,程序持续报错。
  4. 主redis选好了,程序正常运行,最后结束。

我们看到最后一次运行设置的值是aajhbjagag,我们可以连接剩下的2台redis中的任意一台,get hello,结果肯定是一致的。

1.4 redis cluster

上面的章节中,我们分别学习了redis 单点,redis主从,并增加了高可用的 sentinel 哨兵模式。我们所做的这些工作只是保证了数据备份以及高可用,目前为止我们的程序一直都是向1台redis写数据,其他的redis只是备份而已。实际场景中,单个redis节点可能不满足要求,因为:

  • 单个redis并发有限
  • 单个redis接收所有的数据,最终回导致内存太大,内存太大回导致rdb文件过大,从很大的rdb文件中同步恢复数据会很慢。

所有,我们需要redis cluster 即redis集群。

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.

Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

为了配置一个redis cluster,我们需要准备至少6台redis,为啥至少6台呢?我们可以在redis的官方文档中找到如下一句话:

Note that the minimal cluster that works as expected requires to contain at least three master nodes. 

因为最小的redis集群,需要至少3个主节点,既然有3个主节点,而一个主节点搭配至少一个从节点,因此至少得6台redis。然而对我来说,就是复制6个redis配置文件。本实验的redis集群搭建依然在一台电脑上模拟。

1.4.1 配置 redis cluster 集群

上面提到,配置redis集群需要至少6个redis节点。因此我们需要准备及配置的节点如下:

主:redis01  从 redis02    slaveof redis01
主:redis03 从 redis04 slaveof redis03
主:redis05 从 redis06 slaveof redis05
mkdir redis-cluster
cd redis-cluster
mkdir redis01 到 redis06 6个文件夹
cp redis.conf 到 redis01 ... redis06
修改端口
分别配置3组主从关系

1.4.2启动redis集群

上面的配置完成之后,分别启动6个redis实例。配置正确的情况下,都可以启动成功。然后运行如下命令创建集群:

redis-5.0.3/src/redis-cli --cluster create 127.0.0.1:6371 127.0.0.1:6372 127.0.0.1:6373 127.0.0.1:6374 127.0.0.1:6375 127.0.0.1:6376 --cluster-replicas 1

注意,这里使用的是ip:port,而不是 domain:port ,因为我在使用 localhost:6371 之类的写法执行的时候碰到错误:

ERR Invalid node address specified: localhost:6371

执行成功之后,连接一台redis,执行 cluster info 会看到类似如下信息:

cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1515
cluster_stats_messages_pong_sent:1506
cluster_stats_messages_sent:3021
cluster_stats_messages_ping_received:1501
cluster_stats_messages_pong_received:1515
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:3021

我们可以看到cluster_state:ok,cluster_slots_ok:16384,cluster_size:3

1.4.3 使用jedis连接redis cluster 集群

上面我们配置了一个redis集群,包含6个redis节点,3主3从。下面我们来使用jedis来连接redis集群。代码如下:

    public static void main(String[] args) {

        Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6371));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6372));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6373));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6374));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6375));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6376));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set("foo", "bar");
String value = jc.get("foo");
System.out.println(" ===> " + value);
}

上面我们设置了信息set foo bar,但是不知道被设置到那一台redis上去了。请读者思考一下,我们是集群模式,所以数据被分散放到不同的槽中了,Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

看到这里你应该还是不知道set foo bar 放到哪台redis上去了,不妨尝试连接任意一台redis探索一下,你会知道的。

总结

至此,我们了解并动手实践了redis的安装,redis单点,redis主从,redis 哨兵 sentinel,redis 集群cluster。
我们来梳理一下redis主从,redis哨兵,redis机器的区别和关系。

redis主从:是备份关系, 我们操作主库,数据也会同步到从库。 如果主库机器坏了,从库可以上。就好比你 D盘的片丢了,但是你移动硬盘里边备份有。
redis哨兵:哨兵保证的是HA,保证特殊情况故障自动切换,哨兵盯着你的“redis主从集群”,如果主库死了,它会告诉你新的老大是谁。
redis集群:集群保证的是高并发,因为多了一些兄弟帮忙一起扛。同时集群会导致数据的分散,整个redis集群会分成一堆数据槽,即不同的key会放到不不同的槽中。

主从保证了数据备份,哨兵保证了HA 即故障时切换,集群保证了高并发性。

一切动手做了才会熟悉。

Lua脚本在redis分布式锁场景的运用

Netty开发redis客户端,Netty发送redis命令,netty解析redis消息

配置搭建与使用redis的更多相关文章

  1. redis单点、redis主从、redis哨兵sentinel,redis集群cluster配置搭建与使用

    目录 redis单点.redis主从.redis哨兵 sentinel,redis集群cluster配置搭建与使用 1 .redis 安装及配置 1.1 redis 单点 1.1.2 在命令窗口操作r ...

  2. Ubuntu16.04.1上搭建分布式的Redis集群

    为什么要集群: 通常为了,提高网站的响应速度,总是把一些经常用到的数据放到内存中,而不是放到数据库中,Redis是一个很好的Cache工具,当然了还有Memcached,这里只讲Redis.在我们的电 ...

  3. 从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建

    从零开始搭建框架SSM+Redis+Mysql(二)之MAVEN项目搭建 废话不说,直接撸步骤!!! 1.创建主项目:ncc-parent 选择maven创建项目,注意在创建项目中,packing选择 ...

  4. 如何搭建高可用redis架构?

    如何搭建高可用redis架构? 温国兵 架构师小秘圈 昨天 作者:温国兵,曾任职于酷狗音乐,现为三七互娱 DBA.目前主要关注领域:数据库自动化运维.高可用架构设计.数据库安全.海量数据解决方案.以及 ...

  5. Mac下docker搭建lnmp环境 + redis + elasticsearch

    之前在windows下一直使用vagrant做开发, 团队里面也是各种开发环境,几个人也没有统一环境,各种上线都是人肉,偶尔还会有因为开发.测试.生产环境由于软件版本或者配置不一致产生的问题, 今年准 ...

  6. centos下搭建高可用redis

    Linux下搭建高可用Redis缓存 Redis是一个高性能的key-value数据库,现时越来越多企业与应用使用Redis作为缓存服务器.楼主是一枚JAVA后端程序员,也算是半个运维工程师了.在Li ...

  7. 带你自行搭建虚拟机和Redis集群环境,值得收藏!

    前言: 我们看到分析 Redis 使用或原理的文章不少,但是完整搭建一套独立的 redis 集群环境的介绍,并不是很多或者说还不够详细. 那么,本文会手把手带着大家搭建一套 Redis 集群环境,Re ...

  8. Ubuntu16.04.1上搭建分布式的Redis集群,并使用C#操作

    为什么要集群: 通常为了,提高网站的响应速度,总是把一些经常用到的数据放到内存中,而不是放到数据库中,Redis是一个很好的Cache工具,当然了还有Memcached,这里只讲Redis.在我们的电 ...

  9. 使用三台云服务器搭建真正的Redis集群

    三台云服务器搭建redis集群# 今天花了一天的时间弄集群redis:遇到了很多坑,从头开始吧 环境讲解: 两台配置:1核2G,另一台:1核1G: 操作系统:Centos 7.6 Redis:3.2. ...

随机推荐

  1. Shell需注意的语法问题

    1.文件头声明别漏掉#和! #!/bin/bash 2.赋值语句①=号两端不能有空格(判断语句=号两端必须有空格)②使用变量必须使用符号$ var1=valecho $var1 3.if语句写错下面任 ...

  2. OpenGL入门程序三:点、线、面的绘制

    1.点: void TestPoint() { //点的大小默认为一个像素,通过下面的函数可以设置一点的大小 glPointSize(50.0f); glBegin(GL_POINTS); glVer ...

  3. thinkphp导入

    1.页面: <div class="container"> <div style=" margin:10px;"> <div cl ...

  4. Oracle11g温习-第一章:Oracle 体系架构

    2013年4月27日 星期六 10:20 1.oracle 网络架构及应用环境 1. ORACLE 实例——包括内存结构与后台进程 2. ORACLE 数据库——物理操作系统文件的集合 3. 了解内存 ...

  5. 对LOV中的值进行强制验证

    当LOV之中只有一个LovMap返回当前ITEM时,修改了LOV输入框的值,会弹出验证窗口,若此时忽略此窗口,在进行下一步的时候不会去验证此LOV中的值是否一定在可选列表中. 解决方式, 1.在页面加 ...

  6. Animation鱼眼效果

    <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head>    < ...

  7. DB2默认的事务及并发锁机制

    今天有点时间,试验了一下DB2的并发锁机制,结果,和MSSQL的差不多:1.DB2的缺省行为,事务以可执行的SQL开始,以COMMIT或ROLLBACK结束:2.DB2缺省是否提交,以工具的不同而不同 ...

  8. html form表单提交后处理返回数据

    上传如果通过form提交并且需要处理返回值.(其实用ajax上传方式刚好,看需要) 可以这么做: <form id="importBookForm" action=" ...

  9. pthread_cleanup_push与pthread_cleanup_pop与pthread_cancel与pthread_testcancel

    参考: http://blog.csdn.net/zjc156m/article/details/9021343 http://blog.csdn.net/u010027547/article/det ...

  10. 树状数组Lowbit用法

    刚学树状数组,看到这里的时候懵了.经过询问,发现,原来在程序运行时,数据用的都是补码,于是解决了 int Lowbit(x) { return x&(-x); } 如: x =1: 1 &am ...