Spring事务有几种实现方法?针对这个问题,今天小编总结这篇有关云服务器的文章,可供感兴趣的小伙伴们参考借鉴,希望对大家有所帮助。
Spring提供了一个事务管理接口,PlatformTransactionManager它里面提供了常用的事务操作的方法:
public interface PlatformTransactionManager {
//获取事务状态信息
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
//提交事务
void commit(TransactionStatus var1) throws TransactionException;
//回滚事务
void rollback(TransactionStatus var1) throws TransactionException;
}
PlatformTransactionManager接口里面定义了提交,回滚等对事物操作的基本方法。
这里出现了两个接口:
一:TransactionDefinition
它定义了事物的基本属性
public interface TransactionDefinition {
//返回事物的传播行为
int getPropagationBehavior();
//返回事务的隔离级别,事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。
int getIsolationLevel();
//返回事务必须在多少秒内完成
int getTimeout();
//事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。
boolean isReadOnly();
}
事物的传播行为表示一个方法被另一个方法调用时事物如何传播。
我有一篇文章详细的讲解了事物传播行为:
事物的隔离级别 我在这篇文章里有详述:
getTimeout()返回事物的超时时间,事物的执行会不同程度的锁定表,如果时间过长,其它事物对表的操作就会受到影响,执行超时以后事物就会回滚。
isReadOnly()返回事物是否只读,如果事物只是去读取数据库我们可以把它设置为只读,数据库就可以进行相应的优化,提高执行效率。
二:TransactionStatus
此接口提供了事物运行的具体状态
public interface TransactionStatus extends SavepointManager, Flushable { boolean isNewTransaction();//是否是新的事物 boolean hasSavepoint();//是否有恢复点 void setRollbackOnly();//设置为只回滚 boolean isRollbackOnly();//是否为只回滚 boolean isCompleted();//是否已完成 }
在回滚或提交操作的时候需要这些事物的状态作为参数。
PlatformTransactionManager只是一个事物管理的接口,我们真正要用的是该接口的实现类,如果你是用Jdbc或mybatis操作数据库需要使用事务管理类:
org.springframework.jdbc.datasource.DataSourceTransactionManager
如果用的是Hibernate需要使用事物管理类:
org.springframework.orm.hibernate5.HibernateTransactionManager
在spring中实现事物通常有两种方式:
一:基于 XML 的声明式事务控制(配置方式):
通过转账的例子来说明:
数据库:
第一步:导入依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies>
spring-tx是事物管理的依赖,因为spring的事物管理底层使用的是aop所以需要把aop的依赖aspectjweaver也导入进来。
第二步:创建 spring 的配置文件并导入约束
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" 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-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
</beans>
第三步:创建Account实体类
第四步:编写 Dao 接口和实现类
public interface IAccountDao {
//根据名称查询账户信息
Account findAccountByName(String name);
//更新账户信息
void updateAccount(Account account);
}
public class AccountDaoImpl implements IAccountDao { @Autowired private JdbcTemplate jt; public Account findAccountByName(String name) { List<Account> lst = jt.query("select * from account where name like ?",new BeanPropertyRowMapper<Account>(Account.class),name); return lst.isEmpty()?null:lst.get(0); } public void updateAccount(Account account) { jt.update("update account set money = ? where id = ? ",account.getMoney(),account.getId()); } }
第五步:编写业务层接口和实现类
public interface IAccountService { * 转账 * @param sourceName 转出账户名称 * @param targeName 转入账户名称 * @param money 转账金额 */ void transfer(String sourceName,String targeName,Float money);//增删改
}
/** * 账户的业务层实现类 */ public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; public void transfer(String sourceName, String targeName, Float money) { //1.根据名称查询两个账户 Account source = accountDao.findAccountByName(sourceName); Account target = accountDao.findAccountByName(targeName); //2.修改两个账户的金额 source.setMoney(source.getMoney()-money);//转出账户减钱 target.setMoney(target.getMoney()+money);//转入账户加钱 //3.更新两个账户 accountDao.updateAccount(source); int i=1/0; accountDao.updateAccount(target); } }
第六步:在配置文件中配置业务层和持久层
<context:component-scan base-package="cn.xh"></context:component-scan> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"></property> </bean> <!-- 配置 service --> <bean id="accountService" class="cn.xh.service.AccountServiceImpl"> </bean> <!-- 配置 dao --> <bean id="accountDao" class="cn.xh.dao.AccountDaoImpl"> </bean> <!-- 配置数据源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql:///spring_demo01"></property> <property name="username" value="root"></property> <property name="password" value="123456"></property>
</bean>
第七步:配置事务
Spring事务是基于aop的关于aop我在这篇文章里有详细的讲解:
配置步骤:
1: 配置事务管理器:
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入 DataSource -->
<property name="dataSource" ref="dataSource"></property>
</bean>
2:配置事务的通知引用事务管理器:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
</tx:advice>
3:配置事务的属性:
<!-- 配置事务的通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <!-- 配置事务的属性 isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。 propagation:用于指定事务的传播行为。
read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。 timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。 rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。 no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。 --> <tx:attributes> <tx:method name="*" propagation="REQUIRED" read-only="false"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method> </tx:attributes> </tx:advice>
4:配置 AOP 切入点表达式:
<!-- 配置aop--> <aop:config> <!-- 配置切入点表达式--> <aop:pointcut id="pt1" expression="execution(* cn.xh.service.*.*(..))"></aop:pointcut> <!--建立切入点表达式和事务通知的对应关系 --> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor> </aop:config>
我们看看这个配置:
<!-- 配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* cn.xh.service.*.*(..))"></aop:pointcut>
说明对cn.xh.service下的所有类的所有方法加上事务。
再来看看这个配置:
<!-- 配置事务的通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes> <tx:method name="*" propagation="REQUIRED" read-only="false"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method> </tx:attributes> </tx:advice>
这个配置说明以find开头的方法事务的传播方式为SUPPORTS,为只读,其它的方法事务传播方式为REQUIRED,不是只读。
好啦,现在可以测试啦:
@RunWith(SpringJUnit4Cla***unner.class) @ContextConfiguration("classpath:applicationContext.xml") public class serviceTest { @Autowired private IAccountService serviceImpl; @Test public void testDo(){ serviceImpl.transfer("%张%","%李%",1000f); } }
从张三账户往李四账户转1000,因为有除零错误,事务回滚,张三账户还是2000,李四账户还是3000.
再来看看事务实现的第二种方式
二:基于注解的配置方式
我们重点看一下事务的注解配置,其它同上。
配置步骤:
第一步:配置事务管理器并注入数据源
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
第二步:在业务层使用@Transactional 注解:
@Transactional(readOnly=true,propagation=Propagation.SUPPORTS)
public class AccountServiceImpl implements IAccountService {
@Autowired
private IAccountDao accountDao;
@Override
public Account findAccountById(Integer id) {
return accountDao.findAccountById(id);
}
@Override
@Transactional(readOnly=false,propagation=Propagation.REQUIRED)
public void transfer(String sourceName, String targeName, Float money) {
//1.根据名称查询两个账户
Account source = accountDao.findAccountByName(sourceName);
Account target = accountDao.findAccountByName(targeName);
//2.修改两个账户的金额
source.setMoney(source.getMoney()-money);//转出账户减钱
target.setMoney(target.getMoney()+money);//转入账户加钱
//3.更新两个账户
accountDao.updateAccount(source);
//int i=1/0;
accountDao.updateAccount(target);
}
}
该注解的属性和 xml 中的属性含义一致,该注解可以出现在接口上,类上和方法上。
出现接口上,表示该接口的所有实现类都有事务支持。
出现在类上,表示类中所有方法有事务支持
出现在方法上,表示方法有事务支持。
以上三个位置的优先级:方法>类>接口
第三步:在配置文件中开启 spring 对注解事务的支持:
<tx:annotation-driven transaction-manager="transactionManager"/>
关于Spring事务实现方法就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果喜欢这篇文章,不如把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。