[转]Spring的事务管理难点剖析(1):DAO和事务管理的牵绊


原文地址:http://stamen.iteye.com/blog/1441758

有些人很少使用Spring而不使用Spring事务管理器的应用,因此常常有人会问:是否用了Spring,就一定要用Spring事务管理器,否则就无法进行数据的持久化操作呢?事务管理器和DAO是什么关系呢?
也许是DAO和事务管理如影随行的缘故吧,这个看似简单的问题实实在在地存在着,从初学者心中涌出,萦绕在老手的脑际。答案当然是否定的!我们都知道:事 务管理是保证数据操作的事务性(即原子性、一致性、隔离性、持久性,即所谓的ACID),脱离了事务性,DAO照样可以顺利地进行数据的操作。

JDBC访问数据库

下面,我们来看一段使用Spring JDBC进行数据访问的代码:

Java代码
  1. packagecom.baobaotao.withouttx.jdbc;
  2. importorg.springframework.beans.factory.annotation.Autowired;
  3. importorg.springframework.jdbc.core.JdbcTemplate;
  4. importorg.springframework.stereotype.Service;
  5. importorg.springframework.context.ApplicationContext;
  6. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  7. importorg.apache.commons.dbcp.BasicDataSource;
  8. @Service("userService")
  9. publicclassUserJdbcWithoutTransManagerService{
  10. @Autowired
  11. privateJdbcTemplatejdbcTemplate;
  12. publicvoidaddScore(StringuserName,inttoAdd){
  13. Stringsql="UPDATEt_useruSETu.score=u.score+?WHEREuser_name=?";
  14. jdbcTemplate.update(sql,toAdd,userName);
  15. }
  16. publicstaticvoidmain(String[]args){
  17. ApplicationContextctx=new
  18. ClassPathXmlApplicationContext("com/baobaotao/withouttx/jdbc/jdbcWithoutTx.xml");
  19. UserJdbcWithoutTransManagerServiceservice=
  20. (UserJdbcWithoutTransManagerService)ctx.getBean("userService");
  21. JdbcTemplatejdbcTemplate=(JdbcTemplate)ctx.getBean("jdbcTemplate");
  22. BasicDataSourcebasicDataSource=(BasicDataSource)jdbcTemplate.getDataSource();
  23. //①检查数据源autoCommit的设置
  24. System.out.println("autoCommit:"+basicDataSource.getDefaultAutoCommit());
  25. //②插入一条记录,初始分数为10
  26. jdbcTemplate.execute("INSERTINTOt_user(user_name,password,score,last_logon_time)
  27. VALUES('tom','123456',10,"+System.currentTimeMillis()+")");
  28. //③调用工作在无事务环境下的服务类方法,将分数添加20分
  29. service.addScore("tom",20);
  30. //④查看此时用户的分数
  31. intscore=jdbcTemplate.queryForInt(
  32. "SELECTscoreFROMt_userWHEREuser_name='tom'");
  33. System.out.println("score:"+score);
  34. jdbcTemplate.execute("DELETEFROMt_userWHEREuser_name='tom'");
  35. }
  36. }


其中,jdbcWithoutTx.xml的配置文件如下所示:

Xml代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd">
  8. <context:component-scanbase-package="com.baobaotao.withouttx.jdbc"/>
  9. <context:property-placeholderlocation="classpath:jdbc.properties"/>
  10. <beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"
  11. destroy-method="close"
  12. p:driverClassName="${jdbc.driverClassName}"
  13. p:url="${jdbc.url}"
  14. p:username="${jdbc.username}"
  15. p:password="${jdbc.password}"/>
  16. <beanid="jdbcTemplate"class="org.springframework.jdbc.core.JdbcTemplate"
  17. p:dataSource-ref="dataSource"/>
  18. </beans>


运行UserJdbcWithoutTransManagerService,在控制台上打出如下的结果:

引用

defaultAutoCommit:true
score:30


在jdbcWithoutTx.xml中,没有配置任何事务管理器,但是数据已经成功持久化到数据库中。在默认情况下,dataSource数据源的 autoCommit被设置为true——这也意谓着所有通过JdbcTemplate执行的语句马上提交,没有事务。如果将dataSource的 defaultAutoCommit设置为false,再次运行UserJdbcWithoutTransManagerService,将抛出错误,原 因是新增及更改数据的操作都没有提交到数据库,所以代码清单10-1④处的语句因无法从数据库中查询到匹配的记录而引发异常。
对于强调读速度的应用,数据库本身可能就不支持事务:如使用MyISAM引擎的MySQL数据库。这时,无须在Spring应用中配置事务管理器,因为即使配置了,也是没有实际用处的。

Hibernate访问数据库

对于Hibernate来说,情况就有点复杂了。因为Hibernate的事务管理拥有其自身的意义,它和Hibernate一级缓存在密切的关系:当我 们调用Session的save、update等方法时,Hibernate并不直接向数据库发送SQL语句,只在提交事务(commit)或flush 一级缓存时才真正向数据库发送SQL。所以,即使底层数据库不支持事务,Hibernate的事务管理也是有一定好处的,不会对数据操作的效率造成负面影 响。所以,如果是使用Hibernate数据访问技术,没有理由不配置HibernateTransactionManager事务管理器。
但是,不使用Hibernate事务管理器,在Spring中,Hibernate照样也可以工作,来看下面的例子:

Java代码
  1. packagecom.baobaotao.withouttx.hiber;
  2. importorg.springframework.beans.factory.annotation.Autowired;
  3. importorg.springframework.core.io.ClassPathResource;
  4. importorg.springframework.core.io.Resource;
  5. importorg.springframework.jdbc.core.JdbcTemplate;
  6. importorg.springframework.jdbc.core.simple.SimpleJdbcTemplate;
  7. importorg.springframework.stereotype.Service;
  8. importorg.springframework.context.ApplicationContext;
  9. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  10. importorg.springframework.orm.hibernate3.HibernateTemplate;
  11. importorg.apache.commons.dbcp.BasicDataSource;
  12. importorg.springframework.test.jdbc.SimpleJdbcTestUtils;
  13. importcom.baobaotao.User;
  14. @Service("hiberService")
  15. publicclassUserHibernateWithoutTransManagerService{
  16. @Autowired
  17. privateHibernateTemplatehibernateTemplate;
  18. publicvoidaddScore(StringuserName,inttoAdd){
  19. Useruser=hibernateTemplate.get(User.class,userName);
  20. user.setScore(user.getScore()+toAdd);
  21. hibernateTemplate.update(user);
  22. }
  23. publicstaticvoidmain(String[]args){
  24. ApplicationContextctx=new
  25. ClassPathXmlApplicationContext("com/baobaotao/withouttx/hiber/hiberWithoutTx.xml");
  26. UserHibernateWithoutTransManagerServiceservice=
  27. (UserHibernateWithoutTransManagerService)ctx.getBean("hiberService");
  28. JdbcTemplatejdbcTemplate=(JdbcTemplate)ctx.getBean("jdbcTemplate");
  29. BasicDataSourcebasicDataSource=(BasicDataSource)jdbcTemplate.getDataSource();
  30. //①检查数据源autoCommit的设置
  31. System.out.println("autoCommit:"+basicDataSource.getDefaultAutoCommit());
  32. //②插入一条记录,初始分数为10
  33. jdbcTemplate.execute("INSERTINTOt_user(user_name,password,score,last_logon_time)
  34. VALUES('tom','123456',10,"+System.currentTimeMillis()+")");
  35. //③调用工作在无事务环境下的服务类方法,将分数添加20分
  36. service.addScore("tom",20);
  37. //④查看此时用户的分数
  38. intscore=jdbcTemplate.queryForInt(
  39. "SELECTscoreFROMt_userWHEREuser_name='tom'");
  40. System.out.println("score:"+score);
  41. jdbcTemplate.execute("DELETEFROMt_userWHEREuser_name='tom'");
  42. }
  43. }


此时,采用hiberWithoutTx.xml的配置文件,其配置内容如下所示:

Xml代码
  1. <?xmlversion="1.0"encoding="UTF-8"?>
  2. <beansxmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. xmlns:p="http://www.springframework.org/schema/p"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd">
  8. <context:component-scanbase-package="com.baobaotao.withouttx.hiber"/>
  9. <beanid="sessionFactory"
  10. class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
  11. p:dataSource-ref="dataSource">
  12. <propertyname="annotatedClasses">
  13. <list>
  14. <value>com.baobaotao.User</value>
  15. </list>
  16. </property>
  17. <propertyname="hibernateProperties">
  18. <props>
  19. <propkey="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
  20. <propkey="hibernate.show_sql">true</prop>
  21. </props>
  22. </property>
  23. </bean>
  24. <beanid="hibernateTemplate"
  25. class="org.springframework.orm.hibernate3.HibernateTemplate"
  26. p:sessionFactory-ref="sessionFactory"/>
  27. </beans>


com.baobaotao.User是使用了Hibernate注解的领域对象,代码如下所示:

Java代码
  1. packagecom.baobaotao;
  2. importjavax.persistence.Entity;
  3. importjavax.persistence.Table;
  4. importjavax.persistence.Column;
  5. importjavax.persistence.Id;
  6. importjava.lang.reflect.Field;
  7. importjava.io.Serializable;
  8. @Entity
  9. @Table(name="T_USER")
  10. publicclassUserimplementsSerializable{
  11. @Id
  12. @Column(name="USER_NAME")
  13. privateStringuserName;
  14. privateStringpassword;
  15. privateintscore;
  16. @Column(name="LAST_LOGON_TIME")
  17. privatelonglastLogonTime=0;
  18. }


运行UserHibernateWithoutTransManagerService,程序正确执行,并得到类似于 UserJdbcWithoutTransManagerService的执行结果。这说明Hibernate在Spring中,在没有事务管理器的情况 下,依然可以正常地进行数据的访问。

注:以上内容摘自《Spring 3.x企业应用开发实战》

优质内容筛选与推荐>>
1、DNN的数据访问的抽象类
2、hdu 1564
3、MySQL Plugin 'InnoDB' init function returned error
4、asp简单的搜索引擎代码
5、mybatis关系映射之一对多和多对一


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn