`
freeze06
  • 浏览: 10831 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Spring注解方式管理事务与传播行为详解

阅读更多

23.使用Spring注解方式管理事务与传播行为详解

文章分类:Java编程


  前面给大家介绍了怎样使用@Transactional这个注解申明PersonServiceBean这个bean底下的所有方法需要事务管理,那么这个事务管理是如何来管理的呢? 当每个业务方法执行的时候,它都会打开事务,在业务方法执行结束后,它会结束事务,那它什么时候决定事务提交呢?什么时候决定事务回滚呢?原先我们在手工控制事务的时候,通常事务的提交和回滚是由我们自己来操控的,那么现在我们使用容器申明事务管理我们如何知道它到底什么时候提交?什么时候失败呢?这时候大家就要注意了。Spring容器默认情况下对于运行期例外,它会进行事务的回滚;如果它碰到的是用户例外(checked这种例外),事务是不会回滚的。现在做一下测试。。。
数据库person表的记录如下:看图


现在要删除id为5的那条记录
PersonServiceBean.java
Java代码 复制代码 收藏代码
  1. package cn.itcast.service.impl;   
  2.   
  3. import java.util.List;   
  4.   
  5. import javax.sql.DataSource;   
  6.   
  7. import org.springframework.jdbc.core.JdbcTemplate;   
  8. import org.springframework.transaction.annotation.Propagation;   
  9. import org.springframework.transaction.annotation.Transactional;   
  10.   
  11. import cn.itcast.bean.Person;   
  12. import cn.itcast.service.PersonService;   
  13.   
  14. @Transactional  
  15. public class PersonServiceBean implements PersonService {   
  16.     private JdbcTemplate jdbcTemplate;   
  17.        
  18.     public void setDataSource(DataSource dataSource) {   
  19.         this.jdbcTemplate = new JdbcTemplate(dataSource);   
  20.     }   
  21.     // unchecked ,   
  22.     // checked   
  23.     public void delete(Integer personid){   
  24.         jdbcTemplate.update("delete from person where id=?"new Object[]{personid},   
  25.                 new int[]{java.sql.Types.INTEGER});   
  26.         throw new RuntimeException("运行期例外");   
  27.     }   
  28.         ............................................   
  29. }  
package cn.itcast.service.impl;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

@Transactional
public class PersonServiceBean implements PersonService {
	private JdbcTemplate jdbcTemplate;
	
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	// unchecked ,
	// checked
	public void delete(Integer personid){
		jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
				new int[]{java.sql.Types.INTEGER});
		throw new RuntimeException("运行期例外");
	}
        ............................................
}


PersonServiceTest.java
Java代码 复制代码 收藏代码
  1. package junit.test;   
  2.   
  3. import org.junit.BeforeClass;   
  4. import org.junit.Test;   
  5. import org.springframework.context.ApplicationContext;   
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  7.   
  8. import cn.itcast.bean.Person;   
  9. import cn.itcast.service.PersonService;   
  10.   
  11. public class PersonServiceTest {   
  12.     private static PersonService personService;   
  13.   
  14.     @BeforeClass  
  15.     public static void setUpBeforeClass() throws Exception {   
  16.         try {   
  17.             ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");   
  18.             personService = (PersonService) cxt.getBean("personService");   
  19.         } catch (RuntimeException e) {   
  20.             e.printStackTrace();   
  21.         }   
  22.     }   
  23.   
  24.     ........................................   
  25.        
  26.     @Test public void delete(){   
  27.         personService.delete(5);   
  28.     }   
  29.         ........................................   
  30. }  
package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

public class PersonServiceTest {
	private static PersonService personService;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		try {
			ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
			personService = (PersonService) cxt.getBean("personService");
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
	}

	........................................
	
	@Test public void delete(){
	    personService.delete(5);
	}
        ........................................
}

运行单元测试代码:JUnit抛出运行期例外,查看数据库,id为5那条记录还在,没被删掉。如图


因为抛出了运行期例外,容器检测到业务方法抛出的是运行期例外,那么它就会把这个事务进行回滚;如果抛出的是需要checked的这种例外呢?是否它也会进行回滚呢?
PersonServiceBean.java
Java代码 复制代码 收藏代码
  1. package cn.itcast.service.impl;   
  2.   
  3. import java.util.List;   
  4.   
  5. import javax.sql.DataSource;   
  6.   
  7. import org.springframework.jdbc.core.JdbcTemplate;   
  8. import org.springframework.transaction.annotation.Transactional;   
  9.   
  10. import cn.itcast.bean.Person;   
  11. import cn.itcast.service.PersonService;   
  12.   
  13. @Transactional  
  14. public class PersonServiceBean implements PersonService {   
  15.        
  16.     private JdbcTemplate jdbcTemplate;   
  17.   
  18.     public void setDataSource(DataSource dataSource) {   
  19.         this.jdbcTemplate = new JdbcTemplate(dataSource);   
  20.         //把数据源dataSource作为构造器参数传进去   
  21.     }   
  22.   
  23.     public void delete(Integer personid) throws Exception{   
  24.         jdbcTemplate.update("delete from person where id=?"new Object[]{personid},   
  25.                 new int[]{java.sql.Types.INTEGER});   
  26.         throw new Exception("运行期例外");   
  27.     }   
  28.         ......................................   
  29. }  
package cn.itcast.service.impl;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

@Transactional
public class PersonServiceBean implements PersonService {
	
	private JdbcTemplate jdbcTemplate;

	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
		//把数据源dataSource作为构造器参数传进去
	}

	public void delete(Integer personid) throws Exception{
		jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
				new int[]{java.sql.Types.INTEGER});
		throw new Exception("运行期例外");
	}
        ......................................
}

PersonService.java
Java代码 复制代码 收藏代码
  1. package cn.itcast.service;   
  2.   
  3. import java.util.List;   
  4.   
  5. import cn.itcast.bean.Person;   
  6.   
  7. public interface PersonService {   
  8.     //保存person   
  9.     public void save(Person person);   
  10.   
  11.     //更新person   
  12.     public void update(Person person);   
  13.   
  14.     //获取person   
  15.     public Person getPerson(Integer personid);   
  16.   
  17.     //获取所有person   
  18.     public List<Person> getPersons();   
  19.   
  20.     //删除指定id的person   
  21.     public void delete(Integer personid) throws Exception;   
  22. }  
package cn.itcast.service;

import java.util.List;

import cn.itcast.bean.Person;

public interface PersonService {
	//保存person
	public void save(Person person);

	//更新person
	public void update(Person person);

	//获取person
	public Person getPerson(Integer personid);

	//获取所有person
	public List<Person> getPersons();

	//删除指定id的person
	public void delete(Integer personid) throws Exception;
}

PersonServiceTest.java
Java代码 复制代码 收藏代码
  1. package junit.test;   
  2.   
  3. import org.junit.BeforeClass;   
  4. import org.junit.Test;   
  5. import org.springframework.context.ApplicationContext;   
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  7.   
  8. import cn.itcast.bean.Person;   
  9. import cn.itcast.service.PersonService;   
  10.   
  11. public class PersonServiceTest {   
  12.     private static PersonService personService;   
  13.   
  14.     @BeforeClass  
  15.     public static void setUpBeforeClass() throws Exception {   
  16.         try {   
  17.             ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");   
  18.             personService = (PersonService) cxt.getBean("personService");   
  19.         } catch (RuntimeException e) {   
  20.             e.printStackTrace();   
  21.         }   
  22.     }   
  23.   
  24.     @Test public void delete(){   
  25.         //这是要checked的例外,需要我们在外部用try/catch语法对它进行包含   
  26.         try {   
  27.             personService.delete(5);   
  28.         } catch (Exception e) {   
  29.             e.printStackTrace();   
  30.         }   
  31.     }   
  32. }  
package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

public class PersonServiceTest {
	private static PersonService personService;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		try {
			ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
			personService = (PersonService) cxt.getBean("personService");
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
	}

	@Test public void delete(){
        //这是要checked的例外,需要我们在外部用try/catch语法对它进行包含
		try {
			personService.delete(5);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

看下采用这种方式,它是否会进行回滚?运行单元测试代码,看见。。虽然是出现了例外,但是数据里id为5的记录被删掉了。看图:



所以,这里给大家总结一句:Spring开启的事务,默认情况下,如果碰到运行期例外,运行期例外,我们一般叫它unchecked例外;还有一种是要checked的例外,这种例外事务是不会回滚的。
大家应该知道了Spring管理事务,什么时候该提交,什么时候该回滚,它的规则。 那么我们能不能改变这个规则呢?比如现在throw new Exception("运行期例外");它抛出的是checked这种例外,默认情况下它是不会进行事务回滚的,但是如果我们需要它进行事务回滚,这时候可以在delete方法上通过@Transaction这个注解来修改它的行为。

PersonServiceBean.java
Java代码 复制代码 收藏代码
  1. package cn.itcast.service.impl;   
  2.   
  3. import java.util.List;   
  4.   
  5. import javax.sql.DataSource;   
  6.   
  7. import org.springframework.jdbc.core.JdbcTemplate;   
  8. import org.springframework.transaction.annotation.Transactional;   
  9.   
  10. import cn.itcast.bean.Person;   
  11. import cn.itcast.service.PersonService;   
  12.   
  13. @Transactional  
  14. public class PersonServiceBean implements PersonService {   
  15.        
  16.     private JdbcTemplate jdbcTemplate;   
  17.   
  18.     public void setDataSource(DataSource dataSource) {   
  19.         this.jdbcTemplate = new JdbcTemplate(dataSource);   
  20.         //把数据源dataSource作为构造器参数传进去   
  21.     }   
  22.   
  23.     @Transactional(rollbackFor=Exception.class)   
  24.     //rollbackFor这属性指定了,既使你出现了checked这种例外,那么它也会对事务进行回滚   
  25.     public void delete(Integer personid) throws Exception{   
  26.         jdbcTemplate.update("delete from person where id=?"new Object[]{personid},   
  27.                 new int[]{java.sql.Types.INTEGER});   
  28.         throw new Exception("运行期例外");   
  29.     }   
  30.         ....................................   
  31. }  
package cn.itcast.service.impl;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

@Transactional
public class PersonServiceBean implements PersonService {
	
	private JdbcTemplate jdbcTemplate;

	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
		//把数据源dataSource作为构造器参数传进去
	}

	@Transactional(rollbackFor=Exception.class)
	//rollbackFor这属性指定了,既使你出现了checked这种例外,那么它也会对事务进行回滚
	public void delete(Integer personid) throws Exception{
		jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
				new int[]{java.sql.Types.INTEGER});
		throw new Exception("运行期例外");
	}
        ....................................
}

PersonServiceTest.java
Java代码 复制代码 收藏代码
  1. package junit.test;   
  2.   
  3. import org.junit.BeforeClass;   
  4. import org.junit.Test;   
  5. import org.springframework.context.ApplicationContext;   
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  7.   
  8. import cn.itcast.bean.Person;   
  9. import cn.itcast.service.PersonService;   
  10.   
  11. public class PersonServiceTest {   
  12.     private static PersonService personService;   
  13.   
  14.     @BeforeClass  
  15.     public static void setUpBeforeClass() throws Exception {   
  16.         try {   
  17.             ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");   
  18.             personService = (PersonService) cxt.getBean("personService");   
  19.         } catch (RuntimeException e) {   
  20.             e.printStackTrace();   
  21.         }   
  22.     }   
  23.          ................................   
  24.   
  25.     @Test public void delete(){   
  26.         try {   
  27.             personService.delete(4);   
  28.         } catch (Exception e) {   
  29.             e.printStackTrace();   
  30.         }   
  31.     }   
  32.         ................................   
  33. }  
package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

public class PersonServiceTest {
	private static PersonService personService;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		try {
			ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
			personService = (PersonService) cxt.getBean("personService");
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
	}
         ................................

	@Test public void delete(){
		try {
			personService.delete(4);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
        ................................
}


现在数据库person表如下,看图



运行单元测试代码,结果,例外是跑出来了,这种例外是checked这种例外,数据库里,id为4这条记录还在,没有被删掉。看图:



原先,如果我们没有指定@Transactional(rollbackFor=Exception.class)里面rollbackFor这个属性的话,它会提交这个事务,现在要求它碰到checked例外的话,要求他也进行回滚。

同样,如果它抛出的是运行期例外RuntimeException,我们也可以指定它不进行回滚(默认情况下是会进行回滚的,现在要求它不回滚),
PersonServiceTest.java
Java代码 复制代码 收藏代码
  1. package junit.test;   
  2.   
  3. import org.junit.BeforeClass;   
  4. import org.junit.Test;   
  5. import org.springframework.context.ApplicationContext;   
  6. import org.springframework.context.support.ClassPathXmlApplicationContext;   
  7.   
  8. import cn.itcast.bean.Person;   
  9. import cn.itcast.service.PersonService;   
  10.   
  11. public class PersonServiceTest {   
  12.     private static PersonService personService;   
  13.   
  14.     @BeforeClass  
  15.     public static void setUpBeforeClass() throws Exception {   
  16.         try {   
  17.             ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");   
  18.             personService = (PersonService) cxt.getBean("personService");   
  19.         } catch (RuntimeException e) {   
  20.             e.printStackTrace();   
  21.         }   
  22.     }   
  23.          ................................   
  24.   
  25.     @Test public void delete(){   
  26.         try {   
  27.             personService.delete(4);   
  28.         } catch (Exception e) {   
  29.             e.printStackTrace();   
  30.         }   
  31.     }   
  32.         ................................   
  33. }  
package junit.test;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.bean.Person;
import cn.itcast.service.PersonService;

public class PersonServiceTest {
	private static PersonService personService;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		try {
			ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");
			personService = (PersonService) cxt.getBean("personService");
		} catch (RuntimeException e) {
			e.printStackTrace();
		}
	}
         ................................

	@Test public void delete(){
		try {
			personService.delete(4);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
        ................................
}

现在数据库person表记录如下,看图:


运行单元测试代码,id为4的记录被删掉了,看图


通过noRollbackFor这个属性和刚才说的rollbackFor属性就可以改变容器的事务行为。默认情况下,它碰到unchecked这种例外,它会进行回滚;碰到checked例外,它不会进行回滚的。我们可以通过noRollbackFor这个属性和rollbackFor属性来修改默认行为。

它还有几个功能相同的属性,rollbackForClassName,给它传递的是字符串;noRollbackForClassName,它提供的也是一个类的字符串名称;

这事务还有什么样的特点?在PersonServiceBean这个业务bean里面,有一些事务是不需要事务管理的,好比说获取数据的getPersons方法,getPerson方法。 那么不需要事务管理的情况下我们该怎样做呢?因为默认情况下它都会给我们开启事务,开启事务本身对性能会有所影响的,一般不需要事务的话要注明一下它是不需要事务的。可以采用propagation这个事务属性@Transactional(propagation=Propagation.NOT_SUPPORTED),propagation这个属性指定了事务传播行为,我们可以指定它不支持事务,当我们这么写了之后,Spring容器在方法执行前就不会开启事务.

那么对于有数据更新的操作,我们是需要Spring容器默认为我们打开的事务的,我们可以通过propagation这个属性对事务进行控制,可以看下有什么事务传播属性


事务传播属性
-------------------------------------------------------------------
REQUIRED:业务方法需要在一个事务中运行。如果方法运行时,已经处在一个事务中,那么加入到该事务,否则为自己创建一个新的事务。(基本在我们应用开发中,80%是使用这种事务传播行为。在没有标注的操作中,默认是这种行为)
NOT_SUPPORTED:声明方法不需要事务。如果方法没有关联到一个事务,容器不会为它开启事务。如果方法在一个事务中被调用,该事务会被挂起,在方法调用结束后,原先的事务便会恢复执行。
REQUIRESNEW:属性表明不管是否存在事务,业务方法总会为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务会被挂起,新的事务会被创建,直到方法执行结束,新事务才算结束,原先的事务才会恢复执行。
MANDATORY:该属性指定业务方法只能在一个已经存在的事务中执行,业务方法不能发起自己的事务。如果业务方法在没有事务的环境下调用,容器就会抛出例外。
SUPPORTS:这一事务属性表明,如果业务方法在某个事务范围内被调用,则方法成为该事务的一部分。如果业务方法在事务范围外被调用,则方法在没有事务的环境下执行。
Never:指定业务方法绝对不能在事务范围内执行。如果业务方法在某个事务中执行,容器会抛出例外,只有业务方法没有关联到任何事务,才能正常执行。
NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务, 则按REQUIRED属性执行.它使用了一个单独的事务, 这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效


REQUIRED,NOT_SUPPORTED,REQUIRESNEW,MANDATORY,SUPPORTS,Never这几种事务属性他们的作用和EJB里面作用都是一样的,因为这些事务属性原先EJB里面才有的,后来Spring借鉴了EJB里面的一些东西,也把它们引入到Spring里面去了。当然在Spring里面也单独给我们提供了NESTED这种事务属性。

我们看下NESTED这个事务属性的行为,我们对它进行解析下,假设现在我们要使用的是这种事务传播行为

事务传播属性NESTED介绍
-------------------------------------------------------------
Java代码 复制代码 收藏代码
  1. @Resource OtherService otherService;   
  2.   
  3. public void xxx(){   
  4.     stmt.executeUpdate("update person set name='888' where id=1");   
  5.     otherService.update(); //OtherService的update方法的事务传播属性为NESTED   
  6.     stmt.executeUpdate("delete from person where id=9");   
  7. }  
@Resource OtherService otherService;

public void xxx(){
    stmt.executeUpdate("update person set name='888' where id=1");
    otherService.update(); //OtherService的update方法的事务传播属性为NESTED
    stmt.executeUpdate("delete from person where id=9");
}

在这个bean里面,通过@Resource注解把otherService这个bean注入进来,otherService这个bean的update方法的事务传播属性为NESTED。 在xxx这个业务方法里面,它默认是打开事务了的,然后执行第一条update语句,然后执行otherService.update();因为update方法上面标注了事务传播属性为NESTED,(暂时不管。。。),执行完最后的update语句后.......
对方法做下展开,看下面:
Java代码 复制代码 收藏代码
  1. Connection conn = null;   
  2. try {   
  3.     conn.setAutoCommit(false);//把自动提交关闭   
  4.     Statement stmt = conn.createStatement();//然后创建一个语句对象   
  5.     stmt.executeUpdate("update person set name='888' where id=1");//对应前面的第一条语句   
  6.     ----------------------以下部分是Spring容器帮忙做的---------------------------   
  7.     //执行update方法时,判断它的事务属性是NESTED,它会先做一个保存点   
  8.     Savepoint savepoint = conn.setSavepoint();   
  9.     try{      
  10.             conn.createStatement().executeUpdate("update person set name='222' where sid=2");   
  11.     }catch(Exception ex){   
  12.             conn.rollback(savepoint);      
  13.             //当在执行语句时出现问题,这时候会回滚,回滚到保存点   
  14.      }   
  15.      ----------------------以上部分是Spring容器帮忙做的---------------------------   
  16.       stmt.executeUpdate("delete from person where id=9");//再执行前面的第二个update方法   
  17.       conn.commit();//再对事务进行提交   
  18.        stmt.close();   
  19.     } catch (Exception e) {   
  20.          conn.rollback();   
  21.      }finally{   
  22.                try {   
  23.         if(null!=conn && !conn.isClosed()) conn.close();   
  24.                 } catch (SQLException e) { e.printStackTrace(); }   
  25.      }   
  26. }  
Connection conn = null;
try {
    conn.setAutoCommit(false);//把自动提交关闭
    Statement stmt = conn.createStatement();//然后创建一个语句对象
    stmt.executeUpdate("update person set name='888' where id=1");//对应前面的第一条语句
    ----------------------以下部分是Spring容器帮忙做的---------------------------
    //执行update方法时,判断它的事务属性是NESTED,它会先做一个保存点
    Savepoint savepoint = conn.setSavepoint();
    try{   
            conn.createStatement().executeUpdate("update person set name='222' where sid=2");
    }catch(Exception ex){
            conn.rollback(savepoint);   
            //当在执行语句时出现问题,这时候会回滚,回滚到保存点
     }
     ----------------------以上部分是Spring容器帮忙做的---------------------------
      stmt.executeUpdate("delete from person where id=9");//再执行前面的第二个update方法
      conn.commit();//再对事务进行提交
       stmt.close();
    } catch (Exception e) {
         conn.rollback();
     }finally{
               try {
	    if(null!=conn && !conn.isClosed()) conn.close();
                } catch (SQLException e) { e.printStackTrace(); }
     }
}

现在问题是如果上面
Java代码 复制代码 收藏代码
  1. try{      
  2.     conn.createStatement().executeUpdate("update person set name='222' where sid=2");   
  3. }catch(Exception ex){   
  4.     conn.rollback(savepoint);      
  5.     //当在执行语句时出现问题,这时候会回滚,回滚到保存点   
  6.  }  
try{   
    conn.createStatement().executeUpdate("update person set name='222' where sid=2");
}catch(Exception ex){
    conn.rollback(savepoint);   
    //当在执行语句时出现问题,这时候会回滚,回滚到保存点
 }
出错了,那么外部的事务(那两条stmt的update语句)是否还会同步到数据库呢?它是可以的。但是try{}的语句是不能提交到数据库的,因为它出现例外了,事务已经回滚到保存点了。它失败了没关系,它对外部事务没有任何影响,我仍然可以执行后面的语句,再提交。
由此可见,嵌套的事务中,内部事务的回滚并不会对外部事务构成任何影响。当然如果说外部事务出问题了,好比说第二条stmt.executeUpdate()执行时出错了,被最外面的例外捕获到,然后回滚conn,大家说说前面的操作(第一个stmt.executeUpdate和NESTED那个update操作)会不会起效果啊? 是不会起效果的,因为外部事务的回滚,它会引起整个事务的失败,就是说即使里面NESTED那个update事务是成功的,但是因为外部事务执行失败了,那么会导致整个事务,包括NESTED那个update事务都会失败,这就是NESTED这个事务属性内部执行的过程。

 

  除了事务传播行为之外,我们还有其它属性可以设置的,
readOnly:代表只读,可通过这个设成只读事务,对于只读事务,它就不能进行更新操作,这样能提高效率的。
timeout:代表事务的超时时间,
isolation:数据库的隔离级别,这个实际上并不是由Spring容器实现的,这个主要是依赖于底层数据库来实现的。



数据库系统提供了四种事务隔离级
---------------------------------------------------------------------------
数据库系统提供了四种事务隔离级别供用户选择。不同的隔离级别采用不同的锁类型来实现,在四种隔离级别中,Serializable的隔离级别最高,Read Uncommited的隔离级别最低。大多数据库默认的隔离级别为Read Commited,如SqlServer,当然也有少部分数据库默认的隔离级别为Repeatable Read ,如Mysql
Read Uncommited:读未提交数据(会出现脏读,不可重复读和幻读)。
Read Commited:读已提交数据(会出现不可重复读和幻读)
Repeatable Read:可重复读(会出现幻读)
Serializable:串行化

脏读:一个事务读取到另一事务未提交的更新新据。
不可重复读:在同一事务中,多次读取同一数据返回的结果有所不同。换句话说就是,后续读取可以读到另一事务已提交的更新数据。相反,“可重复读”在同一事务中多次读取数据时,能够保证所读数据一样,也就是,后续读取不能读到另一事务已提交的更新数据。
幻读:一个事务读取到另一事务已提交的insert数据。


分享到:
评论

相关推荐

    spring几种事务配置详解【精】

    Spring支持七种事务传播行为: - `REQUIRED`:如果当前没有事务,就新建一个;如果已经存在一个事务,则加入到这个事务中。 - `SUPPORTS`:如果当前存在事务,就加入;如果没有事务,则不开启。 - `MANDATORY`:...

    spring事务详解

    Spring的事务管理还提供了强大的事务传播行为和隔离级别配置,开发者可以根据业务需求来设置事务如何在多个方法调用之间传播,以及事务之间的隔离程度,保证数据的一致性和隔离性。 在实际应用中,Spring事务管理的...

    Spring事务详解

    在Spring中,我们可以选择不同的事务传播行为,例如PROPAGATION_REQUIRED(默认)表示如果当前存在事务,则加入该事务,如果不存在则新建一个;PROPAGATION_REQUIRES_NEW表示始终新建一个事务,与当前事务无关等。...

    Spring声明式事务配置管理方法

    Spring提供了七种事务传播行为: - `PROPAGATION_REQUIRED`:如果存在事务,则加入;否则新建。 - `PROPAGATION_REQUIRES_NEW`:始终新建事务,如果已有事务则挂起。 - `PROPAGATION_SUPPORTS`:如果存在事务,...

    Spring事务优缺点及使用详解.docx

    【Spring 事务管理详解】 一、事务简介 事务是数据库操作的基本单位,它确保一组SQL语句要么全部成功,要么全部失败,以维护数据的一致性。在MySQL中,事务通常涉及INSERT、UPDATE、SELECT和DELETE等操作。当操作...

    Hibernate缓存与spring事务详解

    3. **事务传播行为** - `@Transactional`的propagation属性定义了事务如何在不同方法间传播,如REQUIRED(默认,如果存在事务则加入,否则新建)、REQUIRES_NEW(总是新建事务)等。 4. **事务隔离级别** - 包括...

    Spring 事务隔离与事务传播的详解与对比

    Spring 事务隔离与事务传播的详解与对比 Spring是SSH中的管理员,负责管理其它框架,协调各个部分的工作。今天一起学习一下Spring的事务管理。Spring的事务管理分为声明式跟编程式。声明式就是在Spring的配置文件中...

    spring事务管理

    ### Spring事务管理详解 #### 一、事务管理基础概念 在深入探讨Spring事务管理之前,我们需要先理解什么是事务。事务可以被定义为一系列的操作集合,这些操作作为一个整体被提交或回滚。简单来说,事务就是一个不...

    Spring 事务详解面试

    注解用于声明事务的属性,比如事务的传播行为、隔离级别、回滚规则等。通过注解,开发者可以将事务管理逻辑从业务逻辑中分离出来。 编程式事务则需要开发者在代码中手动控制事务的开始、提交和回滚。虽然这种方法...

    spring编程式事务与声明式事务详解[参照].pdf

    **事务属性**是事务管理的核心部分,包括事务隔离级别和事务传播行为。 **事务隔离级别**决定了并发事务间的隔离程度,防止数据的不一致性和脏读。Spring的TransactionDefinition接口定义了五个常量来表示这些级别...

    Spring事务管理配置

    其中,事务管理是Spring框架中的一个重要组成部分,它使得开发者能够以声明式的方式管理应用程序中的事务,从而提高了代码的可读性和维护性。 ### Spring事务管理的基本原理 Spring的事务管理分为编程式和声明式两...

    spring事务管理.rar

    Spring事务管理是Spring框架的核心特性之一,它提供了一种强大且灵活的方式来管理应用程序中的事务边界。在企业级Java应用中,事务处理是确保数据一致性、完整性和可靠性的关键部分。本篇文章将深入探讨Spring的事务...

    spring事务配置的五种方式

    通过`transactionAttributes`属性,我们可以指定每个方法的事务传播行为和回滚规则等。 #### 四、其他四种事务配置方式简介 除了上述的第一种方式外,还有另外四种常见的事务配置方式,它们分别是: 1. **基于XML...

    详细介绍Spring事务管理

    ### Spring事务管理详解 #### 一、Spring事务管理的重要性及必要性 在现代软件开发中,事务管理是一项至关重要的技术,特别是在涉及数据库操作时。事务能够确保一系列操作要么全部成功,要么全部失败,这对于保持...

Global site tag (gtag.js) - Google Analytics