J2EE 基础知识积累

 

1. 面向对象的思维:

     1. 有哪些类 那些对象
     2. 这些类中,每种类应该具有某种属性和方法
     3. 考虑类与类之间应该具有什么样的关系

 

3. 

     1. 成员变量可以使用java语言中的任何一种数据类型(包括基本类型和引用类型)

     2. 在定义成员变量时可以使其初始化,如果不对其初始化,java使用默认的值对其初始化

     3. 成员变量的租用范围为整个类型

 

4. 如何在内存中区分类和对象

     1. 类是静态的概念,代码区

     2. 对象是new出来的,位于堆内存,类的每个成员变量在不同的对象中都有不同的值(除了静态变量)而方法只有一份,执行的时候才占用内存

 

  eg:String  s

          // 声明一个String类型的引用变量,但并没有使他指向一个对象

     s=new String("Hello world")

     // 使用new语句创建一个String类型的对象并用s指向他,以后可以通过s完成对其的操作

 

5. 方法调用时值传递

6. 方法一旦执行完毕,为这个方法所分配的局部变量的内存(栈内存立刻消失,堆内存可能不是马上消失,等垃圾回收齐回收之后就消失)自动消失

7. 基础类型的变量就一块内存在栈内存中,引用类型的变量两块内存(堆内存和栈内存)

8. 重载指的是方法名相同,参数不同,参数不同包括参数个数和参数的类型不同

 

9. 同一类的每个对象有不同的成员变量存储空间

 

    同一类的每个对象共享该类的方法:

   非静态方法是针对每个对象进行调用的。

 

10. this关键字:

     1. 在类的方法定义中使用的this关键字代表使用该方法的对象的引用.

     2. 当必须指出当前使用方法的对象是谁要使用this.

     3. 有时使用this可以处理方法中成员变量和参数重名的情况

     4. this可以看做是一个变量,他的值是当前对象的引用.

 

11. static 关键字:

     1. 在类中,用static声明的成员变量为静态成员变量,他为该类的公用变量,在第一次使用时被初始化,对该类的所有对象来说,static成员变量只有一份.

     2. 用static声明的方法为静态方法,在调用该方法时,不会将对象的引用传递给他,所以static方法中不可以访问非static的成员.

          2) 静态方法不再是针对于某个对象的调用,所以不能访问非静态成员。

     3. 可以通过对象引用或类名(不需要实例化)访问静态成员.

 

12. static, 静态变量在内存中存放在数据区(data segment)

     字符串常量也分配在data segment区中

 

13. 在java类中使用super来引用基类的成分 

 

14. 继承中的构造方法:

     1. 子类的构造的过程中必须调用其基类的构造方法

     2. 子类可以在自己的构造方法中使用super(argument_list)调用基类的构造方法

          使用this(argument_list)调用本类的另外的构造方法

          如果调用super,必须写在子类构造方法的第一行

     3. 如果子类的构造方法中没有显示的调用基类的构造方法,则系统默认嗲用基类的无参的构造方法

     4. 如果子类构造方法中既没有显示调用基类的构造方法,而基类中又没有无参的构造方法,则变异报错

 

15.  对象转型

     1. 一个基类的引用类型变量可以"指向"其子类的对象

     2. 一个基类的引用不可以访问其子类对象新增加的成员(属性和方法)

     3.可以使用引用变量instanceof 类名 来判断该引用变量所"指向"的对象是否属于该类或该类的子类

     4. 子类的对象可以当做基类的对象来使用称作向上转型(upcasting),反之称为向下转型(downcasting)

 

 

1. 事务特性

原子性、一致性、隔离性、持续性。

这四个属性通常称为ACID特性。

原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。

一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。

隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

持久性(durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

 

事务的传播机制:

REQUIRED(默认值):在有transaction状态下执行;如当前没有transaction,则创建新的transaction;

SUPPORTS:如当前有transaction,则在transaction状态下执行;如果当前没有transaction,在无transaction状态下执行;

MANDATORY:必须在有transaction状态下执行,如果当前没有transaction,则抛出异常IllegalTransactionStateException;

REQUIRES_NEW:创建新的transaction并执行;如果当前已有transaction,则将当前transaction挂起;

NOT_SUPPORTED:在无transaction状态下执行;如果当前已有transaction,则将当前transaction挂起;

NEVER:在无transaction状态下执行;如果当前已有transaction,则抛出异常IllegalTransactionStateException。

http://blog.csdn.net/kiwi_coder/article/details/20214939

 

事务的隔离级别:

Isolation 属性一共支持五种事务设置,具体介绍如下

sqlserver默认隔离级别是:READ_COMMITTED

oracle默认隔离级别是:READ_COMMITTED

Mysql innodb默认隔离级别是:REPEATABLE_READ

DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别

READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )

READ_COMMITTED  会出现不可重复读、幻读问题(锁定正在读取的行)

REPEATABLE_READ 会出幻读(锁定所读取的所有行)

SERIALIZABLE 保证所有的情况不会发生(锁表)

1. 脏读(事务没提交,提前读取):脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。 

2. 不可重复读(两次读的不一致) :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。 

3. 幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。 

4.第一类更新丢失(回滚丢失): 

  当2个事务更新相同的数据源,如果第一个事务被提交,而另外一个事务却被撤销,那么会连同第一个事务所做的跟新也被撤销。也就是说第一个事务做的跟新丢失了。 

5.第二类更新丢失(覆盖丢失): 

  第二类更新丢失实在实际应用中经常遇到的并发问题,他和不可重复读本质上是同一类并发问题,通常他被看做不可重复读的特例:当2个或这个多个事务查询同样的记录然后各自基于最初的查询结果更新该行时,会造成第二类丢失更新。因为每个事务都不知道不知道其他事务的存在,最后一个事务对记录做的修改将覆盖其他事务对该记录做的已提交的跟新... 

不可重复读的重点是修改 : 

同样的条件 ,   你读取过的数据 ,   再次读取出来发现值不一样了 

幻读的重点在于新增或者删除 

同样的条件 ,   第 1 次和第 2 次读出来的记录数不一样

  • Read Uncommitted 未提交读

    事务A更新了数据,但没有提交(commit),允许事务B读到这条变化的数据。如果事务A最终没有提交,而是rollback回原来的状态,那么事务B读到的数据就是一条脏数据。

 

图1 未提交读

 

 

  • Read Committed 提交读

    事务A在更新数据并且提交后,才允许事务B读取到,这样就可以避免脏读。

 

图2 提交读

 

    Read Committed并不能防止不可重复读和幻读,什么是不可重复读和幻读?看下图

 

    不可重复读是事务B在多次读取数据过程中,事务A对数据进行更新或者删除,导致事务B前后读到的数据不一致。

 

图3 不可重复读

 

    幻读是事务B在多次读取过程中,事务A对数据新增了,导致事务B后读的数据比之前读的多了,感觉像是凭空出来的一样。

 

图4 幻读

 

  • Repeatable Read 可重复读

图5 可重复读

 

    显然,要实现可重复读,需要事务B在读取数据后,对SELECT的数据加锁,事务A不能修改,这可以通过“共享读锁”和“排它写锁”来实现。可重复读不能避免幻读。

 

  • Serializable 序列化

    提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。这样可以避免幻读,但是,这样的事务级别,性能也最差。

 

图6 序列化事务

 

下面是隔离级别及其对应的可能出现或不可能出现的现象

 

Dirty Read  

NonRepeatable Read  

Phantom Read 

Read uncommitted

Possible

Possible

Possible

Read committed

Not possible

Possible

Possible

Repeatable read

Not possible

Not possible

Possible

Serializable

Not possible

Not possible

Not possible

 

 

 

 

 

2. Spring

Spring的理解:

http://www.ibm.com/developerworks/cn/java/j-lo-spring-principle/

有三大核心的组件:beans(演员) context(舞台) core(道具)

使用spring 的原因:

1.把对象之间的依赖关系转而用配置文件来管理,也就是依赖注入机制,

这个关系在一个叫IOC 的容器中管理

2. Context类似舞台背景,作为spring的IOC容器,要完成以下几件事情:

标识一个运行环境

利用BeanFactory创建Bean对象

保存对象关系表

能够捕获各种事件

为spring提供一个运行环境,以保证各个对象的状态,要发现每个bean之间的关系,为他们建立

这种关系并且维护好这种关系,所以context就是一个bean关系的集合

这个关系集合又叫IOC容器,一旦建立起这个IOC容器后Spring就可以为你工作了

3. Core就是发现建立和维护每个bean之间的关系所需要的一系列工具

从这个角度来看,core这个组件叫Util更能让人理解

是哪个组件关系:

 

Ioc 容器如何为我所用

前面的介绍了 Spring 容器的构建过程,那 Spring 能为我们做什么,Spring 的 Ioc 容器又能做什么呢?我们使用 Spring 必须要首先构建 Ioc 容器,没有它 Spring 无法工作,ApplicatonContext.xml 就是 Ioc 容器的默认配置文件,Spring 的所有特性功能都是基于这个 Ioc 容器工作的

Ioc 它实际上就是为你构建了一个魔方,Spring 为你搭好了骨骼架构,这个魔方到底能变出什么好的东西出来,这必须要有你的参与。那我们怎么参与?这就是前面说的要了解 Spring 中那有些扩展点,我们通过实现那些扩展点来改变 Spring 的通用行为。至于如何实现扩展点来得到我们想要的个性结果,Spring 中有很多例子,其中 AOP 的实现就是 Spring 本身实现了其扩展点来达到了它想要的特性功能,可以拿来参考。

 

     0

单例模式三个主要的作用:

第一:控制资源的使用,通过线程同步来控制资源的并发访问

第二:控制实例产生的数量,达到节约资源的目的

第三:作为通信媒介使用,也就是数据共享,它可以在不建立直接关联的条件下,让多个不相关的两个线程或者进程之间实现通信。

单例模式的三个重要的特点:

1、确保自己只有一个实例 2、单例类必须创建自己的实例 3、单例类必须为其它的对象提供唯一实例

 

IOC的全称是: Inversion of Control(即: 控制反转).  理解: 在传统的应用程序中,控制权在应用程序本身,程序的控制流程完全由开发者控制。在IOC容器中,控制权发生了反转:从应用程序转移到了IOC容器。组件不再由应用程序负责创建和配置,而是由IOC容器负责,应用程序只需要直接使用已经创建并配置好的组件。 
为了让组件能在IOC容器中被“装配”出来,需要某种“注入”的机制,才能将一种组件“注入”到另一种组件中。 简单来说,依赖注入解决了最主要的问题:将组件的配置与使用相分离,并且由IoC容器负责管理组件的生命周期。 
简单来说: 控制反转就是由容器控制程序之间的(依赖)关系.  
2. 依赖注入的三种实现形式?  
a. 接口注入(Interface Injection) 说明: 通过实现一个接口来实现对依赖对象的
注入. 
b. 设值方法注入(Setter注入). 说明: 对象创建之后,将被依赖对象通过set方法设
置进去. 
c. 构造方法注入(Constructor injection). 说明: 对象创建时,被依赖对象以构造
方法参数的方式注入.

 

3. Spring IOC

Spring IOC 主要采用XML+反射+工厂模式。

AOP = 反 射+ 动态代理 +IOC 

 

      1)Spring MVC工作原理

 

               1. 客户端请求提交到DispatcherServlet

            2. 由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller

            3. DispatcherServlet将请求提交到Controller

            4. Controller调用业务逻辑处理后,返回ModelAndView

            5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

            6. 视图负责将结果显示到客户端

 

三大框架面试题:

http://wenku.baidu.com/link?url=3Ztb8HZ2RkrT0Og2xX38tVp6N02dX1UxPj4LTcdjapNfIpLu6E2a_J7mE14C8HgfuvCme2arFUoUyG_HVL2UCM60CPD-qEqrrYAV0Uim_Qm

 

 

    http://jinnianshilongnian.iteye.com/blog/1594806

      1、  请求如何给前端控制器?

      2、  前端控制器如何根据请求信息选择页面控制器进行功能处理?

      3、  如何支持多种页面控制器呢?

      4、  如何页面控制器如何使用业务对象?

      5、  页面控制器如何返回模型数据?

      6、  前端控制器如何根据页面控制器返回的逻辑视图名选择具体的视图进行渲染?

      7、  不同的视图技术如何使用相应的模型数据?

Spring与Struts一样,是一个开源框架,它的主要好处就是实现了IOC依赖反转。
--
IOC是什么呢?IOC就是根据配置文件,将JavaBean实例化,在Struts中,bean的实例是需要自己申请的,而Spring可以更好的实现Bean与Bean之间的解藕,而且可以更好地实现需求变化的插拔(通过修改配置文件内容而不是修改代码)
--
Spring还有一个好处就是AOP
--
AOP就是可以在不知道源码的情况下,甚至只有class文件的时候,也可以对当前文件插入操作,比如,一段程序需要加入校验代码,但是校验又不属于业务代码的一部分,这时候就可以通过AOP来插入校验代码而不影响业务逻辑。

        2). springBean配置

      http://hehebendan.iteye.com/blog/649829

      1)单态模式:<bean id="bean_test" class="cn.qtone.test.HelloWorld"></bean>

      2)多台模式:<bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype"></bean>

      3)如果HelloWorld类没有空的构造方法,只有如下的两个构造方法,那我们该如何配置呢? 

               … 

            public HelloWorld(String str) 
               { 
                        …… 
               } 

            public HelloWorld(Date date, int i) 
               { 

              …… 

     } 

               …… 
      由于没有默认构造方法,所以我们就需要在bean的配置中写上构造参数才可以,如下: 
      <!-- 使用一个参数的构造 --> 
      <bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype"> 
                <constructor-arg><value>hello</value></constructor-arg> 
      </bean> 

     4) 

           <bean id="bean_test" class="cn.qtone.test.HelloWorld" scope="prototype"> 

                <constructor-arg index="0" ref="bean_date"></constructor-arg> 

                <constructor-arg index="1"><value>345</value></constructor-arg> 

            </bean>

     5) spring 工厂模式来获取bean,一般使用静态工厂模式和实例工厂模式,这两个在spring中配置也是不太一样的。对于静态工厂模式来实例化bean的,我们的配置如     下:

          <bean id="bean_string" class="cn.qtone.test.TestFactory" factory-method="getBean"/> 

 

     3). Spring

           http://blog.csdn.net/cpp_lzth/article/details/5424406

 

     

 

   

 控制反转模式(也称作依赖性介入)的基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器 (在 Spring 框架中是 IOC 容器) 负责将这些联系在一起。

在典型的 IOC 场景中,容器创建了所有对象,并设置必要的属性将它们连接在一起,决定什么时间调用方法。下表列出了 IOC 的一个实现模式。

类型 1

服务需要实现专门的接口,通过接口,由对象提供这些服务,可以从对象查询依赖性(例如,需要的附加服务)

类型 2

通过 JavaBean 的属性(例如 setter 方法)分配依赖性

类型 3

依赖性以构造函数的形式提供,不以 JavaBean 属性的形式公开

 

     面向方面的编程

面向方面的编程,即 AOP,是一种编程技术,它允许程序员对横切关注点或横切典型的职责分界线的行为(例如日志和事务管理)进行模块化。AOP 的核心构造是方面,它将那些影响多个类的行为封装到可重用的模块中。

AOP 和 IOC 是补充性的技术,它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块化,并以声明的方式将它们应用到需要日志的组件上。当然,优势就是 Java 类不需要知道日志服务的存在,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应用程序代码是松散耦合的。

AOP 的功能完全集成到了 Spring 事务管理、日志和其他各种特性的上下文中。

 

Spring AOP

http://blog.csdn.net/wangpeng047/article/details/8560694

http://blog.csdn.net/wangpeng047/article/details/8560694

 

 

 

      4). 单例模

     1)饿汉式单例类

               public class EagerSingleton {

          private static EagerSingleton instance = new EagerSingleton();
          /**
           * 私有默认构造子
          */
          private EagerSingleton(){}
         /**
          * 静态工厂方法
          */
          public static EagerSingleton getInstance(){
              return instance;
         }
 
}
 
 
2) 懒汉模式:
public class LazySingleton {
    private static LazySingleton instance = null;
    /**
     * 私有默认构造子
     */
    private LazySingleton(){}
    /**
     * 静态工厂方法
     */
    public static synchronized LazySingleton getInstance(){
        if(instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}
 
 
3)双重检查加锁 -------------
“双重检查加锁”机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。
public class Singleton {
    private volatile static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        //先检查实例是否存在,如果不存在才进入下面的同步块
        if(instance == null){
            //同步块,线程安全的创建实例
            synchronized (Singleton.class) {
                //再次检查实例是否存在,如果不存在才真正的创建实例
                if(instance == null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

      5). Spring 延迟加载配

           <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"

 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    <bean id="employeeBean" class="javabeat.net.spring.ioc.Employee" />
    <bean id="addressBean" class="javabeat.net.spring.ioc.Address"
        lazy-init="true" /></beans>

 

3. Hibernate

 

     1). hibernate 工作原

               a: 读取并解析配置文件

               b: 读取并解析映射信息,创建SessionFactory

               c: 打开Sesssion

               d: 创建事务Transation

               e: 持久化操作

               f: 提交事务

               g: 关闭Session

               h: 关闭SesstionFactory

     2). load() get() 的区

               a: load加载方法: Java代码  User user=(Users)session.load(Users.class,userId)   

               b: get加载方法:  Java代码    User user=(Users)session.get(Users.class,userId);   

               两加载方法区别: 

               区别1:如果数据库中,没有userId的对象。如果通过get方法加载,则返回的是一个null;如果通过load加载,则返回一个代理对象,如果后面代码如果调用user对象的某个属性(比如user.getPassword())会抛出异常:org.hibernate.ObjectNotFoundException; 

               区别2:load支持延迟加载,get不支持延迟加载。也就是说User user=(Users)session.load(Users.class,userId);这句代码不会执行数据库查询,只有用到user时才会去执行数据库查询。但User user=(Users)session.get(Users.class,userId);则会立即去执行数据库查询。所以User user=(Users)session.load(Users.class,userId);不会执行sql

      

      3) 说下Hibernate的缓存机制  

 

1. 一级缓存session缓存属于应用事物级缓存  不同session之间不能共享数据,默认开启 

2. 二级缓存:sessionFactory 缓存,输入数据库级别缓存,多个session共享的数据,默认是关闭的 

    a) 应用及缓存  

    b) 分布式缓存   

        条件:数据不会被第三方修改、数据大小在可接受范围、数据更新频率低、同一数据被系统频繁使用、非关键数据 

    c) 第三方缓存的实现,可以直接使用  ehcache/jbosscache/oscache/swarmcache hibernate3.3.2之前,ehcache已经集成          

 

    4) 如何优化Hibernate 

http://zhidao.baidu.com/link?url=BtH2mB7MGcYyUjJWcRT5GEykctfpCML5Sa3QDknF6u_abTRVe17RiMcmoPA-7y6CmI3dwfWt9IIAuWIMeoSwCK

            1、使用双向一对多关联,不使用单向一对多      

            2、灵活使用单向一对多关联      

            3、不用一对一,用多对一取代     

            4、配置对象缓存,不使用集合缓存 

            5、一对多集合使用Bag,多对多集合使用set      

            6、继承类使用显示多态 

            7、表字段要少,表关联不要怕多,有二级缓存撑腰 

 

     4) Hibernate的锁机

          hibernate支持两种锁机制:

          悲观锁(Pessimistic Locking)

          乐观锁(Optimistic Locking)

     

           悲观锁案例:

          select * from account where name = "12345" for update

          通过for update子句,这条SQL锁定了account表中所有符合检索条件的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录

          hibernate的悲观所,也是基于数据库的锁机制实现的,下面代码实现了对查询记录的加锁

          String hqlStr = "from TUser as user where user.name='123456'";

          Query query = session.createQuery(hqlStr);

          query.setLockMode("user",LockMode.UPDATE);//加锁

          List userList = query.list();

 

          Hibernate 的加锁模式:

          ◆ LockMode.NONE:无锁机制

          ◆ LockMode.WRITE:Hibernate 在Insert 和Update记录的时候会自动获取

          ◆ LockMode.READ:Hibernate在读取记录的时候会自动获取

          以上三种锁机制一般由Hibernate内部使用,如Hibernate为了保证Update过程中对象不会被外界修改,会在save方法实现中自动为目标添加上WRITE锁。

          这些都是Hibernate内部对数据的锁定机制,与数据库无关。

          ◆ LockMode.UPGRADE:利用数据库的for update子句

          ◆ LockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的for update nowait子句实现加锁

          以上二种锁机制是我们在应用层较为常用的,依赖数据库的悲观锁机制

 

           乐观锁案例:

          Hibernate 中可以通过class描述符的optimistic-lock属性结合version描述符指定

          <class name = "org.hibernate.sample.TUser"

            table="t_user" dynamic-update="true" dynamic-insert="true" optimistic-lock="version">

     </class>

     optimistic-lock属性有如下几个值可选:

          ◆ none:无乐观锁;

          ◆ version:通过版本机制实现乐观锁;

          ◆ dirty:通过检查发生变动过的属性实现乐观锁;

          ◆ all:通过检查所有属性实现乐观锁

          其中通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现,同时也是Hibernate中,目前惟一在实体对象脱离Session发生修改的情况下依然有效的锁  机制。因此,一般情况下,我们都选择version方式作为Hibernate乐观锁实现机制。

 

     5) Hibernate中的对象有三种状态: 瞬时状态 (Transient)持久状态 (Persistent)

1. 脱管状态 (Detached)

1. 1. 瞬时状态 (Transient)

由 new 命令开辟内存空间的 Java 对象,也就是平时所熟悉的普通 Java 对象。

如: Student stu = new Student();

瞬时对象特点:

(1) 不和 Session 实例关联

(2) 在数据库中没有和瞬时对象关联的记录

2. 2. 持久状态 (Persistent)

持久的实例在数据库中有对应的记录,并拥有一个持久化标识 (identifier).

持久对象总是与 Session 和 Transaction 相关联,在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而必须在Transaction 终止,也就是执行 commit() 之后,才在数据库中真正运行 SQL 进行变更,持久对象的状态才会与数据库进行同步。在同步之前的持久对象称为脏 (dirty) 对象。

瞬时对象转为持久对象:

(1) 通过 Session 的 save() 和 saveOrUpdate() 方法把一个瞬时对象与数据库相关联,这个瞬时对象就成为持久化对象。

(2) 使用 fine(),get(),load() 和 iterater() 待方法查询到的数据对象,将成为持久化对象。

持久化对象的特点:

(1) 和 Session 实例关联

(2) 在数据库中有和持久对象关联的记录

3. 3. 脱管状态 (Detached)

与持久对象关联的 Session 被关闭后,对象就变为脱管对象。对脱管对象的引用依然有效,对象可继续被修改。

脱管对象特点:

(1) 本质上和瞬时对象相同

(2) 只是比爱瞬时对象多了一个数据库记录标识值 id.

持久对象转为脱管对象:

当执行 close() 或 clear(),evict() 之后,持久对象会变为脱管对象。

瞬时对象转为持久对象:

通过 Session 的 update(),saveOrUpdate() 和 lock() 等方法,把脱管对象变为持久对象。

三种状态相互转化的状态图如下:

 

一、预备知识 
对于hibernate,它的对象有三种状态,transient、persistent、detached 
下边是常见的翻译办法: 
transient:瞬态或者自由态 
(new DeptPo(1,”行政部”,20,”行政相关”),该po的实例和session没有关联,该po的实例处于transient) 
persistent:持久化状态 
(和数据库中记录想影射的Po实例,它的状态是persistent, 通过get和load等得到的对象都是persistent) 
detached:脱管状态或者游离态 
(1)当通过get或load方法得到的po对象它们都处于persistent,但如果执行delete(po)时(但不能执行事务),该po状态就处于detached, (表示和session脱离关联),因delete而变成游离态可以通过save或saveOrUpdate()变成持久态 
(2)当把session关闭时,session缓存中的persistent的po对象也变成detached 
因关闭session而变成游离态的可以通过lock、save、update变成持久态 
持久态实例可以通过调用 delete()变成脱管状态。 
通过get()或load()方法得到的实例都是持久化状态的。 
脱管状态的实例可以通过调用lock()或者replicate()进行持久化。 

save()和persist()将会引发SQL的INSERT,delete()会引发SQLDELETE, 
而update()或merge()会引发SQL UPDATE。对持久化(persistent)实例的修改在刷新提交的时候会被检测到,它也会引起SQL UPDATE。 
saveOrUpdate()或者replicate()会引发SQLINSERT或者UPDATE 
二、save 和update区别 
把这一对放在第一位的原因是因为这一对是最常用的。 
save的作用是把一个新的对象保存 
update是把一个脱管状态的对象或自由态对象(一定要和一个记录对应)更新到数据库 

三、update 和saveOrUpdate区别 
这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了save和update,而update只是update;引用hibernate reference中的一段话来解释他们的使用场合和区别 
通常下面的场景会使用update()或saveOrUpdate(): 
程序在第一个session中加载对象,接着把session关闭 
该对象被传递到表现层 
对象发生了一些改动 
该对象被返回到业务逻辑层最终到持久层 
程序创建第二session调用第二个session的update()方法持久这些改动 

saveOrUpdate(po)做下面的事: 
如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做任何事 
如果savaOrUpdate(新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个异常 
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.itfuture.www.po.Xtyhb#5] 
saveOrUpdate如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象 

四、persist和save区别 
这个是最迷离的一对,表面上看起来使用哪个都行,在hibernate reference文档中也没有明确的区分他们. 
这里给出一个明确的区分。(可以跟进src看一下,虽然实现步骤类似,但是还是有细微的差别) 
主要内容区别: 
1,persist把一个瞬态的实例持久化,但是并"不保证"标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。 

2,save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert 

五、saveOrUpdate,merge和update区别 
比较update和merge 
update的作用上边说了,这里说一下merge的 
如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象覆盖session已有的持久实例 
(1)当我们使用update的时候,执行完成后,会抛出异常 
(2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中,执行完成后原来是持久状态还是持久态,而我们提供的A还是自由态 

六、flush和update区别 
这两个的区别好理解 
update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象//updateSQL 
而flush是操作的在持久状态的对象。 
默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待hibernate flush就自动更新或保存到数据库了。hibernate flush发生在以下几种情况中: 
1, 调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合 
get()一个对象,把对象的属性进行改变,把资源关闭。 
2,transaction commit的时候(包含了flush) 

七、lock和update区别 
update是把一个已经更改过的脱管状态的对象变成持久状态 
lock是把一个没有更改过的脱管状态的对象变成持久状态(针对的是因Session的关闭而处于脱管状态的po对象(2),不能针对因delete而处于脱管状态的po对象) 
对应更改一个记录的内容,两个的操作不同: 
update的操作步骤是: 
(1)属性改动后的脱管的对象的修改->调用update 
lock的操作步骤是: 
(2)调用lock把未修改的对象从脱管状态变成持久状态-->更改持久状态的对象的内容-->等待flush或者手动flush 
八、clear和evcit的区别 
clear完整的清除session缓存 
evcit(obj)把某个持久化对象从session的缓存中清空。

 

 

Sqlserver

sqlserver锁机制:

RID 行锁 表中的单个行 
Key 行级锁 索引中的行 
Page 页级锁 一个数据页或者索引页 
Extent 页级锁 一组数据页或者索引页 
Table 表级锁 整个表 
Database 数据库级锁 整个数据库 

sqlserver提供的表级锁 

 

锁模式 描述 
共享(S) 用于不更改或不更新数据(只读操作),如SELECT语句 
更新(U) 用于可更新的资源中。防止当多个会话在读取、锁定以及随后可能进行的资源更新时发生常见形式的死锁。 
排它(X) 用于数据修改操作,例如 INSERT、UPDATE或DELETE。确保不会同时对同一资源进行多重更新 
意向 当 Microsoft SQL Server 数据库引擎获取低级别的锁时,它还将在包含更低级别对象的对象上放置意向锁.例如: 当锁定行或索引键范围时,数据库引擎将在包含行或键的页上放置意向锁。当锁定页时,数据库引擎将在包含页的更高级别的对象上放置意向锁。 
意向锁的类型为:意向共享(IS)、意向排它(IX)以及意向排它共享(SIX) 
架构 在执行依赖于表架构的操作时使用。架构锁的类型为:架构修改(Sch-M)和架构稳定(Sch-S) 
大容量更新(BU) 向表中大容量复制数据并指定了TABLOCK提示时使用 


sqlserver所指定的表级锁定提示有如下几种 
1. HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁。  
2. NOLOCK:不添加共享锁和排它锁,当这个选项生效后,可能读到未提交读的数据或“脏数据”,这个选项仅仅应用于SELECT语句。   
3. PAGLOCK:指定添加页锁(否则通常可能添加表锁) 
4. READCOMMITTED用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQL Server 2000 在此隔离级别上操作。 
5. READPAST: 跳过已经加锁的数据行,这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行,而不是阻塞直到其他事务释放锁,READPAST仅仅应用于READ COMMITTED隔离性级别下事务操作中的SELECT语句操作 
6. READUNCOMMITTED:等同于NOLOCK。    
7. REPEATABLEREAD:设置事务为可重复读隔离性级别。  
8. ROWLOCK:使用行级锁,而不使用粒度更粗的页级锁和表级锁。 
9. SERIALIZABLE:用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。 
  10. TABLOCK:指定使用表级锁,而不是使用行级或页面级的锁,SQL Server在该语句执行完后释放这个锁,而如果同时指定了HOLDLOCK,该锁一直保持到这个事务结束。 
11. TABLOCKX:指定在表上使用排它锁,这个锁可以阻止其他事务读或更新这个表的数据,直到这个语句或整个事务结束。 
12. UPDLOCK :指定在读表中数据时设置更新锁(update lock)而不是设置共享锁,该锁一直保持到这个语句或整个事务结束,使用UPDLOCK的作用是允许用户先读取数据(而且不阻塞其他用户读数据),并且保证在后来再更新数据时,这一段时间内这些数据没有被其他用户修改 
SELECT * FROM table WITH (HOLDLOCK) 其他事务可以读取表,但不能更新删除 
SELECT * FROM table WITH (TABLOCKX) 其他事务不能读取表,更新和删除 

posted on 2015-07-07 11:04  马铃豆  阅读(623)  评论(0编辑  收藏  举报

导航