什么是声明式事务控制
- 事务管理和业务逻辑是解耦的,不属于业务逻辑的一部分,Spring声明式事务控制底层就是AOP
- 业务方法是切点,事务管理是增强(通知),通过配置文件进行关系织入
1.简单转账例子:
xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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/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
">
<!--加载jdbc.properties配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"></property>
<property name="jdbcUrl" value="${jdbc.url}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="accountDao" class="com.yq.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!--目标对象,内部的方法就是切点-->
<bean id="accountService" class="com.yq.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
<!--配置一个平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--通知,事务增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!--配置事务的aop织入-->
<aop:config>
<aop:pointcut id="myPointcut" expression="execution(* com.yq.service.impl.*.*(..))"></aop:pointcut>
<!--正常是使用aop:aspect,但是事务管理有封装自己的一个增强-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"></aop:advisor>
</aop:config>
</beans>
- 不同的jdbc底层技术要配置不同的平台事务管理器,比如mybatis和hibernate都不同
AccountController:
package com.yq.controller;
import com.yq.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AccountController {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = (AccountService) applicationContext.getBean("accountService");
accountService.tansfer("lisi","zhangshan",500);
}
}
AccountServiceImpl:
package com.yq.service.impl;
import com.yq.dao.AccountDao;
import com.yq.service.AccountService;
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
//set方法,在xml中依赖注入
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void tansfer(String outMan, String inMan, double money) {
accountDao.out(outMan, money);
int i=1/0;
accountDao.in(inMan, money);
}
}
AccountDaoImpl:
package com.yq.dao.impl;
import com.yq.dao.AccountDao;
import org.springframework.jdbc.core.JdbcTemplate;
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
//set方法,在xml中依赖注入
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public void out(String outMan, double money) {
jdbcTemplate.update("UPDATE account set money=money-? WHERE name=?", money, outMan);
}
public void in(String inMan, double money) {
jdbcTemplate.update("UPDATE account SET money=money+? where name=?", money, inMan);
}
}
2.tx:method详解
<!--通知,事务增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--配置事务的属性信息-->
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED" isolation="REPEATABLE_READ" read-only="false"></tx:method>
<tx:method name="save" propagation="REQUIRED" isolation="REPEATABLE_READ" read-only="false"></tx:method>
<tx:method name="findAll" propagation="REQUIRED" isolation="REPEATABLE_READ" read-only="true"></tx:method>
<!--查询方法,可以设置为只读-->
<tx:method name="find*" propagation="REQUIRED" isolation="REPEATABLE_READ" read-only="true"></tx:method>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
tx:method代表切点方法的事务参数的配置:
- name:切点的方法名称
- isolation:事务的隔离级别
- propogation:事务的传播行为
- timeout:超时时间
- read-only:是否只读