事务管理入门-JDBCHibernate事务管理器Spring注解 3种方式

    技术2022-05-20  49

    事务管理入门-JDBC/Hibernate事务管理器/Spring注解 3种方式

    在软件开发过程中,经常会遇到事务问题,下面我们来看看最简单的JDBC和Spring分别如何处理事务。

     

    关于事务控制的场景当然是转账,我们使用的数据库是MySQL。

    打开test数据库后,运行下面的数据库脚本:

    Sql代码   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);   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);  

    1、JDBC中的事务控制

     

    代码1:AccountDAO.java

    Java代码   package com.coderdream;     import java.sql.Connection;   import java.sql.DriverManager;   import java.sql.ResultSet;   import java.sql.SQLException;   import java.sql.Statement;     public class AccountDAO {         public void transfer(Integer fromAccountId, Integer toAccountId, int money) {           try {               // 1. 注册驱动               Class.forName("com.mysql.jdbc.Driver");                 // 2. 获取数据库的连接               Connection conn = DriverManager.getConnection(                       "jdbc:mysql://localhost/test""root""1234");                 // 3. 获取表达式               Statement stmt1 = conn.createStatement();               Statement stmt2 = conn.createStatement();               Statement stmt3 = conn.createStatement();               Statement stmt4 = conn.createStatement();                 // 执行插入数据的 SQL               ResultSet rs1 = stmt1                       .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID="                              + fromAccountId);               // 5. 显示结果集里面的数据               int money1 = 0;               while (rs1.next()) {                   System.out.println(rs1.getInt(1));                   money1 = rs1.getInt(1);               }                 // 修改               money1 -= money;               System.out.println("money1: " + money1);               stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money1                       + " WHERE ACCOUNTID=" + fromAccountId);                 // 执行插入数据的 SQL               ResultSet rs2 = stmt3                       .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID="                              + toAccountId);               // 5. 显示结果集里面的数据               int money2 = 0;               while (rs2.next()) {                   System.out.println(rs2.getInt(1));                   money2 = rs2.getInt(1);               }                 // 修改               money2 += money;               System.out.println("money2: " + money2);               stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money2                       + " WHERE ACCOUNTID=" + toAccountId);                 // 6. 释放资源               rs1.close();               rs2.close();               stmt1.close();               stmt2.close();               stmt3.close();               stmt4.close();               conn.close();           } catch (ClassNotFoundException e) {               e.printStackTrace();           } catch (SQLException e) {               e.printStackTrace();           }         }   }   package com.coderdream; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class AccountDAO { public void transfer(Integer fromAccountId, Integer toAccountId, int money) { try { // 1. 注册驱动 Class.forName("com.mysql.jdbc.Driver"); // 2. 获取数据库的连接 Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost/test", "root", "1234"); // 3. 获取表达式 Statement stmt1 = conn.createStatement(); Statement stmt2 = conn.createStatement(); Statement stmt3 = conn.createStatement(); Statement stmt4 = conn.createStatement(); // 执行插入数据的 SQL ResultSet rs1 = stmt1 .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID=" + fromAccountId); // 5. 显示结果集里面的数据 int money1 = 0; while (rs1.next()) { System.out.println(rs1.getInt(1)); money1 = rs1.getInt(1); } // 修改 money1 -= money; System.out.println("money1: " + money1); stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money1 + " WHERE ACCOUNTID=" + fromAccountId); // 执行插入数据的 SQL ResultSet rs2 = stmt3 .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID=" + toAccountId); // 5. 显示结果集里面的数据 int money2 = 0; while (rs2.next()) { System.out.println(rs2.getInt(1)); money2 = rs2.getInt(1); } // 修改 money2 += money; System.out.println("money2: " + money2); stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money2 + " WHERE ACCOUNTID=" + toAccountId); // 6. 释放资源 rs1.close(); rs2.close(); stmt1.close(); stmt2.close(); stmt3.close(); stmt4.close(); conn.close(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } }  

    代码2:AccountService.java

    Java代码   package com.coderdream;     public class AccountService {         private AccountDAO accountDAO;         /**       * 通过 Spring 向 Service ͨszh注入 Dao       *        * @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.transfer(fromAccountId, toAccountId, money);       }   }   package com.coderdream; public class AccountService { private AccountDAO accountDAO; /** * 通过 Spring 向 Service ͨszh注入 Dao * * @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.transfer(fromAccountId, toAccountId, money); } }

     

    代码3:Main.java

    Java代码   package com.coderdream;     import org.springframework.context.ApplicationContext;   import org.springframework.context.support.FileSystemXmlApplicationContext;     public class Main {         /**       * @param args       */      public static void main(String[] args) {             ApplicationContext act = new FileSystemXmlApplicationContext(                   "src/applicationContext.xml");           AccountService accountService = (AccountService) act                   .getBean("accountService");           try {               // 帐号1转账1元至帐号2               accountService.transfer(121);//A                  } catch (Exception e) {               System.out.println("转账失败!");           }       }   }   package com.coderdream; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Main { /** * @param args */ public static void main(String[] args) { ApplicationContext act = new FileSystemXmlApplicationContext( "src/applicationContext.xml"); AccountService accountService = (AccountService) act .getBean("accountService"); try { // 帐号1转账1元至帐号2 accountService.transfer(1, 2, 1);//A  } catch (Exception e) { System.out.println("转账失败!"); } } }  

    代码4:applicationContext.xml

    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"      xsi:schemaLocation="http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">        <bean id="accountDAO" class="com.coderdream.AccountDAO" />             <bean id="accountService" class="com.coderdream.AccountService">          <property name="accountDAO" ref="accountDAO"></property>      </bean>  </beans>   <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 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-2.5.xsd"> <bean id="accountDAO" class="com.coderdream.AccountDAO" /> <bean id="accountService" class="com.coderdream.AccountService"> <property name="accountDAO" ref="accountDAO"></property> </bean> </beans>

     

    上面的代码是没有加事务控制的,如果把‘A’处的代码换成:

    Java代码   // 帐号1转账1元至帐号3   accountService.transfer(131);//A   // 帐号1转账1元至帐号3 accountService.transfer(1, 3, 1);//A

     

    则由于帐号3不存在,所以会出现问题,帐号1的金额会减1,而帐号2的金额不会变,转账的1元就“不翼而飞”了,所以必须在Dao层加入事务控制。

     

    代码5:加入事务控制后的AccountDAO

    Java代码   public class AccountDAO {         public void transfer(Integer fromAccountId, Integer toAccountId, int money) {           Connection conn = null;           ResultSet rs1 = null;           Integer rs2 = null;           ResultSet rs3 = null;           Integer rs4 = null;           Statement stmt1 = null;           Statement stmt2 = null;           Statement stmt3 = null;           Statement stmt4 = null;           // 1. 注册驱动           try {               Class.forName("com.mysql.jdbc.Driver");                 // 2. 获取数据库的连接               conn = DriverManager.getConnection("jdbc:mysql://localhost/test",                       "root""1234");                 conn.setAutoCommit(false);                 // 3. 获取表达式               stmt1 = conn.createStatement();               stmt2 = conn.createStatement();               stmt3 = conn.createStatement();               stmt4 = conn.createStatement();                 // 执行插入数据的 SQL               rs1 = stmt1                       .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID="                              + fromAccountId);               // 5. 显示结果集里面的数据               int money1 = 0;               while (rs1.next()) {                   System.out.println(rs1.getInt(1));                   money1 = rs1.getInt(1);               }                 // 修改               money1 -= money;               System.out.println("money1: " + money1);               rs2 = stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money1                       + " WHERE ACCOUNTID=" + fromAccountId);               if (1 != rs2) {                   throw new Exception(" 转出失败,帐号: " + fromAccountId);               }                 // 执行插入数据的 SQL               rs3 = stmt3                       .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID="                              + toAccountId);               // 5. 显示结果集里面的数据               int money2 = 0;               while (rs3.next()) {                   System.out.println(rs3.getInt(1));                   money2 = rs3.getInt(1);               }                 // 修改               money2 += money;               System.out.println("money2: " + money2);               rs4 = stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money2                       + " WHERE ACCOUNTID=" + toAccountId);               if (1 != rs4) {                   throw new Exception(" 转入失败,帐号: " + toAccountId);               }                 conn.commit();               System.out.println("转帐成功!");           } catch (Exception e) {               try {                   conn.rollback();               } catch (Exception e1) {                   e1.printStackTrace();               }               e.printStackTrace();           }           // 6. 释放资源           finally {               try {                   if (rs1 != null) {                       rs1.close();                   }                   if (rs3 != null) {                       rs3.close();                   }                   if (stmt1 != null) {                       stmt1.close();                   }                   if (stmt2 != null) {                       stmt2.close();                   }                   if (stmt3 != null) {                       stmt3.close();                   }                   if (stmt4 != null) {                       stmt4.close();                   }                   if (conn != null) {                       conn.close();                   }               } catch (SQLException e) {                   e.printStackTrace();               }           }       }   }   public class AccountDAO { public void transfer(Integer fromAccountId, Integer toAccountId, int money) { Connection conn = null; ResultSet rs1 = null; Integer rs2 = null; ResultSet rs3 = null; Integer rs4 = null; Statement stmt1 = null; Statement stmt2 = null; Statement stmt3 = null; Statement stmt4 = null; // 1. 注册驱动 try { Class.forName("com.mysql.jdbc.Driver"); // 2. 获取数据库的连接 conn = DriverManager.getConnection("jdbc:mysql://localhost/test", "root", "1234"); conn.setAutoCommit(false); // 3. 获取表达式 stmt1 = conn.createStatement(); stmt2 = conn.createStatement(); stmt3 = conn.createStatement(); stmt4 = conn.createStatement(); // 执行插入数据的 SQL rs1 = stmt1 .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID=" + fromAccountId); // 5. 显示结果集里面的数据 int money1 = 0; while (rs1.next()) { System.out.println(rs1.getInt(1)); money1 = rs1.getInt(1); } // 修改 money1 -= money; System.out.println("money1: " + money1); rs2 = stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money1 + " WHERE ACCOUNTID=" + fromAccountId); if (1 != rs2) { throw new Exception(" 转出失败,帐号: " + fromAccountId); } // 执行插入数据的 SQL rs3 = stmt3 .executeQuery("SELECT MONEY FROM ACCOUNT WHERE ACCOUNTID=" + toAccountId); // 5. 显示结果集里面的数据 int money2 = 0; while (rs3.next()) { System.out.println(rs3.getInt(1)); money2 = rs3.getInt(1); } // 修改 money2 += money; System.out.println("money2: " + money2); rs4 = stmt2.executeUpdate("UPDATE ACCOUNT SET MONEY=" + money2 + " WHERE ACCOUNTID=" + toAccountId); if (1 != rs4) { throw new Exception(" 转入失败,帐号: " + toAccountId); } conn.commit(); System.out.println("转帐成功!"); } catch (Exception e) { try { conn.rollback(); } catch (Exception e1) { e1.printStackTrace(); } e.printStackTrace(); } // 6. 释放资源 finally { try { if (rs1 != null) { rs1.close(); } if (rs3 != null) { rs3.close(); } if (stmt1 != null) { stmt1.close(); } if (stmt2 != null) { stmt2.close(); } if (stmt3 != null) { stmt3.close(); } if (stmt4 != null) { stmt4.close(); } if (conn != null) { conn.close(); } } catch (SQLException e) { e.printStackTrace(); } } } }  

    2、Spring中的事务控制方式一:Hibernate的事务管理器托管

    我们先来看看通过Spring+Hibernate来操作数据库的简单示例。

    先通过 MyEclipse 生成Hibernate 需要的 Bean 及 hbm.xml文件:

     

    代码6:Account.java

    Java代码   package com.coderdream;     /**   * Account entity.   *    * @author MyEclipse Persistence Tools   */  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;       }     }   package com.coderdream; /** * Account entity. * * @author MyEclipse Persistence Tools */ 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; } }  

    代码7:Account.hbm.xml

    Xml代码   <?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="com.coderdream.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>   <?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="com.coderdream.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>  

    代码8:

    Java代码   package com.coderdream;     import org.springframework.orm.hibernate3.support.HibernateDaoSupport;     public class AccountDAO extends HibernateDaoSupport {         public void addMoney(Integer accountId, int money) {           Account account = (Account) getHibernateTemplate().get(Account.class,                   accountId);           account.setMoney(account.getMoney() + money);           getHibernateTemplate().saveOrUpdate(account);       }         public void subMoney(Integer accountId, int money) {           Account account = (Account) getHibernateTemplate().get(Account.class,                   accountId);           account.setMoney(account.getMoney() - money);           getHibernateTemplate().saveOrUpdate(account);       }   }   package com.coderdream; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; public class AccountDAO extends HibernateDaoSupport { public void addMoney(Integer accountId, int money) { Account account = (Account) getHibernateTemplate().get(Account.class, accountId); account.setMoney(account.getMoney() + money); getHibernateTemplate().saveOrUpdate(account); } public void subMoney(Integer accountId, int money) { Account account = (Account) getHibernateTemplate().get(Account.class, accountId); account.setMoney(account.getMoney() - money); getHibernateTemplate().saveOrUpdate(account); } }  

    代码9:

    Java代码   package com.coderdream;     public class AccountService {         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);       }   }   package com.coderdream; public class AccountService { 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); } }  

    代码10:

    Java代码   package com.coderdream;     import org.springframework.context.ApplicationContext;   import org.springframework.context.support.FileSystemXmlApplicationContext;     public class Main {         /**       * @param args       */      public static void main(String[] args) {             ApplicationContext act = new FileSystemXmlApplicationContext(                   "src/applicationContext.xml");           AccountService accountService = (AccountService) act                   .getBean("accountService");           try {               // 帐号1转账1元至帐号2               accountService.transfer(121);// B           } catch (Exception e) {               System.out.println("转账失败");           }       }   }   package com.coderdream; import org.springframework.context.ApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; public class Main { /** * @param args */ public static void main(String[] args) { ApplicationContext act = new FileSystemXmlApplicationContext( "src/applicationContext.xml"); AccountService accountService = (AccountService) act .getBean("accountService"); try { // 帐号1转账1元至帐号2 accountService.transfer(1, 2, 1);// B } catch (Exception e) { System.out.println("转账失败"); } } }  

    上面的代码同样没有加入事务控制,如果在‘B’处将转入的帐号设置为不存在的帐号3,同样会有问题,下面我们来加入事务控制,我们需要修改 applicationContext.xml 文件:

     

    代码11:增加事务后的 applicationContext.xml

    Java代码   <?xml version="1.0" encoding="UTF-8"?>   <beans xmlns="http://www.springframework.org/schema/beans"      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-2.5.xsd">         <bean id="dataSource"          class="org.apache.commons.dbcp.BasicDataSource">           <property name="driverClassName"              value="com.mysql.jdbc.Driver">           </property>           <property name="url" value="jdbc:mysql://localhost:3306/test"></property>           <property name="username" value="root"></property>           <property name="password" value="1234"></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>com/coderdream/Account.hbm.xml</value>               </list>           </property>       </bean>         <!-- 引用Hibernate的事务管理器 -->       <bean id="transactionManager"          class="org.springframework.orm.hibernate3.HibernateTransactionManager">           <property name="sessionFactory" ref="sessionFactory"></property>       </bean>         <bean id="accountDAO" class="com.coderdream.AccountDAO">           <property name="sessionFactory" ref="sessionFactory"></property>       </bean>         <!-- 通过事务管理器来管理Service -->       <bean id="accountService"          class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">           <property name="transactionManager" ref="transactionManager"></property>           <property name="target">               <bean class="com.coderdream.AccountService">                   <property name="accountDAO" ref="accountDAO"></property>               </bean>           </property>           <property name="transactionAttributes">               <props>                   <prop key="transfer">PROPAGATION_REQUIRED</prop>               </props>           </property>       </bean>   </beans>   <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" 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-2.5.xsd"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"> </property> <property name="url" value="jdbc:mysql://localhost:3306/test"></property> <property name="username" value="root"></property> <property name="password" value="1234"></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>com/coderdream/Account.hbm.xml</value> </list> </property> </bean> <!-- 引用Hibernate的事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="accountDAO" class="com.coderdream.AccountDAO"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 通过事务管理器来管理Service --> <bean id="accountService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager" ref="transactionManager"></property> <property name="target"> <bean class="com.coderdream.AccountService"> <property name="accountDAO" ref="accountDAO"></property> </bean> </property> <property name="transactionAttributes"> <props> <prop key="transfer">PROPAGATION_REQUIRED</prop> </props> </property> </bean> </beans>  

    3、Spring中的事务控制方式二:注解方式

    当然,我们还可以通过注解的方式加入事务的控制。

    我们需要先在 applicationContext.xml 声明事务控制器和注解:

     

    代码12:applicationContext.xml

    Java代码   <?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:jee="http://www.springframework.org/schema/jee"      xmlns:tx="http://www.springframework.org/schema/tx"      xmlns:context="http://www.springframework.org/schema/context"      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">         <bean id="dataSource"          class="org.apache.commons.dbcp.BasicDataSource">           <property name="driverClassName"              value="com.mysql.jdbc.Driver">           </property>           <property name="url" value="jdbc:mysql://localhost:3306/test"></property>           <property name="username" value="root"></property>           <property name="password" value="1234"></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>com/coderdream/Account.hbm.xml</value>               </list>           </property>       </bean>         <!-- 引用Hibernate的事务管理器 -->       <bean id="transactionManager"          class="org.springframework.orm.hibernate3.HibernateTransactionManager">           <property name="sessionFactory" ref="sessionFactory"></property>       </bean>         <!-- 使用annotation定义事务 -->       <tx:annotation-driven transaction-manager="transactionManager" />         <bean id="accountDAO" class="com.coderdream.AccountDAO">           <property name="sessionFactory" ref="sessionFactory"></property>       </bean>         <bean id="accountService" class="com.coderdream.AccountService">           <property name="accountDAO" ref="accountDAO"></property>       </bean>   </beans>   <?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:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"> </property> <property name="url" value="jdbc:mysql://localhost:3306/test"></property> <property name="username" value="root"></property> <property name="password" value="1234"></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>com/coderdream/Account.hbm.xml</value> </list> </property> </bean> <!-- 引用Hibernate的事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" /> <bean id="accountDAO" class="com.coderdream.AccountDAO"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="accountService" class="com.coderdream.AccountService"> <property name="accountDAO" ref="accountDAO"></property> </bean> </beans>  

    同时需要在Service层的要使用的方法上声明事务,如:

    Java代码   @Transactional(readOnly = false)   @Transactional(readOnly = false)

     如果只是对数据库进行查询操作,这里的“readOnly = true“,如果是”增/删/改“操作,则为 false。

     

    代码13:在方法上加入“注解式”事务控制后的 AccountService.java

    Java代码   package com.coderdream;     public class AccountService {         private AccountDAO accountDAO;         /**       * 通过 Spring 将 DAO 注入到 Service       *        * @param accountDAO       */      public void setAccountDAO(AccountDAO accountDAO) {           this.accountDAO = accountDAO;       }         /**       * 转账方法包括两个原子方法:转出方法和转入方法       *        * @param fromAccountId       * @param toAccountId       * @param money       */      @Transactional(readOnly = false)       public void transfer(Integer fromAccountId, Integer toAccountId, int money) {           accountDAO.subMoney(fromAccountId, money);           accountDAO.addMoney(toAccountId, money);       }   }  

    最新回复(0)