Spring的事务控制
编程式事务控制相关对象
PlatformTransactionManager
就是一个接口
TransactionDefinition
事务隔离级别
事务传播行为
TransactionStatus
基于XML的声明式事务控制
什么是声明式事务控制
转账业务环境搭建
新建项目、导入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.32</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
编写Dao层
package com.taotao.dao;
import org.springframework.jdbc.core.JdbcTemplate;
@SuppressWarnings({"all"})
public interface AccountDao {
void setJdbcTemplate(JdbcTemplate jdbcTemplate);
void out(String outMan,double money);
void in(String inMan,double money);
}
package com.taotao.dao.impl;
import com.taotao.dao.AccountDao;
import org.springframework.jdbc.core.JdbcTemplate;
@SuppressWarnings({"all"})
public class AccountDaoImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
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);
}
}
实体类
package com.taotao.domain;
@SuppressWarnings({"all"})
public class Account {
private String name;
private double money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
@Override
public String toString() {
return "Account{" +
"name='" + name + '\'' +
", money=" + money +
'}';
}
}
service层
package com.taotao.service;
import com.taotao.dao.AccountDao;
@SuppressWarnings({"all"})
public interface AccountService {
void setAccountDao(AccountDao accountDao);
void transfer(String outMan,String inMan,double money);
}
package com.taotao.service.impl;
import com.taotao.dao.AccountDao;
import com.taotao.service.AccountService;
@SuppressWarnings({"all"})
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
accountDao.in(inMan,money);
}
}
操作类
package com.taotao.controller;
import com.taotao.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@SuppressWarnings({"all"})
public class AccountController {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService accountService = app.getBean(AccountService.class);
accountService.transfer("ano","lucy",500);
}
}
Spring.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"
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">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="accountDao" class="com.taotao.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.taotao.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"/>
</bean>
</beans>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/Test
jdbc.username=root
jdbc.password=12345
测试转账成功
声明式事务控制的表现
当数据异常时,终止提交事务
编辑spring.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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="accountDao" class="com.taotao.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.taotao.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:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.taotao.service.impl.*.*(..))"></aop:advisor>
</aop:config>
</beans>
在业务成加个异常切入点
当异常时,不提交数据
package com.taotao.service.impl;
import com.taotao.dao.AccountDao;
import com.taotao.service.AccountService;
@SuppressWarnings({"all"})
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
int i = 1 / 0;
accountDao.in(inMan,money);
}
}
成功测试
运行
不会滚事务的情况
注销语句
测试运行
钱少了500
切点方法的事务参数的配置
基于注解的声明式事务控制
复制项目
注解修改dao层
package com.taotao.dao.impl;
import com.taotao.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@SuppressWarnings({"all"})
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private JdbcTemplate jdbcTemplate;
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);
}
}
注解修改service层
package com.taotao.service.impl;
import com.taotao.dao.AccountDao;
import com.taotao.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@SuppressWarnings({"all"})
@Service("accountService")
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Autowired
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
int i = 1 / 0;
accountDao.in(inMan,money);
}
}
Spring.xml组件扫描
注意context命名空间配置
<context:component-scan base-package="com.taotao"/>
我们删除一些配置,使用注解完成
下面的都删除
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.taotao.service.impl.*.*(..))"></aop:advisor>
</aop:config>
我们service层加注解(方式1)
package com.taotao.service.impl;
import com.taotao.dao.AccountDao;
import com.taotao.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@SuppressWarnings({"all"})
@Service("accountService")
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Autowired
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Transactional(isolation = Isolation.READ_COMMITTED,propagation = Propagation.REQUIRED)
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
accountDao.in(inMan,money);
}
@Transactional(isolation = Isolation.DEFAULT)
public void xxx(){
}
}
我们service层加注解(方式2)
package com.taotao.service.impl;
import com.taotao.dao.AccountDao;
import com.taotao.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@SuppressWarnings({"all"})
@Service("accountService")
@Transactional(isolation = Isolation.REPEATABLE_READ)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Autowired
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
accountDao.in(inMan,money);
}
public void xxx(){
}
}
我们service层加注解(方式3)
就近原则
package com.taotao.service.impl;
import com.taotao.dao.AccountDao;
import com.taotao.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@SuppressWarnings({"all"})
@Service("accountService")
@Transactional(isolation = Isolation.REPEATABLE_READ)
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;
@Autowired
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED)
public void transfer(String outMan, String inMan, double money) {
accountDao.out(outMan,money);
accountDao.in(inMan,money);
}
public void xxx(){
}
}
Spring配置注解驱动
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="com.taotao"/>
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.driver}"/>
<property name="jdbcUrl" value="${jdbc.url}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="accountDao" class="com.taotao.dao.impl.AccountDaoImpl">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="accountService" class="com.taotao.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:annotation-driven transaction-manager="transactionManager"/>
</beans>
成功测试
转账成功
转账失败
事务中断,不提交
accountDao.out(outMan,money);
int i = 1 / 0;
accountDao.in(inMan,money);
|