栏目导航
热点推荐
- 三十条有用的 Java 编程规则
- Java制作水印图片源码
- Java常见异常及可能的导致原因
- Java中的修饰词使用方法总结
- J2EE系统异常的处理准则
- Java中的异常、断言、日志解析(
- Java面试技巧:Java面试题集锦(
- 面向Java开发人员的Scala指南:
- Java程序员:一刻钟精通正则表达
- 网友经验分享:学好java开发的关
- 专家解答:创建表格与数据库进行
- Java远程访问Domino数据库
阅览排行
Spring 事务管理高级应用难点剖析: 第 1 部分
www.jz123.cn 2010-04-02 来源: 中国建站 责任编辑(袁袁) 我要投递新闻
Spring 最成功,最吸引人的地方莫过于轻量级的声明式事务管理,仅此一点,它就宣告了重量级 EJB 容器的覆灭。Spring 声明式事务管理将开发者从繁复的事务管理代码中解脱出来,专注于业务逻辑的开发上,这是一件可以被拿来顶礼膜拜的事情。但是,世界并未从此消停,开发人员需要面对的是层出不穷的应用场景,这些场景往往逾越了普通 Spring 技术书籍的理想界定。因此,随着应用开发的深入,在使用经过 Spring 层层封装的声明式事务时,开发人员越来越觉得自己坠入了迷雾,陷入了沼泽,体会不到外界所宣称的那种畅快淋漓。本系列文章的目标旨在整理并剖析实际应用中种种让我们迷茫的场景,让阳光照进云遮雾障的山头。
DAO 和事务管理的牵绊
很少有使用 Spring 但不使用 Spring 事务管理器的应用,因此常常有人会问:是否用了 Spring,就一定要用 Spring 事务管理器,否则就无法进行数据的持久化操作呢?事务管理器和 DAO 是什么关系呢?
也许是 DAO 和事务管理如影随行的缘故吧,这个看似简单的问题实实在在地存在着,从初学者心中涌出,萦绕在开发老手的脑际。答案当然是否定的!我们都知道:事务管理是保证数据操作的事务性(即原子性、一致性、隔离性、持久性,也即所谓的 ACID),脱离了事务性,DAO 照样可以顺利地进行数据的操作。
下面,我们来看一段使用 Spring JDBC 进行数据访问的代码:
清单 1. UserJdbcWithoutTransManagerService.java
package user.withouttm; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.apache.commons.dbcp.BasicDataSource; @Service("service1") public class UserJdbcWithoutTransManagerService { @Autowired private JdbcTemplate jdbcTemplate; public void addScore(String userName,int toAdd){ String sql = "UPDATE t_user u SET u.score = u.score + ? WHERE user_name =?"; jdbcTemplate.update(sql,toAdd,userName); } public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("user/withouttm/jdbcWithoutTransManager.xml"); UserJdbcWithoutTransManagerService service = (UserJdbcWithoutTransManagerService)ctx.getBean("service1"); JdbcTemplate jdbcTemplate = (JdbcTemplate)ctx.getBean("jdbcTemplate"); BasicDataSource basicDataSource = (BasicDataSource)jdbcTemplate.getDataSource(); //①.检查数据源autoCommit的设置 System.out.println("autoCommit:"+ basicDataSource.getDefaultAutoCommit()); //②.插入一条记录,初始分数为10 jdbcTemplate.execute( "INSERT INTO t_user(user_name,password,score) VALUES('tom','123456',10)"); //③.调用工作在无事务环境下的服务类方法,将分数添加20分 service.addScore("tom",20); //④.查看此时用户的分数 int score = jdbcTemplate.queryForInt( "SELECT score FROM t_user WHERE user_name ='tom'"); System.out.println("score:"+score); jdbcTemplate.execute("DELETE FROM t_user WHERE user_name='tom'"); } } |
jdbcWithoutTransManager.xml 的配置文件如下所示:
清单 2. jdbcWithoutTransManager.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="user.withouttm"/> <!-- 数据源默认将autoCommit设置为true --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="oracle.jdbc.driver.OracleDriver" p:url="jdbc:oracle:thin:@localhost:1521:orcl" p:username="test" p:password="test"/> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource"/> </beans> |
运行 UserJdbcWithoutTransManagerService,在控制台上打出如下的结果:
defaultAutoCommit:true
score:30
在 jdbcWithoutTransManager.xml 中,没有配置任何事务管理器,但是数据已经成功持久化到数据库中。在默认情况下,dataSource 数据源的 autoCommit 被设置为 true ?? 这也意谓着所有通过 JdbcTemplate 执行的语句马上提交,没有事务。如果将 dataSource 的 defaultAutoCommit 设置为 false,再次运行 UserJdbcWithoutTransManagerService,将抛出错误,原因是新增及更改数据的操作都没有提交到数据库,所以 ④ 处的语句因无法从数据库中查询到匹配的记录而引发异常。
对于强调读速度的应用,数据库本身可能就不支持事务,如使用 MyISAM 引擎的 MySQL 数据库。这时,无须在 Spring 应用中配置事务管理器,因为即使配置了,也是没有实际用处的。
不过,对于 Hibernate 来说,情况就有点复杂了。因为 Hibernate 的事务管理拥有其自身的意义,它和 Hibernate 一级缓存有密切的关系:当我们调用 Session 的 save、update 等方法时,Hibernate 并不直接向数据库发送 SQL 语句,而是在提交事务(commit)或 flush 一级缓存时才真正向数据库发送 SQL。所以,即使底层数据库不支持事务,Hibernate 的事务管理也是有一定好处的,不会对数据操作的效率造成负面影响。所以,如果是使用 Hibernate 数据访问技术,没有理由不配置 HibernateTransactionManager 事务管理器。
但是,不使用 Hibernate 事务管理器,在 Spring 中,Hibernate 照样也可以工作,来看下面的例子:
清单 3.UserHibernateWithoutTransManagerService.java
package user.withouttm; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.orm.hibernate3.HibernateTemplate; import org.apache.commons.dbcp.BasicDataSource; import user.User; @Service("service2") public class UserHibernateWithoutTransManagerService { @Autowired private HibernateTemplate hibernateTemplate; public void addScore(String userName,int toAdd){ User user = (User)hibernateTemplate.get(User.class,userName); user.setScore(user.getScore()+toAdd); hibernateTemplate.update(user); } public static void main(String[] args) { //参考UserJdbcWithoutTransManagerService相应代码 … } } |
此时,采用 hiberWithoutTransManager.xml 的配置文件,其配置内容如下:
清单 4.hiberWithoutTransManager.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" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!--省略掉包扫描,数据源,JdbcTemplate配置部分,参见jdbcWithoutTransManager.xml --> … <bean id="sessionFactory" class= "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" p:dataSource-ref="dataSource"> <property name="annotatedClasses"> <list> <value>user.User</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect"> org.hibernate.dialect.Oracle10gDialect </prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate" p:sessionFactory-ref="sessionFactory"/> </beans> |
运行 UserHibernateWithoutTransManagerService,程序正确执行,并得到类似于 UserJdbcWithoutTransManagerService 的执行结果,这说明 Hibernate 在 Spring 中,在没有事务管理器的情况下,依然可以正常地进行数据的访问。
上一篇:JAVA的字符串拼接与性能 下一篇:Spring 事务管理高级应用难点剖析: 第 2 部分