Notes

目录

in-summary

  1. 找到新职位后,重点看 spring/java 源代码(各种结构等)
  2. 平时还是要多看书,多看原理,并且一定要写博客记录下来。雁过拔毛,某一段时间专攻某一块,比如买大量某一专题的书籍
  3. ThreadLocal具体实现

    Thread 内部有一个ThreadLocalMap
    作用:线程独享,当处理过程很长时,可以用来传值。比如threadLocal.set(connection)
  4. 线程死锁解决方案.

    1.避免实用嵌套锁
    2.用同一资源锁把其他锁组合起来
    e.g. sync(外层锁
         组合锁1
         组合锁2
         ...
  5. restful,soap,rpc区别 link
    1. https://www.zhihu.com/question/28570307
    2. web socket? https://www.zhihu.com/question/20215561
  6. RestController/Controller区别
  7. Date/Timestamp区别

    timestamp 时区会随着系统改动自己变化,date不会
  8. 软引用、弱引用
  9. redis 本身事务
  10. rabbitmq 实现原理,以及如何保证持久化
  11. 几种mq的比较,选型?
  12. solr 架构
  13. 简历逐条过一下,想一下某个项目可能用会问的问题
  14. 数据库中间件?数据库分表分库sharding
  15. form, body怎么拿到数据(mvc)
  16. 线程池原理
见代码
  1. Servlet线程安全?
不安全,单利的,类变量就不安全
  1. SimpleDateFormat的线程不安全
因为共享变量calendar.
解决,每一次都重新new 一个
如果有线程池的情况下,实用ThreadLocal处理.
  1. 哪几种IO模型

    [参考](http://blog.csdn.net/wanghang88/article/details/51922117)
  2. jdk提供的工具(jstack,jstat,jconsole,jvisualvm)
jps(jvm process status) 显示指定系统内所有的hotspot虚拟机进程
jstat(jvm statis monitorning tool) 用于搜集hotspot 虚拟机各方面的运行数据, 比如查看gc信息
jstat -gc 31884 250 20

jinfo(configuration info for java)Java配置信息

jmap(memory map for java) Java内存映射工具,用于生成dump文件
jmap -heap 31884
jhat(jvm heap analysis tool) 堆转存储快照分析工具,搭配jmap,内置微型http/html服务器
jstack(stack trace for java)堆栈跟踪工具,主要生成当前时刻线程快照,数据中心曾经有用到过.

可视化工具
jsonsole(java monitoring and management console). 基于jmx可视化监视,管理工具
内存,线程,类等监控
visualVM(all-in-one java troubleshooting tool),监控-故障处理,性能分析等。
  1. servlet生命周期,servlet,filter,listener分别的用途
周期:加载->实例化(这两步都是常规)->init->service->destory
servlet: 相应请求,做出响应,动态生成web页面 web服务器主体
filter: 不做出响应,只是做一些辅助,比如编码转换,权限校验,业务逻辑判断等。只初始化一次,web应用停止或者重新部署才销毁。责任链模式 pre filter->servlet(dofilter)->after filter
listener:监听服务器的某一执行动作,并作出相应的响应。也即:application/session/request三个对象创建或者消亡时做一些业务操作。比如spring总监听器会在服务器启动时实例化bean对象.只初始化一次,随着web应用的停止而销毁.
interceptor: 框架级别的拦截器,基于代理模式,比如在方法调用前,调用后做些什么灯。
  1. java集合特性及源码,ArrayList, LinkedList, HashMap, LinkedHashMap, TreeMap, HashTable, ConcurrentHashMap区别/实现
  2. tomcat,nginx区别
  3. tomcat原理
  4. 负载均衡方案
  5. 详细描述rabbitMQ工作流程
  6. redis与mongoDB区别
  7. 秒杀设计方案
  8. 微信红包设计方案
  9. sql优化查询的方法

    <ol><li>分库,分表</li>
    <li>索引
  • sdfsd
  • Quartz

    主要接口

    • Schedule
    • Trigger
      • SimpleTrigger
      • CronTrigger
    • Job
    • JobDetail

    示例代码

    package com.desmond.codebase.qaurtz;
    
    import java.io.Serializable;
    import java.util.Date;
    
    import org.quartz.*;
    import org.quartz.impl.StdSchedulerFactory;
    
    import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
    import static org.quartz.TriggerBuilder.newTrigger;
    
    /**
     * Created by Li.Xiaochuan on 17/8/4.
     */
    public class MyJob implements Serializable, Job{
    
        @Override
        public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println(new Date() + ": doging something.");
        }
    
        public static void main(String[] args) throws SchedulerException {
            // 1. define the job and tie it to our MyJob class
            JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                    .withIdentity("job1", "group1")
                    .build();
    
            // 2. trigger the job to run now, and the repeat every 10 seconds
            SimpleTrigger trigger = newTrigger()
                    .withIdentity("trigger1", "group1")
                    .startNow()
                    .withSchedule(
                            simpleSchedule()
                                    .withIntervalInSeconds(10)
                                    .repeatForever())
                    .build();
    
            // 3. tell quartz to schedule the job using our trigger
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(jobDetail, trigger);
    
            scheduler.start();
    
        }
    
    }

    基本思路

    业务工作放在自定义job中,e.g. MyJob implements Job. MyJob在由JobDetail 创建。JobDetail 有JobDataMap 用来给Job instance 传递各种各样的参数.

    // define the job and tie it to our DumbJob class
      JobDetail job = newJob(DumbJob.class)
          .withIdentity("myJob", "group1") // name "myJob", group "group1"
          .usingJobData("jobSays", "Hello World!")
          .usingJobData("myFloatValue", 3.141f)
          .build();
    
    public class DumbJob implements Job {
    
        public DumbJob() {
        }
    
        public void execute(JobExecutionContext context)
          throws JobExecutionException
        {
          JobKey key = context.getJobDetail().getKey();
    
          JobDataMap dataMap = context.getJobDetail().getJobDataMap();
    
          String jobSays = dataMap.getString("jobSays");
          float myFloatValue = dataMap.getFloat("myFloatValue");
    
          System.err.println("Instance " + key + " of DumbJob says: " + jobSays + ", and val is: " + myFloatValue);
        }
      }

    常见的Trigger有SimpleTrigger/CronTrigger,前者可以用于简单的触发器,后者则使用cron expression作为出发条件,用于高级的日期触发。Scheduler是一个容器,负责注册trigger/jobdetail, 并把他们配对。在合适的时候利用trigger出发job execution。容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。
    这里写图片描述

    动态调度

    Quartz的JobDetail、Trigger都可以在运行时重新设置,并且在下次调用时候起作用。这就为动态作业的实现提供了依据。你可以将调度时间策略存放到数据库,然后通过数据库数据来设定Trigger,这样就能产生动态的调度

    Thread

    线程基本概念

    状态

    1. new , 创建后进入的状态, e.g. Thread t = new MyThread();
    2. runnable, 调用 t.start, 就绪,等待cpu
    3. running, 运行。只有先runnable才能到running.
    4. blocked. 放弃对cpu使用权,停止执行

      1. 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

      2.同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

      3.其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

    5. dead. 执行完或者异常退出run,生命周期结束.
    6. 状态图
      状态图
    7. 参考

    创建方式

    1. extend Thread
    2. implemnts Runnable
    3. implemnts Callable
        feature 其实是一种Callable. thread->Runnable->Callable
    

    线程安全实现方法

    互斥(阻塞/唤醒)同步
    1. synchronized
        1. 方法
        2. 代码块
        3. 锁 实例/类
    2. ReetrantLock
    3. 可重入锁定义
     ```
     线程可以进入任何一个它已经拥有的锁所同步着的代码块
     ```
    
    非阻塞同步(乐观锁)
    CAS(compare and swap), 变量内存地址V, 旧的预期值A, 新值B, 当且仅当V=A时,处理器用B更新V的值,否则就不执行。该操作利用cpu指令,为原子性的。但是会产生A-B-A的问题。i.e. 如果变量V初次读取的是A,并且准备赋值检查时仍然是A,没有问题吗?如果他在这段时间被改为B,然后又被改为了A,那么CAS会认为他没改变。为解决这个问题加一个变量控制版本. 1A-2B-3A
    无同步方案
    1. 可重入代码
    ```
    状态量都由参数出入等,不应用堆上数据集,不使用公用的系统资源的功能.
    ```
    2. 线程本地存储(ThreadLocal)
    
    synchronized 与 reentrantLock 比较
    1. 功能相似
    2. synchronized 语法层面、reentrantLockAPI层面,灵活(显示lock/unlock, try-finally)
    3. reentrantLock 3项区别
      1. 等待可中断:持有锁的线程长时间不释放锁,等待的线程可以选择放弃,改做其他的事情.synchronized没有此功能.原理:Thread.interrupt()用于中断处于阻塞状态的线程。如果线程处于不可立即中断状态,那么Thread.interrupt()只会标志线程的中断状态,以便后续操作用于判断。线程等待获取内部锁的时候,是一种立即中断状态,即线程不会立即响应中断而是会继续等待。这种等待可能会造成资源浪费或者死锁。新Lock锁提供了等待锁资源时可立即响应中断的lockInterruptibly()方法和tryLock(long time, TimeUnit unit)方法及其实现,当使用这两个方法去请求锁时,如果主通过Thread.interrupt()对它们发起中断,那么它们会立即响应中断,不再继续等待获取锁,这让主线程(管理调度线程)在特殊情况下可以使用生杀大权,以避免系统陷于死锁状态或者避免资源严重浪费 参考
      2. 公平锁:多个线程再等待同一个锁,必须按照申请锁的时间顺序依次获得;而非公平锁则不保证,他是抢占式的,在锁被释放时,任何一个等待锁的线程都有机会获得锁。synchronized锁是非公平的,reentrantLock默认也是非公平的,可以通过带boolean的构造器指定为公平锁,但是保证公平锁是需要额外的工作会牺牲一定的性能.
      3. 锁可以绑定多个条件: lock绑定多个条件,不同条件对于不同实现情况。比如缓存队列. 参考
        java
        final Lock lock = new ReentrantLock();//锁对象
        final Condition notFull = lock.newCondition();//写线程条件
        final Condition notEmpty = lock.newCondition();//读线程条件
        notFull.await();//阻塞写线程
        notFull.signal();//唤醒写线程
    4. 性能 1.6之前,reentrantLock优鱼synchronized,1.6差不多,jvm会重点优化synchronized,因此使用时,有限考虑synchronized

    线程池

    1. 使用线程池的背景:
      线程分为 T1创建时间,T2执行时间,T3销毁时间(run结束后,自动GC销毁) 当T1 + T3 > T2, 则可采用线程池,以减少创建/销毁带来的额外开销(cpu,内存等).
    2. 组成部分
      1. 线程管理器(ThreadPool): 用于创建并管理线程池,包括 创建线程池/销毁线程池/添加任务等.
      2. 工作线程(WorkThread): 线程池中的线程,没有任务时,处于等待状态,可以循环执行任务,该线程必须处于活动状态,以防止被结束,其他的 比如 数据库连接/ http连接 也是一样的原理.
      3. 任务接口(Task): 供工作线程调用,业务代码的具体实现的地方.
      4. 任务队列(queue): 用于存放没有处理的认为,提供一种缓存机制.
    3. 原理: 重复利用线程,没有任务时阻塞,不断循环地去拿任务.

    分布式锁

    背景

    线上服务器采用集群方式的,多台服务器提供同一样的服务,当扣数据库库存时需要分布式锁.

    实现方式

    采用redis 实现。
    利用 setnx,get,getset 三个命令.
    public boolean tryLock(String lockKey, int ttl) {
            int now = DateTimeUtils.getCurrentTimeInSeconds();
    
            boolean isSucess = RedisUtil.setIfAbsent(lockKey, now + ttl);
    
            if(isSucess) { // 尝试获取锁,如果成功,则直接返回.
                return true;
            }
    
            Long oldExpireTime = RedisUtil.get(lockKey); // 获取锁的过期时间.
    
            if(oldExpireTime != null && oldExpireTime < now) { // 还未过期
                return false;
            }
    
            // 锁已经过期
            long newExpireTime = (now + ttl);
            Long replacedExpire = RedisUtil.getAndSet(lockKey, newExpireTime);
    
            // 再次确认已经过期, 并且 replacedExpire == oldExpireTime,防止并发
            if(replacedExpire != null && now > replacedExpire && replacedExpire == oldExpireTime) {
                return true;
            } else {
                return false;
            }
        }
    

    乐观锁/悲观锁

    乐观锁 假定没人竞争,去操作,拿得到的结果与期望结果进行比较,符合期望则成功,不符合期望则做其他的操作进行补偿(比如不断地重试)

    1. 数据库
    采用 update `order` set status=1 where status=0 and act_id=80223, 如果结果返回1 则占位成功,否则失败,失败可能需要重试或者放弃
    1. Java
    CAS, 失败则不停地重试,或者放弃做其他的事情.

    悲观锁

    1. 数据库

      事物隔离级别调整为Seriable,行级锁等
    2. Java

      采用阻塞同步方式, 比如 synchronized, reentrantLock等.

    MySql索引

    本质

    索引的本质是数据结构
    在数据之外,数据库系统还维护着满足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。

    B,B-,B+树

    1. B树的搜索

      B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中;否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键
    2. B-
      特性:
      1. 关键字集合分布在整颗树中;
      2. 任何一个关键字出现且只出现在一个结点中;
      3. 搜索有可能在非叶子结点结束(每个关键字下都带有data,可以简单的认为关键字就是数据);
      4. 其搜索性能等价于在关键字全集内做一次二分查找(log2n);
      5. 自动层次控制(插入删除新的数据记录会破坏B-Tree的性质,因此在插入删除时,需要对树进行一个分裂、合并、转移等操作以保持B-Tree性质);
      6. B-
    3. B+
      特性:
      1. 所有关键字都出现在叶子结点的链表中(稠密索引),且链表中的关键字恰好是有序的;
      2. 不可能在非叶子结点命中;
      3. 非叶子结点相当于是叶子结点的索引(稀疏索引),叶子结点相当于是存储(关键字)数据的数据层;
      4. 更适合文件索引系统;
      5. B+
    4. B+ 比 B- 的优势

      1. B+树的磁盘读写代价更低

        B+树的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
        举个例子,假设磁盘中的一个盘块容纳16bytes,而一个关键字2bytes,一个关键字具体信息指针2bytes。一棵9阶B-tree(一个结点最多8个关键字)的内部结点需要2个盘快。而B+树内部结点只需要1个盘快。当需要把内部结点读入内存中的时候,B 树就比B+树多一次盘块查找时间
      2. B+树的查询效率更加稳定
      由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
      

    Mysql执行计划

    在mysql命令行中,执行explain命令可以看到sql执行计划
    1.  SIMPLE  title   NULL    ref title_from_date title_from_date 155 const,const 2683    100.00  Using index condition

    执行计划

    Type:表示MySQL在表中找到所需行的方式,又称“访问类型”
    
    ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行
    index:Full Index Scan,index与ALL区别为index类型只遍历索引树
    range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询
    ref:非唯一性索引扫描,返回匹配某个单独值的所有行。常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找
    eq_ref:唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
    const、system:当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量。system是const类型的特例,当查询的表只有一行的情况下, 使用system
    NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引
    
    Extra
    
    包含不适合在其他列中显示但十分重要的额外信息
    
    Using index:该值表示相应的select操作中使用了覆盖索引(Covering Index)【注:MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件  包含所有满足查询需要的数据的索引称为 覆盖索引】
    Using where:表示MySQL服务器在存储引擎受到记录后进行“后过滤”(Post-filter),如果查询未能使用索引,Using where的作用只是提醒我们MySQL将用where子句来过滤结果集
    Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询
    Using filesort:  MySQL中无法利用索引完成的排序操作称为“文件排序”

    两种引擎区别

    1. 主要方面区别
        1. MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持
        2. MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持以及外部键等高级数据库功能
    2. 在索引方面区别
    
     ```
     索引分为主索引(Unique Index)(primary,unique)和辅助索引(index).
     1. MyISAM引擎使用B+树作为索引结构,叶节点的data域存放的是数据记录的地址
     2. 在MyISAM中,主索引和辅助索引(Secondary key)在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复
     3. 第一个重大区别是InnoDB的数据文件本身就是索引文件。从前面知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引
     4. 第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域
    

    聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获 得记录。

    
    # JVM原理
    # GC
    # Spring
    [参考](http://blog.csdn.net/EthanWhite/article/details/51329657)
    
    ## Bean 生命周期
    1. 实例化(new) ->
    2. pre-initialized
        1. beananmeaware(把配置的beanid 传过来)
        2. beanfactoryware(传递过来bean工场,可以用来获取其他bean)
        3. applicationcontextaware(传递过来bean工厂,可以用来获取其他的bean)
        4. beanpostprocesser(对bean进行修改,在init之前调用)
        5. 配置文件配置了init-method,会自动调用该方法
        6. beanpostprocesser(在init之后调用)
    3. ready: bean 准备工作, protype, single
    4. destory
        1. destory() impment DisposableBean
        2. destory-method
    
    ## AOP
    # Spring MVC
    # Mybaits
    # RabbitMQ
    ## 概念
    ### 结构图 ![t](https://img-blog.csdn.net/20160818204838832?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
    ### 基本概念
    1. Server(broker): 接受客户端连接,实现AMQP消息队列的路由功能的进程,简单来说就是消息队列服务器实体
    2. Vhost:虚拟机,一个broker可以开设多个vhost,用作不同用户的权限分离,权限控制组,用户只能关联到一个vhost上,一个vhost中可以有若干个Exchange和Queue,默认vhost是'/'
    3. Exchange:接受生产者发送的消息,并根据Binding规则将消息路由给服务器中的队列Exchange type 决定了Exchange路由消息的行为。direct/fanout/topic/header
    4. queue:用于存储还未消费的消息。消息队列的载体,每个消息都会被投入到一个或多个队列。
    5. message:由header和body组成,header是由生产者添加到各种属性的集合,包括message是否会被持久化,是由哪个message queue接受优先级是多少等,而body是真正需要传输的app数据
    6. Binding:绑定,他的作用是吧exchange与queue按照路由规则绑定起来
    7. bindingkey:在mq中设置绑定的key
    8. routing key:路由关键字,exchange根据这个关键字精选消息投递
    9. producer:生产者,投递消息的程序
    10. consumer:消费者
    11. channel:消息通道,再客户端的每个连接里,可以建立多个channel,每个channel代表一个回话任务
    ## 原理
    
    ## 与Kafka的比较
     1. rabbitMQ 遵循amqp, 以broker未中心,有消息确认机制,kafka以consumer为中心,无消息确认机制
     2. 吞吐量
    # Redis
    ## 类型以及命令
    [参考](http://blog.csdn.net/hechurui/article/details/49508735)
    
    0. 基本
    
     ```
     分库.
     批处理:一次发送多条命令
     可以支持任何类型的字符串,包含二进制数据,一个字符串最大512MB,是其他4种类型的基础.
     增删查改,长度
     ttl,del,haskey,exits,type(5种类型)/expire(设置过期时间)
     /expireat/setnx/getset
     ```
    1. 字符串
     ```
     基本的,可以存一个json字符串,二进制文件等
     set/mset
     del
     get/mget
     strlen
     setnx/getset/increment
     ```
    2. 散列表hash
    
     ```
     key-value形式。可以用来存放数据库中的某一行。key:行号,hashkey:列号,value:值
    
     hset e.g. hset key1 hashkey1 value1
     hget e.g. hget key1 haskkey1
     incrment e.g. HINCRBYFLOAT key1 field -5
     hmset e.g. hmset key1 hashkey1 value1 hashkey2 value2
     hgetall e.g. hget key1  return:  hashkey1 value1 hashkey2 value2
     hkeys e.g. hkeys key1 return: hashkey1 hashkey2
     hvals e.g. hvals key1 return: value1 value2
     hdel e.g. hdel key1 hashkey1
     hlen e.g. hlen key1
     删除整个key, 直接 del key1
    
    
     ```
    
    3. 列表
    
     ```
     可以用作队列,栈,有序,有重复,可以用于计算好的结果,例如活动列表的缓存
     lpush
     lpop
     rpush
     rpop
     llen
     lrange: lrange key1 0 100, 可以拉去某一长度的列表
     lrem key count value 删除列表中前count个值为value的元素,当count>0时从左边开始数,count<0时从右边开始数,count=0时会删除所有值为value的元素
     ```
    
    4. 无序集合
    

    无序无重复,取出数据是随机的。可以去重。
    可以做集合运算。

    sadd e.g. sadd key1 1 2 3
    spop 随机弹出一个元素
    srem 删除 srem key1 value1 value2
    smembers 返回所有元素 semembers key
    sismember 判断是否在集合中

    sidff 差集 sdiff key1 key2 key3 先key1,key2做差,然后与key3做差
    sinter 交集 sinter key1 key2 key3
    sunion 并集 sunion key1 key2 key3

    sdiffsore 对集合做差集并将结果存储,用法:SDIFFSTORE destination key1 key2 [key3 …]

    sinterstore 对集合做交集运算并将结果存储,用法:SINTERSTORE destination key1 key2 [key3 …]

    sunionstore 对集合做并集运算并将结果存储,用法:SUNIONSTORE destination key1 key2 [key3 …]

    SRANDMEMBER 随机获取集合中的元素,用法:SRANDMEMBER key [count],当count>0时,会随机中集合中获取count个不重复的元素,当count<0时,随机中集合中获取|count|和可能重复的元素。

    scard 合集中个数 scard key

    
    5. 有序集合
    

    有序的。有序集合是在集合的基础上为每一个元素关联一个分数,这就让有序集合不仅支持插入,删除,判断元素是否存在等操作外,还支持获取分数最高/最低的前N个元素。可以用于topN的获取

    zadd e.g. zadd key1 score1 value1 score2 value2
    zrem zrem key value1 value2
    zscore 获取元素的分数 zscore key value
    zrange/zrevrange 按value排名在某个返回 zrange key 0 1
    zrangebyscore/zrevrangebyscore 按分数排序 zrange math 1 100

    zinterstore
    zunionstore

    
    ## 用途
    1. 缓存
        1. TopN - zset
        2. 存 map - hash
    2. 消息队列 -list类型
    3. 集合运算 -set
    4. 分布式锁 setnx get getset
    ## 与memcached比较
    1. memached 只支持 key-value
    2. memached 多线程,redis单线程,一核redis胜,多核memcached胜
    3. redis 支持持久化,memcached不支持
    # http/https基本原理
    # Restful协议
    # nginx/httpd/tomcat基本配置
    # 设计模式
    ### 单例
    ### 代理
    ### 工厂
    #### 简单工厂
    #### 工厂方法
    # 大数据相关
    ## hadoop
    ## spark
    ## hive
    ## hue
    ## oozie
    ## sqoop
    
    # Mysql优化
     1. 索引的选择
         1. 优点:可以加快查询速度
         2. 缺点:索引文件本身需要消耗存储空间,更新索引(增、删、改)会增加修改记录的负担,mysql运行时也需要消耗资源维护索引,不是越多越好
         3. 不建议建立索引
             1. 表记录少,一般<20002. 索引选择性低: 选择性S 为 不重复的索引值(C) 与记录表记录数(T)的比值, Index S=C/T, 值越大越好.
             `select count(distinct from_date)/count(0) from title` 极端例子 男女 2/10000=0.0005, 主键 10000/10000=1. 
             基于btree去理解,主键是完全的二分查找, log2n. 如果只有两个值,开始是二分查找,最后数据都集中到一个链表中,为n.
     2. 优化
         1. 最左前缀原理
          ```
          联合索引<emp_no,title,from_date>, 当emp_no,title,from_date 都匹配上为全列匹配,e.g. where emp_no=1 and title='title' and from_date=123; 当只有一个为部分匹配, e.g. where emp_no=1 and from_date=3, 这时会部分匹配 emp_no, 这个时候可以填上title 来使用索引.e.g. where emp_no = 1 and title in(所有title) and from_date=3;
    
          查询的条件如果没有指定索引的第一项,则不会用索引.e.g. where from_date=123;
          范围查询可以用到索引,最对能用于一个范围
          ```
         2. 函数表达式不能用索引
         3. innoDB没有特别的业务要求,要使用一个与业务无关的自增字段作为主键。使用自增作为主键,每次都会顺序添加到当前索引节点的后续位置,近似顺序填满,不需要移动现有的数据,索引开销不大。如果使用非自增的主键(身份证、学号等),近视随机数据,每次插入现有的索引之间,这样要频繁地移动数据,也会留下磁盘碎片
    
    
    # 数据库事务
     `事务把数据库从一种一致性的状态转换成另一种一致状态`
    
    ## ACID
    1. Atomicity 原子性 `要不都失败,要不都成功`
    2. Consistncy 一致性 `在一个事务执行之前和执行之后数据库必须处于一致性状态,比如买票,库存表扣掉的库存会到订单表里`
    3. Isolation 隔离性 `并发的事务是相互隔离的`
    4. Durability 持久性 `系统或者介质发生故障时,已经提交的事务不丢失`
    
    ## ACID 实现原理
    ### Atomicity/Durablity

    借助undo log:
    a=1,b=2
    事务开始
    数据读入内存
    记录a=1到undolog
    修改a=10(内存中)
    记录b=2到undolog
    修改b=20(内存中)
    将undolog写入磁盘(我理解为数据已经到数据库中了,已经持久化了,只是缺少一个标识说这是不是一个正常的数据)
    将数据从内存中写入磁盘
    提交事务
    io频繁

    undolog + redolog:
    a=1,b=2
    事务开始
    记录a=1到undolog
    修改a=10
    记录a=10到redolog
    记录b=2到undolog
    修改b=20
    记录b=20到redolog
    将redolog 写入磁盘
    提交事务

    把undo也写入redolog中,而redolog可以缓存起来,可以减少io.
    回滚操作本质上也是对数据进行修改.

    ### Consistency

    事务开始前和开始后都必须处于一致的状态,这个感觉要Mysql+应用程序一起来控制

    
    ### Isolation

    由存储引擎(比如innodb)来实现,采用Next-key Locking方式来加锁。
    Record Lock:单个行记录锁
    GAP Lock:间隙锁,锁定一个范围,但不包含记录本身,

    Next-key Lock:锁定一定范围,并锁定记录本身=record lock + gap lock
    比如有一个字id, 值有 1,3,5,8,10,17,22
    那没 锁的范围可能 为 (-无穷,1],(1,8],(8,17],(17~+无穷)
    那么trans1 真该更改 8, 那么 1~17 是被锁定的(8为record lock, 1~7,9~17为gap lock),其他transaction 是不能修改1~17的.

    
    ## Isolation隔离性
    
    ### 隔离级别
    1. 读未提交(Read Uncommitted)
    2. 读已提交(Read Committed)
    3. 可重复读(Repeatable Read)
    4. 可串行化(Serializable)
    5. Mysql 默认是 Repetable Read, Oracle 默认是 Read Committed
    
    ### Isolation并发带来的问题
    1. 脏读 `读到未提交的数据`
    2. 不可重复读 `同一事务中如果在T1读取了一些记录,在T2再读同样的记录时,这些记录可能被修改、删除不见了`
    3. 幻读 `保证在同一事务中可重复读数据,但是在另事务中更新后某一结果后,当前事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉`
    ### 不同隔离级别出现的问题(Y-会出现,N-不会出现)
    
    |隔离级别|脏读|不可重复读|幻读|
    |:--:|:--:|:--:|:--:|
    |读未提交|Y|Y|Y|
    |读提交|N|Y|Y|
    |可重复读|N|N|Y|
    |串型化|N|N|N|
    
    
    ### 示例
    `myqsl 事务隔离级别分为全局级别和会话级别,spring 中可以指定当前事务的隔离级别,默认采用default,即数据库的事务隔离级别,区别是通过客户端连接的一个会话,启动会话isolation时会去读会话的isolation,之后自己可以通过set 去改变global isolation(全局改完,系统的会话初始的isolation也会改变,当开始新的session,会采用默认的系统的会话isolation), 也可以set 当前会话的isolation.`
    
    `可重复读:tra1 开启,第一次读数据有2条,tra2 开启,插入一条新数据,然后commit, 这时候tra1再查询,查到的数据仍然是2条。也就是说对于tra1事务没有结束,不管其他事务是否修改了数据,那么数据都是不变的。这样会导致幻读`
    
    `感觉问题都是一级一级新产生<->解决的,终极方案是用串行化: 读未提交->产生脏读现象->为解决脏读,推迟读提交->产生不可重复读现象->为解决不可重复度,推出可重复度->产生幻读现象->为解决幻读,推出终极方案:串行化`
    
    
    ```sql
    select @@global.tx_isolation,@@tx_isolation;
    set global txt_isolation='repeatable-read';
    set txt_isolation='repeatable-read';

    参见具体示例

    Spring中的事务

    事务隔离级别

    同数据库的,默认采用数据库设置的级别

    事务的传播性

    事务传播性都是针对方法而言的

    类型描述
    REQUIRED业务方法需要在一个事务中运行,如果方法运行时,已处在一个事务中,那么就加入该事务,否则自己创建一个新的事务.这是spring默认的传播行为
    SUPPORTS如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分,如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行
    MANDATORY只能在一个已存在事务中执行,业务方法不能发起自己的事务,如果业务方法在没有事务的环境下调用,就抛异常
    REQUIRES_NEW业务方法总是会为自己发起一个新的事务,如果方法已运行在一个事务中,则原有事务被挂起,新的事务被创建,直到方法结束,新事务才结束,原先的事务才会恢复执行
    NOT_SUPPORTED声明方法需要事务,如果方法没有关联到一个事务,容器不会为它开启事务.如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行
    NEVER声明方法绝对不能在事务范围内执行,如果方法在某个事务范围内执行,容器就抛异常.只有没关联到事务,才正常执行
    NESTED如果一个活动的事务存在,则运行在一个嵌套的事务中.如果没有活动的事务,则按REQUIRED

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值