最近想搞懂 Spring 怎么管理 transaction 的
先从程式可以开始跑开始,照书上设定了几个范例
目前在试 @Transactional,遇到无法 rollback 的问题,想请教
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:jee="http://www.springframework.org/schema/jee"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd ">
<context:property-placeholder location="classpath:idv/sql/jdbc.properties" />
<context:component-scan base-package="idv.spring.tx.dao,
idv.spring.tx.ch02_spring.e_annotation.service" />
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
</beans>
Service.java
@Service("spring_annotation_memberService")
public class MemberService {
@Autowired
@Qualifier("jdbc_tx_memberDao")
private MemberDao memberDao;
@Autowired
@Qualifier("jdbc_tx_memberDetailDao")
private MemberDetailDao memberDetailDao;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor =
Exception.class)
public void saveMember(Member member, MemberDetail memberDetail) {
try {
memberDao.addMember(member);
memberDetailDao.addMemberDetail(memberDetail);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Main.java
public class SpringTxMain {
public static void main(String[] args) {
ApplicationContext context =
new
ClassPathXmlApplicationContext("classpath:idv/spring/tx/ch02_spring/e_annotation/applicationContext.xml");
Member member = new Member();
member.setId("xxxxx");
member.setAccount("xxxxx");
member.setNickName("Xxxxx");
member.setStatus(Status.ACTIVE);
MemberDetail memberDetail = new MemberDetail();
memberDetail.setId("00001");
// memberDetail.setMemberId(member.getId());
memberDetail.setMemberId(member.getId() + "xxxxxxxxxxxxxxxx"); //
this would cause SQLException
memberDetail.setFirstName("YYYY");
memberDetail.setLastName("ZZZZ");
memberDetail.setIdNum("asdfghjkl");
MemberService memberService =
context.getBean("spring_annotation_memberService", MemberService.class);
memberService.saveMember(member, memberDetail);
((AbstractApplicationContext) context).close();
}
}
Dao 的部份应该不用附程式吧,就是直接用 jdbcTemplate 而已
故意在 service 的 memberDetailDao.addMemberDetail(memberDetail); 出错
不过 memberDao.addMember(member); 还是成功写入数据库了
测试的 DB 是 H2 和 MySQL(community-5.7.14.0)
一开始在练习由程控 transaction 时
有遇到 org.springframework.jdbc.datasource.DriverManagerDataSource
不能 disable auto-commit,所以一直失败
改为 org.apache.commons.dbcp.BasicDataSource
并设定 <property name="defaultAutoCommit" value="false" /> 就成功
不过接着试了
1. DataSourceTransactionManager
2. TransactionTemplate
都是只用 org.springframework.jdbc.datasource.DriverManagerDataSource
也有成功 rollback
再试
3. TransactionProxyFactoryBean
4. <tx:advice>
也是失败
其中 TransactionProxyFactoryBean 管理 transaction 设定比较复杂
所以先跳过不看
<tx:advice> 则应该是 <aop:pointcut> 的部份设定有错
这要回头去补 AOP 的设定方式,也是后续把 AOP 设定搞懂后再说
现在是试 @Transactional 的方式时也失败了,但是找不到错在哪
想请教先进问题在哪?
另外想请教想知道 Spring 怎么实做的
比如 AOP,大概只知道 proxy pattern
但想知道诸如 @Aspect,@Before,<aop:config>...
如何爬原始码会比较好