2e Spring-事务.txt
UP 返回
1.导入jar及基础说明
1.1 spring提供的事务管理:spring-tx-4.2.0.RELEASE.jar
该jar中有3个顶级接口:
PlatformTransactionManager:平台事务管理器,spring要管理并配置事务,必须配置事务管理器
TransactionDefinition :事务详情(事务定义,事务属性)spring用于确定事务具体详情,例如隔离级别、是否只读、超时时间等。进行事务配置时必须配置详情,spring将配置项封装到该对象实例
TransactionStatus :事务状态,spring用于记录当前事务运行状态。例如是否有保存点,事务是否完成。spring底层根据状态进行相应操作
1.2 PlatformTransactionManager 事务管理器
导入jar:
spring-jdbc-4.2.0.RELEASE.jar jdbc开发
spring-orm-4.2.0.RELEASE.jar Hibernate开发
常用的两个事务管理器:
DataSourceTransactionManager jdbc事务管理器
HibernateTransactionManager Hibernate事务管理器
1.3 TransactionStatus 事务状态
boolean isNewTransaction(); 是否是新的事务
boolean hasSavepoint(); 是否有保存点
void setRollbackOnly(); 设置回滚
boolean isRollbackOnly(); 是否回滚
void flush(); 刷新
boolean isCompleted(); 是否完成
1.4 TransactionDefinition
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1; ■隔离级别取值
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1; ■默认超时时间。默认值-1,使用数据库底层的超时时间
int getPropagationBehavior(); ■传播行为(参下面的说明)
int getIsolationLevel(); ■隔离级别
int getTimeout(); ■获得超时时间
boolean isReadOnly(); ■是否只读(增删改:读写;查询:只读)
String getName(); ■配置事务详情名称。一般方法名称,例如save,add*等
★传播行为:在两个业务之间如何共享事务
PROPAGATION_REQUIRED required , 必须 【默认值】 支持当前事务,A如果有事务,B将使用该事务。如果A没有事务,B将创建一个新的事务。
PROPAGATION_SUPPORTS supports ,支持 支持当前事务,A如果有事务,B将使用该事务。如果A没有事务,B将以非事务执行。
PROPAGATION_MANDATORY mandatory ,强制 支持当前事务,A如果有事务,B将使用该事事务。如果A没有事务,B将抛异常。
PROPAGATION_REQUIRES_NEW requires_new(必须新的) 如果A有事务,将A的事务挂起,B创建一个新的事务。如果A没有事务,B创建一个新的事务
PROPAGATION_NOT_SUPPORTED not_supported ,不支持 如果A有事务,将A的事务挂起,B将以非事务执行。如果A没有事务,B将以非事务执行
PROPAGATION_NEVER never,从不 如果A有事务,B将抛异常。如果A没有事务,B将以非事务执行
PROPAGATION_NESTED nested ,嵌套 A和B底层采用保存点机制,形成嵌套事务。
2.手动管理事务案例(底层就是这样实现的,了解即可)
★配置文件 beans.xml(properties和04文件中的一样就不写了)
<?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:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--配置DBCP DataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!--配置dao-->
<bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置事务管理器-->
<bean id="txManager" 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="txManager"></property>
</bean>
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
<!--▶一层一层往上套着写bean。主要看每一个bean里的set方法来看看要补充什么属性-->
<property name="transactionTemplate" ref="transactionTemplate"></property>
</bean>
</beans>
■账户dao接口及其实现
public interface IAccountDao {
//扣钱
public void out(String outer,Integer money);
//进账
public void in(String inner,Integer money);
}
public class AccountDaoImpl extends JdbcDaoSupport implements IAccountDao {
@Override
public void out(String outer, Integer money) {
getJdbcTemplate().update("update account set money=money-? where username=?",money,outer);
}
@Override
public void in(String inner, Integer money) {
getJdbcTemplate().update("update account set money=money+? where username=?",money,inner);
}
}
■service接口及其实现
public interface IAccountService {
public void transfer(String outer,String inner,Integer money);
}
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
//▶Spring配置事务模板[让spring注入]
private TransactionTemplate transactionTemplate;
public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}
@Override
public void transfer(String outer, String inner, Integer money) {
this.transactionTemplate.execute(new TransactionCallbackWithoutResult() { //▶实现事务管理
@Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
accountDao.out(outer,money); //▶写在该方法中的语句如果出现异常,spring将自动进行回滚
accountDao.in(inner,money);
}
});
}
}
■测试类
public class Test1 {
@Test
public void testTransfer(){
ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
IAccountService accountService=(AccountServiceImpl)context.getBean("accountService");
//转账
accountService.transfer("jack","rose",100);
}
}
■数据库表结构(account表名)
create table account(
id int primary key auto_increment,
username varchar(50),
money int
);
insert into account(username,money) values('jack','10000');
insert into account(username,money) values('rose','10000');
3.半自动事务管理
Spring提供管理事务的代理工厂bean:TransactionProxyFactoryBean
★配置文件beans2,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">
<!--读取properties数据-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--配置DBCP DataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!--配置dao-->
<bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置service-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--▶配置工厂代理-->
<bean id="proxyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<!--接口-->
<property name="proxyInterfaces" value="com.service.IAccountService"></property>
<!--目标对象-->
<property name="target" ref="accountService"></property>
<!--切面对象:spring已经做了就不用写了-->
<!--事务管理器-->
<property name="transactionManager" ref="txManager"></property>
<!--▶事务属性/详情配置
key:写方法名
value:写事务配置
格式:PROPAGATION,ISOLATION,readOnly,-Exception,+Exception
传播行为 隔离级别 是否只读 异常回滚 异常提交
-->
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT</prop> ▶对应service中的每一个操作方法,故麻烦
</props>
</property>
</bean>
</beans>
■service改为原先的版本(不需要事务模板)
public class AccountServiceImpl implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer,money);
accountDao.in(inner,money);
}
}
■测试类
public class Test1 {
@Test
public void testTransfer(){
ApplicationContext context=new ClassPathXmlApplicationContext("beans2.xml");
IAccountService accountService=(IAccountService)context.getBean("proxyService"); //▶使用代理获取
//转账
accountService.transfer("jack","rose",100);
}
}
●其他补充:
事务属性的配置语句的一些说明
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,readOnly</prop> ▶只允许进行读操作
<prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,+java.lang.ArithmeticException</prop> ▶+异常类型,表示即使出现该异常,之前执行过的语句也照样提交
4.AOP事务配置
★配置文件beans3.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/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">
<!--读取properties数据-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--配置DBCP DataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!--配置dao-->
<bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置service-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--●1.配置通知的事务管理器-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<!--事务详情:传播行为,隔离级别可以不配置,但是方法需要-->
<tx:attributes>
<tx:method name="transfer"/>
</tx:attributes>
</tx:advice>
<!--●2.事务通知与切入点关联-->
<aop:config>
<!--●下面这两句写法采用的是引用,后面的是直接赋值,效果是一样的
▶表达式表示service包下和其子包下的所有类都是切入点(service后面两个点)
<aop:pointcut id="myPointCut" expression="execution(* com.service..*.*(..))"></aop:pointcut>
事务与连接点关联
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointCut"></aop:advisor>
-->
<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.service..*.*(..))"></aop:advisor>
</aop:config>
</beans>
■测试类
public class Test1 {
@Test
public void testTransfer(){
ApplicationContext context=new ClassPathXmlApplicationContext("beans3.xml");
IAccountService accountService=(IAccountService)context.getBean("accountService");
//转账
accountService.transfer("jack","rose",100);
}
}
5.注解事务配置(建议放到配置文件中去,一目了然)
★配置文件
<?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/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">
<!--读取properties数据-->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!--配置DBCP DataSource-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${password}"></property>
</bean>
<!--配置dao-->
<bean id="accountDao" class="com.dao.impl.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置service-->
<bean id="accountService" class="com.service.impl.AccountServiceImpl2">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!--1.配置事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--▶开启事务注解驱动-->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
</beans>
■service注解:
//▶如果只想单个方法有事务就把注释放到方法上去
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT) //▶如果这两个值都是默认的值的话可以不用写的
public class AccountServiceImpl2 implements IAccountService {
private IAccountDao accountDao;
public void setAccountDao(IAccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String outer, String inner, Integer money) {
accountDao.out(outer,money);
accountDao.in(inner,money);
}
}
DOWN 返回