在软件开发过程中,经常会遇到事务问题,下面我们来看看最简单的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(1, 2, 1);//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(1, 3, 1);//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(1, 2, 1);// 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); } }