Spring-JDBC事务管理

sinanry 贡献于2011-08-26

作者 Administrator  创建于2009-01-09 00:09:00   修改者Administrator  修改于2009-01-09 00:10:00字数24414

文档摘要:Spring提供编程式的事务管理(Programma tictransaction manage-ment)与声明式的事务管理(Declarative transaction management),为不同的事务实现提供了一致的编程模型,这节以JDBC事务为例,介绍Spring的事务管理。
关键词:

Spring-JDBC事务管理  Spring提供编程式的事务管理(Programmatic transaction manage- ment)与声明式的事务管理(Declarative transaction management),为不同的事务实现提供了一致的编程模型,这节以JDBC事务为例,介绍Spring的事务管理。  5.3.1  Spring对事务的支持  事务是一组原子(Atomic)操作的工作单元,以数据库存取的实例来说,就是一组SQL指令,这一组SQL指令必须全部执行成功,若因为某个原因未全部执行成功(例如其中一行SQL有错误),则先前所有执行过的SQL指令都会被撤消。  举个简单的例子,一个客户从A银行转账至B银行,要作的动作为从A银行的账户扣款、在B银行的账户加上转账的金额,两个动作必须成功,如果有一个动作失败,则此次转账失败。  事务还必须保持所参与资源的一致性(Consistent),例如在银行账户的例子中,两个账户的转账金额,B账户取款的金额不能大于A账户的存款金额。每个事务彼此之间必须是隔离的(Isolated),例如在A账户中可能有两笔事务,同时进行存款与提款的动作,两个事务基本上不需意识到彼此的存在。事务还必须是可持续的(Durable),在某一笔事务之后,这笔事务必须是被记录下来的。  在这里将介绍JDBC如何使用事务管理。首先来看看事务的原子性实现,在JDBC中,可以操作Connection的setAutoCommit() 方法,给定false参数,在下达一连串的SQL语句后,自行执行Connection的commit()来送出变更,如果中间发生错误,则执行rollback() 来撤消所有的执行,例如:  Java代码  1. try {   2.    3.     .....   4.    5.     connection.setAutoCommit(false);   6.    7.     .....   8.    9.     // 一连串SQL操作   10.    11.     connection.commit();   12.    13. } catch(SQLException) {   14.    15.     // 发生错误,撤消所有变更   16.    17.     connection.rollback();   18.    19. }   在Spring中对JDBC的事务管理加以封装,Spring事务管理的抽象关键在于org.springframework.transaction.PlatformTransactionManager接口的实现:  ...  Java代码  1. public interface PlatformTransactionManager {   2.    3.     TransactionStatus getTransaction(TransactionDefinition    4.    5.                     definition)  throws TransactionException;   6.    7.     void commit(TransactionStatus status)    8.    9.                                    throws TransactionException;   10.    11.     void rollback(TransactionStatus status)    12.    13.                                    throws TransactionException;   14.    15. }   PlatformTransactionManager接口有许多具体的事务实现类,例如DataSourceTransactionManager、HibernateTransactionManager、JdoTransaction- Manager、JtaTransactionManager等,通过依赖于PlatformTransactionManager接口及各种的技术实现,Spring在事务管理上可以让开发人员使用一致的编程模型,即使所使用的是不同的事务管理技术。  TransactionException是Unchecked Exception。事务的失败通常都是致命的错误,Spring不强迫您一定要处理,而是让您自行选择是否要捕捉异常。  getTransaction() 方法根据一个TransactionDefinition对象来回传一个TransactionStatus对象,TransactionDefinition接口的实例定义了事务的隔离程度(Isolation level)、传播行为(Propagation behavior)、超时(Timeout)、只读(Read-only)等,TransactionStatus代表着一个新的事务发起或已经存在的事务,您可以通过它来控制事务的执行或调查的状态:  ...  Java代码  1. public interface TransactionStatus {   2.    3.     boolean isNewTransaction();   4.    5.     void setRollbackOnly();   6.    7.     boolean isRollbackOnly();   8.    9. }   Spring提供编程式的事务管理(Programmatic transaction management)与声明式的事务管理(Declarative transaction management):  l   编程式的事务管理  编程式的事务管理可以清楚地控制事务的边界,也就是让您自行实现事务开始时间、撤消操作的时机、结束时间等,可以实现细粒度的事务控制。  l   声明式的事务管理  然而多数的情况下,事务并不需要细粒度的控制,而是采用声明式的事务管理,好处是Spring事务管理的相关API可以不用介入程序之中,从对象的角度来看,它并不知道自己正被纳入事务管理之中,在不需要事务管理的时候,只要在设置文件上修改一下设置,即可移去事务管理服务。  5.3.2  JDBC编程事务管理  Spring提供两种方式实现编程式的事务管理,一是直接使用PlatformTransaction- Manager实现,二是使用org.springframework.transaction.support.Transaction- Template。  先来看看如何使用PlatformTransactionManager,在这里使用它的实现类DataSourceTransactionManager,可以改写一下之前5.2.1节中的JdbcTemplateDemo项目,让它具有事务管理功能,修改一下UserDAO类的insert() 方法来作示范:  ProgrammaticTransactionDemo   UserDAO.java  Java代码  1. package onlyfun.caterpillar;   2.    3. import java.util.Iterator;   4.    5. import java.util.List;   6.    7. import java.util.Map;   8.    9. import javax.sql.DataSource;   10.    11. import org.springframework.dao.DataAccessException;   12.    13. import org.springframework.jdbc.core.JdbcTemplate;   14.    15. import org.springframework.jdbc.   16.    17.             datasource.DataSourceTransactionManager;   18.    19. import org.springframework.transaction.TransactionDefinition;   20.    21. import org.springframework.transaction.TransactionStatus;   22.    23. import org.springframework.transaction.   24.    25.             support.DefaultTransactionDefinition;   26.    27. public class UserDAO implements IUserDAO {   28.    29.     private DataSourceTransactionManager transactionManager;   30.    31.     private DefaultTransactionDefinition def;   32.    33.     private JdbcTemplate jdbcTemplate;   34.    35.        36.    37.     public void setDataSource(DataSource dataSource) {   38.    39.         jdbcTemplate = new JdbcTemplate(dataSource);   40.    41.         transactionManager =    42.    43.             new DataSourceTransactionManager(dataSource);   44.    45.         // 建立事务的定义   46.    47.         def = new DefaultTransactionDefinition();   48.    49.         def.setPropagationBehavior(   50.    51.                 TransactionDefinition.PROPAGATION_REQUIRED);   52.    53.     }   54.    55.        56.    57.     public void insert(User user) {   58.    59.        String name = user.getName();   60.    61.        int age = user.getAge().intValue();   62.    63.           64.    65.        TransactionStatus status =    66.    67.            transactionManager.getTransaction(def);   68.    69.        try {   70.    71.            jdbcTemplate.update("INSERT INTO user (name,age) "    72.    73.                    + "VALUES('" + name + "'," + age + ")");   74.    75.            // 下面的SQL有错误,用以测试事务   76.    77.            jdbcTemplate.update("INSER INTO user (name,age) "    78.    79.                    + "VALUES('" + name + "'," + age + ")");   80.    81.        }   82.    83.        catch(DataAccessException e) {   84.    85.            transactionManager.rollback(status);   86.    87.            throw e;    88.    89.        }   90.    91.        transactionManager.commit(status);   92.    93.     }   94.    95.     public User find(Integer id) {   96.    97.         List rows = jdbcTemplate.queryForList(   98.    99.           "SELECT * FROM user WHERE id=" + id.intValue());   100.    101.            102.    103.         Iterator it = rows.iterator();   104.    105.         if(it.hasNext()) {   106.    107.             Map userMap = (Map) it.next();   108.    109.             Integer i = new Integer(   110.    111.                     userMap.get("id").toString());   112.    113.             String name = userMap.get("name").toString();   114.    115.             Integer age = new Integer(   116.    117.                     userMap.get("age").toString());   118.    119.             User user = new User();   120.    121.                122.    123.             user.setId(i);   124.    125.             user.setName(name);   126.    127.             user.setAge(age);   128.    129.                130.    131.             return user;   132.    133.         }   134.    135.         return null;   136.    137.     }   138.    139. }   在insert()方法中使用了DataSourceTransactionManager来进行事务管理,如果发生了异常,则catch区块中会进行事务的Rollback,在insert() 方法中故意写入错误的SQL(注意INSERT方法少写了一个T),因此实际上数据并不会被储存至数据库中。  要使用MySQL数据库进行事务处理,必须建立支持事务的表格类型,例如InnoDB的表格类型,这里用来建立表格的SQL如下所示:  Java代码  1.  CREATE TABLE user (   2.    3.     id INT(11) NOT NULL auto_increment PRIMARY KEY,   4.    5.     name VARCHAR(100) NOT NULL default '',   6.    7.     age INT   8.    9. ) TYPE = InnoDB;   另一个实现编程式事务管理的方法是使用TransactionTemplate,它需要一个TransactionManager实例,如下所示:  ...  Java代码  1. TransactionTemplate transactionTemplate =    2.    3.         new TransactionTemplate(transactionManager);   4.    5. ...   6.    7. transactionTemplate.execute(new TransactionCallback() {   8.    9.     public Object doInTransaction(TransactionStatus status) {   10.    11.          return jdbcTemplate.update("INSERT INTO user (name,age) "    12.    13.                + "VALUES('" + name + "'," + age + ")");   14.    15.     }   16.    17. });   如果发生了异常,则会进行Rollback,否则提交事务,如果没有回传值,则也可以使用TransactionCallbackWithoutResult:  ...  Java代码  1. transactionTemplate.execute(   2.    3.         new TransactionCallbackWithoutResult() {   4.    5.                 public void doInTransactionWithoutResult(   6.    7.                                 TransactionStatus status) {   8.    9.             .        ...   10.    11.                 }   12.    13.             });   5.3.3  JDBC声明事务管理  Spring声明式的事务管理依赖它的AOP框架来完成。使用声明事务管理的好处是,事务管理不能侵入您所开发的组件,具体来说,DAO对象不会意识到正在事务管理之中,事实上也应当如此,因为事务管理是属于系统层面的服务,而不是业务逻辑的一部分,如果想要改变事务管理策略的话,也只需要在定义文件中重新配置。  举个例子来说,可以将5.2.1节中的JdbcTemplateDemo项目修改一下,在不修改UserDAO类的情况下,可以为它加入事务管理的服务,一个简单的方法是使用TransactionProxyFactoryBean,指定要介入的事务管理对象及其方法,这需要在定义文件中修改,如下所示:  DeclarativeTransactionDemo  beans-config.xml  Java代码  1.     2.    3.    10.    11.      12.    13.          20.    21.             24.    25.            28.    29.             30.    31.             32.    33.         34.    35.        36.    37.         42.    43.             44.    45.         46.    47.        48.    49.        52.    53.            54.    55.        56.    57.        58.    59.         64.    65.             66.    67.                68.    69.                 onlyfun.caterpillar.IUserDAO   70.    71.                72.    73.             74.    75.             76.    77.             80.    81.             82.    83.                 84.    85.                 PROPAGATION_REQUIRED    86.    87.                 88.    89.                    90.    91.            92.    93.    TransactionProxyFactoryBean需要一个TransactionManager,由于这里使用的是JDBC,所以使用DataSourceTransactionManager,TransactionProxyFactoryBean是个代理对象,"target" 属性指定要代理的对象,事务管理会自动介入指定的方法前后,这里使用 "transactionAttributes" 属性指定,"insert*" 表示指定方法名称以insert开头的都要纳入事务管理,您也可以指定方法全名,如果在方法执行过程中发生错误,则所有先前的操作自动撤回,否则正常提交。  在"insert*" 等方法上指定了 "PROPAGATION_REQUIRED",表示在目前的事务中执行操作,如果事务不存在就建立一个新的,相关的常数意义都可以在API文件的TransactionDefinition接口中找到。您可以加上多个事务定义,中间使用逗号 "," 区隔,例如可以加上只读,或者是指定某个异常发生时撤回操作:  PROPAGATION_REQUIRED,readOnly,-MyCheckedException  MyCheckedException前面加上 "-" 时,表示发生指定异常时撤消操作,如果前面加上 "+",表示发生异常时立即提交。  由于"userDAO"被"userDAOProxy"代理了,所以要做的是取得"userDAOProxy",而不是"userDAO",例如:  DeclarativeTransactionDemo  SpringDAODemo.java  Java代码  1. package onlyfun.caterpillar;   2.    3. import org.springframework.context.ApplicationContext;   4.    5. import org.springframework.context.   6.    7.               support.ClassPathXmlApplicationContext;   8.    9. public class SpringDAODemo {   10.    11.     public static void main(String[] args) {   12.    13.         ApplicationContext context =    14.    15.             new ClassPathXmlApplicationContext(   16.    17.                     "beans-config.xml");   18.    19.            20.    21.         User user = new User();   22.    23.            24.    25.         user.setName("caterpillar");   26.    27.         user.setAge(new Integer(30));   28.    29.            30.    31.         IUserDAO userDAO =    32.    33.             (IUserDAO) context.getBean("userDAOProxy");   34.    35.            36.    37.         userDAO.insert(user);   38.    39.            40.    41.         user = userDAO.find(new Integer(1));   42.    43.            44.    45.         System.out.println("name: " + user.getName());   46.    47.     }   48.    49. }    您也可以设置不同的TransactionInterceptor来得到更多的管理细节,例如:  Java代码  1.     2.    3.    10.    11.      12.    13.          20.    21.             24.    25.            28.    29.             30.    31.             32.    33.        34.    35.         40.    41.             42.    43.         44.    45.        46.    47.        50.    51.            52.    53.        54.    55.         60.    61.             62.    63.             68.    69.             70.    71.        72.    73.         78.    79.             80.    81.                82.    83.                 onlyfun.caterpillar.IUserDAO   84.    85.                86.    87.             88.    89.             90.    91.            92.    93.                94.    95.                 transactionInterceptor    96.    97.                98.    99.             100.    101.           102.    103.    即使后来不再需要事务管理,也可以直接在Bean定义文件中修改配置,而不用修改程序重新进行编译等动作。  声明事务管理是利用Spring AOP来达成的,所以执行以上的程序时,请记得您的Classpath设置中必须包括spring-aop.jar。  5.3.4  事务的属性介绍  Spring使用AOP来完成声明式的事务管理,因而声明式事务是以方法为边界的,Spring的事务属性(Transaction attribute)自然就在于描述事务应用至方法上的策略,在Spring中事务属性分作以下的几个参数:  l   传播行为(Propagation behavior)  传播行为定义了事务应用于方法上之边界(Boundaries),它告知何时该开始一个新的事务,或何时事务该被暂停,或方法是否要在事务中进行。  Spring定义了几个传播行为,可以在TransactionDefinition的API文件说明上找到相对应的常数与说明,以下列出几个:  表5.1  事务传播行为说明  传播行为                                            说明  PROPAGATION_MANDATORY         方法必须在一个现存的事务中进行,否则丢出异常  PROPAGATION_NESTED            在一个嵌入的事务中进行,如果不是,则同PROPAGATION_REQUIRED  PROPAGATION_NEVER             指出不应在事务中进行,如果有就丢出异常  PROPAGATION_NOT_SUPPORTED     指出不应在事务中进行,如果有就暂停现存的事务  PROPAGATION_REQUIRED          支持现在的事务,如果没有就建立一个新的事务  PROPAGATION_REQUIRES_NEW      建立一个新的事务,如果现存一个事务就暂停它  PROPAGATION_SUPPORTS          支持现在的事务,如果没有就以非事务的方式执行  举个例子来说,如果传播行为被声明为PROPAGATION_REQUIRED,则事务的边界在开始第一个事务的方法呼叫及结束时,如果先前没有事务被开始,则事务边界即为目前方法的执行前后。又如果传播行为被声明为PROPAGATION_REQUIRES_NEW,则事务的边界即为该方法执行的前后。  l   隔离层级(Isolation level)  在一个应用程序中,可能有多个事务同时在进行,这些事务应当彼此之间互相不知道另一个事务的存在,好比现在整个应用程序就只有一个事务存在,由于事务彼此之间独立,若读取的是同一个数据的话,就容易发生问题,例如:  n  Dirty read  某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个Roll back了操作,则后一个事务所读取的数据就会是不正确的。  n  Non-repeatable read  在一个事务的两次查询之中数据不一致,这可能是因为两次查询过程中间插入了一个事务更新的原有的数据。  n  Phantom read  在一个事务的两次查询中数据笔数不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。  为了避免以上问题的方法之一,需要在某个事务进行过程中锁定正在更新或查询的数据字段,直到目前的事务完成,然而完全锁定字段时,若另一个事务来查询同一份数据就必须等待,直到前一个事务完成并解除锁定为止,因而会造成应用程序在查询或更新数据时效率上的问题,而事实上根据需求的不同,并不用在事务进行时完全地锁定数据,隔离层级可以让您根据实际的需求,对数据的锁定进行设置。  Spring提供了几种隔离层级设置,同类型的设置可以在TransactionDefinition的API文件说明上找到相对应的常数与说明,以下列出几个:  表5.2  事务隔离层级说明          隔离层级                                      说明  ISOLATION_DEFAULT           使用底层数据库预设的隔离层级  ISOLATION_READ_COMMITTED    允许事务读取其他并行的事务已经送出(Commit)的                                   数据字段,可以防止Dirty read问题  ISOLATION_READ_UNCOMMITTED   允许事务读取其他并行的事务还没送出的数据,会发                                   生Dirty、Nonrepeatable、Phantom read等问题  续表            隔离层级                                    说明  ISOLATION_REPEATABLE_READ      要求多次读取的数据必须相同,除非事务本身更新                                     数据,可防止Dirty、Nonrepeatable read问题  ISOLATION_SERIALIZABLE         完整的隔离层级,可防止Dirty、Nonrepeatabl                                 e、Phantom read等问题,会锁定对应的数据表                                      格,因而有效率问题  l   只读提示(Read-only hints)  如果事务只进行读取的动作,则可以利用底层数据库在只读操作时发生的一些最佳化动作,由于这个动作利用到数据库在只读的事务操作最佳化,因而必须在事务中才有效,也就是说要搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。  l   事务超时期间(The transaction timeout period)  有的事务操作可能延续很长一段的时间,事务本身可能关联到数据表格的锁定,因而长时间的事务操作会有效率上的问题,对于过长的事务操作,您要考虑Roll back事务并要求重新操作,而不是无限时的等待事务完成。  您可以设置事务超时期间,计时是从事务开始时,所以这个设置必须搭配传播行为PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED来设置。  5.3.5  TransactionAttributeSource、TransactionAttribute  在TransactionProxyFactoryBean上有setTransactionAttributeSource()与setTransaction Attributes()方法,它们是用来设置事务属性的策略实例。  org.springframework.transaction.interceptor.TransactionAttributeSource接口上有一个getTransactionAttribute() 方法,您可以根据传递给它的Method实例与Class实例,决定该回传一个什么内容的org.springframework.transaction. interceptor.TransactionAttribute实例,一个最简单的TransactionAttributeSource实现是org.springframework.transaction.interceptor.MatchAlwaysTransaction- AttributeSource,对于每一个方法执行都会应用事务,它回传的TransactionAttribute实例的默认传播行为是PROPAGATION_REQUIRED,隔离层级为ISOLATION_DEFAULE。  一个应用的例子如下所示:  ...  Java代码  1.    6.    7.    12.    13.        14.    15.            16.    17.             onlyfun.caterpillar.IUserDAO   18.    19.            20.    21.        22.    23.        24.    25.        26.    27.        30.    31.    ...  您可以使用org.springframework.transaction.interceptor.DefaultTransaction- Attribute,并设置自己的事务策略,之后设置给TransactionAttributeSource,例如:  ...  Java代码  1.    6.    7.        10.    11.        14.    15.    16.    17.    22.    23.        26.    27.    28.    29.    34.    35.        36.    37.            38.    39.             onlyfun.caterpillar.IUserDAO   40.    41.            42.    43.        44.    45.        46.    47.        48.    49.        52.    53.    ...  可以使用org.springframework.transaction.interceptor.NameMatchTransaction- AttributeSource来指定某些方法要应用事务,以及要应用的事务策略,例如:  ...  Java代码  1.    6.    7.        8.    9.            10.    11.             PROPAGATION_REQUIRES_NEW   12.    13.            14.    15.        16.    17.    18.    19.    24.    25.        26.    27.            28.    29.             onlyfun.caterpillar.IUserDAO   30.    31.            32.    33.        34.    35.        36.    37.        38.    39.        42.    43.    ...  在NameMatchTransactionAttributeSource的 "properties"属性上,可以指定方法名称与事务策略,方法名称的指定可以指定全名,也可以使用Wildcard来指定,例如上面的指定中,只要方法名称以insert为开头的都会应用相对应的事务策略。  在指定事务策略时,指定的格式如下:  传播行为,隔离层级,只读,+异常, -异常  除了传播行为一定要设置之外,其他都可选择性的设置,中间以逗号区隔,例如:  PROPAGATION_REQUIRED,readOnly,-MyCheckedException  MyCheckedException前面加上 "-" 时,表示发生指定异常时撤消操作,如果前面加上 "+",表示发生异常时立即提交。  在比较简单的设置中,可以仅设置TransactionProxyFactoryBean,并在它的 "transactionAttributes" 属性上直接设置要应用事务的方法及事务策略,例如:  ...  Java代码  1.    6.    7.        8.    9.            10.    11.             onlyfun.caterpillar.IUserDAO   12.    13.            14.    15.        16.    17.        18.    19.        20.    21.        22.    23.            24.    25.             PROPAGATION_REQUIRED   26.    27.            28.    29.        30.    31.    ...  甚至也可以直接指定TransactionInterceptor,以获得更多的控制,例如:  ...  Java代码  1.    6.    7.        8.    9.               ref="transactionManager"/>   10.    11.        14.    15.    16.    17.    22.    23.        24.    25.            26.    27.             onlyfun.caterpillar.IUserDAO   28.    29.            30.    31.        32.    33.        34.    35.        36.    37.    ...  选择哪一种设置方式是需求的问题,您可以尝试在DeclarativeTransactionDemo项目的Bean定义文件上设置以上所介绍的方式,基于篇幅的限制,以上仅列出部分的设置内容。  5.3.6  Spring 2.0声明式事务管理:基于XML Schmea  在Spring 2.0中要设置声明式事务管理,可以依赖于Spring 2.0的标签,因而要记得加入相关的名称空间声明:  Java代码  1.     2.    3.    22.    23.     …    24.    25.    事务是系统层面的服务,也就是一个Aspect,其实具体来说就是一个Advice,您可以使用标签来提供这个Advice,它需要设置一个TransactionManager,并在当中使用来设置事务相关属性。  可以将先前的DeclarativeTransactionDemo项目改写,修改其beans-config.xml为使用标签的方式:  DeclarativeTransactionDemo2  beans-config.xml  Java代码  1.     2.    3.    22.    23.      24.    25.          32.    33.             36.    37.            40.    41.             42.    43.             44.    45.         46.    47.        48.    49.         54.    55.             56.    57.         58.    59.        60.    61.        64.    65.            66.    67.        68.    69.        70.    71.        74.    75.            76.    77.                78.    79.                80.    81.            82.    83.        84.    85.      86.    87.        88.    89.            92.    93.            96.    97.        98.    99.    注意到中的属性设置,对于传播行为、隔离层级、只读、超时、异常时撤回或提交,都有对应的"propagation"、"isolation"、"timeout"、"read-only"、"rollback-for"、"no-rollback-for"属性可以设置,若不设置,"propagation"属性默认是"REQUIRE","isolation"属性默认是"DEFAULT"、"timeout"属性默认是"-1"(单位是秒)、"read-only"属性默认是"false"。  与先前介绍Spring 2.0基于XML Schema的AOP设置相同,由于不再于设置文件中设置代理对象,所以直接取得"userDAO"实例进行操作即可。  5.3.7  Spring 2.0声明式事务管理:基于Annotation  声明式事务管理在Spring 2.0中,也支持使用Annotation的标示方式,方法是使用@Transactional来标示,例如可以将DeclarativeTransactionDemo项目的UserDAO改写,在上头直接标示@Transactional,并设置相关属性:  DeclarativeTransactionDemo3 UserDAO.java  Java代码  1. package onlyfun.caterpillar;   2.    3. import java.util.Iterator;   4.    5. import java.util.List;   6.    7. import java.util.Map;   8.    9. import javax.sql.DataSource;   10.    11. import org.springframework.jdbc.core.JdbcTemplate;   12.    13. import org.springframework.transaction.annotation.Propagation;   14.    15. import org.springframework.transaction.annotation.Transactional;   16.    17. public class UserDAO implements IUserDAO {   18.    19.     private JdbcTemplate jdbcTemplate;    20.    21.     public void setDataSource(DataSource dataSource) {   22.    23.         jdbcTemplate = new JdbcTemplate(dataSource);   24.    25.     }   26.    27.     @Transactional(propagation = Propagation.REQUIRED)   28.    29.     public void insert(User user) {   30.    31.        String name = user.getName();   32.    33.        int age = user.getAge().intValue();   34.    35.           36.    37.        jdbcTemplate.update("INSERT INTO user (name,age) "    38.    39.                + "VALUES('" + name + "'," + age + ")");   40.    41.     }   42.    43.        44.    45.     @Transactional(readOnly=true)   46.    47.     public User find(Integer id) {   48.    49.         List rows = jdbcTemplate.queryForList(   50.    51.           "SELECT * FROM user WHERE id=" + id.intValue());   52.    53.            54.    55.         Iterator it = rows.iterator();   56.    57.         if(it.hasNext()) {   58.    59.             Map userMap = (Map) it.next();   60.    61.             Integer i = new Integer(userMap.get("id").toString());   62.    63.             String name = userMap.get("name").toString();   64.    65.             Integer age =    66.    67.                   new Integer(userMap.get("age").toString());   68.    69.             User user = new User();   70.    71.             user.setId(i);   72.    73.             user.setName(name);   74.    75.             user.setAge(age);   76.    77.                78.    79.             return user;   80.    81.         }   82.    83.         return null;   84.    85.     }   86.    87. }   在使用@Transactional时,相关的属性设置为"propagation"、"isolation"、"readOnly"、"timeout"、"rollbackFor"、"noRollbackFor"等,而在beans-config.xml中,则要使用标签,并指定TransactionManager,例如:  DeclarativeTransactionDemo3  beans-config.xml  Java代码  1.     2.    3.    16.    17.      18.    19.          26.    27.             30.    31.            34.    35.             36.    37.             38.    39.         40.    41.        42.    43.         48.    49.             50.    51.         52.    53.        54.    55.        58.    59.            60.    61.        62.    63.        64.    65.        66.    67.    同样的,由于不再于设置文件中设置代理对象,所以直接取得"userDAO"实例进行操作即可

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享文档获得金币 ] 6 人已下载

下载文档