java基础笔记

  1. 基本数据类型和包装类型

    基本数据类型:short、int、long、double、float、char、string、boolean

    包装类型:Short、Integer、Long、Double、Float、Char、String、Boolean

    装箱:1. 手动装箱:Integer.valueOf(1) ; 2. 自动装箱:Integer i = 1;

    拆箱:1. 手动拆箱:int j = i.intValue() ; 2. 自动拆箱:int j = i ;

    JDK1.5开始为什么要引入包装类型:java是面向对象的语言,而基本的数据类型不具备面向对象的特性。

    例:用Integer和int分别表示一个类的ID,进行非空判断的时候,Integer只要判断是否为null,int还要判断是否为0;

    Integer num1 = new Integer(100);
    Integer num2 = new Integer(100);
    System.out.println("num1==num2 " + (num1 == num2));

    Integer num3 = 100;
    Integer num4 = 100;
    System.out.println("num3==num4 " +(num3 == num4));

    Integer num5 = 128;
    Integer num6 = 128;
    System.out.println("num5==num6 " + (num5 == num6));

    Integer num7 = 100;
    Integer num8 = new Integer(100);
    System.out.println("num7==num8 " + (num7 == num8));

    int num9 = 100;
    Integer num10 = new Integer(100);
    Integer num11 = 100;
    System.out.println("num9==num10 " + (num9 == num10));
    System.out.println("num9==num11 " + (num9 == num11));

    结果:num1==num2 false
    num3==num4 true
    num5==num6 false
    num7==num8 false
    num9==num10 true
    num9==num11 true
    源码:
    public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
    }

    private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];

    static {
    // high value may be configured by property
    int h = 127;
    String integerCacheHighPropValue =
    sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
    if (integerCacheHighPropValue != null) {
    try {
    int i = parseInt(integerCacheHighPropValue);
    i = Math.max(i, 127);
    // Maximum array size is Integer.MAX_VALUE
    h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
    } catch( NumberFormatException nfe) {
    // If the property cannot be parsed into an int, ignore it.
    }
    }
    high = h;

    cache = new Integer[(high - low) + 1];
    int j = low;
    for(int k = 0; k < cache.length; k++)
    cache[k] = new Integer(j++);

    // range [-128, 127] must be interned (JLS7 5.1.7)
    assert IntegerCache.high >= 127;
    }

    private IntegerCache() {}
    }
    分析:
    1.==对于对象来说比较的是对象的地址,两个新new的对象地址不同,输出false
    2.jvm在初始化的时候,会将低值(-128)到高值(默认127)之间的数字加载到内存中。低值是固定的,高值是可变的。在java程序执行的时候加上 -XX:AutoBoxCacheMax=<size> 的参数即可。缓如果初始化的数字是-128~127之间就会引用内存中的地址,输出true
    3.同上。
    4.num7是引用的本地内存地址,而num8是new出来的,所以地址不同,输出false
    5.包装类Integer和基本数据类型int类型比较时,会自动拆箱为int类型比较,实际上就变成两个基本的数据类型int类型进行比较,而基本类型==比较的是值而不是地址,所以输出true
    6.同上,即使是新new出来的地址不同,但是最终拆箱为int类型比较值是否相等,所以输出true
  2. “==”和“equals()” 方法区别

    变量分为基本数据类型和引用数据类型

    1)对于==,比较的是值是否相等

    ​ 如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;

      如果作用于引用类型的变量,则比较的是所指向的对象的地址

    2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象

      如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;

      诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。

  3. String、StringBuilder、StringBuffer区别

    在这方面运行速度快慢为:StringBuilder > StringBuffer > String

    1.String底层使用final关键字修饰的数组,因此不可变
    /** The value is used for character storage. */
    private final char value[];
    2.StringBuilder继承AbstractStringBuilder抽象类使用的是普通数组所以可以改变。
    /** The value is used for character storage.*/
    char[] value;
    3.StringBuffer继承AbstractStringBuilder抽象类使用的是普通数组所以可以改变。并且与StringBuilder重写的方法不同,方法添加了synchronized关键字,线程安全但是效率低。

    String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

    String:适用于少量的字符串操作的情况

    StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况

    StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

  4. java中的集合

    java中的集合分类存储value(继承Collection接口)和存储key-value(继承)形式。

    存储值:List、Set

    List是有序的,可以重复的。

    Set是无序的,不可以重复的。根据equals和hascode判断,也就是如果一个对象要存储在Set中,必须重写equals和hasCode方法。

    存储键值:Map

  5. ArrayList和LinkedList的区别和使用场景

    1.ArrayList底层使用的是数组。
    transient Object[] elementData;
    2.LinkedList底层使用的是链表。
    transient Node<E> first;
    transient Node<E> last;

    区别:

    数组查询特定元素快,而插入、删除和修改比较慢,因为数组在内存中是一块连续的内存,如果是插入或删除需要移动内存。

    链表在内存中是不连续的,在当前元素中存放的是下一个或者上一个元素的地址。查询时需要从头部开始查找至尾部,效率低。而插入时不需要移动内存,只需要改变节点指针即可。所以插入或删除效率高。

    使用场景:

    ArrayList使用在查询比较多,但是插入和删除比较少的情况,

    LinkedList使用在查询比较少,但是插入和删除比较多的情况。

  6. HashMap和Hashtable的区别

    相同点:都可以用来存储Key-Value类型数据

    不同点:

    1. HashMap可以使用null值作为key或者value,而Hashtable不行。

    2. HashMap是线程不安全的,效率高。而Hashtable是线程安全的,效率低。

    3. HashMap继承了AbstractMap抽象类同时实现Map, Cloneable, Serializable接口,而Hashtable继承了Dictionary抽象类同时实现Map, Cloneable, Serializable接口。

    线程安全又要效率高?ConcurrentHashMap

    通过把整个Map分为N个Segment(类似于Hashtable),可以提供相关的线程安全,又可以提升效率,默认提升16倍。

  7. 实现一个拷贝文件的工具类使用字节流还是字符流

    我们拷贝的文件不确定是只包含字符流,有可能有字节流(图片、声音、图像等),为考虑到通用性,要使用字节流。

  8. 线程的几种实现方式

    1. 通过继承Thread类实现一个线程

    2. 通过实现Runnable接口实现一个线程

    3. 通过实现callable接口,重写call函数

      import java.util.concurrent.Callable;
      import java.util.concurrent.FutureTask;

      public class ThreadDemo {

      public static void main(String[] args) {

      // ======= 创建线程方式一 开始 (Thread是一个类继承了Runnable接口) =======
      Thread thread = new Thread(){
      @Override
      public void run() {//该方法中写我们业务代码

      while (true) {
      try {
      Thread.sleep(1000);//休眠1000毫秒(就是1秒)
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      //打印当前线程名称
      System.out.println("创建线程方式一,打印线程名称: "+Thread.currentThread().getName());

      //打印当前线程名称,这里采用this来获取,在某些时候这里并不适用,推荐使用上面一种方式
      System.out.println("创建线程方式一,通过this调用getName方法,打印线程名称: "+this.getName());
      }
      }
      };

      thread.start();//启动线程
      // ======= 创建线程方式一 结束 =======

      // ======= 创建线程方式二开始 (Runnable是一个接口)=======
      Thread thread2 = new Thread(new Runnable() {

      @Override
      public void run() {//该方法中写我们业务代码
      while (true) {
      try {
      Thread.sleep(1000);//休眠1000毫秒(就是1秒)
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      //打印当前线程名称
      System.out.println("创建线程方式二,打印线程名称: "+Thread.currentThread().getName());

      //TODO 这种方式就不适合上面打印2的方式通过this来调用获取当前线程名称的方法
      }

      }
      });

      thread2.start();//启动线程
      // ======= 创建线程方式二 结束 =======


      // ======= 创建线程方式三 开始 =======
      FutureTask<Integer> thread3 = new FutureTask<>(new Callable<Integer>() {

      @Override
      public Integer call() throws Exception {
      int count =0;
      for(int i=0;i<=10;i++){
      count=count+i;
      }
      //打印当前线程名称
      System.out.println("创建线程方式三,打印线程名称: "+Thread.currentThread().getName());
      return count; //返回值
      }
      });

      new Thread(thread3,"这是线程名称").start();//启动线程
      try {
      System.out.println("创建线程方式三,打印返回值:"+ thread3.get());//打印返回值
      } catch (Exception e) {
      e.printStackTrace();
      }
      // ======= 创建线程方式三 结束 =======
      }
      }

      区别:

      • 采用继承Thread类方式:

        ​ 优点:编写简单,如果需要访问当前线程,无需使用Thread.currentThread()方法,直接使用this,即可获得当前线程。

        ​ 缺点:因为线程类已经继承了Thread类,所以不能再继承其他的父类。

      • 采用实现Runnable接口方式:

        ​ 优点:线程类只是实现了Runable接口,还可以继承其他的类。在这种方式下,可以多个线程共享同一个目标对象,所以非常适合多个相同线程来处理同一份资源的情况,从而可以将CPU代码和数据分开,形成清晰的模型,较好地体现了面向对象的思想。

        ​ 缺点:编程稍微复杂,如果需要访问当前线程,必须使用Thread.currentThread()方法。

  9. 线程池

    1. newCachedThreadPool

    创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

    这种类型的线程池特点是:

    • 工作线程的创建数量几乎没有限制(其实也有限制的,数目为Interger. MAX_VALUE), 这样可灵活的往线程池中添加线程。
    • 如果长时间没有往线程池中提交任务,即如果工作线程空闲了指定的时间(默认为1分钟),则该工作线程将自动终止。终止后,如果你又提交了新的任务,则线程池重新创建一个工作线程。
    • 在使用CachedThreadPool时,一定要注意控制任务的数量,否则,由于大量线程同时运行,很有会造成系统瘫痪。

    示例代码如下:

    package test;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
    ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
    for (int i = 0; i < 10; i++) {
    final int index = i;
    try {
    Thread.sleep(index * 1000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    cachedThreadPool.execute(new Runnable() {
    public void run() {
    System.out.println(index);
    }
    });
    }
    }
    }
    1. newFixedThreadPool

    创建一个指定工作线程数量的线程池。每当提交一个任务就创建一个工作线程,如果工作线程数量达到线程池初始的最大数,则将提交的任务存入到池队列中。

    FixedThreadPool是一个典型且优秀的线程池,它具有线程池提高程序效率和节省创建线程时所耗的开销的优点。但是,在线程池空闲时,即线程池中没有可运行任务时,它不会释放工作线程,还会占用一定的系统资源。

    示例代码如下:

    package test;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 10; i++) {
    final int index = i;
    fixedThreadPool.execute(new Runnable() {
    public void run() {
    try {
    System.out.println(index);
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    }
    }
    }

    因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
    定长线程池的大小最好根据系统资源进行设置如Runtime.getRuntime().availableProcessors()

    1. newSingleThreadExecutor

    创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。如果这个线程异常结束,会有另一个取代它,保证顺序执行。单工作线程最大的特点是可保证顺序地执行各个任务,并且在任意给定的时间不会有多个线程是活动的。

    示例代码如下:

    package test;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 10; i++) {
    final int index = i;
    singleThreadExecutor.execute(new Runnable() {
    public void run() {
    try {
    System.out.println(index);
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    }
    });
    }
    }
    }
    1. newScheduleThreadPool

    创建一个定长的线程池,而且支持定时的以及周期性的任务执行,支持定时及周期性任务执行。

    延迟3秒执行,延迟执行示例代码如下:

    package test;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.schedule(new Runnable() {
    public void run() {
    System.out.println("delay 3 seconds");
    }
    }, 3, TimeUnit.SECONDS);
    }
    }

    表示延迟1秒后每3秒执行一次,定期执行示例代码如下:

    package test;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
    public void run() {
    System.out.println("delay 1 seconds, and excute every 3 seconds");
    }
    }, 1, 3, TimeUnit.SECONDS);
    }
    }
  10. 使用线程池的风险,为什么使用线程池

风险:

  1. 死锁
  2. 资源不足
  3. 并发错误
  4. 线程泄漏
  5. 请求过载

作用:(连接池同理)

  1. 限定线程的个数,不会由于线程过多而导致系统运行缓慢或崩溃
  2. 线程池不需要每次去创建或销毁,节约资源,响应速度快
  1. 设计模式

    常用的设计模式:

    1. 单例模式(饱汉模式、饿汉模式):

      (1)构造方法私有化,在除了自己类中其他地方都不能创建

      (2)在自己的类中创建一个单实例(饱汉模式是一出来就创建单实例,而饿汉模式需要用到的时候才创建)

      (3)提供一个方法或获取该实例对象(创建时需要进行方法同步)

    2. 工厂模式:SpringIOC使用的就是工厂模式,对象的创建交给一个工厂 创建。

    3. 代理模式:SpringAOP使用的就是动态代理。

javaWeb笔记

  1. Http Get和Post请求的区别

    相同点:

    Get和Post请求都是Http请求方式,用户通过不同的Http请求对资源实现不同的操作。GET,POST,PUT,DELETE对应着对资源的查,改,增,删4个操作,GET一般用于获取/查询资源信息,而POST用于更新资源信息。

    区别:

    1. GET请求提交的数据会在地址栏显示出来,而POST请求地址栏不会改变,数据放置在HTTP包体中。
    2. 传输数据的大小不同,GET由于浏览器对地址长度的限制导致传输的数据有限制,而POST不会。
    3. GET提交的数据会在地址中显示出来,安全性较低,而POST则不会。
  2. servlet的理解

    Servlet 是用java编写的服务器端程序,而这些Servlet都要实现Servlet接口。主要用于交互式地浏览和修改数据,生成动态Web内容。Servlet运行于支持java的web容器中。

    HttpServlet重写doGet和doPost方法或者service方法完成对get和post请求的响应。

  3. servlet的生命周期

    1. 加载Servlet的class
    2. 实例化Servlet
    3. 调用Servlet的init完成实例化
    4. 运行service方法,响应doGet或doPost请求
    5. 调用destory方法销毁实例
  4. Servlet API中forward() 和redirect()区别

    forward:转发,地址不变,服务端跳转

    redirect:重定向,地址改变,客户端跳转

  5. Session和Cookie区别

    相同点:

    Session和cookie都是会话跟踪技术。Cookie通过在客户端记录信息确定用户身份,Session通过在服务端记录信息确定用户身份。但是Session是实现依赖于Cookie,sessionId(session的唯一标识需要存放在客户端)

    区别:

    1. Cookie数据存放在客户端浏览器,Session存放在服务器上

    2. Cookie安全性较Session差

    3. Session运行时间久会占用较多服务器内存,影响服务器性能

    4. 单个Cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个Cookie

    5. 登录信息等重要信息存放在Session中,安全性较高

      其他信息如果需要保留,存在Cookie中(比如购物车的实现,但是Cookie在客户端是可以禁用的,所以可以采用cookie+数据库方式实现)

  6. MVC的各部分都有哪些技术来实现

    • M(Model) 模型 javabean……
    • V(View) 视图 html、jsp、freemarker、thymeleaf……
    • C(Control)控制器 Servlet、Action……

数据库笔记

  1. 数据库分类

    • 关系型数据库

      MySql、Oracle、SqlServer……

    • 非关系型数据库

      redis、memcache、mogodb、hadoop……

  2. 关系型数据库三范式

    1. 第一范式(1NF)所谓第一范式(1NF)是指数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值,即实体中的某个属性不能有多个值或者不能有重复的属性。如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多关系。在第一范式(1NF)中表的每一行只包含一个实例的信息。

      在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。理解注释:列不可分。

    2. 第二范式(2NF)第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。第二范式(2NF)要求数据库表中的每个实例或行必须可以被惟一的区分。为实现区分通常需要为表加上一个列,以存储各个实例的惟一标识。要求实体的属性完全依赖于主关键字。理解注释:不能部分依赖。即:一张表存在组合主键时,其他非主键字段不能部分依赖。

    3. 第三范式(3NF)满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关键字信息。在第二范式的基础上,数据表中如果不存在非关键字段对任一候选关键字段的传递函数依赖则符合第三范式。理解注释:不能存在传递依赖。即:除主键外,其他字段必须依赖主键。

  3. 事务四个基本特征ACID特性

    ​ 事务是并发控制的单位,使用户定义的一个操作序列。这些操作要么都做,要么都不做,是一个不可分割的工作单位。事务(transaction)所应该具有的四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability).这是可靠数据库所应具备的几个特性.

    • 原子性

      整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。

    • 一致性

      在事务开始之前和事务结束以后,数据库的完整性约束没有被破坏。

    • 隔离性

      隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。

    • 持久性

      在事务完成以后,该事务所对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

  4. MySql数据库默认的最大连接数

    特定服务器上的数据库只能支持一定数目同时连接,这时候需要我们设置最大连接数(最多同时服务多少连接),在my.ini中查看设置

    # The maximum amount of concurrent sessions the MySQL server will
    # allow. One of these connections will be reserved for a user with
    # SUPER privileges to allow the administrator to login even if the
    # connection limit has been reached.
    max_connections=151
  5. MySql分页、Oracle分页和SqlServer分页

    MySql使用limit关键字来分页

    Oracle使用rownum

    SqlServer使用top

  6. 触发器使用场景

前端笔记

框架笔记

  1. SpringMVC执行流程

    1. 用户向服务器发送请求,请求被Spring前端控制器DispatcherServlet拦截
    2. DispatcherServlet对请求的URL进行解析,得到请求资源标识符(URL)。然后根据URI调用HandlerMapping获的该Handler配置的所有相关对象,最后以HandlerExecutionChain对象的形式返回
    3. DispatcherServlet根据获得的Handler,选择一个合适的HandlerAdapter适配器,提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller),Handler执行完成后,向DispatcherServlet返回一个ModelAndVIew对象
    4. DispatcherServlet根据返回的ModelAndVIew,选择一个合适的ViewResolver视图解析器
    5. 通过ViewResolver结合Model和View。来渲染视图,DispatcherServlet将渲染结果返回给客户端
  2. Struts2和SpringMVC区别

    1. Struts2的前端控制器是Filter,SpringMVC是Servlet
    2. SpringMVC是基于方法设计,而Struts2是基于对象
    3. SpringMVC属于Spring大家族中的一员,Spring对于SpringMVC的控制器管理更加方便,而Struts2采用XML配置参数来管理
    4. Struts2中自身提供多种参数接收,其实都是通过ValueStack进行传递和赋值,而SpringMVC是通过方法的参数进行接收
    5. Struts2拥有较多的技术点,比如拦截器、值栈和OGNL表达式,学习成本较高,而SpringMVC相对比较简单
    6. Struts有自己的interceptor拦截机制,SpringMVC使用的是独立的AOP
    7. SpringMVC处理Ajax请求,直接通过返回数据,方法中使用注解@ResponseBody直接转为JSON对象返回,而Struts2是通过插件的方式处理
  3. Spring中的两大核心

    1. IOC(Inversion of Control)或DI(Dependency Injection)

      IOC控制反转:

      在spring中BeanFactory是IOC容器的核心接口,负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。XmlBeanFactory实现BeanFactory接口,通过获取xml配置文件数据,组成应用对象及对象间的依赖关系。

      Spring中有三种注入方式:set注入、接口注入、构造方法注入

      核心原理:配置文件+反射+容器

    2. AOP面向切面编程:

      使用动态代理的方式在执行前后或出现异常后执行相关逻辑

      主要用于:事务、日志、权限校验

  4. ORM框架

    为了解决面向对象与关系数据库存在的互不匹配的现象的框架

  5. Mybatis和Hibernate区别

    相同点:

    ​ 都是java中的ORM框架、屏蔽了jdbc api的底层访问细节。

    ​ mybatis:专注sql本身,需要程序员自己编写sql语句,sql修改、优化比较方便。mybatis是一个不完全的ORM框架,虽然程序员自己写sql,mybatis也可以实现映射(输入映射,输出映射)

    ​ 应用场景:适用需求变化较多的项目,比如:互联网项目。

    ​ hibernate:是一个标准的ORM框架(对象关系映射)。入门门槛较高,不需要写sql,sql语句自动生成,对sql语句进行优化、修改比较困难。

    ​ 应用场景:适用需求变化不多的中小型项目,比如:后台管理系统,erp,orm,oa等

  6. Hibernate映射对象的状态

    1. 临时状态(transient)(瞬态):刚用new 语句创建,还没有被持久化,并且不处于Sesssion 的缓存中。处于临时状态的Java 对象被称为临时对象。
    2. 持久化状态(persistent):已经被持久化,并且加入到Session 的缓存中。处于持久化状态的Java 对象被称为持久化对象。
    3. 删除状态(removed):不再处于Session 的缓存中,并且Session 已经计划将其从数据库中删除。处于删除状态的Java 对象被称为删除对象。
    4. 游离状态(detached):已经被持久化,但不再处于Session 的缓存中。处于游离状态的Java 对象被称为游离对象。

    下面以具体的代码来说明这四种状态:

    public class Test {  

    public static void main(String[] args) {
    SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
    Session session=sessionFactory.openSession(); // 生成一个session
    session.beginTransaction(); // 开启事务

    Person p1=new Person("天天","18","3009"); // 临时对象1
    Person p2=new Person("小李","23","4009"); // 临时对象1
    session.save(p1); // 持久化对象
    session.save(p2); // 持久化对象

    session.delete(p2); // 删除对象

    session.getTransaction().commit(); // 提交事务
    session.close(); // 关闭session

    System.out.println(p1.getName()); // 游离对象
    System.out.println(p2.getName()); // 删除对象
    }
    }
  7. Hibernate缓存机制

    ​ 使用缓存是为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能

    ​ Hibernate缓存分为一级缓存和二级缓存,一级缓存就是Session级别的缓存,在事务范围内有效是,内置的不能被卸载。二级缓存是SesionFactory级别的缓存,从应用启动到应用结束有效。是可选的,默认没有二级缓存,需要手动开启。

    什么样的数据适合存放到第二级缓存中?   

    ​ 1) 很少被修改的数据  帖子的最后回复时间 

    ​ 2) 经常被查询的数据 电商的地点

    ​ 3) 不是很重要的数据,允许出现偶尔并发的数据   

    ​ 4) 不会被并发访问的数据   

    ​ 5) 常量数据

    扩展:hibernate的二级缓存默认是不支持分布式缓存的。使用memcahe,redis等中央缓存来代替二级缓存。

  8. webservice使用场景

    ​ webservice是一个SOA(面向服务的编程)的架构,它是不依赖于语言,不依赖于平台,可以实现不同的语言间的相互调用,通过Internet进行基于Http协议的网络应用间的交互。

    1. 异构系统(不同语言)的整合

    2. 不同客户端的整合,浏览器、手机端(android,ios.塞班)、微信端、PC端等终端来访问

    3. 实实在在的列子:

      天气预报:可以通过实现webservice客户端调用远程天气服务实的。

      单点登录:一个服务是所有系统的登录

服务器及优化

  1. Linux常用命令

    常用:

    ​ Pwd 获取当前路径

    ​ Cd 跳转到目录

    ​ Su -u 切换到管理员

    ​ Ls ls 列举目录

    文件操作命令:

    ​ 文件

    ​ tail 查看

    ​ rm -rf

    ​ vi

    ​ 文件夹

    ​ mkdir

    ​ rm -r

  2. 数据库优化

    做过mysql数据库的优化、其他数据库类似

    定位:查找、定位慢查询

    优化手段:

    ​ a) 创建索引:创建合适的索引,我们就可以现在索引中查询,查询到以后直接找对应的记录。

    ​ b) 分表:当一张表的数据比较多或者一张表的某些字段的值比较多并且很少使用时,采用水平分表和垂直分表来优化

    ​ c) 读写分离:当一台服务器不能满足需求时,采用读写分离的方式进行集群。

    ​ d) 缓存:使用redis来进行缓存

    ​ e) 一些常用优化技巧

    优化