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

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

[b] [size=large]JDBC访问数据库[/size][/b]

下面,我们来看一段使用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" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}"/>

<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
p:dataSource-ref="dataSource"/>
</beans>

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

[b][size=large]Hibernate访问数据库[/size][/b]

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

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"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="dataSource">
<property name="annotatedClasses">
<list>
<value>com.baobaotao.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</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>

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

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中,在没有事务管理器的情况下,依然可以正常地进行数据的访问。

[color=red][b] 注:以上内容摘自《Spring 4.x企业应用开发实战》 [/b][/color]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值