原文转自:获取
Spring的早期版本用户必须通过TransactionProxyFactoryBean代理对需要事务管理的业务类进行代理,便于实施事务功能的增强。
让我们先看代码吧!
业务层代码:
1
2
3
4
5
|
public
interface
UserScoreService {
public
UserScore getUserSocore(String userNo);
public
void
addUserScore(UserScore us);
public
int
getUsableScore(String userNo);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public
class
UserScoreServiceImpl
implements
UserScoreService {
private
UserScoreRepository userScoreRepository;
public
void
setUserScoreRepository(UserScoreRepository userScoreRepository) {
this
.userScoreRepository = userScoreRepository;
}
@Override
public
UserScore getUserSocore(String userNo) {
return
userScoreRepository.getUserSocore(userNo);
}
@Override
public
void
addUserScore(UserScore us) {
userScoreRepository.addUserScore(us);
}
@Override
public
int
getUsableScore(String userNo) {
return
userScoreRepository.getUsableScore(userNo);
}
}
|
持久层代码:
1
2
3
4
5
|
public
interface
UserScoreRepository {
public
UserScore getUserSocore(String userNo);
public
void
addUserScore(UserScore us);
public
int
getUsableScore(String userNo);
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public
class
UserScoreRepositoryImpl
implements
UserScoreRepository {
private
JdbcTemplate jdbcTemplate;
public
void
setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this
.jdbcTemplate = jdbcTemplate;
}
@Override
public
UserScore getUserSocore(String userNo) {
final
UserScore us =
new
UserScore();
StringBuffer sql =
new
StringBuffer();
sql.append(
"select * from userscore where userNo = ?"
);
jdbcTemplate.query(sql.toString(),
new
Object[]{userNo},
new
RowCallbackHandler() {
@Override
public
void
processRow(ResultSet rs)
throws
SQLException {
us.setId(rs.getInt(
"id"
));
us.setHonourScore(rs.getInt(
"honourScore"
));
us.setUsableScore(rs.getInt(
"usableScore"
));
us.setUserName(rs.getString(
"userName"
));
us.setUserNo(rs.getString(
"userNo"
));
}
});
return
us;
}
@Override
public
void
addUserScore(UserScore us) {
}
@Override
public
int
getUsableScore(String userNo) {
return
0
;
}
}
|
Spring配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
<!-- 定义一个数据源 -->
<
bean
id
=
"dataSource"
class
=
"org.apache.tomcat.jdbc.pool.DataSource"
>
<
property
name
=
"driverClassName"
value
=
"com.mysql.jdbc.Driver"
/>
<
property
name
=
"url"
value
=
"jdbc:mysql://localhost:3306/spring_test"
/>
<
property
name
=
"username"
value
=
"root"
/>
<
property
name
=
"password"
value
=
"root"
/>
</
bean
>
<!-- 定义JdbcTemplate的Bean -->
<
bean
id
=
"jdbcTemplate"
class
=
"org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref
=
"dataSource"
>
</
bean
>
<
bean
id
=
"userScoreRepository_jdbc"
class
=
"net.hingyi.springDemo.transaction.repository.UserScoreRepositoryImpl"
p:jdbcTemplate-ref
=
"jdbcTemplate"
/>
<!-- 声明事务管理器 -->
<
bean
id
=
"txManager"
class
=
"org.springframework.jdbc.datasource.DataSourceTransactionManager"
>
<
property
name
=
"dataSource"
ref
=
"dataSource"
></
property
>
</
bean
>
<!-- 需要实施事务增强的目标业务Bean -->
<
bean
id
=
"userScoreTarget"
class
=
"net.hingyi.springDemo.transaction.service.UserScoreServiceImpl"
p:userScoreRepository-ref
=
"userScoreRepository_jdbc"
/>
<!-- 使用事务代理工厂类为目标业务Bean提供事务增强 -->
<!-- p:transactionManager-ref="txManager" 指定事务管理器 -->
<!-- p:target-ref="userScoreTarget" 指定目标业务Bean -->
<
bean
id
=
"userScore"
class
=
"org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
p:transactionManager-ref
=
"txManager"
p:target-ref
=
"userScoreTarget"
>
<
property
name
=
"transactionAttributes"
>
<
props
>
<
prop
key
=
"get*"
>PROPAGATION_REQUIRED,readOnly</
prop
>
<!-- 只读事务 -->
<
prop
key
=
"*"
>PROPAGATION_REQUIRED</
prop
>
<!-- 可写事务 -->
</
props
>
</
property
>
</
bean
>
|
web.xml配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<
context-param
>
<
param-name
>log4jConfigLocation</
param-name
>
<
param-value
>classpath:log4j.properties</
param-value
>
</
context-param
>
<
context-param
>
<
param-name
>contextConfigLocation</
param-name
>
<
param-value
>classpath:applicationContext.xml</
param-value
>
</
context-param
>
<
listener
>
<
listener-class
>org.springframework.web.util.Log4jConfigListener</
listener-class
>
</
listener
>
<
listener
>
<
listener-class
>org.springframework.web.context.ContextLoaderListener</
listener-class
>
</
listener
>
|
异常回滚/提交规则
上面spring配置中的<prop>内的值为事务属性信息,匹配格式为:
PROPAGATION (传播行为)
扫描二维码关注公众号,回复:
489417 查看本文章
|
, |
ISOLATION (隔离级别(可选)) |
, |
readOnly (是否为只读事务(可选)) |
, |
-Exceptions (发生这些异常时回滚事务(可选))
|
, |
+Exceptions (发生这些异常时照样提交事务(可选)) |
Spring事务的传播类型
Spring在TransactionProxyFactory接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务发生嵌套调用时候是怎么传播的。如:
事务传播行为类型 |
说明 |
PROPAGATION_REQUIRED |
如果当前没有事务,就新建一个事务;如果已经存在一个事务,加入到这个事务中。(这个是最常见的选择) |
PROPAGATION_SUPPORTS |
支持当前事务。如果当前没有事务,就以非事务方式执行 |
PROPAGATION_MANDATORY |
使用当前的事务。如果当前没有事务,就抛出异常 |
PROPAGATION_REQUIRES_NEW |
新建事务。如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NOT_SUPPORTED |
以非事务的方式执行操作。如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NEVER |
以非事务方式执行。如果当前存在事务,则抛出异常 |
PROPAGATION_NESTED |
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 PROPAGATION_REQUIRED类似的操作 |
隔离级别
隔离级别是可选的,默认的为ISOLATION_DEFAULT,表示数据库的默认隔离级别。隔离级别的值如下:
隔离级别 |
脏读 |
不可重复读 |
幻象读 |
第一类丢失更新 |
第二类丢失更新 |
ISOLATION_READ_UNCOMMITED |
允许 |
允许 |
允许 |
不允许 |
允许 |
ISOLATION_READ_COMMITED |
不允许 |
允许 |
允许 |
不允许 |
允许 |
ISOLATION_REPEATABLE_READ |
不允许 |
不允许 |
允许 |
不允许 |
不允许 |
ISOLATION_SERIALIZABLE |
不允许 |
不允许 |
不允许 |
不允许 |
不允许 |
默认情况下,当发生运行异常时,事务将被回滚,发生检查型异常时,既不回滚也不提交,控制权交给外层调用。所以,带负号的异常设置仅对检查型异常有意义。