您的位置:首页 > 编程语言 > Java开发

spring学习笔记:spring事务管理

2009-12-30 13:02 375 查看
数据库事务的4个特性:
原子性(atomic): 都成功或者都失败;
一致性(consistency):事务操作之后,数据库所处的状态和业务规则是一致的;比如a,b账户相互转账之后,总金额不变;
隔离性(isolation):操作中的事务不相互影响;
持久性(durability):事务提交后被持久化到数据库.
数据并发产生的问题:
脏读:一个事物a读到了另一个事务b未提交的数据,则b回滚后,a读取的数据无效;
不可重复读:一个事物a第二次读到了另一个事务b修改的数据;
幻读:在统计数据的事务a两次统计的数据不一致(因为有其他事务新增数据)
第一类丢失更新:a事务回滚覆盖了b事务提交的数据;
第二类丢失更新:a事务覆盖了b事务提交的数据.
事物隔离级别: READ_UNCOMMITED, READ_COMMITED, REPEATABLE_READ, SERIALIZABLE; 一般情况下READ_COMMITED足够了.
spring事务管理相关的接口:
TransactionDefinition:代表一个事物,描述了事务的隔离级别, 超时时间,事务是否只读, 传播规则等等;
TransactionStatus:描述事物的状态;
PlatformTransactionManager:事务管理器接口, 只定义了3个方法:getTransaction()获取事务的状态; commit();rollback();
事务管理器的实现类有多种,根据具体的持久层框架的不同而不同;
spring中的事务传播行为的种类:
PROPAGATION_REQUIRED: 如果当前没有事务,就创建一个事务;如果已经存在事务,则加入事务;
PROPAGATION_SUPPORTS: 如果已经存在事务,则加入事务;如果没有事务,则以非事务的方式执行;
PROPAGATION_MANDATORY: 使用当前事务, 如果没有, 则抛出异常;
PROPAGATION_REQUIRED_NEW: 新建事务,如果当前有事务, 则挂起;
PROPAGATION_NOT_SUPPORTED:以非事务的方式执行, 如果当前有事务, 则挂起;
PROPAGATION_NEVER:以非事务的方式执行, 如果当前有事务,则抛出异常;
使用spring声明式的事务管理:
大多数情况下,事务会放在services层,spring声明式的事务管理中,需要做以下的工作:
1 把dao,service注入到spring容器(这些dao, service不涉及事务);
2 需要注入一个transactionManager(它需要dataSource);
3 通过TransactionProxyFactoryBean为目标对象(需要事务的dao, service等等)提供事务增强,产生增强后的代理对象.
看代码:
先添加一个CompanyService:

package services;
import java.util.List;
import model.Company;
import dao.hibernate.CompanyDao;

public class CompanyService {
 private CompanyDao companyDao;
 public CompanyDao getCompanyDao() {
  return companyDao;
 }
 public void setCompanyDao(CompanyDao companyDao) {
  this.companyDao = companyDao;
 }
 public void insertCompany(Company c){
  //some security check
  companyDao.save(c);
  //some updates
 }
 public void deleteCompany(int id){
  //some security check
  companyDao.deleteById(id);
  // some updates
 }
 public void updateCompany(Company c){
  companyDao.save(c);
 }
 public List list(){
  return companyDao.list();
 }
}

它调用dao组件执行crud.事务控制一般都放在这一层.

spring事务管理第一种配置方式:

为每个目标bean配置一个代理

<bean id="companyDao" class="dao.hibernate.CompanyDaoImpl">
 <property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<!-- 需要被增强的bean通常命名为xxxxTarget -->
<bean id="companyServiceTarget" class="services.CompanyService">
 <property name="companyDao" ref="companyDao" />
</bean>
<!-- 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
 <property name="dataSource" ref="dataSource" />
</bean>
<!-- 被代理之后的service,它具有事务功能,程序中我们就使用它 -->
<bean id="companyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
 <!-- 事务管理器 -->
 <property name="transactionManager" ref="txManager" />
 <!-- 需要被代理的目标 -->
 <property name="target" ref="companyServiceTarget" />
 <!-- optimize可选,true代表使用CGLib, false代表使用jdk proxy -->
 <property name="optimize" value="true" />
 <!-- 事务属性, 顺序: PROPAGATION, ISOLATION, readOnly, -Exceptions, +Exceptions -->
 <property name="transactionAttributes">
  <props>
   <prop key="insert*">PROPAGATION_REQUIRED</prop>
   <prop key="update*">PROPAGATION_REQUIRED</prop>
   <prop key="delete*">PROPAGATION_REQUIRED</prop>
   <prop key="list">PROPAGATION_REQUIRED, readOnly</prop>
   <prop key="search*">PROPAGATION_REQUIRED, readOnly</prop>
  </props>
 </property>
</bean>
测试:

public class Test {
 public static void main(String[] args) throws InterruptedException, SQLException{
  ApplicationContext c = new ClassPathXmlApplicationContext("spring-test.xml");
  CompanyService s = (CompanyService)c.getBean("companyService");
  List list = s.list();
  System.out.println(list.size());
  s.insertCompany(new Company("www.ddd.com","ddd","wuhan", new Date()));
}}

你会发现,这里的配置和前面讲的spring aop多么的相同,不错,他们的原理都是一样的,如果你没有了解过spring aop, 建议看一下。

通常情况下,service层需要的事务控制的配置大都相同,而且方法名大都是insertXXX, updateXXX, deleteXXX, searchXXX, checkXXX诸如此类,所以我们可以配置一个可复用的事务代理:

spring事务管理第二种配置方式:目标bean共享代理基类

<!-- abstract="true"标明它是抽象的 -->
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
 <property name="transactionManager" ref="txManager" />
 <!-- target被注释掉 -->
 <!--property name="target" ref="companyServiceTarget" /-->
 <property name="transactionAttributes">
  <props>
   <prop key="insert*">PROPAGATION_REQUIRED</prop>
   <prop key="update*">PROPAGATION_REQUIRED</prop>
   <prop key="delete*">PROPAGATION_REQUIRED</prop>
   <prop key="list">PROPAGATION_REQUIRED, readOnly</prop>
   <prop key="search*">PROPAGATION_REQUIRED, readOnly</prop>
  </props>
 </property>
</bean>
<bean id="companyService" parent="baseTransactionProxy">
 <property name="target" ref="companyServiceTarget" />
</bean>
<bean id="otherService" parent="baseTransactionProxy">
 <property name="target" ref="otherServiceTarget" />
</bean>
......
<!-- abstract="true"标明它是抽象的 -->
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
 <property name="transactionManager" ref="txManager" />
 <!-- target被注释掉 -->
 <!--property name="target" ref="companyServiceTarget" /-->
 <property name="transactionAttributes">
  <props>
   <prop key="insert*">PROPAGATION_REQUIRED</prop>
   <prop key="update*">PROPAGATION_REQUIRED</prop>
   <prop key="delete*">PROPAGATION_REQUIRED</prop>
   <prop key="list">PROPAGATION_REQUIRED, readOnly</prop>
   <prop key="search*">PROPAGATION_REQUIRED, readOnly</prop>
  </props>
 </property>
</bean>
<bean id="companyService" parent="baseTransactionProxy">
 <property name="target" ref="companyServiceTarget" />
</bean>
<bean id="otherService" parent="baseTransactionProxy">
 <property name="target" ref="otherServiceTarget" />
</bean>
......

虽然我们为需要事务增强的bean配置了代理类,但是难保用户还会直接使用目标对象companyServiceTarget; 可以使用拦截器.

spring事务管理第三种配置方式:使用拦截器

<!-- 配置一个事务拦截器,他对目标对象有事务增强的作用 -->
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
 <property name="transactionManager" ref="txManager" />
    <property name="transactionAttributes"> 
        <props> 
            <prop key="*">PROPAGATION_REQUIRED</prop> 
        </props> 
    </property> 
</bean>
<!-- 为目标对象自动创建代理 -->
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 
    <property name="beanNames">
        <list> 
            <value>companyServiceTarget</value>
        </list> 
    </property> 
    <property name="interceptorNames"> 
        <list> 
            <value>transactionInterceptor</value> 
        </list> 
    </property> 
</bean>
测试:此时可以直接使用companyServiceTarget.

public class Test {
 public static void main(String[] args) throws InterruptedException, SQLException{
  ApplicationContext c = new ClassPathXmlApplicationContext("spring-test.xml");
  //直接使用目标对象
  CompanyService s = (CompanyService)c.getBean("companyServiceTarget");
  List list = s.list();
  System.out.println(list.size());
  s.insertCompany(new Company("www.ddd.com","ddd","wu</span></p>
        <p> <!--<A href="#">http://msnpiki.msnfanatic.com/index.php/Main_Page</A>--></p>
  <div id="ad_f4" class="ad_f4"><script src="/js/2009/ad/ad_f4.js"></script></div>
      <div id="ad_f10" class="ad_f10"><script src="/js/2009/ad/ad_f10.js"></script></div><div id="ad_f11" class="ad_f11"><script src="/js/2009/ad_f11.js"></script></div>
   </div>
      <div align="center" class="pager w635px"><span id="pagesSpan"> <span id="1">1</span> <a href="176485_2.html">2</a></span></div>
      <div class="fh b14 w635px"> 如果图片或页面不能正常显示请<a onClick="#" onMouseOver="this.style.cursor='hand';" class= "redlink"><font color="#990000"><strong>点击这里</strong></font></a> 站内搜索:
     <iframe id="baiduframe" marginwidth="0" marginheight="0" scrolling="no"
  framespacing="0" vspace="0" hspace="0" frameborder="0" width="280" height="21"
  src="http://unstat.baidu.com/bdun.bsc?tn=diybl_pg&cv=0&cid=1061623&csid=541&bgcr=ffffff&urlcr=0000ff&tbsz=180&sropls=2,99&insiteurl=diybl.com&defid=99&kwgp=0&ch=1">
</iframe>
      </div>
      <div class="toollinks hui"> 【<A href="javascript:window.external.addFavorite(window.location,'MSN协议分析-DIY部落');">收藏此页</a>】【<A
      href="http://www.diybl.com/course/webjsh/osgl/5589fdssd.html" target="_blank">BBS社区</A>】【<A href="#comment">发表评论</A>】【<a href="#">返回顶部</a>】【<A
      href="javascript:window.close()">关闭</A>】 </div>
      <div class="p_bottom">
                 
                     <a href="/course/3_program/java/javajs/20090922/176484.html">上一篇文章:JCR-170 java 内容仓库</a>
                                      <br>
                                        <a href="/course/3_program/java/javajs/20090922/176486.html">下一篇文章:eclipse中多java项目打jar包简要说明</a>
                         </div>
    </div>
    <!--content area end!-->
    <div class="fc"></div>
    <div class="left-contect mtop blue border">
      <div class="b14 bold fh left-width">推荐文章</div>
    </div>
    <div class="left-contect white border recommend">
      <div class="tj_l fh20 white">
       <UL>
           
                                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/2008318/104924.html" target="_blank">My first Java program:Ap..</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/2007114/83346.html" target="_blank">Java面向对象程序设计之..</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/20090405/164284.html" target="_blank">一题多解教你SQL语句删除..</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/20090925/177093.html" target="_blank">JSP开发的模式</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/20071215/91918.html" target="_blank">Eclipse WTP使用经验--禁..</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/2007917/71620.html" target="_blank">SVG显示中文问题解决步骤</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/200797/70151.html" target="_blank">使用XML作为持久存储介质</a></LI>
                              <LI>  <a href="http://www.diybl.com/course/3_program/java/javajs/200865/122098.html" target="_blank">hibernate总结</a></LI>
                 </UL></div>
      <div class="tj_r fh20 white">
      <ul>
                                               <li><a href="http://www.diybl.com/course/3_program/java/javajs/2007927/74783.html" target="_blank">招聘——项目经理</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/200847/108540.html" target="_blank">java排序算法</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/20091120/183025.html" target="_blank">java中输入输出总结</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/200797/69982.html" target="_blank">JAVA开源工具大全</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/2008426/111471.html" target="_blank">Velocity 的应用示例</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/20071022/79291.html" target="_blank">EJB工作原理</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/2008924/145139.html" target="_blank">        构造函数的继承..</a></li>
                                <li><a href="http://www.diybl.com/course/3_program/java/javajs/20071111/85257.html" target="_blank">apache+Tomcat负载平衡设..</a></li>
                        </ul>
      </div>
    </div>
    <div class="fc"></div>
    <div class="left-contect mtop gray border-hui">
      <div class="b14 bold fh left-width"><a name="comment"></a>文章评论</div>
    </div>
    <div class="left-contect border-hui">
   <div id="divComment" class="left-width fh"></div>
    </div>
    <div class="fc"></div>
    <div class="comment_1 mtop border w_l">
      <div class="blue fh b14 bold pleft">请您留言</div>
      <div class="cleanblock fh22">
        昵称:
         <input name="tbName" id="tbName" class="input input_comment" type="text" size="15" value="" onclick="this.focus();this.select()"maxlength="20"/>       
        <br />
  <span style="float:left;">验证码:<input name="tbCode" id="tbCode" class="input input_comment" type="text" size="6"  /></span><span id="spanCode" style=" float:left; clear:right; "><img  id="Img2" onclick="this.src=this.src"  style="display:none;"/></span>
        <a href="http://user.diybl.com/register.aspx" target="_blank"><font color=red><br />
        注册会员</font></a> <a href="http://user.diybl.com/login.aspx" target="_blank">会员登陆</a> <br />
        <textarea name="tbContent" id="tbContent" rows="6" class=" input" style="VERTICAL-ALIGN: text-top; WIDTH:290px; HEIGHT: 7em">

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息