Spring的事务管理难点剖析(1):DAO和事务管理的牵绊
有些人很少使用Spring而不使用Spring事务管理器的应用,因此常常有人会问:是否用了Spring,就一定要用Spring事务管理器,否则就无法进行数据的持久化操作呢?事务管理器和DAO是什么关系呢?
也许是DAO和事务管理如影随行的缘故吧,这个看似简单的问题实实在在地存在着,从初学者心中涌出,萦绕在老手的脑际。答案当然是否定的!我们都知道:事务管理是保证数据操作的事务性(即原子性、一致性、隔离性、持久性,即所谓的ACID),脱离了事务性,DAO照样可以顺利地进行数据的操作。
JDBC访问数据库
下面,我们来看一段使用Spring JDBC进行数据访问的代码:
package com.baobaotao.withouttx.jdbc;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("userService")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("com/baobaotao/withouttx/jdbc/jdbcWithoutTx.xml"); UserJdbcWithoutTransManagerService service = (UserJdbcWithoutTransManagerService)ctx.getBean("userService"); 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,last_logon_time) VALUES('tom','123456',10,"+System.currentTimeMillis()+")"); //③调用工作在无事务环境下的服务类方法,将分数添加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'"); }} 其中,jdbcWithoutTx.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="com.baobaotao.withouttx.jdbc"/> <context:property-placeholder location="classpath:jdbc.properties"/> <bean id="dataSource" p:driverClassName="${jdbc.driverClassName}"p:url="${jdbc.url}" p:username="${jdbc.username}"p:password="${jdbc.password}"/> <bean id="jdbcTemplate" name="code">package com.baobaotao.withouttx.hiber;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.ClassPathResource;import org.springframework.core.io.Resource;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;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 org.springframework.test.jdbc.SimpleJdbcTestUtils;import com.baobaotao.User;@Service("hiberService")public class UserHibernateWithoutTransManagerService { @Autowired private HibernateTemplate hibernateTemplate; public void addScore(String userName,int toAdd){ User user = hibernateTemplate.get(User.class,userName); user.setScore(user.getScore()+toAdd); hibernateTemplate.update(user); } public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("com/baobaotao/withouttx/hiber/hiberWithoutTx.xml"); UserHibernateWithoutTransManagerService service = (UserHibernateWithoutTransManagerService)ctx.getBean("hiberService"); 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,last_logon_time) VALUES('tom','123456',10,"+System.currentTimeMillis()+")"); //③调用工作在无事务环境下的服务类方法,将分数添加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'"); }}此时,采用hiberWithoutTx.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="com.baobaotao.withouttx.hiber"/> … <bean id="sessionFactory" name="code">package com.baobaotao;import javax.persistence.Entity;import javax.persistence.Table;import javax.persistence.Column;import javax.persistence.Id;import java.lang.reflect.Field;import java.io.Serializable;@Entity@Table(name="T_USER")public class User implements Serializable{ @Id @Column(name = "USER_NAME") private String userName; private String password; private int score; @Column(name = "LAST_LOGON_TIME") private long lastLogonTime = 0; …}运行UserHibernateWithoutTransManagerService,程序正确执行,并得到类似于UserJdbcWithoutTransManagerService的执行结果。这说明Hibernate在Spring中,在没有事务管理器的情况下,依然可以正常地进行数据的访问。
注:以上内容摘自《Spring 3.x企业应用开发实战》
Hibernate自身具备一个缺省的事务管理,只要用到了SessionFactory,也就意味着使用了这个事务控制。
有些人是这样配置的:
<bean id="transactionManager" ref="sessionFactory"/>
</bean>
其实,无需任何配置即可自动开启事务控制。
作者认同否?
--------------------------------------------------
此外,我建议使用以下配置:
<property name="packagesToScan">
<list>
<value>com.baobaotao</value>
</list>
</property>
这样也就无需一个个配置Entity类了。
最好把Entity集中放在一个目录中,这样就更好了。 3 楼 wzg1101 2012-06-11 文章写的很不错,不知楼主可不可以发一个多数据源的解决方案呢,网上看到的几种解决方案感觉都不是很好