好记性不如烂笔头96-spring3学习(17)-利用debug观察事务传播
1) 前提和准备
我们需要利用log4j的debug模式来观察,因此我们需要系统能支持log4j运行;
我们需要观察事务,因此我们要访问一个数据库。
create table FFM_USER
(
USERNAME VARCHAR2(64),
PASSWORD VARCHAR2(64),
LAST_LOGON_TIME VARCHAR2(64),
CHARGE INTEGER
)
里面有一条数据: 在username字段对应“ffm”
2) 业务场景
一个嵌套事务的服务方法。
有两个service。UserService 本身有数据库访问,另外也调用了ChargeServer的数据库操作方法。
都使用了AOP进行事务增强。
3) 实现简单事务传播的源代码
模拟spring事务嵌套调用的父类
package com.spring.propagation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 模拟spring事务嵌套调用的父类
* @author 范芳铭
*/
public class BaseService {
protected static final Logger log = LoggerFactory.getLogger(BaseService.class);
}
模拟spring事务嵌套调用的主方法
package com.spring.propagation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* 模拟spring事务嵌套调用的主方法
*
* @author 范芳铭
*/
@Service("userService")
public class UserService extends BaseService{
@Autowired private JdbcTemplate jdbcTemplate;
@Autowired private ChargeService chargeService;
public void logon(String userName){
System.out.println("--before,本地方法 userService运行");
updateLastLogonTime(userName);
System.out.println("--after,本地方法 userService 运行");
System.out.println("-- before ,调用其他服务类 chargeService 的方法");
chargeService.addCharge(userName, 20);
System.out.println("-- after ,调用其他服务类 chargeService 的方法");
}
public void updateLastLogonTime(String userName){
String sql = "update ffm_user u set u.last_logon_time = ? where username =? ";
jdbcTemplate.update(sql, System.currentTimeMillis(),userName);
}
}
模拟spring事务嵌套调用的配套方法
package com.spring.propagation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* 模拟spring事务嵌套调用的配套方法
*
* @author 范芳铭
*/
@Service("chargeService")
public class ChargeService extends BaseService{
@Autowired private JdbcTemplate jdbcTemplate;
public void addCharge(String userName,int toAdd){
String sql = " update ffm_user u set u.charge =nvl(u.charge,0) + ? where username = ? ";
jdbcTemplate.update(sql,toAdd,userName);
}
}
模拟容器运行
package com.spring.propagation;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
/**
* 模拟容器运行,执行logon方法
*
* @author 范芳铭
*/
public class EasyApplicationContext {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("b_propagation.xml");
UserService service = (UserService)ctx.getBean("userService");
service.logon("ffm");
}
}
4)配置文件b_propagation.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:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd">
<context:component-scan base-package="com.spring.propagation"/>
<context:property-placeholder location="classpath:dbconfig.properties" />
<bean id = "dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method = "close"
p:driverClassName="${jdbc.o2o.driverClassName}"
p:url="${jdbc.o2o.url}"
p:username="${jdbc.o2o.username}"
p:password="${jdbc.o2o.password}"
/>
<bean id="jdbcTemplate" class ="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource" />
<bean id="jdbcManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource" />
<tx:advice id="jdbcAdvice" transaction-manager="jdbcManager">
<tx:attributes>
<tx:method name = "*" />
</tx:attributes>
</tx:advice>
<aop:config proxy-target-class="true">
<aop:pointcut id="serviceJdbcMethod" expression="within(com.spring.propagation.BaseService+)" />
<aop:advisor pointcut-ref="serviceJdbcMethod" advice-ref="jdbcAdvice" order="0" />
</aop:config>
</beans>
5)观察和结论
开启DEBUG模式,启动“模拟容器运行”应用。查看日志。
…
Getting transaction for [com.spring.propagation.UserService.logon]
–before,本地方法 userService运行
…
在执行
– before ,调用其他服务类 chargeService 的方法
之后,看到:
[DEBUG] Participating in existing transaction …
后面一个事务,就直接利用第一个事务了。
在这里,发生了一个明显的事务的传播的行为,两个数据库的操作行为,共享了一个事务。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。