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

Spring基础学习(五)—事务管理

2017-02-10 00:00 169 查看

一、事务基本认识

1.事务的概述

为了保证数据库中数据的一致性,数据的操作应当是离散的成组的逻辑单元。当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,整个事务应当全部视为错误,所有从起始点以后的操作应全部回退到开始状态。

事务的操作: 先定义开始一个事务,然后对数据做修改操作,这时如果提交(commit),这些数据就永久的保存下来,如果回退(rollback),数据库管理系统就放弃所有的修改而回到开始事务的状态。

2.事务的属性

(1)原子性(Atmicity)

原子性是指事务是一个不可分割的工作单位,事务的操作要么都发生,要么都不发生。

(2)一致性(Consistency)

事务必须使数据库从一个一致性状态变换到另外一个一致性的状态。

(3)隔离性(Isolation)

事务的隔离性是指一个事务的执行不能被其他事务干扰,即一个事务内部操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。

(4)持久性(Durability)

持久性是一个事务一旦被提交,它对数据库中的数据改变就是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。

3.数据库的隔离级别

数据库事务的隔离性: 数据库系统必须具有隔离并发运行各个事务的能力,使它不会相互影响,避免各种并发问题。

隔离级别: 一个事务与其他事务隔离的程度称为隔离级别。数据库规定了多种隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,一致性就越好,但并发性越弱。

对于同时运行的多个事务,当这些事务访问数据库相同数据时,如果没有采用必要的隔离机制,就会导致各种并发问题。

脏读对于两个事务T1,T2,T1读取了已经被T2修改但未提交的字段。
不可重复读T1读取了一个字段,然后T2更新了该字段,之后T1再次读取同一个字段,值就不同了。
幻读T1从一个表读了一个字段,T2在该表插入一些新行,T1再读,就多几行了。
看到上面的,我感觉不可重复读和幻读貌似区别不大,但是上网搜了下,有人说了它俩的区别。

不可重复读的重点是修改。同样的条件, 你读取过的数据, 再次读取出来发现值不一样了。
幻读的重点在于新增或者删除。同样的条件, 第1次和第2次读出来的记录数不一样。


数据库提供了4种事务隔离级别

隔离级别
描述
Read UnCommited(读未提交)
允许事务读取其他事务未提交的修改。脏读、不可重复读、幻读都会出现。
Read Commited(读已提交)
只允许事务读取其他事务提交的数据。可避免脏读,不能避免不可重复读、幻读。
Repeatable Read(可重复读)
确保事务可以从一个字段读相同的值,在这个事务持续期间,其他事务不能对这个字段进行更新。可避免脏读、不可重复读,不能避免幻读。
Serializable(串行化)
确保事务可以从一个表读取相同行。在这个事务持续期间,禁止其他事务对该表执行插入、更新、删除。所有并发问题都可以避免,但是性能十分低下。
Oracle 支持的 2 种事务隔离级别: READ COMMITED, SERIALIZABLE。Oracle 默认的事务隔离级别为: READ COMMITED 。Mysql 支持 4 中事务隔离级别. Mysql 默认的事务隔离级别为: REPEATABLE READ。

二、事务的使用

AccountDao.java

1
2
3
4
5
6
7
8
9
10
11
12
public
interface
AccountDao{


/*

 
* 汇款

 
*/

public
void
send(String sender,
int
money);


/*

 
* 收款

 
*/

public
void
receive(String receiver,
int
money);

}

AccountDaoImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public
class
AccountDaoImpl
extends
JdbcDaoSupport
implements
AccountDao{


@Override

public
void
send(String sender,
int
money){


this
.getJdbcTemplate().update(
"update account set money = money - ? where username = ?"
,money,sender);


}


@Override

public
void
receive(String receiver,
int
money){


this
.getJdbcTemplate().update(
"update account set money = money + ? where username = ?"
,money,receiver);


}

}

AccountService.java

1
2
3
4
5
6
7
public
interface
AccountService{


/*

 
* 转账

 
*/

public
void
transfer(String sender,String receiver,
int
money);

}

AccountServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public
class
AccountServiceImpl
implements
AccountService{


private
AccountDao accountDao;


public
void
setAccountDao(AccountDao accountDao){

this
.accountDao = accountDao;

}


@Override

public
void
transfer(String sender,String receiver,
int
money){


//两个操作

accountDao.send(sender,money);

int
i =
1
/
0
;

accountDao.receive(receiver,money);

}

}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> 
<!-- 加载属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties" />

<!-- 1.数据源 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}" />
<property name="jdbcUrl" value="${jdbcUrl}" />
<property name="user" value="${user}" />
<property name="password" value="${password}" />
</bean>

<!-- 2.dao -->
<bean id="accountDao" class="com.kiwi.dao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 3.service -->
<bean id="accountService" class="com.kiwi.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>

<!-- 4.1 事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- 4.2 将事务管理器交予Spring -->
<tx:annotation-driven transaction-manager="txManager"/>

</beans>


Test.app

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith
(SpringJUnit4ClassRunner.
class
)

@ContextConfiguration
(locations=
"classpath:applicationContext.xml"
)

@Transactional

public
class
TestApp{


@Autowired

private
AccountService accountService;


@Test

public
void
test1(){

accountService.transfer(
"AAA"
,
"BBB"
,
500
);

}

}

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