先介绍一下事务的特性
1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么均不执行。
2、一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序串行执行的结果相一致。
3、隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
4、持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失,即使数据库出现故障。
1. 脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问 这个数据,然后使用了这个数据。
2. 不可重复读 :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不 可重复读。例如,一个编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果 只有在作者全部完成编写后编辑人员才可以读取文档,则可以避免该问题。
3. 幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。 如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。
补充 : 基于元数据的 Spring 声明性事务 :
Isolation 属性一共支持五种事务设置,具体介绍如下:
l DEFAULT 使用数据库设置的隔离级别 ( 默认 ) ,由 DBA 默认的设置来决定隔离级别 .
l READ_UNCOMMITTED 会出现脏读、不可重复读、幻读 ( 隔离级别最低,并发性能高 )
l READ_COMMITTED 会出现不可重复读、幻读问题(锁定正在读取的行)
l REPEATABLE_READ 会出幻读(锁定所读取的所有行)
Spring实现事务管理的几种方式简介:
1通过aop实现。(以银行转账为例,一个转入一个转出,如果中间出现异常要么都执行,要么都不执行)
public interface AccountDao { void outMoney(String out,Double money); void inMoney(String in,Double money); }
public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void transfer(String out, String in, Double money) { accountDao.outMoney(out,money); int s=1/0; accountDao.inMoney(in,money); } }
<!--引入外部属性文件--> <context:property-placeholder location="classpath:jdbc.properties"/> <!--配置C3P0连接池--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driverClass}"/> <property name="jdbcUrl" value="${jdbc.url}"/> <property name="user" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="accountService2" class="com.smart.two.AccountServiceImpl2" p:accountDao-ref="accountDao"/> <bean id="accountService" class="com.smart.domain.AccountServiceImpl" p:accountDao-ref="accountDao"/> <!--配置DAO类--> <bean id="accountDao" class="com.smart.domain.AccountDaoImpl" p:dataSource-ref="dataSource"/> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="pointcut1" expression="execution(* com.smart.domain.AccountService+.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/> </aop:config>测试:
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo { @Resource(name="accountService") private AccountService accountService; @Test public void demo1(){ accountService.transfer("aaa","bbb",200d); } }2通过事务注解实现
<!--开启注解事务,这样就可以用注解了--> <tx:annotation-driven transaction-manager="transactionManager"/>
/** * @Transaction注解中的属性: * propagation:事务的传播行为 * isolation:事务的隔离级别 * readOnly:只读 * rollbackFor:发生哪些异常会回滚 * noRollbackFor:发生哪些异常不回滚 * */ @Transactional(propagation = Propagation.REQUIRED ,isolation = Isolation.DEFAULT ,readOnly = true) public class AccountServiceImpl2 implements AccountService{ private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void transfer(String out, String in, Double money) { accountDao.outMoney(out,money); accountDao.inMoney(in,money); } }@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo2 { @Resource(name="accountService2") private AccountService accountService2; @Test public void demo1(){ accountService2.transfer("aaa","bbb",200d); } }