spring事务原理1-事务的抽象

概要

spring事务包含3个最主要的接口PlatformTransactionManager,TransactionStatus,TransactionDefinition 。其中PlatformTransactionManager负责管理事务的边界,
TransactionStatus负责描述事务的状态,TransactionDefinition定义事务相关属性,例如隔离级别,传播行为等。

PlatformTransactionManager

PlatformTransactionManager 的整个抽象体系基于Strategy 模式,由PlatformTransactionManager 对事务界定进行统一抽象,而具体的界定策略的实现则交由具体的实现类。

public interface PlatformTransactionManager {

  TransactionStatus getTransaction(TransactionDefinition definition)
    throws TransactionException;

  void commit(TransactionStatus status) throws TransactionException;

  void rollback(TransactionStatus status) throws TransactionException;
}

TransactionDefinition

TransactionDefinition定义了事务的相关属性:隔离级别,传播性,超时,只读状态。

  • Isolation: The degree to which this transaction is isolated from the work of other transactions. For example, can this transaction see uncommitted writes from other transactions?

  • Propagation: Typically, all code executed within a transaction scope will run in that transaction. However, you have the option of specifying the behavior in the event that a transactional method is executed when a transaction context already exists. For example, code can continue running in the existing transaction (the common case); or the existing transaction can be suspended and a new transaction created. Spring offers all of the transaction propagation options familiar from EJB CMT. To read about the semantics of transaction propagation in Spring, see Section 10.5.7, “Transaction propagation”.

  • Timeout: How long this transaction runs before timing out and being rolled back automatically by the underlying transaction infrastructure.

  • Read-only status: A read-only transaction can be used when your code reads but does not modify data. Read-only transactions can be a useful optimization in some cases, such as when you are using Hibernate.

TransactionStatus

org.springframework.transaction.TransactionStatus 接口定义表示整个事务处理过程中的事务状态,更多时候,我们将在编程式事务中使用该接口。

public interface TransactionStatus extends SavepointManager {

    boolean isNewTransaction();

    boolean hasSavepoint();

    void setRollbackOnly();

    boolean isRollbackOnly();

    void flush();

    boolean isCompleted();

}

在事务处理过程中,我们可以使用TransactionStatus 进行如下工作。

  • 使用TransactionStatus 提供的相应方法查询事务状态。
  • 通过setRollbackOnly() 方法标记当前事务以使其回滚。
  • 如果相应的PlatformTransactionManager支持Savepoint,可以通过TransactionStatus 在当前事务中创建内部嵌套事务。

spring事务原理2-隔离级别

spring提供了5种事务的隔离级别:

ISOLATION_DEFAULT

如果指定隔离级别为ISOLATION_DEFAULT ,则表示使用数据库默认的隔离级别,通常情况下是Read Committed 。

ISOLATION_READ_UNCOMMITTED

对应Read Uncommitted 隔离级别,无法避免脏读,不可重复读和幻读。

ISOLATION_READ_COMMITTED

对应Read Committed 隔离级别,可以避免脏读,但无法避免不可重复读和幻读。

ISOLATION_REPEATABLE_READ

对应Repeatable read隔离级别,可以避免脏读和不可重复读,但不能避免幻读.

ISOLATION_SERIALIZABLE

对应Serializable 隔离级别,可以避免所有的脏读,不可重复读以及幻读,但并发性效率最低.

spring事务原理3-事务的传播行为

事务的传播行为

在spring管理的事务中,需要认识到物理和逻辑事务的不同,并且如何设置这些不同。

  • PROPAGATION_REQUIRED

如果当前存在一个事务,则加入当前事务。如果不存在任何事务,则创建一个新的事务。总之,要至少保证在一个事务中运行。PROPAGATION_REQUIRED通常作为默认的事务传播行为。

  • PROPAGATION_SUPPORTS

如果当前存在一个事务,则加入当前事务。如果当前不存在事务,则直接执行。对于一些查询方法来说,PROPAGATION_SUPPORTS通常是比较合适的传播行为选择。

  • PROPAGATION_MANDATORY

PROPAGATION_MANDATORY 强制要求当前存在一个事务,如果不存在,则抛出异常.

  • PROPAGATION_REQUIRES_NEW

不管当前是否存在事务,都会创建新的事务。如果当前存在事务,会将当前的事务挂起(Suspend)。如果某个业务对象所做的事情不想影响到外层事务,PROPAGATION_REQUIRES_NEW 应该是合适的选择。比如,假设当前的业务方法需要向数据库中更新某些日志信息,但即使这些日志信息更新失败,我们也不想因为该业务方法的事务回滚,而影响到外层事务的成功提交。因为这种情况下,当前业务方法的事务成功与否对外层事务来说是无关紧要的。

  • PROPAGATION_NOT_SUPPORTED

不支持当前事务,而是在没有事务的情况下执行。如果当前存在事务的话,当前事务原则上将被挂起(Suspend).

  • PROPAGATION_NEVER

永远不需要当前存在事务,如果存在当前事务,则抛出异常。

  • PROPAGATION_NESTED

如果存在当前事务,则在当前事务的一个嵌套事务中执行,否则与PROPAGATION_REQUIRED 的行为类似,即创建新的事务,在新创建的事务中执行.

PROPAGATION_NESTED事务是依赖的吧,不可分割的,PROPAGATION_REQUIRES_NEW是独立的,相互分离的。

PROPAGATION_NESTED uses a single physical transaction with multiple savepoints that it can roll back to. Such partial rollbacks allow an inner transaction scope to trigger a rollback for its scope, with the outer transaction being able to continue the physical transaction despite some operations having been rolled back. This setting is typically mapped onto JDBC savepoints, so will only work with JDBC resource transactions. See Spring’s DataSourceTransactionManager.

2014年下半年计划

2014年已经过去一半了,感觉什么事也没做。
上半年买的书都还有大半没看完,进度太慢了。发现再这样下去还是不行的,必须要给自己一点压力,让自己成长起来。so,so,so制定下下半年的计划,不能再这样继续荒废时间了:

plan1: 读书

  • 《java性能优化》

    根据书上的性能优化措施,看完了至少能将公司的项目提升一个层次。

  • 《android4高级编程》

    希望能上架自己的1,2个小应用,暂时还没想好做什么。

  • 《数据挖掘》《深入浅出数据分析》《大数据》《大规模分布式存储系统》

    想办法做好公司的BI系统吧。

  • 《大型网站系统与java中间件架构实践》《大型网站技术架构》《软件架构设计》

    要多练练架构才好,不过这些书讲的太过空泛了。

  • 《深入理解计算机系统》《计算机程序的构造和解释》《代码大全》

    底层也要多了解了解才好。

plan2: 分析开源框架

  • spring

感觉对spring的理解还是比较欠缺,下半年努力把spring的方方面面都理解清楚吧。

  • 网络,并发

netty,concurrent包,这两部分也是需要继续研究的。

  • 大数据

如果还有精力的话,就研究hadoop的代码吧。

plan3: 锻炼

  • 每周必须要跑一次步

  • 计划一次爬山

  • 每天至少3分钟平板支撑

plan4: 赚钱

没钱的屌丝,要想办法赚钱呀。

  • 炒股

炒股就是博弈,人生要敢于冒风险。希望自己的资产能够在过年的时候上涨10%。

linux环境变量的加载顺序

当使用export设置环境变量的时候,注意前面的环境变量会覆盖后面设置的环境变量。
例如:

1
2
export JAVA_HOME/usr/java1.7
export PATH=$PATH:$JAVA_HOME/bin

当在/etc/profile中设置这2个选项的时候,如果PATH中已经包含了java的运行时环境,那么此设置会失败。

要想使自定义设置生效,最好将自定义的path设置在前面,如下:

1
2
export JAVA_HOME/usr/java1.7
export PATH=$JAVA_HOME/bin:$PATH

理解Android Activity

每一个Activity都表示一个屏幕,应用程序会把它呈现给用户。应用程序越复杂,需要的屏幕可能越多。

典型情况下,这至少包括一个用来处理应用程序的主ui功能的主屏幕。这个主界面由许多fragment组成,并且通常由一组次要Activity支持。要在屏幕之间进行切换,就要启动一个新的Activity。

Activity的生存周期

1.activity栈

每一个Activity的状态是由它所在Activity栈中所处的位置所决定的,Activity栈是当前所有正在运行的Activity的后进先出的集合。当一个新的Activity启动时,它就变为Activity状态了,并被移动到栈顶。如果用户使用Back(返回)按钮返回到了刚才的Activity,或者前台Activity被关闭了,那么栈中的下一个Activity就会移动到栈顶,变为活动状态。

2.Activity的状态

随着Activity的创建和销毁,它们会按照上图从栈中进进出出。在这个过程中,它们经历了一下4中状态:

  • 活动状态
    当一个Activity位于栈顶的时候,它是可见的,具有焦点的前台Activity,这时候它可以接收用户输入。Android将会不惜一切代价来保持它处于活动状态,并根据需要来销毁栈下面部分的Activity,以保证这个Activity拥有它所需要的资源。当另一个Activity变为活动状态的时候,这个Activity就被暂停。

  • 暂停状态
    在某些情况下,Activity是可见的,但是没有获得焦点,此时它就处于暂停状态。当一个透明的或者非全屏的Activity位于该Activity之前时,就会达到这个状态。当Activity被暂停的时候,它任然会被当做近视与活动状态的状态,但是它不能接受用户的输入事件。在极端情况下,Android会终止暂停的Activity,以方便为活动状态的Activity释放资源。当一个Activity变得完全不可见的时候,它就变为停止状态。

  • 停止状态
    当一个Activity不可见的时候,它就处于停止状态。此时,Activity仍然会停留在内存中,保存所有的状态信息,然而当系统的其他地方要求使用内存的时候,他们就会成为被终止的首要侯选对象。在一个Activity停止的时候,保存数据和当前的UI状态以及停止任何飞关键操作是很重要的。一旦一个Activity被退出或者关闭,它就会变为非活动状态。

  • 非活动状态
    当一个Activity被终止后,在启动之前它就处于非活动状态。处于非活动状态的Activity已经从Activity栈中删除了,因此,在他们可以被显示和使用之前,需要重新被启动。

3.理解Activity的生命周期

  • 完整生命周期

Activity的完整生成周期是指对OnCreate方法的第一次调用和对OnDestroy方法的最后一次调用之间的时间范围。有时候还会发生一个Activity的进程被终止,却没有调用OoDestory方法的情况。

OnCreate方法来初始化Activity:填充用户界面,得到对Fragment的引用,分配对类变量的引用,将数据绑定到控件,并启动Service和定时器。

OnDestory方法来清理OnCreate方法创建的所有资源,并保证所有的外部连接都被关闭了。

  • 可见生存期

一个Activity的可见生成期是指调用Onstart和Onstop之间的那段时间。在这个时间段中,Activity是对用户可见的,但是他们可能不具有焦点,或者她可能被部分遮挡了。

OnStop方法应该用来暂停或者停止动画,线程,传感器监听器,GPS查找,定时器,Service或者其他专门用于更新用户界面的进程。当UI不可见的时候它是没有意义的,因为这消耗了资源缺没起到实际的作用。

当UI再次可见的时候,可以使用OnStart或者OnRestart方法来恢复或者重启这些进程。OnRestart在除了对Onstart方法的第一次调用之外的所有方法之前被立即调用。

  • 活动生存期

活动生存期是指OnResume及对应的OnPause之间的那段时间。

一个处于活动状态的Activity是在前台的,并且正在接受用户输入事件。一定要让OnPause和OnResume中的代码执行迅速,并且其中的代码尽可能的少,以保证在前台和后台之间进行切换的时候应用程序能够迅速响应。

Intent和Broadcast Receiver

Intent简介

Intent是一种消息传递机制,可以在应用程序中使用, 也可以在应用程序间使用。Intent可以用于:

  • 使用类名显示启动一个特定的Service或Activity
  • 启动Activity或Service来执行一个动作的Intent,通常需要使用特定的数据,或者对特定的数据执行动作。
  • 广播某个事件的发生。

使用Intent来启动Activity

显示:

1
2
Intent intent = new Intent(MyActivity.this, MyOtherActivity.class);
startActivity(intent);

隐式:
隐式的Intent提供了一种机制,可以让匿名的应用程序组件响应动作请求。这意味着可以要求系统启动一个可执行给定动作的Activity,而不必知道需要启动哪个应用程序或Activity。

例如:如果希望用户从应用程序中打电话,可以实现一个新的拨号程序,也可以使用一个隐式的Intent来请求一个在电话号码(表示为一个URI)上执行动作(拨号)。

1
2
3
4
5
if(somethingWeird&&itDontLookGood){
Intent intent =
new Intent (Intent.Action_DLL,Uri.parse("tel:555-2368"));
startActivity(intent);
}

Android就会解析这个Intent,并启动一个新的Activity,该Activity会提供对这个电话号码进行拨号的动作—-在这种情况下,通常是Phone Dialer.

Linfify简介

Linkify是一个辅助类,它会自动地在TextView类(或者TextView的派生类)中通过RegEx模型匹配来创建超链接。

那些匹配一个指定的RegEx模式的文本都将会被转换为一个可以单击的超链接,这些超链接可以隐式使用匹配的文本作为目标URI来触发startActivity(new Intent(Intent.ACTION_VIEW,uri))。

原生Linkify链接类型

Linkify类有一些预设值可以检测到Web URL,电子邮件地址和电话号码,并把他们转换为链接。要应用一个预设值,需要使用静态的Linkify.addLinks方法,并传入要建立的链接的视图,以及以下的一个活更多个自描述的Linkify类常量的位掩码:WEB_URLS,EMAIL_ADDRESS,PHONE_NUMBERS和ALL。

1
2
TextView textView = (TextView)findViewById(R.id.myTextView);
Linkify.addLinks(textView,Linkify.WEB_URLS|Linkify.EMAIL_ADDRESSES);

也可以使用Android:autoLink属性来在一个布局内部链接视图。

1
2
3
4
5
6
<TextView 
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:text = "@string/linkify_name"
android:autoLink = "phone|email"
/>

创建定制的链接字符串

使用Match Filter

使用Transform Filter

Transform Filter 允许修改匹配的链接文本生成的隐式URI。把链接文本和目标URI分离开,你能够更自由的决定如何把数据字符串显示给用户。

使用Intent广播事件

作为一个系统级的消息传递机制,Intent可以在进程之间发送结构化的消息。因此,可以通过实现Broadcast Receiver来监听和响应应用程序内的这些Broadcast Intent。

Broadcast Intent 用于向监听器通知系统的应用程序或应用事件,从而可以扩展应用程序间的事件驱动的编程模型。

Broadcast Intent 可以是应用程序更加开发:通过使用Intent来广播一个事件,可以在不用修改原始应用程序的情况下,让你和第三方开发人员对事件做出反应。在应用程序中,可以通过监听Broadcast Intent来对设备状态变化和第三方应用程序事件做出反应。

使用 Intent广播事件

在应用程序组件中,可以构建希望广播的Intent,然后使用sendBroadcast方法来发送它。

可以对Intent的动作,数据和分类进行设置,从而使Broadcast Receiver能够精确的确定他们的需求。

使用Broadcast Receiver来监听广播

Broadcast Receiver可以用来监听Broadcast Intent。要使Broadcast Receiver 能够接受广播,就需要对其进行注册,即可以使用代码,也可以在应用程序的manifest文件中注册。无论怎么注册,都要使用一个Intent Filter来指定它要监听哪些Intent和数据。

impala 使用连接池报“Cannot get a connection, pool exhausted”异常

最近在使用dbcp 为impala创建连接池时,创建的时候没有报错,但是取连接的时候发现报错了,错误信息如下:

1
Caused by: org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool exhausted

通过debug发现连接池中的连接数为0,断定是创建连接池的时候出了异常。
于是debug进入commons dbcp的源代码中,发现在PoolableConnectionFactory中的passivateObject(Object obj)方法中出了异常。

public void passivateObject(Object obj) throws Exception {
    if(obj instanceof Connection) {
        Connection conn = (Connection)obj;
        if(!conn.getAutoCommit() && !conn.isReadOnly()) {
            conn.rollback();
        }
        conn.clearWarnings();
        //由于impala没有事务,所以设置自动提交必然失败
        conn.setAutoCommit(true);
    }
    if(obj instanceof DelegatingConnection) {
        ((DelegatingConnection)obj).passivate();
    }
}

发现dbcp代码有问题后,首先看了下版本号1.2.1。进入官网后,发现有1.4的新版本,于是下载下来后,查看源代码:

public void passivateObject(Object obj) throws Exception {
    if(obj instanceof Connection) {
        Connection conn = (Connection)obj;
        if(!conn.getAutoCommit() && !conn.isReadOnly()) {
            conn.rollback();
        }
        conn.clearWarnings();
        if(!conn.getAutoCommit()) {
            conn.setAutoCommit(true);
        }
    }
    if(obj instanceof DelegatingConnection) {
        ((DelegatingConnection)obj).passivate();
    }
}

发现在1.4的代码中已经先判断连接自动提交的状态再设置。果断更新dbcp后,运行一切正常。

android 特殊事件处理

在android中,可能需要一些特定的事件来处理某些任务。下面我们将介绍android中比较特殊的2种事件处理。

响应系统设置事件

在开发android中, 我们可能需要让应用程序随着系统的设置而响应。例如判断屏幕的方向,导航的方向等。

Configuration类介绍

Configuration类用于描述手机设备上的配置信息,这些配置信息包括用户特定的配置项,也包括系统的动态配置项。

Configuration cfg = getResources().getConfiguration();

  • fontScale — 来源于system.prop中 sys.font.scale配置项
    输入设备类型配置:系统加入的任何输入device必须拥有输入属性:现在android中仅支持touchscreen(触摸),keyboard(键盘),navigation(滚动球)
  • orientation — 屏幕方位
  • keyboardHidden — 如果是划盖或开盖手机并且没有软键盘支持,这个设成true
  • hardKeyboardHidden — 如果是划盖或开盖手机,这个设成true
  • locale — 用户选择的location信息
  • theme — 皮肤,资源等等

重写onConfigurationChanged响应系统设置更改

如果应用程序需要监听系统设置的更改,则可以考虑重写Activityd的onConfigurationChanged(Configuation newConfig)方法,该方法是一个基于回调的事件处理方法:当系统设置发生更改是,改方法会被自动触发。

为了在程序中动态的更改系统设置,我们可以调用Activity的setRequestedQrientation(int)方法来修改屏幕的方向。

Handler消息传递机制

Android的消息传递机制是另一种形式的“事件处理”,这种机制主要是为了解决Android应用的多线程问题—android平台不允许Activity新启动的线程访问该Activity里的界面组件,这样会导致新启动的线程无法动态改变界面组件的属性值。但在实际Android开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程周期性的改变界面组件的属性值,这就需要借助于Handler的消息传递机制来实现了。

Handler类简介

Handler类的主要作用:

  • 在新启动的线程中发送消息。
  • 在主线程中获取,处理消息。

为了让主线程能“适时”地处理新启动的线程锁发送的消息,显然只能通过回调的方式来实现—开发者只要重写Handler类中处理消息的方法,当新启动的线程发送消息时,Handler类中处理消息的方法被自动回调。
Handler类包含如下方法用于发送,处理消息。

android 事件机制

android提供了2中事件处理方式:基于回调的事件处理和基于监听器的事件处理。

基于监听的事件处理

在事件监听处理的处理模型中,主要涉及如下3种类型:

  • Event Source(事件源):事件发生的各个场所,通常是各个组件,例如按钮,窗口,菜单等。
  • Event(事件):事件封装了界面组件上发生的特定事件(通常就是一次用户操作)。
  • Event Listener(事件监听器):监听事件源发生的事件,对各个事件做出响应。

Android的事件处理机制是一种委派式事件处理方式:普通组件(事件源)将整个事件处理委托给特定的对象(事件监听器);当该事件源发生特定的事件时,就通知所委托的事件监听器,由事件监听器来处理这个事件。

基于回调的事件处理

如果说事件监听机制是一种委托的事件处理,那么回调机制正好相反:对于基于回调的时间爱你处理模型来说,事件源与事件监听器是统一的,或者说事件监听器完全消失了。当用户在gui组件上激发某个事件的时候,组件自己特定的方法将会负责处理该事件。

比较

对于基于监听的事件处理模型来说,事件源和事件监听器是分离的,当事件源上发生特定的事件后,该事件交给事件监听器处理;对于基于回调的事件处理模型来说,事件源和事件监听器是统一的,当事件源发生特定的事件后,该事件还是由事件源本身负责处理。