Spring事务
Spring事务的本质其实就是数据库对事务的支持,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交。
有了Spring,我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作,使得我们把更多的精力放在处理业务上。事实上Spring并不直接管理事务,而是提供了多种事务管理器。他们将事务管理的职责委托给Hibernate或者JTA等持久化机制所提供的相关平台框架的事务来实现。
一、编程式事务
编程式事务管理我们可以通过PlatformTransactionManager实现来进行事务管理,同样的Spring也为我们提供了模板类TransactionTemplate进行事务管理,下面主要介绍模板类,我们需要在配置文件中配置。
1.applicationContext.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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 开启注解-->
<context:component-scan base-package="com.it.spring.tx"></context:component-scan>
<!-- 引入工程中src下的db.properties文件-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- 设置连接数据库的值 spring管理c3p0数据库连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${url}"></property>
<property name="user" value="${user}"></property>
<property name="driverClass" value="${driverClass}"></property>
<property name="password" value="${password}"></property>
</bean>
<!-- 配置平台事物管理器-->
<bean id="dataSourceTransactionManager" 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="dataSourceTransactionManager"></property>
</bean>
</beans>
2.编写DAO接口
package com.it.spring.tx.dao;
/**
* 实现转账业务
*/
public interface
AccountDAO {
//出账
void outMoney(String from,Double money);
//入账
void inMoney(String in,Double money);
}
DAO实现类
package com.it.spring.tx.dao;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.sql.DataSource;
@Repository
//JdbcDaoSupport就是为了简化我们dao类有关JdbcTemplate的注入的相关工作量。
public class AccountDAOImpl extends JdbcDaoSupport implements AccountDAO {
@Resource
private DataSource dataSource;
//初始化dataSources
@PostConstruct
private void init(){
//调用JdbcDaoSupport的setDataSource方法 或者使用带参构造函数
setDataSource(dataSource);
}
@Override
public void outMoney(String from, Double money) {
System.out.println(getJdbcTemplate());
getJdbcTemplate().update("update account set money=money-? where id=?",money,from);
}
@Override
public void inMoney(String in, Double money) {
getJdbcTemplate().update("update account set money=money+? where id=?",money,in);
}
}
3.service接口
package com.it.spring.tx.service;
/**
* 实现转账业务
*/
public interface AccountService {
void transfer(String from,String to,Double money);
}
service实现类
package com.it.spring.tx.service;
import com.it.spring.tx.dao.AccountDAO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource;
@Service
public class AccountServiceImpl implements AccountService {
@Resource
AccountDAO accountDAO;
//而TransactionTemplate的编程式事务管理是使用模板方法设计模式对原始事务管理方式的封装
@Resource
private TransactionTemplate transactionTemplate;
// @Override
// public void transfer(String from, String to, Double money) {
// accountDAO.outMoney(from,money);
System.out.println(12/0);
// //添加事务进行解决 使用TransactionTemplate模块
// accountDAO.inMoney(to,money);
// }
@Override
public void transfer(String from, String to, Double money) {
//所以当我们借助TransactionTemplate.execute( ... )执行事务管理的时候,传入的参数有两种选择:
//1、TransactionCallback
//2、TransactionCallbackWithoutResult
//两种区别从命名看就相当明显了,一个是有返回值,一个是无返回值。这个的选择就取决于你是读
// //设置事务传播属性
// transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// // 设置事务的隔离级别,设置为读已提交(默认是ISOLATION_DEFAULT:使用的是底层数据库的默认的隔离级别)
// transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
// // 设置是否只读,默认是false
// transactionTemplate.setReadOnly(true);
// // 默认使用的是数据库底层的默认的事务的超时时间
// transactionTemplate.setTimeout(30000);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
try {
accountDAO.outMoney(from, money);
System.out.println(12 / 0);
accountDAO.inMoney(to, money);
} catch (Exception e){
//回滚状态
transactionStatus.setRollbackOnly();
}
}
});
}
}
4.测试类
package com.it.spring.tx.test;
import com.it.spring.tx.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class SpringTxTest1 {
@Resource
AccountService accountService;
@Test
public void Test1(){
accountService.transfer("18","17",1000.0);
}
}
二、声明式事务
声明式事务管理有两种常用的方式,一种是基于tx和aop命名空间的xml配置文件,一种是基于@Transactional注解,随着Spring和Java的版本越来越高,大家越趋向于使用注解的方式,下面我们两个都说。
1.基于tx和aop命名空间的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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.it.spring.tx2.*"></context:component-scan>
<!-- 引入工程中src下的db.properties文件2-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- spring管理c3p0数据库连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${url}"></property>
<property name="password" value="${password}"></property>
<property name="user" value="${user}"></property>
</bean>
<!--配置平台事物管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置增强(就是自定义的的切面) -->
<!-- 配置事物增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- propagation事务传播行为 isolation隔离机制-->
<tx:attributes>
<!-- <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT"></tx:method>-->
<!-- <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT"></tx:method>-->
<!-- <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT"></tx:method>-->
<!-- <tx:method name="query*" read-only="true"></tx:method>-->
<tx:method name="*" propagation="REQUIRED"></tx:method>
</tx:attributes>
</tx:advice>
<!-- 配置AOP-->
<aop:config>
<!-- 设置切点-->
<aop:pointcut id="pointcut1" expression="execution(* com.com.it.spring.tx2.service.AccountServiceImpl.transfer(..))"></aop:pointcut>
<!-- aop:aspect 多个通知和多个切入点的组合-->
<!--aop:advisor 单个通知和单个切入点的组合-->
<aop:advisor pointcut-ref="pointcut1" advice-ref="txAdvice"></aop:advisor>
</aop:config>
</beans>
service实现类发生变化
package com.it.spring.tx2.service;
import com.it.spring.tx2.dao.AccountDAO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
@Resource
AccountDAO accountDAO;
@Override
public void transfer(String from, String to, Double money) {
accountDAO.outMoney(from,money);
// System.out.println(12/0);
accountDAO.inMoney(to,money);
}
}
测试类
package com.it.spring.tx2.test;
import com.it.spring.tx2.service.AccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class SpringTxTest2 {
@Resource
AccountService accountService;
@Test
public void fun1(){
accountService.transfer("11","10",1000.0);
}
}
2.基于@Transactional注解
这种方式最简单,也是最为常用的,只需要在配置文件中开启对注解事务管理的支持。
applicationContext3.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"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
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
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.it.spring.tx3.*"></context:component-scan>
<!-- 引入工程中src下的db.properties文件2-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- spring管理c3p0数据库连接池-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${driverClass}"></property>
<property name="jdbcUrl" value="${url}"></property>
<property name="password" value="${password}"></property>
<property name="user" value="${user}"></property>
</bean>
<!--配置平台事物管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启事物注解-->
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>
services实现类
package com.it.spring.tx3.service;
import com.it.spring.tx3.dao.AccountDAO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
//在业务层添加注解
@Service
@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)
public class AccountServiceImpl implements AccountService {
@Resource
AccountDAO accountDAO;
@Override
public void transfer(String from, String to, Double money) {
accountDAO.outMoney(from,money);
// System.out.println(12/0);
accountDAO.inMoney(to,money);
}
}
以上就是Spring管理事务的方式。感谢阅读。