Spring 事务管理高级应用难点剖析: 第1 部分(Spring事务介绍)
http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts1/
文章中注意点:
从上面的输入日志中,可以清楚地看到 Spring 为 UserService#logon() 方法启动了一个新的事务,而 UserSerive#updateLastLogonTime()和 UserService#logon() 是在相同的类中,没有观察到有事务传播行为的发生,其代码块好像“直接合并”到UserService#logon()中。接着,当执行到ScoreService#addScore() 方法时,我们就观察到了发生了事务传播的行为:Participating in existing transaction,这说明ScoreService#addScore() 添加到 UserService#logon() 的事务上下文中,两者共享同一个事务。所以最终的结果是 UserService 的 logon(),updateLastLogonTime() 以及 ScoreService 的 addScore 都工作于同一事务中。
如果两个方法是在同一个类中,即使事务定义的是PROPAGATION_REQUIRES_NEW,两个方法也只会工作在同一个事务中,而不会重新起两个事务;
看来事务传播机制是针对多个不同类之间的调用,serviceA-->serviceB;
如下情况
classA中调用
serviceA.addMethodA();
serviceA.addMethodB();
即使我们配置针对serviceA.add* 方法传播机制为PROPAGATION_REQUIRED,MethodA和MethodB都会重新启动一个事务,两个方法启动的事务是互不相干的。
如下情况
serviceA.insertMethodA--->serviceB.insertMethodB
(1) 如果我们只是配置了serviceA.insert*事务机制为PROPAGATION_REQUIRED,methodB没有配置相应的事务,则methodA与methodB工作在同一个事务;
(2) 如果我们针对两个service都配置了insert*的事务机制为PROPAGATION_REQUIRES_NEW,首先A开启一个事务,执行到methodB,A事务挂起,给B开启一个新的事务,B事务提交,A事务恢复,A提交
如果执行过程中,A挂起,B新建事务,B抛出异常,则A,B事务都会回滚;
如果执行过程中,A挂起,B新建事务,B事务提交,A事务恢复,A事务抛出异常,则只回滚A事务,B事务不会回滚。
Spring AOP声明式事务异常回滚
Spring的AOP事务管理默认是针对uncheckedexception回滚。
也就是默认对RuntimeException()异常极其子类进行事务回滚。
Exception作为基类,下面还分checked exception和unchecked exception。如果客户端可以通过其他的方法恢复异常,那么这种异
常就是checked exception;如果客户端对出现的这种异常无能为力,那么这种异常就是Uncheckedexception;简单来说,继承于
RuntimeException的都是uncheckedexception。
Error:
1.总是不可控制的(unchecked)
2.经常用来用于表示系统错误或低层资源的错误
3.如何可能的话,应该在系统级被捕捉
Exception:
1.可以是可被控制(checked)或不可控制的(unchecked)
2.表示一个由程序员导致的错误
3.应该在应用程序级被处理
Java 中定义了两类异常:
1) Checked exception: 这类异常都是Exception的子类。异常的向上抛出机制进行处理,假如子类可能产生A异常,那么在父类中
也必须throws A异常。可能导致的问题:代码效率低,耦合度过高。
2) Unchecked exception: 这类异常都是RuntimeException的子类,虽然RuntimeException同样也是Exception的子类,但是它们是
非凡的,它们不能通过client code来试图解决,所以称为Unchecked exception。
解决办法:
1.在针对事务的类中抛出RuntimeException异常,而不是抛出Exception。
2.在txAdive中增加rollback-for,里面写自己的exception,例如自己写的exception为
com.cn.untils.exception.***Exception
<tx:advice id="txAdvice"transaction-manager="transactionManager">
<tx:attributes>
<tx:methodname="*" rollback-for="com.cn.untils.exception.***Exception"/>
</tx:attributes>
</tx:advice>
或者
定义不会滚的异常
<tx:adviceid="txAdvice">
<tx:attributes>
<tx:method name="update*"no-rollback-for="IOException"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
在声明事务中这样配置,如果自定义异常需要回滚的话
-Exception表示有Exception抛出时,事务回滚. -代表回滚+就代表提交
<propertyname="transactionAttributes">
<props>
<propkey="insert*">PROPAGATION_REQUIRES_NEW,-DataAccessException</prop>
<propkey="Add*">PROPAGATION_REQUIRED</prop>
<propkey="get*">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
Spring 事务管理高级应用难点剖析: 第 2 部分(Spirng 声明事务管理)
http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts2/
Spring 事务管理高级应用难点剖析: 第 3 部分(连接池泄露相关介绍)
http://www.ibm.com/developerworks/cn/java/j-lo-spring-ts3/index.html?ca=drs-cn-0329
补充:
(1)正是因为JdbcTemplate 严谨的获取连接,释放连接的模式化流程保证了 JdbcTemplate 对数据连接泄漏问题的免疫性。所以,如有可能尽量使用JdbcTemplate,HibernateTemplate 等这些模板进行数据访问操作,避免直接获取数据连接的操作。
(2)
终于轮到连接池了,通过上面的介绍,我们对线程及线程池都有个一个大致的了解。
在正常情况下,直接使用JDBC调用数据库可以满足一个小型系统的要求,但是当系统规模比较大的情况下,就会出现数据库的访问量迅速提升而令服务器不堪重负的现象,因而为了解决这一性能问题,常常会使用数据库连接池作为一个缓存的方式解决。
连接池类似上面介绍的线程池。
每次数据库连接的建立都需要花费一定的时空费用,而使用连接池,可以事先建立连接。当应用程序需要开始使用时,就从连接池中获取一个连接使用,应用程序使用完毕,通过close()方法将连接归还连接池。讲到这里,我门就不必在担心close()方法会不会影响性能了,完全可以放心大胆的使用。因为,它实际上并没有关闭连接,而是将连接归还连接池,供下次使用。
当并发增加是,连接池会不断的自动创建新的连接满足调用,直到达到连接池的最大数目;当连接池连接减少甚至没有时,连接池自动关闭一些连接,保持最小数目。
因此连接池的使用节省了连接建立时间,消除了数据库频繁连接带来的开销和瓶颈。
小提示:不知道大家有没有注意到配置websphere时有关于连接池最大最小数目的配置。呵呵,道理就在这。
那么,我们经常面对的连接未关闭的问题导致的系统速度很慢的问题就很容易说明了,就是因为线程池已经达到了最大数目,没有可用的了。所以,其他操作只有等待的份,等待那些应用用完了,被垃圾回收了,才能释放出可用的连接。