Vincent Jia 博客

to be a better man, to be a bad man.

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  29 随笔 :: 3 文章 :: 0 评论 :: 0 Trackbacks

#

“开-闭”原则 (Open-Closed principle, OCP)

 

一个软件实体应当对扩展开放,对修改关闭。

Software entities should be open for extension, but closed for modification.

在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。

 

“可变性的封装原则”从工程的角度讲解了如何实现“开-闭”原则。

   “可变性的封装原则”意味着两点:

1.一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。继承应当被看做是封装变化的方法,而不应当被认为是从一般的对象生成特殊的对象方法。

2.一种可变性不应当与另一种可变性混合在一起。所有的类图的继承结构一般不会超过两层,不然就意味着将两种不同的可变性混合在一起。

 

“开-闭”原则与其他原则的关系:

 

里氏代换原则是,任何基类可以出现的地方,子类一定可以出现。

里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体体现,所以里氏代换原则是对实现抽象化的具体步骤的规范。违反里氏代换原则的,也违背“开-闭”原则,反之不一定成立。

 

依赖倒转原则是,要依赖于抽象,不要依赖于实现。

“开-闭”原则是目标,依赖倒转原则是手段。

 

合成/聚合复用原则是,要尽量使用合成/聚合,而不是继承关系达到复用的目的。

合成/聚合复用原则与里氏代换原则相辅相成,两者都是实现“开-闭”原则的具体步骤的规范。

 

迪米特法则是,一个软件实体应当与尽可能少的其他实体发生相互作用。

一个遵守迪米特原则设计出来的系统在功能需要扩展时,会相对更容易地做到对修改的关闭。

 

接口隔离原则是,应当为客户端提供尽可能小的单独的接口,而不是提供大的总接口。

接口隔离原则与广义的迪米特法则都是对一个软件实体与其他的软件实体的通信的限制。遵循接口隔离原则,会使一个软件系统在功能扩展的过程当中,不会将修改的压力传递到其他的对象。

 

一个重构方法的讨论

 

“将条件转移语句改写成为多态性”是一条广为流传的代码重构做法。

这一做法本身并不能保证“开-闭”原则,应当以“开-闭”原则判断是否需要改写成多态。条件转移并不是错误,如果需要,完全可以选择使用条件转移。

如果一个条件转移语句确实封装了某种商务逻辑的可变性,那么将此种可变性封装起来就符合“开-闭”原则设计思想了。如果一个条件转移语句没有涉及重要的商务逻辑,或者不会随着时间的变化而变化,也不意味着任何的可扩展性,那么它就没有涉及任何有意义的可变性。这时候将这个条件转移语句改写成多态性就是一种没有意义的浪费。

 

抽象类应当拥有尽可能多的共同代码

 在一个继承的等级结构中,共同的代码应当尽量向等级结构的上方移动。把重复的代码从子类里面移动到超类里面,可以提高代码的复用率。在代码发生改变时,设计师之需要修改一个地方。

 

抽象类应当拥有尽可能少的数据

与代码的移动方向相反,数据的移动方向是从抽象类到具体类,向等级结构的下方移动。一个对象的数据不论是否使用都会占用资源,所以应当放到等级结构的低端。

 

什么时候才应当使用继承复用

1.子类是超类的一个特殊种类,而不是超类的一个角色,Is-A才符合继承关系。

2.永远不会出现需要将子类换成另一个类的子类的情况。

3.子类具有扩展超类的责任,而不是具有置换掉(Override)和注销掉(Nullify)超类的责任。

4.只有在分类学角度上有意义时,才可以使用继承,不要从工具类继承。


转载自:“开-闭”原则 (Open-Closed principle, OCP)
posted @ 2011-12-08 16:51 iLinux 阅读(187) | 评论 (0)编辑 收藏

前段时间系统升级时遭遇了OOM,具体解决过程见 遭遇OutOfMemoryError
为了巩固对于java启动各项参数的认识,决定将所有参数列举出来,并一一解释,以便后查;

java启动参数共分为三类;
其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容;
其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容;
其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用;
本文主要描述标准参数部分,剩下的两个部分将会陆续推出;

标准参数列表如下:
-client 
 设置jvm使用client模式,特点是启动速度比较快,但运行时性能和内存管理效率不高,通常用于客户端应用程序或者PC应用开发和调试。

-server
 设置jvm使server模式,特点是启动速度比较慢,但运行时性能和内存管理效率很高,适用于生产环境。在具有64位能力的jdk环境下将默认启用该模式,而忽略-client参数。

-agentlib:libname[=options] 
 用于装载本地lib包;
 其中libname为本地代理库文件名,默认搜索路径为环境变量PATH中的路径,options为传给本地库启动时的参数,多个参数之间用逗号分隔。在Windows平台上jvm搜索本地库名为libname.dll的文件,在linux上jvm搜索本地库名为libname.so的文件,搜索路径环境变量在不同系统上有所不同,比如Solaries上就默认搜索LD_LIBRARY_PATH。
 比如:-agentlib:hprof
 用来获取jvm的运行情况,包括CPU、内存、线程等的运行数据,并可输出到指定文件中;windows中搜索路径为JRE_HOME/bin/hprof.dll。

-agentpath:pathname[=options] 
 按全路径装载本地库,不再搜索PATH中的路径;其他功能和agentlib相同;更多的信息待续,在后续的JVMTI部分会详述。

-classpath classpath 
-cp classpath
 
 告知jvm搜索目录名、jar文档名、zip文档名,之间用分号;分隔;使用-classpath后jvm将不再使用CLASSPATH中的类搜索路径,如果-classpath和CLASSPATH都没有设置,则jvm使用当前路径(.)作为类搜索路径。
 jvm搜索类的方式和顺序为:Bootstrap,Extension,User。
 Bootstrap中的路径是jvm自带的jar或zip文件,jvm首先搜索这些包文件,用System.getProperty("sun.boot.class.path")可得到搜索路径。
 Extension是位于JRE_HOME/lib/ext目录下的jar文件,jvm在搜索完Bootstrap后就搜索该目录下的jar文件,用System.getProperty("java.ext.dirs")可得到搜索路径。
 User搜索顺序为当前路径.、CLASSPATH、-classpath,jvm最后搜索这些目录,用System.getProperty("java.class.path")可得到搜索路径。

-Dproperty=value
 设置系统属性名/值对,运行在此jvm之上的应用程序可用System.getProperty("property")得到value的值。
 如果value中有空格,则需要用双引号将该值括起来,如-Dname="space string"。
 该参数通常用于设置系统级全局变量值,如配置文件路径,以便该属性在程序中任何地方都可访问。

-enableassertions[:<package name>"..." | :<class name> ] 
-ea[:<package name>"..." | :<class name> ]
 
 上述参数就用来设置jvm是否启动断言机制(从JDK 1.4开始支持),缺省时jvm关闭断言机制。
 用-ea 可打开断言机制,不加<packagename>和classname时运行所有包和类中的断言,如果希望只运行某些包或类中的断言,可将包名或类名加到-ea之后。例如要启动包com.wombat.fruitbat中的断言,可用命令java -ea:com.wombat.fruitbat...<Main Class>。

-disableassertions[:<package name>"..." | :<class ; ] 
-da[:<package name>"..." | :<class name> ]

 用来设置jvm关闭断言处理,packagename和classname的使用方法和-ea相同,jvm默认就是关闭状态。
 该参数一般用于相同package内某些class不需要断言的场景,比如com.wombat.fruitbat需要断言,但是com.wombat.fruitbat.Brickbat该类不需要,则可以如下运行:
 java -ea:com.wombat.fruitbat...-da:com.wombat.fruitbat.Brickbat <Main Class>。
 
-enablesystemassertions 
-esa
 
 激活系统类的断言。
 
-disablesystemassertions 
-dsa
 
 关闭系统类的断言。

-jar 
 指定以jar包的形式执行一个应用程序。
 要这样执行一个应用程序,必须让jar包的manifest文件中声明初始加载的Main-class,当然那Main-class必须有public static void main(String[] args)方法。

-javaagent:jarpath[=options] 
 指定jvm启动时装入java语言设备代理。
 Jarpath文件中的mainfest文件必须有Agent-Class属性。代理类也必须实现公共的静态public static void premain(String agentArgs, Instrumentation inst)方法(和main方法类似)。当jvm初始化时,将按代理类的说明顺序调用premain方法;具体参见java.lang.instrument软件包的描述。

-verbose 
-verbose:class
 
 输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断。
-verbose:gc 
 输出每次GC的相关情况。
-verbose:jni 
 输出native方法调用的相关情况,一般用于诊断jni调用错误信息。
 
-version 
 输出java的版本信息,比如jdk版本、vendor、model。
-version:release 
 指定class或者jar运行时需要的jdk版本信息;若指定版本未找到,则以能找到的系统默认jdk版本执行;一般情况下,对于jar文件,可以在manifest文件中指定需要的版本信息,而不是在命令行。
 release中可以指定单个版本,也可以指定一个列表,中间用空格隔开,且支持复杂组合,比如:
 -version:"1.5.0_04 1.5*&1.5.1_02+"
 指定class或者jar需要jdk版本为1.5.0_04或者是1.5系列中比1.5.1_02更高的所有版本。

-showversion 
 输出java版本信息(与-version相同)之后,继续输出java的标准参数列表及其描述。
 
-? 
-help
 
 输出java标准参数列表及其描述。

-X 
 输出非标准的参数列表及其描述。

以上的这些参数我们经常会在很多情况下用到多个的组合,比如我们在用JProfiler进行跟踪监控时,需要在被监控java启动参数中加上如下配置:
-agentlib:jprofilerti=port=8849  -Xbootclasspath/a:/usr/local/jprofiler5/bin/agent.jar
其中就用到两个-agentlib和-X参数,bootclasspath参数的详细信息将会在非标准参数中详细说明。

转自:http://blog.csdn.net/sfdev/article/details/2062042

这篇文章补充说明了-X、-XX参数的说明:Java命令行运行参数说明大全(偷来的)

posted @ 2011-12-08 15:49 iLinux 阅读(5130) | 评论 (0)编辑 收藏

     摘要: 作者:北南南北赞助: eTony,pandonny,懒猫, Arch来自:LinuxSir.Org摘要: 超级用户是系统最高权限的拥有者,是系统管理唯一的胜任者;由于权限的超级并且达到无所不能的地步,如果管理不擅,必会对系统安全造成威胁。 除了尽可能的避免用直接用超级用户root登录系统外,我们还要学会在普通用户下临时切换到超级用户root下完成必要的系统管理工作;从用户管理和...  阅读全文
posted @ 2011-12-08 15:36 iLinux 阅读(1450) | 评论 (0)编辑 收藏

hibernate中,比如B类继承了A类,它们是可以对应同一张表的。
可以参考如下文章Hibernate继承映射一:每个类分层结构一张表

posted @ 2011-12-08 12:50 iLinux 阅读(127) | 评论 (0)编辑 收藏

1 web容器启动,初始化ActionServlet,加载struts-config.xml,根据请求路径和信息找到ActionBean与FormBean

2 确定将要调用的ActionBean与FormBean,将请求中包含的值填充到FormBean中(Action中要准备好ActionMapping的参数)

3 struts将请求分发到相应的的ActionBean处理,ActionMapping参数ActionForm参数request,resposne都做为参数传给处理请求的ActionBean的execute方法

4 Action调用业务逻辑方法,得到返回值ActionForward对象

5 控制控重回ActionServlet,根据Action返回的ActionForward对象,转发到相应的页面

6 处理结果返回浏览器

posted @ 2011-12-08 12:29 iLinux 阅读(98) | 评论 (0)编辑 收藏

UML类图中的关联、聚合、组合

posted @ 2011-12-08 12:25 iLinux 阅读(97) | 评论 (0)编辑 收藏

nio:  http://jiayanjujyj.iteye.com/blog/1044364



posted @ 2011-12-08 00:14 iLinux 阅读(810) | 评论 (0)编辑 收藏

1 小白长得很像他的哥哥,打一句成语

答案:真相大白
Q:老板,你这不叫牛肉面吗?怎么连牛肉都没有?!  

A:人家还叫老婆饼呢,难不成你买的时候还送你一个老婆 ?! 
Q一根手指头的英文叫做 ONE,两根手指头的英文叫做TWO,依次类推,四根手手指头的英文叫做 four,那么弯起来的四根手指头的英文叫什么  

A答案:WONDERFFUL (弯的 FOUR)  
Q:一只兔子和一只跑得很快的乌龟赛跑,猜一猜谁赢拉?  

A:兔子 ~~

Q:错~!是乌龟拉,前面有说是一只跑很快的乌龟,跑很快噢~~

Q:兔子不甘心,又和一只戴了墨镜的乌龟比赛跑步,这次谁赢拉?  

A:恩。。兔子吧

Q:错~~!那只乌龟把墨镜一摘,也!又是刚才那只跑很快的乌龟噢

english version: http://translate.google.com/translate?langpair=zh-CN%7Cen&hl=zh-CN&ie=UTF8&u=http%3A//www.blogjava.net/iLinux/archive/2011/12/07/322634.html
posted @ 2011-12-07 23:31 iLinux 阅读(131) | 评论 (0)编辑 收藏

括号为是否线程安全
list: LinkedList(no) ArrayList(no) Vector(yes) Stack(yes)
map: HashMap(no) LinkedHashMap(no) HashTable(yes) WeakHashMap TreeMap
set: HashSet(no) LinkedHashSet(no) SortedSet TreeSet
最常用的好像为每行的前两个
特征:
1. Linked开头的适合快速插入,删除元素, linked维护元素插入的次序
2. Set 在 HashMap 的基础上实现, 所以Set结尾的key是不会重复的
3. Tree开头的是每次改变发生排序的, 速度慢
适用:
1. 需要快速插入,删除元素, 用 LinkedList; 需要快速随机访问元素,用 ArrayList
2. Vector 类似 ArrayList, 但是是同步的
3. Stack 继承 Vector , 是后进先出的堆栈
4. HashMap, put进去的对象位置会发生变化, LinkedHashMap 则不会
5. HashSet 是专门为快速查询而设计的, 插入会产生排序(LinkedHashSet 不会), 存入HashSet的对象必须定义hashCode方法
   我的补充:关于“存入HashSet的对象必须定义hashCode方法”,其实不是必须的,但是,当我们没有重写hashCode()时,则所有我们添加进Set的对象都不会有重复现象,我们可以添加多个具有相等值得对象,但是,这就与我们的初衷有了背离,Set本身用于存储unique的对象,所以我们重写hashCode()和equals(),符合我们的业务逻辑。
6. SortedSet 是保持元素的有序顺序的Set接口, 添加到 SortedSet 实现类的元素必须实现Comparable接口, TreeSet 类是它的唯一一份实现
其它:
1. 非同步的可以进行外部同步,或者使用Collections.synchronizedMap()的方法包装成一个thread-safe的Map/Set
2. LinkedHashMap支持两种排序:插入顺序、访问顺序。前者是指按照插入时的顺序排序,后者是指按照最旧使用到最近使用的顺序
3. 既然 Set 在 HashMap 的基础上实现, 那么 HashMap 和 HashSet 有什么区别吗?
答: HashMap提供get和put方法, 允许null 值和null 键; HashSet 提供add、remove、contains和size方法, 允许null 元素; 其它未知

转自:http://xu20cn.blog.51cto.com/274020/229009/
posted @ 2011-12-07 17:02 iLinux 阅读(877) | 评论 (0)编辑 收藏

一、事务的4个基本特征 
    当事务处理系统创建事务时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。这些特性称为ACID特性。 ACID就是:原子性(Atomicity )、一致性( Consistency )、隔离性或独立性( Isolation)和持久性(Durabilily)。 
1、原子性 (Atomicity ) 
    原子性属性用于标识事务是否完全地完成,一个事务的任何更新要在系统上完全完成,如果由于某种原因出错,事务不能完成它的全部任务,系统将返回到事务开始前的状态。 
让我们再看一下银行转帐的例子。如果在转帐的过程中出现错误,整个事务将会回滚。只有当事务中的所有部分都成功执行了,才将事务写入磁盘并使变化 永久化。为了提供回滚或者撤消未提交的变化的能力,许多数据源采用日志机制。例如,SQL Server使用一个预写事务日志,在将数据应用于(或提交到)实际数据页面前,先写在事务日志上。但是,其他一些数据源不是关系型数据库管理系统 (RDBMS),它们管理未提交事务的方式完全不同。只要事务回滚时,数据源可以撤消所有未提交的改变,那么这种技术应该可用于管理事务。 
2、一致性( Consistency ) 
    事务在系统完整性中实施一致性,这通过保证系统的任何事务最后都处于有效状态来实现。如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。因为事务开 
始时系统处于一致状态,所以现在系统仍然处于一致状态。 再让我们回头看一下银行转帐的例子,在帐户转换和资金转移前,帐户处于有效状态。如果事务成功地完成,并且提交事务,则帐户处于新的有效的状态。如果事务出错,终止后,帐户返回到原先的有效状态。 
记住,事务不负责实施数据完整性,而仅仅负责在事务提交或终止以后确保数据返回到一致状态。理解数据完整性规则并写代码实现完整性的重任通常落在 开发者肩上,他们根据业务要求进行设计。 当许多用户同时使用和修改同样的数据时,事务必须保持其数据的完整性和一致性。因此我们进一步研究A C I D特性中的下一个特性:隔离性。 
3、隔离性 ( Isolation) 
    在隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在 系统中认为只有该事务在使用系统。 这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。重要的是,在隔离状态执行事务, 系统的状态有可能是不一致的,在结束事务前,应确保系统处于一致状态。但是在每个单独的事务中,系统的状态可能会发生变化。如果事务不是在隔离状态运行, 它就可能从系统中访问数据,而系统可能处于不一致状态。通过提供事务隔离,可以阻止这类事件的发生。在银行的示例中,这意味着在这个系统内,其他过程和事 务在我们的事务完成前看不到我们的事务引起的任何变化,这对于终止的情况非常重要。如果有另一个过程根据帐户余额进行相应处理,而它在我们的事务完成前就 能看到它造成的变化,那么这个过程的决策可能 
建立在错误的数据之上,因为我们的事务可能终止。这就是说明了为什么事务产生的变化,直到事务完成,才对系统的其他部分可见。隔离性不仅仅保 证多个事务不能同时修改相同数据,而且能够保证事务操作产生的变化直到变化被提交或终止时才能对另一个事务可见,并发的事务彼此之间毫无影响。这就意味着 所有要求修改或读取的数据已经被锁定在事务中,直到事务完成才能释放。大多数数据库,例如SQL Server以及其他的RDBMS,通过使用锁定来实现隔离,事务中涉及的各个数据项或数据集使用锁定来防止并发访问。 
4、持久性 (Durabilily) 
    持久性意味着一旦事务执行成功,在系统中产生的所有变化将是永久的。应该存在一些检查点防止在系统失败时丢失信息。甚至硬件本身失败,系统的状态仍能通过在日志中记录事务完成的任务进行重建。持久性的概念允许开发者认为不管系统以后发生了什么变化,完 
成的事务是系统永久的部分。 在银行的例子中,资金的转移是永久的,一直保持在系统中。这听起来似乎简单,但这,依赖于将数据写入磁盘,特别需要指出的是,在事务完全完成并提交后才写 入磁盘的。 所有这些事务特性,不管其内部如何关联,仅仅是保证从事务开始到事务完成,不管事务成功与否,都能正确地管理事务涉及的数据 ,当事务处理系统创建事务 时,将确保事务有某些特性。组件的开发者们假设事务的特性应该是一些不需要他们亲自管理的特性。 
二、为什么需要对事务并发控制 
    如果不对事务进行并发控制,我们看看数据库并发操作是会有那些异常情形 
1、丢失更新(Lost update) 
    两个事务都同时更新一行数据,但是第二个事务却中途失败退出,导致对数据的两个修改都失效了。 
2、脏读(Dirty Reads) 
    一个事务开始读取了某行数据,但是另外一个事务已经更新了此数据但没有能够及时提交。这是相当危险的,因为很可能所有的操作都被回滚。 
3、非重复读(Non-repeatable Reads) 
   一个事务对同一行数据重复读取两次,但是却得到了不同的结果。同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生非重复读。 
4、二类丢失更新(Second lost updates problem) 
    无法重复读取的特例。有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。 
5、幻像读(Phantom Reads) 
    事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查 
询中未出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。 
三、数据库的隔离级别 
   为了兼顾并发效率和异常控制,在标准SQL规范中,定义了4个事务隔离级别,(ORACLE和SQLSERER对标准隔离级别有不同的实现 ) 
1、未提交读(Read Uncommitted) 
    直译就是"读未提交",意思就是即使一个更新语句没有提交,但是别 
的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。 
2、提交读(Read Committed) 
   直译就是"读提交",可防止脏读,意思就是语句提交以后即执行了COMMIT以后 
别的事务就能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 
3、可重复读(Repeatable Read): 
   直译就是"可以重复读",这是说在同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读 
4、串行读(Serializable) 
   直译就是"序列化",意思是说这个事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

 

四,隔离级别对并发的控制 
下表是各隔离级别对各种异常的控制能力。


LU丢失更新DR脏读NRR非重复读SLU二类丢失更新PR幻像读
未提交读 RUYYYYY
提交读 RCNNYYY
可重复读 RRNNNNY
串行读 SNNNNN

 

 

顺便举一小例。

MS_SQL: 
--事务一 
set transaction isolation level serializable 
begin tran 
insert into test values('xxx') 
--事务二 
set transaction isolation level read committed 
begin tran 
select * from test 
--事务三 
set transaction isolation level read uncommitted 
begin tran 
select * from test 
在查询分析器中执行事务一后,分别执行事务二,和三。结果是事务二会等待,而事务三则会执行。

ORACLE: 
--事务一 
set transaction isolation level serializable; 
insert into test values('xxx'); 
select * from test; 
--事务二 
set transaction isolation level read committed--ORACLE默认级别 
select * from test 
执行事务一后,执行事务二。结果是事务二只读出原有的数据,无视事务一的插入操作。

MYSQL 
查看InnoDB系统级别的事务隔离级别: 
以下为引用的内容: 
mysql> SELECT @@global.tx_isolation; 
+-----------------------+ 
| @@global.tx_isolation | 
+-----------------------+ 
| REPEATABLE-READ   | 
+-----------------------+ 
1 row in set (0.00 sec) 
查看InnoDB会话级别的事务隔离级别: 
以下为引用的内容: 
mysql> SELECT @@tx_isolation; 
+-----------------+ 
| @@tx_isolation | 
+-----------------+ 
| REPEATABLE-READ | 
+-----------------+ 
1 row in set (0.00 sec) 
修改事务隔离级别: 
以下为引用的内容: 
  mysql> set global transaction isolation level read committed; 
  Query OK, 0 rows affected (0.00 sec) 
  mysql> set session transaction isolation level read committed; 
  Query OK, 0 rows affected (0.00 sec) 
InnoDB的可重复读隔离级别和其他数据库的可重复读是有区别的,不会造成幻象读(phantom read),所谓幻象读,就是同一个事务内,多次select,可以读取到其他session insert并已经commit的数据。下面是一个小的测试,证明InnoDB的可重复读隔离级别不会造成幻象读。测试涉及两个session,分别为 session 1和session 2,隔离级别都是repeateable read,关闭autocommit 
以下为引用的内容: 
mysql> select @@tx_isolation; 
+-----------------+ 
| @@tx_isolation | 
+-----------------+ 
| REPEATABLE-READ | 
+-----------------+ 
1 row in set (0.00 sec) 
  mysql> set autocommit=off; 
  Query OK, 0 rows affected (0.00 sec) 
  session 1 创建表并插入测试数据 
  mysql> create table test(i int) engine=innodb; 
  Query OK, 0 rows affected (0.00 sec)

  mysql> insert into test values(1); 
  Query OK, 1 row affected (0.00 sec) 
  session 2 查询,没有数据,正常,session1没有提交,不允许脏读 
  mysql> select * from test; 
  Empty set (0.00 sec) 
  session 1 提交事务 
  mysql> commit; 
  Query OK, 0 rows affected (0.00 sec) 
  session 2 查询,还是没有数据,没有产生幻象读 
  mysql> select * from test; 
  Empty set (0.00 sec) 
以上试验版本: 
mysql> select version(); 
+-------------------------+ 
| version()       | 
+-------------------------+ 
| 5.0.37-community-nt-log | 
+-------------------------+ 
1 row in set (0.00 sec)

五、并发一致性问题的解决办法 
1 封锁(Locking) 
    封锁是实现并发控制的一个非常重要的技术。所谓封锁就是事务T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该 数据对象有了一定的控制,在事务T释放它的锁之前,其它的事务不能更新此数据对象。 基本的封锁类型有两种:排它锁(Exclusive locks 简记为X锁)和共享锁(Share locks 简记为S锁)。 
    排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其它事务在T释放A上的锁之前不能再读取和修改A。 
    共享锁又称为读锁。若事务T对数据对象A加上S锁,则其它事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其它事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。 
2 封锁协议 
    在 运用X锁和S锁这两种基本封锁,对数据对象加锁时,还需要约定一些规则,例如应何时申请X锁或S锁、持锁时间、何时释放等。我们称这些规则为封锁协议 (Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。下面介绍三级封锁协议。三级封锁协议分别在不同程度上解决了丢失的修改、不 可重复读和读"脏"数据等不一致性问题,为并发操作的正确调度提供一定的保证。下面只给出三级封锁协议的定义,不再做过多探讨。 
    1 级封锁协议是:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。 1级封锁协议可防止丢失修改,并保证事务T是可恢复的。在1级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,所以它不能保证可重复读和不 读"脏"数据。 
    2级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后即可释放S锁。2级封锁协议除防止了丢失修改,还可进一步防止读"脏"数据。 
    3级封锁协议是:1级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。3级封锁协议除防止了丢失修改和不读'脏'数据外,还进一步防止了不可重复读。 
六、一般处理并发问题时的步骤: 
1、开启事务。 
2、申请写权限,也就是给对象(表或记录)加锁。 
3、假如失败,则结束事务,过一会重试。 
4、假如成功,也就是给对象加锁成功,防止其他用户再用同样的方式打开。 
5、进行编辑操作。 
6、写入所进行的编辑结果。 
7、假如写入成功,则提交事务,完成操作。 
8、假如写入失败,则回滚事务,取消提交。 
9、(7.8)两步操作已释放了锁定的对象,恢复到操作前的状态。

转自:http://www.cnblogs.com/tqsummer/archive/2010/07/11/1775209.html

posted @ 2011-12-07 14:11 iLinux 阅读(547) | 评论 (0)编辑 收藏

仅列出标题
共3页: 上一页 1 2 3 下一页