`
liu0107613
  • 浏览: 74087 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Spring的事务管理例子代码

    博客分类:
  • java
阅读更多

事务管理:

  分global事务管理和local事务管理,global要跨越多个事务资源,而local一般是本地资源,如JDBC,比较好控制。

 

下面的例子展示怎么Spring的事务管理。声明式事务管理

 

 

其实个人感觉还是手工控制事务舒服一些,因为被Spring管理后,觉得真的很简单了,特感觉没有深度东西可以做了。。。个人感受。

此代码是ProSpring书上面,经过简单改造,用Mysql数据库,把不完整的代码补充完整。

 

数据库:


DROP TABLE IF EXISTS `accounts`;
CREATE TABLE `accounts` (
  `AccountId` int(10) unsigned NOT NULL auto_increment,
  `AccountNumber` varchar(20) NOT NULL,
  `Balance` decimal(10,2) NOT NULL,
  PRIMARY KEY  (`AccountId`),
  UNIQUE KEY `AccountId` (`AccountNumber`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

 

DROP TABLE IF EXISTS `history`;
CREATE TABLE `history` (
  `HistoryId` bigint(20) unsigned NOT NULL auto_increment,
  `Account` varchar(20) NOT NULL,
  `Operation` varchar(50) NOT NULL,
  `Amount` decimal(10,2) NOT NULL,
  `TransactionDate` timestamp NOT NULL,
  `TargetAccount` varchar(20) default NULL,
  UNIQUE KEY `HistoryId` (`HistoryId`)
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;

--
-- Dumping data for table `history`
--

 

接口操作方法:

  package com.apress.prospring.ch12.business;

import java.math.BigDecimal;

import com.apress.prospring.ch12.domain.Account;
   
public interface AccountManager {
 
    /**
     * 插入账户
     * @param account
     */
    public void insert(Account account);
   
    /**
     * 往账户里面存钱
     * @param accountId
     * @param amount
     */
    public void deposit(String accountId, BigDecimal amount);
   
    /**
     * 从sourceAccount往targetAccount转账
     * @param sourceAccount
     * @param targetAccount
     * @param amount
     */
    public void transfer(String sourceAccount, String targetAccount, BigDecimal amount);
   
    /**
     * 数据库中账户的数量
     * @return
     */
    public int count();
}

 

抽象类实现:

 

package com.apress.prospring.ch12.business;

import java.math.BigDecimal;
import java.util.Date;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;

import com.apress.prospring.ch12.domain.Account;
import com.apress.prospring.ch12.domain.AccountDao;
import com.apress.prospring.ch12.domain.History;
import com.apress.prospring.ch12.domain.HistoryDao;

public abstract class AbstractAccountManager
implements InitializingBean, AccountManager {
private AccountDao accountDao;
private HistoryDao historyDao;

protected void doInsert(Account account) {
    getAccountDao().insert(account);
    History history = new History();
    history.setAccount(account.getAccountNumber());
    history.setAmount(account.getBalance());
    history.setOperation("Initial deposit");
    history.setTargetAccount(null);
    history.setTransactionDate(new Date());
    getHistoryDao().insert(history);
}

protected void doDeposit(String accountId, BigDecimal amount) {
    History history = new History();
    history.setAccount(accountId);
    history.setAmount(amount);
    history.setOperation("Deposit");
    history.setTargetAccount(null);
    history.setTransactionDate(new Date());

    getAccountDao().updateBalance(accountId, amount);
    getHistoryDao().insert(history);
}

protected void doTransfer(String sourceAccount,
  String targetAccount, BigDecimal amount) {
    Account source = getAccountDao().getAccountById(sourceAccount);

    if (source.getBalance().compareTo(amount) > 0) {
        // transfer allowed
        getAccountDao().updateBalance(sourceAccount, amount.negate());
        getAccountDao().updateBalance(targetAccount, amount);

        History history = new History();
        history.setAccount(sourceAccount);
        history.setAmount(amount);
        history.setOperation("Paid out");
        history.setTargetAccount(targetAccount);
        history.setTransactionDate(new Date());
        getHistoryDao().insert(history);

        history = new History();
        history.setAccount(targetAccount);
        history.setAmount(amount);
        history.setOperation("Paid in");
        history.setTargetAccount(sourceAccount);
        history.setTransactionDate(new Date());
        getHistoryDao().insert(history);
    } else {
        throw new RuntimeException("Not enough money");
    }
}

protected int doCount() {
    return getAccountDao().getCount();
}   


public final void afterPropertiesSet() throws Exception {
    if (accountDao == null) throw new
        BeanCreationException("Must set accountDao");
    if (historyDao == null) throw new
        BeanCreationException("Must set historyDao");
    initManager();
}

protected void initManager() {
   
}

protected AccountDao getAccountDao() {
    return accountDao;
}

public void setAccountDao(AccountDao accountDao) {
    this.accountDao = accountDao;
}

protected HistoryDao getHistoryDao() {
    return historyDao;
}

public void setHistoryDao(HistoryDao historyDao) {
    this.historyDao = historyDao;
}
}

默认实现:

package com.apress.prospring.ch12.business;

import java.math.BigDecimal;

import com.apress.prospring.ch12.domain.Account;

public class DefaultAccountManager extends AbstractAccountManager {
   
    public void insert(Account account) {
        doInsert(account);
    }
   
    public void deposit(String accountId, BigDecimal amount) {
        doDeposit(accountId, amount);
    }
   
    public void transfer(String sourceAccount, String targetAccount, BigDecimal amount) {
        doTransfer(sourceAccount, targetAccount, amount);
    }

 public int count() {
  return 0;
 }
   
}

 

数据库操作的两个接口类dao

 

 

 

package com.apress.prospring.ch12.domain;

import java.math.BigDecimal;

public interface AccountDao {
   
 
 /**
  * get account by account number
  * @param accountId
  * @return
  */
 public Account getAccountById(String accountId);

 /**
  * @param sourceAccount
  * @param amount
  */
 public void updateBalance(String sourceAccount, BigDecimal amount);

 /**
  * @param account
  */
 public void insert(Account account);

 /**
  * @return
  */
 public int getCount();

}

package com.apress.prospring.ch12.domain;
   
// in HistoryDao.java:
import java.util.List;
   
public interface HistoryDao {
    public List getByAccount(int account);
    public History getById(int historyId);
    public void insert(History history);
}

AccountDao.xml

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>

    <typeAlias type="com.apress.prospring.ch12.domain.Account" alias="account"/>
    <resultMap class="account" id="result">
        <result property="accountNumber" column="AccountNumber"/>
        <result property="balance" column="Balance"/>
    </resultMap>   
     <insert id="insertAccout" parameterClass="account">
        insert into accounts (AccountNumber, Balance) values (#accountNumber#,#balance#)
    </insert>
   
   
    <select id="getAccountById" resultMap="result" parameterClass="int" >
        select * from accounts where AccountNumber=#value#
    </select>
   
   
   
    <update id="update" parameterClass="map">
        update accounts set  Balance=#balance# where AccountNumber=#accountNumber#
    </update>
   
   
</sqlMap>

 

HistoryDao.xml

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap>

    <typeAlias type="com.apress.prospring.ch12.domain.History" alias="history"/>
    <resultMap class="history" id="result">
        <result property="account" column="Account"/>
        <result property="operation" column="Operation"/>
        <result property="amount" column="Amount"/>
        <result property="transactionDate" column="TransactionDate"/>
        <result property="targetAccount" column="TargetAccount"/>
    </resultMap>   
     <insert id="insertHistory" parameterClass="history">
        insert into history (Account,Operation,Amount,TransactionDate, TargetAccount)
        values (#account#,#operation#,#amount#,#transactionDate#,#targetAccount#)
    </insert>
   

   
</sqlMap>

 

applicationContext.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
   
<beans>
   
    <!-- Data source bean -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"    destroy-method="close" >
        <property name="driverClassName">
            <value>com.mysql.jdbc.Driver</value>
        </property>
        <property name="url">
            <value>jdbc:mysql://localhost/test</value></property>
        <property name="username"><value>root</value></property>
        <property name="password"><value>G@111111</value></property>
    </bean>
   
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource"><ref local="dataSource"/></property>
    </bean>
   
    <bean id="sqlMapClient"
        class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
        <property name="configLocation"><value>sqlMapConfig.xml</value></property>
    </bean>
   
    <bean id="accountDao"
        class="com.apress.prospring.ch12.data.SqlMapClientAccountDao">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="sqlMapClient"><ref local="sqlMapClient"/></property>
    </bean>
   
    <bean id="historyDao"
        class="com.apress.prospring.ch12.data.UnreliableSqlMapClientHistoryDao">
        <property name="dataSource"><ref local="dataSource"/></property>
        <property name="sqlMapClient"><ref local="sqlMapClient"/></property>
    </bean>
   
    <bean id="accountManagerTarget"
        class="com.apress.prospring.ch12.business.DefaultAccountManager">
        <property name="accountDao"><ref local="accountDao"/></property>
        <property name="historyDao"><ref local="historyDao"/></property>
    </bean>
   
    <bean id="accountManager"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager"/></property>
        <property name="target"><ref local="accountManagerTarget"/></property>
        <property name="transactionAttributes">
            <props>
                <prop key="insert*">
                    PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
                <prop key="transfer*">
                    PROPAGATION_REQUIRED, ISOLATION_SERIALIZABLE</prop>
                <prop key="deposit*">
                    PROPAGATION_REQUIRED, ISOLATION_READ_COMMITTED</prop>
            </props>
        </property>
    </bean>
</beans>

 

 

package com.apress.prospring.ch12.business;

import java.math.BigDecimal;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.apress.prospring.ch12.domain.Account;

public class AccountManagerTest {
   
    private ApplicationContext context;
   
    private void run() {
        System.out.println("Initializing application");
        context = new ClassPathXmlApplicationContext(new String[] {
            "applicationContext.xml" });
        AccountManager manager = (AccountManager)context.getBean(
            "accountManager");
       
        int count = manager.count();
        int failures = 0;
        int attempts = 100;
       
        for (int i = 0; i < attempts; i++) {
            Account a = new Account();
            a.setBalance(new BigDecimal(10));
            a.setAccountNumber("123 " + i);

            try {
                manager.insert(a);
            } catch (RuntimeException ex) {
                System.out.println("Failed to insert account " + ex.getMessage());
                failures++;
            }
        }
       
        System.out.println("Attempts  : " + attempts);
        System.out.println("Failures  : " + failures);
        System.out.println("Prev count: " + count);
        System.out.println("New count : " + manager.count());
       
        System.out.println("Done");
    }
   
    public static void main(String[] args) {
        new AccountManagerTest().run();
    }
   
}

 

 

 

分享到:
评论

相关推荐

    Spring的事务管理小案例

    在本文中,我们将深入探讨Spring框架中的事务管理。Spring是一个广泛应用的Java企业级应用开发框架,它提供...如果你想要深入了解,可以参考提供的博客链接或其他相关资料,进一步学习Spring事务管理的细节和最佳实践。

    Spring事务管理的jar包

    Spring事务管理分为编程式事务管理和声明式事务管理两种方式。编程式事务管理通过使用PlatformTransactionManager接口的begin、commit、rollback等方法直接控制事务的生命周期,这种方式灵活但容易导致代码过于繁琐...

    spring事务案例分析.zip

    本主题将深入探讨“Spring事务案例分析.zip”中的关键知识点,包括Spring事务管理及其在实际项目中的应用。 首先,我们来了解什么是Spring事务管理。在分布式系统或数据库操作中,事务管理是确保数据一致性和完整性...

    Spring 事务简单完整例子

    本文将深入探讨在Spring框架中如何管理事务,以“Spring 事务简单完整例子”为出发点,结合标签“spring,事务,jdbc事务”,我们将详细解释Spring事务管理的原理和实践。 首先,Spring提供了两种事务管理方式:编程...

    spring事务管理

    为了更好地理解Spring事务管理的实际应用,可以通过以下简单的例子进行演示: ```java @Service public class AccountService { @Autowired private AccountRepository accountRepository; @Transactional...

    Spring 事务 代码

    虽然提供的示例是入门级别的,但它揭示了Spring事务管理的核心概念,为进一步学习和理解Spring事务处理的高级特性奠定了基础。在实际项目中,我们需要根据需求选择合适的配置,确保事务的正确性和数据的一致性。

    spring 自定义事务管理器,编程式事务,声明式事务@Transactional使用

    在Spring框架中,事务管理是核心功能之一,它确保了数据操作的一致性和完整性。本教程将深入探讨如何在Spring中实现自定义事务管理器...这将加深你对Spring事务管理的理解,帮助你在实际项目中更加熟练地运用这些技术。

    spring 事务管理例子(TransactionProxyFactoryBean代理机制 和 tx/aop)

    总结来说,本例子通过`TransactionProxyFactoryBean`和`@Transactional`展示了如何在Spring中实现声明式事务管理,这两种方式都利用了AOP来封装事务逻辑,使代码更加整洁,降低了事务管理的复杂性。在实际应用中,...

    Spring事务管理A方法内部调用B方法的回滚问题测试代码

    在Spring框架中,事务管理是核心特性之一,用于确保数据操作的一致性和完整性。当一个方法(A方法)内部调用另一个方法(B方法)时,可能会遇到事务控制...这个示例代码对于理解和调试Spring事务管理的问题非常有帮助。

    Spring事务例子

    通过运行这些例子,你将对Spring事务管理有更深入的理解,知道何时选择编程式还是声明式事务,以及如何有效地处理事务异常。 总之,Spring的事务管理是其强大功能的一部分,无论是编程式还是声明式,都能帮助开发者...

    spring事务管理.rar

    Spring事务管理是Spring框架的核心特性之一,它提供了一种强大且灵活的方式来管理应用程序中的事务边界。在企业级Java应用中,事务处理是确保数据一致性、完整性和可靠性的关键部分。本篇文章将深入探讨Spring的事务...

    SPRING事务机制DEMO

    Spring事务管理提供了一种声明式的方式来控制事务边界,使得开发者无需显式地调用开始、提交或回滚事务。 在Spring中,有以下两种事务管理方式: 1. **编程式事务管理**:开发者需要手动调用`...

    spring 注解事务管理

    Spring事务管理主要分为两种方式:编程式事务管理和声明式事务管理。编程式事务管理是通过编写代码来控制事务的开始、提交、回滚等操作,而声明式事务管理则是通过配置或注解来定义事务边界,更加直观和易于使用。 ...

    Spring事务优缺点及使用详解.docx

    Spring事务管理提供了统一的事务处理模型,使得开发者无需关注具体数据库访问技术的事务细节,简化了事务控制代码,提高了代码的可读性和可维护性。无论是使用注解还是AOP配置,都能有效地管理和协调事务,确保应用...

    JavaEE spring半自动bean管理事务案例

    Spring事务管理还支持编程式事务管理,但这需要开发者手动调用`TransactionTemplate`或`PlatformTransactionManager`来控制事务的开始、提交、回滚等操作,相对而言更复杂,但在某些特定场景下更有灵活性。...

    Spring事务管理的方法

    ### Spring事务管理的方法 #### 一、引言 在企业级应用开发中,事务管理是一项至关重要的技术。Spring框架作为Java领域中一个非常流行的轻量级框架,为开发者提供了多种方式来实现事务管理,其中主要分为编程式...

    spring 简单实例 事务回滚

    总之,这个“spring简单实例 事务回滚”案例为我们提供了一个学习Spring事务管理的好起点。通过理解如何配置事务管理器,使用`@Transactional`注解,以及异常处理机制,我们可以更好地掌握Spring如何保证数据的一致...

    spring 事务基于注解模式

    Spring事务管理分为编程式和声明式两种。编程式事务管理通过编程的方式(如使用`TransactionTemplate`或直接调用`PlatformTransactionManager`)来控制事务的开始、提交、回滚等操作。而声明式事务管理则是在配置...

Global site tag (gtag.js) - Google Analytics