一.Spring封装了事务管理操作
1.事务管理的操作:1.打开事务
2.回滚事务(操作出现异常,把数据返回)
3.提交事务(进行数据更新)
2.Spring中的操作对象
(1)不同平台,操作事务的代码各不相同.spring给我们提供了一个接口 PlatformTransactionManager
我们使用的都是接口的实现类,整合jdbc使用的DatasourceTransactionManager,整合hibernate使用的则HibernateTransitionmanager
注意的是:在spring中的事务管理,核心对象就是TransactionManager对象
(2)spring管理事务的属性介绍
事务隔离级别: 1读未提交
2 读已提交
4 可重复读
8 串行化
是否只读 true 只读
False 可操作
事务的传播行为:
二:Sprig管理事务方式
事务控制分为两种:编程式事务控制
声明式事务控制
所谓编程式事务控制就是自己写方法来实现
编程式事务实现(基本不用,但是也要了解一下,):
1.将核心事务管理器配置到spring容器
2.配置TransactionTemplate模板
3.将事务模板注入到Service
4.在Service中调用模板
编码式事务控制繁琐且容易出错,所以一般使用声明式的事务管理
声明式事务管理是指在xml配置设置,一次设置,全局生效
声明式事务管理步骤:
导包
加约束
配置通知:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd ">
<!-- 0.spring读取配置文件,配置文件写的是sqL配置,这样就可以直接改动文件,更方便 -->
<context:property-placeholder location="classpath:db.properties"/>
<!--1.配置数据连接池 -->
<bean name ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 引入db.properties的内容 -->
<property name ="driverClass" value="${mysql.driverClass}"></property>
<property name ="jdbcUrl" value="${mysql.url}"></property>
<property name ="user" value="${mysql.username}"></property>
<property name ="password" value="${mysql.password}"></property>
</bean>
<!-- 配置AccountDaoImpl层 -->
<bean name="accountDao" class="cn.oracle.userdao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- spring编码式的事务管理 -->
<!-- 配置事务管理器 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务 -->
<!-- beans: 最基本
context:读取properties配置
aop:配置aop
tx:配置事务通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 以方法为单位,指定方法应用事务什么属性,
isolation:隔离级别
read-only:只读属性
propagation:传播行为
-->
<!-- 增加删除等配置基本信息 -->
<tx:method name="transform" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="add*" isolation="DEFAULT" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
<tx:method name="get*" isolation="DEFAULT" propagation="REQUIRED" read-only="true"/>
<tx:method name="save*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="persist*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="delete*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="remove*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
<tx:method name="update*" isolation="DEFAULT" read-only="false" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<!-- 切入点表达式,不用切入点不知道用哪个方法,第一个*代表的是返回值 -->
<aop:pointcut expression="execution(* cn.oracle.services.*.*(..))"
id="myPoint"/>
<!-- 织入事务管理和切入方法 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPoint"/>
</aop:config>
<!-- 配置业务层 把dao层注入-->
<bean name="accountService" class="cn.oracle.services.AccountServicesImpl">
<property name="ad" ref="accountDao"></property>
</bean>
</beans>
实现业务
package cn.oracle.userdao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao{
//转账业务逻辑
@Override
public void addMoney(Integer id, double money) {
String update ="update t_user set money=money+? where id=?";
System.out.println(super.getJdbcTemplate());
super.getJdbcTemplate().update(update,money,id);
//StringBuffer a=new StringBuffer();
//a.append("sa");
}
//减
@Override
public void minusMoney(Integer id, double money) {
String update ="update t_user set money=money-? where id=?";
super.getJdbcTemplate().update(update,money,id);
}
services层
package cn.oracle.services;
import cn.oracle.userdao.AccountDao;
/*基于xml方式的aop事务的声明式管理*/
public class AccountServicesImpl implements AccountService {
AccountDao ad;
//转账,先减后加(转账人,转账目标人,转账金额)
public void setAd(AccountDao ad) {
this.ad = ad;
}
@Override
public void transform(final Integer from, final Integer to,final double money) {
//调用减法和加法同时
ad.minusMoney(from,money);
int i= 1 / 0;
ad.addMoney(to,money);
}
}
测试
import cn.oracle.advice.AccountServicesImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AccountServicesImplTest {
@Resource(name="accountService")
private AccountServicesImpl as;
@Test
public void testTransform() {
as.transform(1, 2,100);
}
}
结果
如果失败的话会自动回滚,不发生改变
二:补充说明:基于注解的实现事务控制,这种方式比较简单,但是不方便大量的services层的时候使用
基于注解的xml
<bean name ="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<!-- 引入db.properties的内容 -->
<property name ="driverClass" value="${mysql.driverClass}"></property>
<property name ="jdbcUrl" value="${mysql.url}"></property>
<property name ="user" value="${mysql.username}"></property>
<property name ="password" value="${mysql.password}"></property>
</bean>
<!-- 配置AccountDaoImpl层 -->
<bean name="accountDao" class="cn.oracle.userdao.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- spring编码式的事务管理 -->
<!-- 配置事务管理器 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启使用注解管理aop业务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 配置业务层 把dao层注入-->
<bean name="accountService" class="cn.oracle.advice.AccountServicesImpl">
<property name="ad" ref="accountDao"></property>
</bean>
</beans>
services层
public class AccountServicesImpl {
@Autowired
private AccountDao ad;
//转账,先减后加(转账人,转账目标人,转账金额)
public void setAd(AccountDao ad) {
this.ad = ad;
}
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)
public void transform(final Integer from, final Integer to,final double money) {
//调用减法和加法同时
ad.minusMoney(from,money);
//int i= 1 / 0;
ad.addMoney(to,money);
}
dao层不需要修改,测试结果
补充一些常见错误点:
1.使用事务的话mysql数据库需要更改表类型为inndB,不然不支持,
2.dataSource属性未找到,注意看你的xml配置中是否链接上数据链接池。
暂时没有出现其他错误,出现了再改。