ISOLATION_DEFAULT:默认级别.
Mysql repeatable_read oracle read_commited
ISOLATION_READ_UNCOMMITTED
ISOLATION_READ_COMMITTED
ISOLATION_REPEATABLE_READ
ISOLATION_SERIALIZABLE
事务的传播行为:(不是JDBC事务管理,用来解决实际开发的问题.)传播行为
解决业务层之间的调用的事务的关系.
1. PROPAGATION_REQUIRED :支持当前事务,如果不存在 就新建一个,A,B 如果A有事务,B使用A的事务,如果A没有事务,B就开启一个新的事务.(A,B是在一个事务中。)
2. PROPAGATION_SUPPORTS :支持当前事务,如果不存在,就不使用事务,A,B 如果A有事务,B使用A的事务,如果A没有事务,B就不使用事务.
PROPAGATION_MANDATORY :支持当前事务,如果不存在,抛出异常,A,B 如果A有事务,B使用A的事务,如果A没有事务,抛出异常.
3. PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务,A,B 如果A有事务,B将A的事务挂起,重新创建一个新的事务.(A,B不在一个事务中.事务互不影响.)
4. PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务,A,B 非事务的方式运行,A有事务,就会挂起当前的事务.
5. PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
6. PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行,基于SavePoint技术,A,B A有事务,A执行之后,将A事务执行之后的内容保存到SavePoint.B事务有异常的话,用户需要自己设置事务提交还是回滚.
常用:(重点)
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_NESTED
是否有保存点
是否一个新的事务
事务是否已经提交
关系:PlatformTransactionManager通过TransactionDefinition设置事务相关信息管理事务,管理事务过程中,产生一些事务状态:状态由TransactionStatus记录.
1.IOC配置dao
如果dao层使用了JdbcDaoSupport,那么可以直接注入dataSource或者jdbcTemplate
2.IOC配置service
dao(service需要调用dao层)
transactionTemplate(service需要使用transactionTemplate来管理实务)
3.IOC配置TransactionManager,根据不同的技术使用不用的类的实现
dataSource
4.IOC配置TransactionTemplate
transactionManager
transactionTemplate.execute(new TransactionCallBackWithoutResult)
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
/** * 模拟账户1向账户2汇款 * @param money */
public void out(double money) {
String sql = "update account set money=money-100 where id =1 ";
this.getJdbcTemplate().update(sql);
int a = 1/0;
}
/** * 模拟账户2接收账户1的汇款 * @param money */
public void in(double money) {
String sql = "update account set money=money+100 where id =2 ";
this.getJdbcTemplate().update(sql);
}
}
public class AccountService {
private AccountDao accountDao;
private TransactionTemplate transactionTemplate;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
public void transfer(final double money){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
accountDao.out(money);
accountDao.in(money);
}
});
}
}
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="yzgylq"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
<bean id="accountDao" class="com.njust.learning.spring.transaction.AccountDaoImpl">
<property name="dataSource" ref="datasource"></property>
</bean>
<bean id="accountService" class="com.njust.learning.spring.transaction.AccountService">
<property name="accountDao" ref="accountDao"></property>
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
<!--事务管理的配置-->
<!--因为这里使用的是jdbc的方式进行数据层的操作,所以需要使用DataSourceTransactionManager-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"></property>
</bean>
<!--使用自己编码的方式进行事务的处理,这里使用的是事务的处理模板-->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"></property>
</bean>
需要在自己的代码里面添加transactionTemplate.execute,对自己的代码造成了入侵
解决:可以使用springaop的动态代理,生成源service的代理对象,在代理对象中进行事务的管理
使用TransactionProxyFactoryBean对需要事物管理的方法的动态代理
applicationContext.xml
1. dataSource
2. dao
dataSource或者jdbcTemplate
3. service
dao
4. transactionManager
5. TransactionProxyFactoryBean
注意事项:
target即目标对象必须要有,可能eclipse不能提示这个属性
prop的key就是方法名,表示这个方法需要进行事物管理
prop内容的格式:
PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
顺序:传播行为、隔离级别、事务是否只读、发生哪些异常可以回滚事务(所有的
异常都回滚)、发生了哪些异常不回滚.
例如:
+java.lang.ArithmeticException,就表示发生了这个异常还是可以提交事物
public class AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(final double money){
accountDao.out(money);
accountDao.in(money);
}
}
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="yzgylq"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
<bean id="accountDao" class="com.njust.learning.spring.transaction.AccountDaoImpl">
<property name="dataSource" ref="datasource"></property>
</bean>
<bean id="accountService" class="com.njust.learning.spring.transaction.AccountService">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--基于动态代理的事务管理-->
<bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="transactionManager"></property>
<property name="target" ref="accountService"></property>
<!--这个就相当于通知Advice-->
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"></property>
</bean>
原始的方式实现事物的管理的缺点:对于每一个service都需要手动配置TransactionProxyFactoryBean很麻烦
tx:advice(用于配置增强,主要用于配置对于不同的方法的事物属性进行配置)
aop:config(用于配置切面,切面就是切点和增强的结合,由于是一个切点和一个切面,所以
使用advisor)
即上面的dao的代码,一模一样
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="username" value="root"></property>
<property name="password" value="yzgylq"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>
<bean id="accountDao" class="com.njust.learning.spring.transaction.AccountDaoImpl">
<property name="dataSource" ref="datasource"></property>
</bean>
<bean id="accountService" class="com.njust.learning.spring.transaction.AccountService">
<property name="accountDao" ref="accountDao"></property>
</bean>
<tx:advice id="transaction_advice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="REPEATABLE_READ"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="mypointcut" expression="execution(* com.njust.learning.spring.transaction.AccountService.*(..))"/>
<aop:advisor advice-ref="transaction_advice" pointcut-ref="mypointcut"></aop:advisor>
</aop:config>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="datasource"/>
</bean>