mybatis: 一级缓存(session) 二级缓存(同于一个mapper)
openSession();
.......
commit();
close();
目的: 减少数据库的io访问
缓存就是数据存放在距离计算最近的位置以加快处理速度。缓存是改善软件性能的第一手段,缓存意在减少系统对数据库的过多访问,通过减少对数据库的访问次数,改用访问内存的方式,提升系统的性能。直接从内存获取数据,较之从数据库获取数据,效率可以得到显著的提升。提高客户端的体验。
系统由于多次查询数据库,消耗大量系统资源,且查询效率可能因为开发者的个人能力导致查询效率不高,或占用过多资源影响系统性能。使用缓存管理,系统只有第一次查询访问数据库,而后皆通过访问内存取得数据,不需要在计较这次查询的SQL是否过于复杂,是否效率低下,直接取得数据返回即可。
本地缓存:在应用服务器本地缓存着热点(频繁访问)数据,应用程序可以在本机内存中直接访问数据,而无需访问数据库。
分布式缓存:在应用服务器的数据量非常庞大,即使只缓存一小部分,需要的内存空间也不是单机能承受的,所以除了本地缓存,还需要分布式缓存,将数据缓存在一个专门的分布式缓存集群中,应用程序通过网络通信访问数据。
主流缓存技术有Redis和Memcached。二者谁的性能更高?单纯从缓存命中的角度来说,是Memcached要高,Redis和Memcache的差距不大。但是,Redis提供的功能更加的强大。
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库(数据结构),并提供多种语言的API。redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助
关系型数据库:mysql oracel db2 sqlserver ...
规则的二维表:通过我们的主外键构建表关系
非关系型数据库:Redis、Memcached、mongodb
key-value(存储不规则数据)
用于显示当前库中匹配的key,如果为设置为*表示显示库中所有的key 192.168.18.200:6379> keys *
测试指定的key是否存在,如果存在返回1,不存在返回0。 192.168.18.200:6379> exists name (integer) 1 192.168.18.200:6379> exists address (integer) 0
删除库中指定的key的信息 192.168.18.200:6379> del name > (integer) 1 > 可以一次性删除多个key的信息,同时返回被删除的个数。 > 192.168.18.200:6379> del name1 name2 > (integer) 2 > ``` ## flushdb命令 ```text Flushdb 命令用于清空当前数据库中的所有 key,总是返回 OK。 192.168.18.200:6379> flushdb OK
Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key)。 192.168.18.200:6379> flushall OK
Type命令用于返回 key 所储存的值的类型。 192.168.18.200:6379> type name string
string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。 string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。 string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
set命令
设置key和value并保存到当前数据库中。 语法:set key value 192.168.18.200:6379> set name zhangsan OK
get命令
获取指定key的值 语法:get key 192.168.18.200:6379> get name "zhangsan"
append命令
在原来的值的基础上追加新值,并返回总字符串的长度。 语法:append key value 192.168.18.200:6379> append name feng (integer) 12
strlen命令
获取指定key的值的长度 语法:strlen key 192.168.18.200:6379> strlen name (integer) 12
getrange命令
获取指定key的值,从start位置开始,end位置结束 语法:getrange key start end 192.168.18.200:6379> getrange name 2 7 "angsan"
setrange命令
从起始位置替换值 语法:setrange key offset value 192.168.18.200:6379> setrange name 2 abc (integer) 12
setex命令
设置key的值并指定存活时间 语法:setex key second value 192.168.18.200:6379> setex name2 100 lisi OK
setnx命令
设置key的值并且永久有效 语法:setnx key value 192.168.18.200:6379> setnx address beijing (integer) 1
incr命令
对key的值自增1 语法:incr key 192.168.18.200:6379>incr currentPage
decr命令
对key的值自减1 语法:decr key 192.168.18.200:6379>decr currentPage
incrby命令
对key的值递增指定步长的值 语法:incrby key number 192.168.18.200:6379>incrby currentPage 10
decrby命令
对key的值递减指定步长的值 语法:decrby key number 192.168.18.200:6379>decrby currentPage 5
mset命令
一次性设置多个key-value键值对 语法:mset key1 value1 key2 value2 .... 192.168.18.200:6379>mset name1 zhangsan name2 lisi name3 wangwu
mget命令
一次性获取多个key的值 语法:mget key1 key2 .... 192.168.18.200:6379>mget name1 name2
expire命令
设置key的存活时间 seconds秒数 语法:ttl key 192.168.18.200:6379>expire address 30
persist命令
设置指定的key永久有效 语法: persist key 192.168.18.200:6379>persist address
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。 List list = new ArrayList(); 16个空间
lpush命令
向key集合的左边依次添加值 语法:lpush key value1 value2.... 192.168.18.200:6379>lpush ages 22 34 21 45 20
rpush命令
向key集合的右边依次添加值 语法:rpush key value1 value2.... 192.168.18.200:6379>192.168.18.200:6379>rpush names zhangsan lisi wangwu zhaoliu zhangsan
lrange命令
取key集合中指定的start位置到stop位置的内容(-1代表集合结束) 语法:lrange key start stop 192.168.18.200:6379>lrange ages 0 2 192.168.18.200:6379>lrange ages 0 -1 192.168.18.200:6379>lrange ages 0 100
llen命令
查看key集合的长度 语法:llen key 192.168.18.200:6379>llen ages
lpop命令
删除key集合的第一个元素 语法:lpop key 192.168.18.200:6379>lpop ages
rpop命令
删除key集合的最后一个元素 语法:rpop key 192.168.18.200:6379>rpop ages
lindex命令
获取key集合的index索引的元素 语法:lindex key index lindex ages 2
lrem命令
删除key集合的count个索引的元素(集合中有重复值) 语法:lrem key count value 192.168.18.200:6379>lrem ages 2 45
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。 比较适合存储java对象: key : value([(属性名:属性值),(key:value)]); map("key":Map<String,value>)
hset命令
设置key的field字段的值 语法:hset key field value 192.168.18.200:6379>hset person name lisi 192.168.18.200:6379>hset person address changsha 192.168.18.200:6379>hset person birthday 1997-10-10
hget命令
获取key的field字段的值 语法:hget key field 192.168.18.200:6379>hget person name
hmset命令
一次设置key的多个字段的值 语法:hmset key field1 value1 field2 value2 .... 192.168.18.200:6379>hmset student name wagnwu age 22 gender man
hmget命令
一次获取key的多个字段的值 语法:hmget key field1 field2 .... 192.168.18.200:6379>hmget student name age gender
hgetall命令
获取key的多个字段的值(包括键和值) 语法:hgetall key 192.168.18.200:6379>hgetall student
hkeys命令
获取key的所有字段 语法:hkeys key 192.168.18.200:6379>hkeys student
hvals命令
获取key的所有字段的值 语法:hvals key 192.168.18.200:6379>hvals student
hdel命令
删除大key小中指定的多个小key的值 语法:hdel key field1 field2 ... 192.168.18.200:6379> hdel student name gender age
hlen命令
返回key的所有键值对的个数 语法: hlen key 192.168.18.200:6379>hlen student
hexists命令
返回key的field字段是否存在 语法:hexists key field 192.168.18.200:6379>hexists student name
Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。 Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
sadd命令
向为key的集合中添加多个值(去重) 语法:sadd key value1 value2 ... 192.168.18.200:6379>sadd empNames zhangsan lisi wangwu zhaoliu lisi
smembers命令
循环key集合中的所有值 语法:members key 192.168.18.200:6379>smembers empNames
scard命令
统计key集合中的元素个数 语法:scard key 192.168.18.200:6379> scard empNames
srem命令
删除key集合中的value值 语法:srem key value 192.168.18.200:6379>srem empNames lisi
spop命令
随机删除key集合中的某个值 语法:spop key 192.168.18.200:6379>spop empNames
smove命令
将集合中的某个值赋给另外一个集合: SMOVE 源集合 目的集合 值 语法:smove source destination member 192.168.18.200:6379>smove empNames works zhangsan
Sdiff命令
求差集 语法:Sdiff 集合1 集合2 192.168.18.200:6379>sadd seta a b c d e 192.168.18.200:6379> sadd setb c d e f g 192.168.18.200:6379>sdiff seta setb 1) "a" 2) "b" sdiff setb seta 1) "f" 2) "g"
sinter命令
求交集 语法:sinter 集合1 集合2 192.168.18.200:6379>sinter seta setb 1) "d" 2) "c" 3) "e"
sunion命令
求并集 语法:sunion 集合1 集合2 192.168.18.200:6379> sunion seta setb 1) "d" 2) "a" 3) "b" 4) "c"
Redis 有序集合和list集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
zadd命令
向为key的集合中添加多个(score-value) 语法:zadd key score value ... 192.168.18.200:6379>zadd students 1 zhangsan 3 lisi 2 wangwu 5 zhaoliu
zrange命令
循环key的集合从start位到stop位置的值 语法:zrange key start stop [WITHSCORES] 192.168.18.200:6379>zrange students 0 -1 1) "zhangsan" 2) "wangwu" 3) "lisi" 4) "zhaoliu"
zrem命令
删除key集合中指定的value元素。 语法:zrem key value 192.168.18.200:6379>zrem students lisi
zrevrange命令
逆序显示key集合中的元素。 语法:zrevrange key start stop [WITHSCORES] 192.168.18.200:6379>zrevrange students 0 -1 192.168.18.200:6379>zrevrange students 0 -1 withscores
zrangebyscore命令
根据分数区间查询内容 语法:zrangebyscore key min max 192.168.18.200:6379>zrangebyscore students 2 5
zcard命令
统计key集合中有多少个键值对 语法:zcard key 192.168.18.200:6379> zcard students
zcount命令
统计key集合中min到max区间元素。 语法:zcount key min max zcount students 1 4
zrank命令
统计key集合中指定元素索引。 语法:zrank students wangwu 192.168.18.200:6379>zrank students wangwu
zscore命令
统计key集合中指定元素的分数 语法:zscore key value 192.168.18.200:6379>zscore students zhangsan
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
Jedis jedis=new Jedis("192.168.18.200",6379);
@Test public void testJedis() { Jedis jedis=new Jedis("192.168.18.131",6379); jedis.set("birthday", "1991-10-30"); jedis.set("address", "beijing"); String address=jedis.get("address"); String birthday=jedis.get("birthday"); System.out.println("address:"+address); System.out.println("birthday:"+birthday); jedis.close(); }
Connection con c3p0连接
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency>
//创建JedisPoolConfig对象 JedisPoolConfig poolConfig=new JedisPoolConfig(); //最大空闲连接数 poolConfig.setMaxIdle(3); //大连接数 poolConfig.setMaxTotal(5); //连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true poolConfig.setBlockWhenExhausted(true); //获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常 poolConfig.setMaxWaitMillis(30000); //在获取连接的时候检查有效性 poolConfig.setTestOnBorrow(true); JedisPool jedisPool=new JedisPool(poolConfig,"192.168.18.200",6379,30000,"123456");
Jedis jedis=jedisPool.getResource(); jedis.set("name", "wangxiaobing"); jedis.set("age", "22"); String name=jedis.get("name"); String age=jedis.get("age"); System.out.println("name:"+name); System.out.println("age:"+age);
spring和redis的整合,其它就是把redis的实例化过程交给spring容器来实例化,现在我们创建Jedis对象是通过JedisPool获取的,而创建JedisPool就必须实体化JedisPoolConfig对象,所以我们把JedisPoolConfig、JedisPool都交给spring容管理,我们只从容器取获取JedisPool对象进行注入即可。
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.7</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.7</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> </dependencies>
<!-- 连接池的配置对象 --> <bean id="config" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="5"></property> <property name="maxIdle" value="3"></property> <property name="blockWhenExhausted" value="true"></property> <property name="maxWaitMillis" value="3000"></property> <property name="testOnBorrow" value="true"></property> </bean> <!-- 连接池的对象 --> <bean id="pool" class="redis.clients.jedis.JedisPool"> <constructor-arg name="poolConfig" ref="config"></constructor-arg> <constructor-arg name="host" value="192.168.11.113"></constructor-arg> <constructor-arg name="port" value="6379"></constructor-arg> <constructor-arg name="timeout" value="3000"></constructor-arg> <constructor-arg name="password" value="123456"></constructor-arg> </bean>
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class JedisTest { @Autowired private JedisPool jedisPool; @Test public void testAddPerson(){ Person person=new Person(100,"张三","男",22,new Date()); Jedis jedis = jedisPool.getResource(); // jedis.set("person", JsonUtils.objectToJson(person)); jedis.hset("persons",person.getName(),JsonUtils.objectToJson(person)); jedis.close(); } @Test public void testAddPerson2(){ Jedis jedis = jedisPool.getResource(); String jsonData=jedis.get("person"); Person person=JsonUtils.jsonToEntity(jsonData,Person.class); System.out.println(person); jedis.close(); } }
Nginx (engine x) 是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。
Nginx是一款轻量级的Web服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,在BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力在同类型的网页服务器中表现较好,中国大陆使用nginx网站用户有:百度、京东、新浪、网易、腾讯、淘宝等。
Nginx是一款高性能的http 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。并且cpu、内存等资源消耗却非常低,运行非常稳定。
http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
虚拟主机。可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机(虚拟路径)。图片挂载:虚拟路径
反向代理(nginx代理多台服务器),负载均衡(客户端压力平分到多个tomcat上)。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。
负载均衡(Load Balance)其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。负载均衡构建在原有网络结构之上,它提供了一种透明且廉价有效的方法扩展服务器和网络设备的带宽、加强网络数据处理能力、增加吞吐量、提高网络的可用性和灵活性。
一台普通服务器的处理能力是有限的,假如能达到每秒几万个到几十万个请求,但却无法在一秒钟内处理上百万个甚至更多的请求。但若能将多台这样的服务器组成一个系统,并通过软件技术将所有请求平均分配给所有服务器,那么这个系统就完全拥有每秒钟处理几百万个甚至更多请求的能力。这就是负载均衡最初的基本设计思想。
负载均衡是由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求按照某种策略分配到服务器集合的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡解决了大量并发访问服务问题,其目的就是用最少的投资获得接近于大型主机的性能。
动静分离是在web服务器架构中,将静态页面与动态页面或者静态内容接口和动态内容接口分开不同系统访问的架构设计方法,进而提升整个服务访问性能和可维护性。
Tomcat处理静态资源的效率并没有Nginx高,我们可以通过动静分离将静态资源和动态资源分割开来,Tomcat处理动态资源,Nginx响应静态资源,从而减轻tomcat的压力,各自发挥自己的长处,从而提高响应速度,提高访问能力。
<%@ page language="java" import="java.util.Date,java.text.SimpleDateFormat" ontentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <h1>这是tomcat1主页</h1> <% Date date=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String strDate=sdf.format(date); out.println(strDate+"<br>"); %> <img src="images/aaa.jpg"> </body> </html>
<%@ page language="java" import="java.util.Date,java.text.SimpleDateFormat" ontentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> </head> <body> <h1>这是tomcat2主页</h1> <% Date date=new Date(); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String strDate=sdf.format(date); out.println(strDate+"<br>"); %> <img src="images/aaa.jpg"> </body> </html>
upstream tomcat{ server 192.168.18.201:8081 weight=2; server 192.168.18.201:8082; } server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; location / { proxy_pass http://tomcat; index index.html index.htm; } location ~\.(jsp|do|action)$ { proxy_pass http://tomcat; } location ~\.(html|css|js|gif|jpg|png|bmp|swf)$ { root /usr/local/staticresources; }
重新启动nginx
输入http://IP地址/show.jsp