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

数据库事务的四大特性、隔离级别以及Spring中如何利用AOP进行事务管理

2017-03-18 13:55 816 查看
首先,什么是事务?

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

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

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)配置事务管理类

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

(2)配置事务属性

<!-- 配置事务的属性 -->  
    <tx:advice id="TestAdvice" transaction-manager="transactionManager">  
        <!--配置事务传播性,隔离级别以及超时回滚等问题 -->  
        <tx:attributes>  
            <tx:method name="search*" propagation="REQUIRED" read-only="true" isolation="DEFAUT" TIMEOUT="-1" />  
            <tx:method name="del*" propagation="REQUIRED" />  
            <tx:method name="update*" propagation="REQUIRED" />  
            <tx:method name="add*" propagation="REQUIRED" />  
        </tx:attributes>  
    </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切入点

<aop:config>  
        <!--配置事务切点 -->  
        <aop:pointcut id="services"  
            expression="execution(public* com.pb.service.*.*(..))" />  
        <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />  
    </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"
/>

package demo.spring.dao;

import java.util.Iterator;
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 demo.spring.entity.Person;
@Transactional//将此类进行事务管理
public class PersonDaoImpl implements PersonDao {
private JdbcTemplate jt;

public void setDataSource(DataSource dataSource){
jt = new JdbcTemplate(dataSource);
}
@Override
public void insert(long id, String name, int age) {
jt.update("insert into person values('"+id+"','"+name+"','"+age+"')");

}

@Transactional(propagation= Propagation.REQUIRED)//定义要事务管理的方法,指定传播行为
public void batchInsert(List persons) {
for(Iterator it = persons.iterator(); it.hasNext(); ){
Person p = (Person) it.next();
insert(p.getId(),p.getName(),p.getAge());
}
}

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