一.数据库事务的概念
数据库事务是指作为单个逻辑工作单元执行的一系列操作。设想网上购物的一次交易,其付款过程至少包括以下几步数据库操作: 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>
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上设置事务