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 返回