那就迫切的需要事务来进行管理了,给大家演示在Spring中,要给咱们Service加事务,怎么加,
现在是不是还没有加事务的,现在没有加事务,怎么加,我们要演示三种方式,三种方式 演示完,
Spring管理事务方式,这三种方式分别是,编码式,其中编码式我要把它标成是,绿色,这个编码式你可以
理解为观光代码,以后咱们不会用的,然后就是xml的配置式,括号aop,还有 一个是注解配置,也是属于AOP的,
紫色,明白是啥意思不,这个绿色话看着好玩,紫色是你们未来,以后都是这种紫色的这种方式,就这样了,这是
你们的final版,这是final版的,先来看轻松地,没用的编码式,顾名思义,你得在代码里编写事务,那这样缺点
在没有写你就知道,我有10个业务方法的话,我就在10个里面用事务管理的编码,先来说一下步骤,这个步骤的话
这样,他们共有的我提取到外面,准备工作第一步,别忘了刚才咱们说的,事务管理器,接口不行,你得说实现类,
咱们说这个是事务的核心,不管用三种方式的哪一种,都得把Manager给加上,所以这里的话,第一个,将核心事务管理器,
配置到Spring容器,第一步写完咱们就做一下,这里写一个bean,然后呢,class属性,DataSourceTransactionManager,
咱们就把DataSourceTransactionManager用进来,然后前面给他来一个名字,name等于transactionManager,这个
transactionManager是Spring操作事务的核心,那你说他有没有依赖呢,他依赖是谁,能想到吗,事务的操作,依赖谁,
还要问吗,你直接就能够想到的,这个哥们显然是依赖谁,是不是dataSource,为啥依赖dataSource,那咱们刚才说了
半天,操作事务,你怎么打开,connection.setAutoCommit,false,提交你事务咋提交,connection.commit,那这个哥们
负责调这些方法,手头得有connection,是不是这个意思,那connection从哪里来,是不是连接池来的,知道啥意思,
依赖关系就是这样,知道啥意思不,你说你要去花钱,那我问你依赖啥,钱,是不是依赖钱,连接池,操作咱们事务的操作,
那你操作事务,是不是得有连接事务的操作,没连接你封装什么,知道啥意思,所以他依赖于dataSource,这理解啥意思不,
所以这东西,事务的核心管理器,然后这里面封装了所有事务操作,依赖于咱们的连接池,有了核心事务管理器之后,
那咱们编码式操作事务,需要使用一个事务模板对象,这个模板对象是直接配上的,事务模板对象,name,class,
TransactionTemplate,这个咱们复制,这个transactionTemplate,这个是事务模块,这jdbc模板道理一样,他把事务
操作给你封装进去了,那就是你要想控制事务的话,一会在咱们的service里面,需要调事务的这个方法,你可以把事务
加进去,那事务模板也有依赖关系,它依赖于谁,这里只是调方法,所以他是需要transactionManager的,ref等于
transactionManager,这样的话事务模板有了,那编码式的事务,把tt属性注入进来,ref叫做transactionTemplate,
这个注入进来,然后接下来在service当中,写代码就是tt点,调用它的execute方法,然后这个execute方法,需要你
传入一个接口,TransactionCallback,那这个TransactionCallback我看一下,他的子类叫做
TransactionCallbackWithoutResult,这个TransactionTemplate,它是把事务打开和关闭的调用,
给你封装好了,然后你只需要告诉他,你打算把什么操作纳入到事务管理当中就可以了,模板他已经封装好了,
什么时候打开事务,什么时候关闭事务,什么时候回滚事务,
你只需要告诉模板,你需要干嘛就可以了,那你怎么告诉模板你需要干啥呢,就是实现这个接口,然后这里面有
这个方法,当然这里匿名内部类访问外部的需要加final,我写一个伪代码,execute方法大概就是长这样的,
首先它第一步打开,打开花事务,然后第二步调用这个方法,执行你传进去的代码,接下来第三步,提交事务,
然后你这个方法有异常的话,调你这个方法的时候会加一个try catch,如果出异常的话,它会把你这个事务进行回滚,
知道啥意思不,所以说白了,打开事务和提交事务代码已经封装好了,这样的话你代码就在事务环境内了,
看明白啥意思不,啥叫模板,就是这些代码是固定的,那这样的话事务就已经加完了,就这么简单,是不是可以执行
一下了,咱们把数据库复位,现在转100块钱,现在没有异常,先看没有异常执行成不成功,是不是没有问题,是不是
900和1100,接下来咱们造一个异常,看模板好不好使,造异常是不是把1除以0打开,这回再到Demo这儿,再运行这个
方法,这个方法肯定报错,是不是by zero,除0,那主要是看事务的问题,如果还是900和1100就对了,是这个效果,
这样就是通过编码式来控制事务,说了这是一个观光代码,因为这样的话你想,如果方法有10个,你这个execute要
调10次,虽然你不用手写打开关闭事务的代码了,但是跟以前一样,每一个业务方法里面都调这个方法,是不是麻烦,
所以这是咱们的观光代码
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd ">
<!-- 指定spring读取db.properties配置 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 事务核心管理器,封装了所有事务操作. 依赖于连接池 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- 事务模板对象 -->
<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
<property name="transactionManager" ref="transactionManager" ></property>
</bean>
<!-- 1.连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" >
<property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property>
<property name="driverClass" value="${jdbc.driverClass}" ></property>
<property name="user" value="${jdbc.user}" ></property>
<property name="password" value="${jdbc.password}" ></property>
</bean>
<!-- 2.Dao-->
<bean name="accountDao" class="com.learn.dao.AccountDaoImpl" >
<property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- 3.Service-->
<bean name="accountService" class="com.learn.service.AccountServiceImpl" >
<property name="ad" ref="accountDao" ></property>
<property name="tt" ref="transactionTemplate" ></property>
</bean>
</beans>
package com.learn.dao;
public interface AccountDao {
//加钱
void increaseMoney(Integer id,Double money);
//减钱
void decreaseMoney(Integer id,Double money);
}
package com.learn.dao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void increaseMoney(Integer id, Double money) {
getJdbcTemplate().update("update t_account set money = money+? where id = ? ", money,id);
}
@Override
public void decreaseMoney(Integer id, Double money) {
getJdbcTemplate().update("update t_account set money = money-? where id = ? ", money,id);
}
}
package com.learn.service;
public interface AccountService {
//转账方法
void transfer(Integer from,Integer to,Double money);
}
package com.learn.service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import com.learn.dao.AccountDao;
@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)
public class AccountServiceImpl implements AccountService {
private AccountDao ad ;
private TransactionTemplate tt;
@Override
public void transfer(final Integer from,final Integer to,final Double money) {
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus arg0) {
//减钱
ad.decreaseMoney(from, money);
int i = 1/0;
//加钱
ad.increaseMoney(to, money);
}
});
// 1.打开事务
// 2.调用doInTransactionWithoutResult方法
// 3.提交事务
}
public void setAd(AccountDao ad) {
this.ad = ad;
}
public void setTt(TransactionTemplate tt) {
this.tt = tt;
}
}
package com.learn.tx;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.learn.service.AccountService;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {
@Resource(name="accountService")
private AccountService as;
@Test
public void fun1(){
as.transfer(1, 2, 100d);
}
}