现在的位置: 首页 > 综合 > 正文

数据库事务管理

2014年01月09日 ⁄ 综合 ⁄ 共 8078字 ⁄ 字号 评论关闭

最近重新学习了数据库事务管理 纠正了好多错误的观念,下面从数据库事务的概念,JDBC事务,Spring+Hibernate事务管理三部分来介绍。

一.数据库事务的概念

数据库事务是指作为单个逻辑工作单元执行的一系列操作。设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作:  
1更新客户所购商品的库存信息  2保存客户付款信息--可能包括与银行系统的交互  
3生成订单并且保存到数据库中  4更新用户相关信息,例如购物数量等等
正常的情况下,这些操作将顺利进行,最终交易成功,与交易相关的所有数据库信息也成功地更新。但是,如果在这一系列过程中任何一个环节出了差错,例如在更新商品库存信息时发生异常、该顾客银行帐户存款不足等,都将导致交易失败。一旦交易失败,数据库中所有信息都必须保持交易前的状态不变,比如最后一步更新用户信息时失败而导致交易失败,那么必须保证这笔失败的交易不影响数据库的状态--库存信息没有被更新、用户也没有付款,订单也没有生成。否则,数据库的信息将会一片混乱而不可预测。

二.JDBC事务

这里要注意以下几个问题

1.使用con.setAutoCommit(false);更改JDBC事务的默认提交方式,默认为true,一旦关闭了自动提交,除非通过调用 commit() 显式地告诉它提交语句,否则无法提交 SQL 语句(即,数据库将不会被持久地更新)。在提交之前的任何时间,我们都可以调用 rollback() 回滚事务,并恢复最近的提交值(在尝试更新之前)。

2.使用try--catch--finally处理异常,并关闭连接

3.使用commit显式的提交事务,提交之后就无法更改。

使用上述方法可以在事务建立至事务提交之间添加多个SQL,即构成了事务。

public int delete(int sID) {   
 dbc = new DataBaseConnection();   
 Connection con = dbc.getConnection();   
 try {   
con.setAutoCommit(false);// 更改JDBC事务的默认提交方式,默认为true,  
dbc.executeUpdate("delete from bylaw where ID=" + sID);   
dbc.executeUpdate("delete from bylaw _content where ID=" + sID);   
dbc.executeUpdate("delete from bylaw _affix where bylawid=" + sID);   
con.commit();//提交JDBC事务,commit之后就无法从数据库中抹去
con.setAutoCommit(true);// 恢复JDBC事务的默认提交方式   
dbc.close();   
return 1;   
 }   
 catch (Exception exc) {   
con.rollBack();//回滚JDBC事务   
exc.printStackTrace();   
dbc.close();   
return -1;   
 }   
}  

三 spring hibernate整合事务

一个较为典型的Spring 托管hibernate的applicationContext的配置:

<?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:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
	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


http://www.springframework.org/schema/mvc


http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd


http://www.springframework.org/schema/aop


http://www.springframework.org/schema/aop/spring-aop-3.0.xsd


http://www.springframework.org/schema/tx

         http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

	<!-- property configure 获取property配置文件的路径 -->
	<context:property-placeholder
		location="classpath:conf/constant.properties,
	classpath:conf/db.properties,classpath:conf/ctx.properties" />
        <!-- 自动搜索 base-package 的注解配置-->
	<context:component-scan base-package="com"/>
	
	<!-- DataSource 配置数据源-->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="${jdbc.driverClassName}"></property>
		<property name="url" value="${jdbc.url}"></property>
		<property name="username" value="${jdbc.user}"></property>
		<property name="password" value="${jdbc.password}"></property>
		<property name="maxActive" value="200"></property>
		<property name="maxIdle" value="30"></property>
		<property name="maxWait" value="500"></property>
		<property name="defaultAutoCommit" value="true"></property>
	</bean>
	
	<!-- Hibernate Properties -->
	<bean id="hibernateProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="properties">
			<props>
				<prop key="hibernate.dialect">${hibernate.dialect}</prop>
				<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
				<prop key="jdbc.fetch_size">50</prop>
				<prop key="jdbc.batch_size">25</prop>	
				<prop key="hibernate.connection.autocommit">false</prop>	
				<!--
				<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
				 -->
				<prop key="hibernate.query.substitutions">true 1,false 0</prop>
			</props>
		</property>
	</bean>
	
	<!-- SessionFactory 配置 SessionFactory  以便注入-->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		
		<property name="hibernateProperties">
			<ref local="hibernateProperties"/>
		</property>
		
		<property name="mappingResources">
			<list>
				<value>com/amazon/model/User.hbm.xml</value>
			</list>
		</property>
		<!--  <property name="mappingDirectoryLocations">
			<list>
				<value>com/amazon/model/User.hbm.xml</value>
			</list>
		</property>-->
	</bean>
	
	<!-- Transaction Manager 事务管理-->
	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory">
			<ref local="sessionFactory"/>
		</property>
	</bean>
	
	<tx:annotation-driven transaction-manager="transactionManager" />
	<!--  Base Transaction Proxy -->
	<!-- 
	<bean id="baseTxProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
		<property name="transactionManager">
			<ref local="transactionManager"/>
		</property>
		<property name="transactionAttributes">
			<props>
				<prop key="*">PROPAGATION_REQUIRED</prop>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
				<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
			</props>
		</property>
	</bean>
	-->
	
	<!-- views configuration 配置前端视图,可以完成多视图配置-->
	<bean id="freeMarkerConfigurer"
		class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
		<property name="templateLoaderPath" value="/" />
		<property name="freemarkerSettings">
			<props>
				<prop key="locale">zh_cn</prop>
				<prop key="template_update_delay">0</prop>
				<prop key="number_format">0.##########</prop>
				<prop key="defaultEncoding">UTF-8</prop>
				<prop key="auto_include"></prop>
			</props>
		</property>
		<property name="freemarkerVariables">
			<map>
				<entry key="xml_escape" value-ref="fmXmlEscape" />
			</map>
		</property>
	</bean>
	<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape" />
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
		<property name="contentType">
			<value>text/html; charset=UTF-8</value>
		</property>
		<property name="cache" value="true" />
		<property name="prefix" value="/WEB-INF/tmpl/" />
		<property name="suffix" value=".ftl" />
		<property name="exposeSpringMacroHelpers" value="true"></property>
		<property name="exposeRequestAttributes" value="true"></property>
	</bean>
</beans>

Dao的实现

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.amazon.dao.UserDao;
import com.amazon.model.User;

@Repository("userDao")
public class UserDaoImpl implements UserDao{
	 
	@Autowired
	private SessionFactory sessionFactory;
	
	public void getAll() {
		// TODO Auto-generated method stub
	}

	@Override
	public void getById(long id) {
		// TODO Auto-generated method stub
		
	}
	//添加Transactional 才能使用getCurrentSession
	@Transactional
	@Override 
	public void insert(User user) {
		// TODO Auto-generated method stub
		Session session=sessionFactory.getCurrentSession();//openSession();
		session.save(user);
	}

	public void setSesionFactory(SessionFactory sesionFactory) {
		this.sessionFactory = sesionFactory;
	}

	public SessionFactory getSesionFactory() {
		return sessionFactory;
	}
	
}

测试文件

import javax.annotation.Resource;

import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import com.amazon.dao.UserDao;
import com.amazon.model.User;
@Component
public class BaseTest {
	private static  SessionFactory sessionFactory;
	@Resource
	public  void setSessionFactory(SessionFactory sessionFactory) {
		BaseTest.sessionFactory = sessionFactory;
	}
	public  SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
	public static void main(String args[]){
		ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
		System.out.println(sessionFactory);
		UserDao userDao=(UserDao)ctx.getBean("userDao");
		User user=new User();
		user.setUserName("aaa");
		user.setUserStatus("Admin");
		userDao.insert(user);
	}
}

在此要注意openSession和getCurrentSession的区别

1 openSession  
  a.永远创建session 
  b.需要关闭 session 2.getCurrentSession  
 a.如果当前上下文中存在可用的session会获取,如果不存在则会创建  b.不需要关闭session  
getCurrentSession()   
1.用途:界定事务边界 2.事务提交自动关闭

2.只有在抛出RuntimeException的时候才能回滚,其他的Exception不能够回滚

3.在事务的设置上,最好在Service上设置事务

抱歉!评论已关闭.