Spring配置事务的五种方式

来源:互联网 发布:淘宝联盟怎么看隐藏券 编辑:程序博客网 时间:2024/05/24 01:15

Spring
1:对每一个服务层类Bean配置一个代理:
a.首先创建一个maven quick-start 项目,然后配置依赖包:
mysql-connector,spring-context,spring-orm,hibernate,
hibernate-core,dbcp2(数据源)
b.在test数据库中编写数据库脚本并执行,以及编写applicationContext.xml文件(在src目录下):

DROP TABLE IF EXISTS account;  CREATE TABLE account (  accountId int primary key auto_increment,  accountname varchar(20),  money int not null  );  INSERT INTO ACCOUNT(ACCOUNTNAME,MONEY) VALUES('zhangsan',100);  INSERT INTO ACCOUNT(ACCOUNTNAME,MONEY) VALUES('lisi',100);  
<?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-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  <bean id="dataSource"          class="org.apache.commons.dbcp2.BasicDataSource">          <property name="driverClassName"              value="com.mysql.jdbc.Driver">          </property>          <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;serverTimezone=GMT"></property>          <property name="username" value="root"></property>          <property name="password" value="mysqladmin"></property>      </bean>      <bean id="sessionFactory"          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">          <property name="dataSource">              <ref bean="dataSource" />          </property>          <property name="hibernateProperties">              <props>                  <prop key="hibernate.dialect">                      org.hibernate.dialect.MySQLDialect                  </prop>                  <prop key="hibernate.show_sql">true</prop>              </props>          </property>          <property name="mappingResources">              <list>                  <value>kai/SpringTransaction1/Account.hbm.xml</value>              </list>          </property>      </bean>      <!-- 定义事务管理器(声明式的事务) -->      <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <!-- 配置DAO和service -->    <bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">     <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="accountServiceTarget" class="kai.SpringTransaction1.AccountService">        <property name="accountDAO" ref="accountDAO" />    </bean>      <!-- 每个bean配置一个代理 -->    <bean id="accountService"          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">             <!-- 配置事务管理器 -->             <property name="transactionManager" ref="transactionManager" />             <property name="target" ref="accountServiceTarget" />           <property name="proxyInterfaces" value="kai.SpringTransaction1.IAccountService" />        <!-- 配置事务属性 -->          <property name="transactionAttributes">              <props>                  <prop key="*">PROPAGATION_REQUIRED</prop>            </props>          </property>      </bean>  </beans>

c.编写Account类

package kai.SpringTransaction1;public class Account implements java.io.Serializable {      /**      *       */      private static final long serialVersionUID = 909891879728703117L;      private Integer accountId;      private String accountname;      private Integer money;      // Property accessors      public Integer getAccountId() {          return this.accountId;      }      public void setAccountId(Integer accountId) {          this.accountId = accountId;      }      public String getAccountname() {          return this.accountname;      }      public void setAccountname(String accountname) {          this.accountname = accountname;      }      public Integer getMoney() {          return this.money;      }      public void setMoney(Integer money) {          this.money = money;      }      // Constructors      /** default constructor */      public Account() {      }      /** full constructor */      public Account(String accountname, Integer money) {          this.accountname = accountname;          this.money = money;      }  }  

d.编写AccountDAO和IAccountService,AccountService和Account.hbm.xml,因为是基于代理的,因此服务层必须要有接口,即必须有IAccountService,不能直接代理AccountService。

package kai.SpringTransaction1;import org.hibernate.SessionFactory;public class AccountDAO  {        public SessionFactory sessionFactory;      public void setSessionFactory(SessionFactory sessionFactory){          this.sessionFactory=sessionFactory;      }    @SuppressWarnings("deprecation")    public void addMoney(Integer accountId, int money) {          Account ac=(Account) sessionFactory.getCurrentSession().get(Account.class, accountId);        ac.setMoney(money+ac.getMoney());        sessionFactory.getCurrentSession().update(ac,accountId);    }      public void subMoney(Integer accountId, int money) {          Account ac=(Account) sessionFactory.getCurrentSession().get(Account.class, accountId);        ac.setMoney(ac.getMoney()-money);        sessionFactory.getCurrentSession().update(ac,accountId);     }  }  package kai.SpringTransaction1;public interface IAccountService {     public void transfer(Integer fromAccountId, Integer toAccountId, int money) ;}package kai.SpringTransaction1;public class AccountService implements IAccountService{       private AccountDAO accountDAO;       /**       * 通过 Spring 将 DAO 注入到 Service       *        * @param accountDAO       *      */      public void setAccountDAO(AccountDAO accountDAO) {           this.accountDAO = accountDAO;       }       /**       * 转账方法包括两个原子方法:转出方法和转入方法       *        * @param fromAccountId       * @param toAccountId       * @param money       */      public void transfer(Integer fromAccountId, Integer toAccountId, int money) {           accountDAO.subMoney(fromAccountId, money);           accountDAO.addMoney(toAccountId, money);       }   }  <?xml version="1.0" encoding="utf-8"?>  <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  <!--      Mapping file autogenerated by MyEclipse Persistence Tools -->  <hibernate-mapping>      <class name="kai.SpringTransaction1.Account" table="account" catalog="test">          <id name="accountId" type="java.lang.Integer">              <column name="accountId" />              <generator class="native" />          </id>          <property name="accountname" type="java.lang.String">              <column name="accountname" length="20" />          </property>          <property name="money" type="java.lang.Integer">              <column name="money" length="20" />          </property>      </class>  </hibernate-mapping>  

e.编写测试类

package kai.SpringTransaction1;import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;/** * Hello world! * */public class App {    public static void main( String[] args )    {        System.out.println( "Hello World!" );        ApplicationContext act = new FileSystemXmlApplicationContext(                   "src/applicationContext.xml");           IAccountService accountService = (IAccountService) act                   .getBean("accountService");           try {               // 帐号1转账1元至帐号2               accountService.transfer(1, 2, 1);          } catch (Exception e) {               System.out.println("转账失败");           }       }}

f.运行:查看数据库可知钱成功转账,若将测试类中改为从账户1转到不存在的张户2,则1的钱也不会减少。
2.对服务层所有bean配置同一个代理:
只需将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-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  <bean id="dataSource"          class="org.apache.commons.dbcp2.BasicDataSource">          <property name="driverClassName"              value="com.mysql.jdbc.Driver">          </property>          <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;serverTimezone=GMT"></property>          <property name="username" value="root"></property>          <property name="password" value="mysqladmin"></property>      </bean>      <bean id="sessionFactory"          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">          <property name="dataSource">              <ref bean="dataSource" />          </property>          <property name="hibernateProperties">              <props>                  <prop key="hibernate.dialect">                      org.hibernate.dialect.MySQLDialect                  </prop>                  <prop key="hibernate.show_sql">true</prop>              </props>          </property>          <property name="mappingResources">              <list>                  <value>kai/SpringTransaction1/Account.hbm.xml</value>              </list>          </property>      </bean>      <!-- 定义事务管理器(声明式的事务) -->      <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <!-- 配置DAO和service -->    <bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">     <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="accountServiceTarget" class="kai.SpringTransaction1.AccountService">        <property name="accountDAO" ref="accountDAO" />    </bean>    <!-- 配置所有服务层bean的共同代理-->         <bean id="transactionBase"              class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"              lazy-init="true" abstract="true">          <!-- 配置事务管理器 -->          <property name="transactionManager" ref="transactionManager" />          <!-- 配置事务属性 -->          <property name="transactionAttributes">              <props>                  <prop key="*">PROPAGATION_REQUIRED</prop>              </props>          </property>      </bean>          <!-- 所有bean配置一个代理 -->    <bean id="accountService" parent="transactionBase">          <property name="target" ref="accountServiceTarget" />      </bean>  </beans>

3.基于拦截器的实现,也是只需要修改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-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  <bean id="dataSource"          class="org.apache.commons.dbcp2.BasicDataSource">          <property name="driverClassName"              value="com.mysql.jdbc.Driver">          </property>          <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;serverTimezone=GMT"></property>          <property name="username" value="root"></property>          <property name="password" value="mysqladmin"></property>      </bean>      <bean id="sessionFactory"          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">          <property name="dataSource">              <ref bean="dataSource" />          </property>          <property name="hibernateProperties">              <props>                  <prop key="hibernate.dialect">                      org.hibernate.dialect.MySQLDialect                  </prop>                  <prop key="hibernate.show_sql">true</prop>              </props>          </property>          <property name="mappingResources">              <list>                  <value>kai/SpringTransaction1/Account.hbm.xml</value>              </list>          </property>      </bean>      <!-- 定义事务管理器(声明式的事务) -->      <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <!-- 配置DAO和service -->    <bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">     <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="accountService" class="kai.SpringTransaction1.AccountService">        <property name="accountDAO" ref="accountDAO" />    </bean>     <!-- 配置拦截器实现事务 -->      <bean id="transactionInterceptor"          class="org.springframework.transaction.interceptor.TransactionInterceptor">          <property name="transactionManager" ref="transactionManager" />          <!-- 配置事务属性 -->          <property name="transactionAttributes">              <props>                  <prop key="*">PROPAGATION_REQUIRED</prop>              </props>          </property>      </bean>    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">          <property name="beanNames">              <list>                  <value>*Service</value>            </list>          </property>          <property name="interceptorNames">              <list>                  <value>transactionInterceptor</value>              </list>          </property>      </bean>  </beans>

4.使用AOP方式实现:
在1的基础上修改applicationContext.xml文件以及引入依赖包:aspectj和aspectjweaver。

<?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-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  <bean id="dataSource"          class="org.apache.commons.dbcp2.BasicDataSource">          <property name="driverClassName"              value="com.mysql.jdbc.Driver">          </property>          <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;serverTimezone=GMT"></property>          <property name="username" value="root"></property>          <property name="password" value="mysqladmin"></property>      </bean>      <bean id="sessionFactory"          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">          <property name="dataSource">              <ref bean="dataSource" />          </property>          <property name="hibernateProperties">              <props>                  <prop key="hibernate.dialect">                      org.hibernate.dialect.MySQLDialect                  </prop>                  <prop key="hibernate.show_sql">true</prop>              </props>          </property>          <property name="mappingResources">              <list>                  <value>kai/SpringTransaction1/Account.hbm.xml</value>              </list>          </property>      </bean>      <!-- 定义事务管理器(声明式的事务) -->      <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <!-- 配置DAO和service -->    <bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">     <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="accountService" class="kai.SpringTransaction1.AccountService">        <property name="accountDAO" ref="accountDAO" />    </bean>      <!-- 下面使用aop切面的方式来实现 事务控制-->      <tx:advice id="TestAdvice" transaction-manager="transactionManager">          <!--配置事务传播性,隔离级别以及超时回滚等问题 -->          <tx:attributes>              <tx:method name="save*" propagation="REQUIRED" />              <tx:method name="del*" propagation="REQUIRED" />              <tx:method name="update*" propagation="REQUIRED" />              <tx:method name="add*" propagation="REQUIRED" />              <tx:method name="*" propagation="REQUIRED" />          </tx:attributes>      </tx:advice>      <aop:config>          <!--配置事务切点 -->          <aop:pointcut id="services"              expression="execution(* kai.SpringTransaction1.AccountService.*(..))" />          <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />      </aop:config>  </beans>

5.注解式事务:(这是我觉得最优雅的):
修改applicationContext.xml文件同时在需要加事务控制的方法上加上@Transactional注解。此处即在AccountService的transfer方法上加上@Transactional注解。

<?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-2.5.xsd           http://www.springframework.org/schema/context           http://www.springframework.org/schema/context/spring-context-2.5.xsd           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  <bean id="dataSource"          class="org.apache.commons.dbcp2.BasicDataSource">          <property name="driverClassName"              value="com.mysql.jdbc.Driver">          </property>          <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;serverTimezone=GMT"></property>          <property name="username" value="root"></property>          <property name="password" value="mysqladmin"></property>      </bean>      <bean id="sessionFactory"          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">          <property name="dataSource">              <ref bean="dataSource" />          </property>          <property name="hibernateProperties">              <props>                  <prop key="hibernate.dialect">                      org.hibernate.dialect.MySQLDialect                  </prop>                  <prop key="hibernate.show_sql">true</prop>              </props>          </property>          <property name="mappingResources">              <list>                  <value>kai/SpringTransaction1/Account.hbm.xml</value>              </list>          </property>      </bean>      <!-- 定义事务管理器(声明式的事务) -->      <bean id="transactionManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>    <!-- 配置DAO和service -->    <bean id="accountDAO" class="kai.SpringTransaction1.AccountDAO">     <property name="sessionFactory" ref="sessionFactory" />    </bean>    <bean id="accountService" class="kai.SpringTransaction1.AccountService">        <property name="accountDAO" ref="accountDAO" />    </bean>      <!-- 下面使用全注解的方式来实现 事务控制-->   <tx:annotation-driven transaction-manager="transactionManager"/></beans>

补充说明:
1.@Transactional
(1)这个注解放在类上面,会对这个类中的所有public方法都起作用;
(2)放在方法上,只有当这个方法是public方法才起作用。
(3)事务的传播性:@Transactional(propagation=Propagation.REQUIRED)
(4)事务的隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED)
参考文章:
http://blog.csdn.net/it_man/article/details/5074371
http://blog.csdn.net/lifangshui/article/details/6324348
http://blog.csdn.net/qh_java/article/details/51811533

原创粉丝点击