0%

事务管理

事务管理可以分为编程式事务管理和声明式事务管理。
编程式事务管理:类似命令式的事务管理,只是把涉及到事务操作的逻辑抽取成目标类,使用者只需要关注数据库操作;

声明式事务管理:声明式编程的事务管理方式,通过响应的配置,告诉让框架来我们需要达到什么样的效果,让框架来管理事务,而不需要使用者手动管理;

网络图片

编程式事务管理

手动编写

不使用框架,纯粹开发者自己编写,可以使用Connection接口的commit,rollback方法,自行判断异常等逻辑进行手动事务管理;

Spring 事务模板

纯粹的开发自己编写,会存在大量的样板代码,比如Connection,statement的关闭等;Spring 提供和很多模板代码,可以解决这些问题,其中
Spring 就提供了事务的模板代码;

Spring 内部封装了一个事务管理的TransactionTemplate模板类,其内部的transactionManager专门负责事务管理,其最终也是调用Connection的commit,rollback方法进行事务管理;

下面的代码用到了Spring 依赖注入,注入了一个TransactionTemplate的实例;要执行的数据库操作,都在模板类中执行;

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
public class AccountServiceImplPragram implements AccountService {

private AccountDao accountDao;
private TransactionTemplate transactionTemplate;

public void transfer(final String out, final String in, final Double money) {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.inMoney(in, money);
// int i = 1 / 0;
accountDao.outMoney(out, money);
}
});

}

public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
}

声明式事务管理

即使Spring 提供了事务管理的模板,当时事务管理还是有点繁琐,而且这种事务管理方式有一定的侵入性;

能否有一种方式,可以让Service只是普通的Service,在调用DAO层的时候无需关心其事务问题;

有! Spring 提供了如下三中方式,解决这个问题,其中基于注解的方式,和基于AspectJ xml,虽然还是有一定的侵入性,但是这种方式极其简单,是日常开发常用的事务管理方式;

基于TransactionProxyFactoryBean代理的方式,使用不方便,而且还具有侵入性,通常不使用;

基于 TransactionProxyFactoryBean代理的Service方式事务管理

这种基于 TransactionProxyFactoryBean代理的Service方式,每次增加一个Service就必须增加一个相对的TransactionProxyFactoryBean用于增强对应的Service类,使用起来不方便;然后将这个TransactionProxyFactoryBean注入到Controller中,具有侵入性;

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
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:springconfig_statement1.xml")
public class TestTransactionManagerStatement1 {

@Resource(name = "transactionProxyFactoryBean")
private AccountService accountService;

@Test
public void testTransactionManagerStatement1() {

accountService.transfer("aaa", "bbb", 200d);

}
}

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionProxyFactoryBean"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--配置注入要增强的类-->
<property name="target" ref="accountService"/>
<!--配置注入transactionManager-->
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<!--key 可以是 instert update transfer -->
<!--value 格式
PROPAGATION:事务的传播级别
ISOLATION :事务的隔离级别
readOnly : 只读 (不可以进行 instert update delete)
-Exception : 发生哪些异常执行回滚
+Exception : 发生哪些异常 不执行回滚

<prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop>
-->
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>



基于AspectJ xml 配置声明式的事务管理

通过Spring AOP 织入的方式给需要添加事务管理的方法增加事务管理。

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
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:springconfig_statement2.xml")
public class TestTransactionManagerStatement2 {

@Resource(name = "accountService")
private AccountService accountService;

@Test
public void testTransactionManagerStatement2() {

accountService.transfer("aaa", "bbb", 200d);

}
}

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer"
propagation="REQUIRED"
/>
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="pointcut1"
expression="execution(* com.conan.springtransaction.service.AccountService.transfer(..))"/>
</aop:config>

<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
</aop:config>


基于注解方式的声明式事务管理

如下代码Spring是采用xml的配置方式,如果采用Java config配置方式,会更加简洁,只需要关注Service类上的@Transactional就好;
通过设置@Transactional的属性就能达到事务管理的目的;

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
45
46
47
48
49
50
51
52
53
54
55
56
57
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:springconfig_statement3.xml")
public class TestTransactionManagerStatement3 {

@Resource(name = "accountService")
private AccountService accountService;

@Test
public void testTransactionManagerStatement3() {

accountService.transfer("aaa", "bbb", 200d);

}
}

@Transactional(propagation = Propagation.REQUIRED)
public class AccountServiceImplStatement3 implements AccountService {

private AccountDaoImplStatement1 accountDao;

public void transfer(String out, String in, Double money) {
accountDao.inMoney(in, money);
int i = 1 / 0;
accountDao.outMoney(out, money);
}

public void setAccountDao(AccountDaoImplStatement1 accountDao) {
this.accountDao = accountDao;
}
}

<!--引入实现文件-->
<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="accountDao" class="com.conan.springtransaction.dao.AccountDaoImplStatement1">
<property name="dataSource" ref="dataSource"/>
</bean>

<bean id="accountService" class="com.conan.springtransaction.service.AccountServiceImplStatement3">
<property name="accountDao" ref="accountDao"/>
</bean>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>


<tx:annotation-driven transaction-manager="transactionManager"/> //激活注解

GitHub登录不了?信任该网站之后再登录。