数据库的四个特性 以及在Spring中如何使用事务管理

首先,什么是事务?

事务就是业务上的一个逻辑单元,它能够保证其中对数据所有的操作,要么成功,要么失败。

其次,事务的特性有哪些?

1.原子性。

例如,转账,A账户减少,B账户增加。虽然是两条 DML语句,但是被当做是一个整体,一次事务。两条语句只能同时成功或者同时失败。

2.一致性。

账户A和B,要么都是转账前的状态,要么都是转账后的状态。(不能A账户的钱减少了但是B账户的钱没有增加)。

3.隔离性。

虽然在某个时间段很多人都在转账,但是每个人的转账都是在一个自己的事务中,彼此不会影响。

4.持久性。

事务提交成功后,数据修改永远生效。

在考虑事务的隔离级别之前,需要认识到如果不考虑事务的隔离性,会发生的异常情况:

1.脏读

一个事务读取了另外一个事务未提交的数据。(会对系统的并发处理带来很大的隐患)

2.不可重复读

在同一个事务内,多次读同一个数据时,发现该数据已经 被另一个已经提交的事务修改。(在一个事务内两次读到的数据时是不一样的。)

3.幻读

一个事务根据相同的查询条件,重新执行查询,返回的记录中包含与前一次执行查询返回的记录不同的行。


以上这三种 情况都是同时进行的几个事务对相同的数据进行读取时造成的。

如何处理这几种异常呢?

ANSI SQL-92标准中定义了以下几种事务隔离级别:

1.Read Uncommitted

最低等级的事务隔离,仅仅保证读取过程中不会读到非法数据。(三种异常情况均可能发生)

2.Read Committed

避免了“脏读”。一个select查询只能查看到查询开始之前提交的数据。在查询执行时,其他事务修改或者提交的数据它看不到(数据库默认的事务隔离级别)

3.Repeatable Read

避免了“脏读”和“不可重复读”。一个事务不可能更新由另一个事务读取但是没有提交的数据。应用并不广泛。因为它可能出现幻读。同时带来更多性能损失。

4.Serializable

ORACLE数据库只支持Read Committed 和Serializable两种隔离级别。另外自定义了一个Read Only的隔离级别,只允许读,不允许改。避免不可重复读和幻读

三种都能避免。所有事务串行,而不是并行。

Spring事务的隔离级别
 1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
      另外四个与JDBC的隔离级别相对应
 2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
      这种隔离级别会产生脏读,不可重复读和幻像读。
 3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
 4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
      它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
 5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
      除了防止脏读,不可重复读外,还避免了幻像读。

使用Spring AOP实现声明式事务管理

1.基于XML配置(使用较多)

(1)配置事务管理类


   
   
  1.   <!– 定义事务管理器 –>  
  2. <bean id=“transactionManager”  
  3.      class= “org.springframework.jdbc.datasource.DataSourceTransactionManager”>  
  4.      <property name=“dataSource” ref=“dataSource” />  
  5. </bean>  
在spring的配置中配置数据源(dataSource)、事务管理器,事务管理器使用不同的orm框架事务管理器类就不同,mybatis 是 org.springframework.jdbc.datasource.DataSourceTransactionManager  。而hibernate事务管理器为org.springframework.orm.hibernate3.HibernateTransactionManager  

(2)配置事务属性


   
   
  1. <!-- 配置事务的属性 -->  
  2.      <tx:advice id="TestAdvice" transaction-manager="transactionManager">  
  3.          <!--配置事务传播性,隔离级别以及超时回滚等问题 -->  
  4.          <tx:attributes>  
  5.              <tx:method name="search*" propagation="REQUIRED" read-only="true" isolation="DEFAUT" TIMEOUT="-1" />  
  6.              <tx:method name="del*" propagation="REQUIRED" />  
  7.              <tx:method name="update*" propagation="REQUIRED" />  
  8.              <tx:method name="add*" propagation="REQUIRED" />  
  9.          </tx:attributes>  
  10.      </tx:advice>

事务属性在<tx:method>中进行设置,Spring支持对不同的方法设置不同的事务属性,所以可以为一个<tx:advice>设置多个<tx:method>,其中name属性指定匹配的方法(这里需要对这些方法名进行约定,如果事务切入点在service上,则最好和Dao的方法命名区分开,也不要使用get set关键字,防止和属性的getter setter发生混淆)

事务有以下几个常用属性:

a.read-only:设置该事务中是否允许修改数据。(对于只执行查询功能的事务,设置为TRUE可以提高事务的执行速度)  

b.propagation:事务的传播机制。一般设置为required。可以保证在事务中的代码只在当前事务中运行,防止创建多个事务。

c.isolation:事务隔离级别。不是必须的。默认值是default。

d.timeout:允许事务运行的最长时间,以秒为单位。

e.rollback-for:触发回滚的异常。

f.no-rollback-for:不会触发回滚的异常。

***实际开发中,对于只执行查询功能的事务,要设置read-only为TRUE,其他属性一般使用默认值即可。


(3)配置事务的AOP切入点


   
   
  1. <aop:config>  
  2.          <!--配置事务切点 -->  
  3.          <aop:pointcut id="services"  
  4.              expression= "execution(public* com.pb.service.*.*(..))" />  
  5.          <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />  
  6.      </aop:config>  

该设置的含义是:对于com.pb.service.impl包及子包下的所有类的所有公共方法进行切入。(被切入的 方法经过<tx:method>筛选)web应用程序最合适的事务切入点是Service的方法上。

—-通过以上三个步骤设置好声明式事务后,当Service中 的业务方法被调用之前,Spring会获取事务对象并启动事务。并使用try-catch-finally来处理异常。业务方法执行成功则会提交事务,默认情况下如果抛出了RuntimeException 或者Rrror 对象就会回滚事务。(注意: 这里注意一下,在tx:method中配置了rollback_for 中配置的Exception 这个是运行时的异常才会回滚不然其他异常是不会回滚的!)

2.使用annotation配置

*1.在事务管理的dao实现类之前标注@Transactional

*2.在要进行事务管理的方法前加上@Transactional(propagation= Propagation.REQUIRED)

*3.在配置文件中指定驱动:<tx:annotation-driven transaction-manager=”transactionManager” />


   
   
  1. package demo.spring.dao;
  2. import java.util.Iterator;
  3. import java.util.List;
  4. import javax.sql.DataSource;
  5. import org.springframework.jdbc.core.JdbcTemplate;
  6. import org.springframework.transaction.annotation.Propagation;
  7. import org.springframework.transaction.annotation.Transactional;
  8. import demo.spring.entity.Person;
  9. @Transactional//将此类进行事务管理
  10. public class PersonDaoImpl implements PersonDao {
  11. private JdbcTemplate jt;
  12. public void setDataSource(DataSource dataSource){
  13. jt = new JdbcTemplate(dataSource);
  14. }
  15. @Override
  16. public void insert(long id, String name, int age) {
  17. jt.update("insert into person values('"+id+"','"+name+"','"+age+"')");
  18. }
  19. @Transactional(propagation= Propagation.REQUIRED)//定义要事务管理的方法,指定传播行为
  20. public void batchInsert(List persons) {
  21. for(Iterator it = persons.iterator(); it.hasNext(); ){
  22. Person p = (Person) it.next();
  23. insert(p.getId(),p.getName(),p.getAge());
  24. }
  25. }
  26. }

            </div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值