事务管理总结

一.JDBC事务管理

JDBC 事务是用 Connection 对象控制的。JDBC Connection 接口( java.sql.Connection )提供了两种事务模式:自动提交和手工提交。 java.sql.Connection 提供了以下控制事务的方法:
public void setAutoCommit(boolean)
public boolean getAutoCommit()
public void commit()
public void rollback()
java使用JDBC来处理事务的代码:
public int delete(int sID) {
 dbc = new DataBaseConnection();
 Connection con = dbc.getConnection();
 try {
  con.setAutoCommit(false);// 更改JDBC事务的默认提交方式
  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事务
  con.setAutoCommit(true);// 恢复JDBC事务的默认提交方式
  dbc.close();
  return 1;
 }
 catch (Exception exc) {
  con.rollBack();//回滚JDBC事务
  exc.printStackTrace();
  dbc.close();
  return -1;
 }
}


二.Hibernate事务管理

1.在pom.xml添加Hibernate等jar包

 	<!-- hibernate4 -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.1.7.Final</version>
        </dependency>
		<!--sqlserver驱动包 -->  
		<dependency>  
		    <groupId>com.microsoft.sqlserver</groupId>  
		    <artifactId>sqljdbc4</artifactId>  
		    <version>4.0</version>  
		</dependency>  
		<dependency>  
		    <groupId>commons-dbcp</groupId>  
		    <artifactId>commons-dbcp</artifactId>  
		    <version>1.4</version>  
		</dependency> 
		<!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
2.在src目录下编写hibernate.cfg.xml的配置

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
	<session-factory>

		<!-- Database connection settings -->
		<property name="connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
		<property name="connection.url">jdbc:sqlserver://172.25.6.146:1433;DatabaseName=xsjdd;SelectMethod=cursor;</property>
		<property name="connection.username">sa</property>
		<property name="connection.password">cosnet</property>

		<!-- SQL dialect -->
		<property name="dialect">org.hibernate.dialect.SQLServerDialect</property>
		<!--
			将Session扔到线程里去处理,Enable Hibernate's automatic session context
			management
		-->
		<property name="current_session_context_class">thread</property>

		<!-- 在控制台打印SQL语句 -->
		<property name="show_sql">true</property>

		<!-- 自动把实体类与属性映射成数据库中的表与列 -->
		<property name="hbm2ddl.auto">update</property>

		<!-- 自动扫描注解方式配置的hibernate类文件 -->
		<mapping class="com.cosconet.model.User" />

	</session-factory>
</hibernate-configuration>
3.编写实体类

package com.cosconet.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "BD_TestUser", schema = "dbo")
public class User implements java.io.Serializable {

    // Fields
    private String id;
    private String name;
    private String pwd;
    private Date createdatetime;
    private Date modifydatetime;

    // Constructors

    /** default constructor */
    public User() {
    }

    /** minimal constructor */
    public User(String id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    /** full constructor */
    public User(String id, String name, String pwd, Date createdatetime, Date modifydatetime) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
        this.createdatetime = createdatetime;
        this.modifydatetime = modifydatetime;
    }

    // Property accessors
    @Id
    @Column(name = "ID", unique = true, nullable = false, length = 36)
    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Column(name = "NAME",nullable = false, length = 100)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name = "PWD", nullable = false, length = 32)
    public String getPwd() {
        return this.pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "CREATEDATETIME", length = 7)
    public Date getCreatedatetime() {
        return this.createdatetime;
    }

    public void setCreatedatetime(Date createdatetime) {
        this.createdatetime = createdatetime;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "MODIFYDATETIME", length = 7)
    public Date getModifydatetime() {
        return this.modifydatetime;
    }

    public void setModifydatetime(Date modifydatetime) {
        this.modifydatetime = modifydatetime;
    }
}
4.编写测试类

package com.cosconet.test;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import com.cosconet.model.User;

public class TestHibernate {

	@Test
	public void save()
	{
		List<User> list = new LinkedList<User>();
        User user = new User();
        user.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        user.setName("哈宇华帝");
        user.setPwd("123");
        user.setCreatedatetime(new Date()); 
        list.add(user);
        User user1 = new User();
        user1.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        user1.setName("哈宇华帝1");
        user1.setPwd("123");
        user1.setCreatedatetime(new Date()); 
        list.add(user1);
        Configuration conf = new Configuration().configure();  
        SessionFactory sf = conf.buildSessionFactory();  
        Session session = sf.openSession();  
        Transaction t = session.beginTransaction();//说明一  
        try{  
        	for(int i=0;i<list.size();i++)
        	{
        		User u = list.get(i);
        		session.save(u);
        	}
            t.commit();//说明二  
        }catch(Exception e){  
            t.rollback();  
            e.printStackTrace();
        }finally{  
            if(session.isOpen()){  
            	session.close();  
            }  
        } 
	}
}
5.说明一 :Hibernate本身没有实现自己的事务管理功能,而是对底层JDBC事务或JTA事务的轻量级封装
org.hibernate.impl.SessionImpl类(该类是会话的实现类):
public Transaction beginTransaction() throws HibernateException {  
       errorIfClosed();  
    if ( rootSession != null ) {  
       log.warn( "Transaction started on non-root session" );  
    }  
    Transaction result = getTransaction();  
    result.begin();  
    return result;  
}  
   
public Transaction getTransaction() throws HibernateException {  
    errorIfClosed();  
    return jdbcContext.getTransaction();  
}
org.hibernate.jdbc.JDBCContext类:
public Transaction getTransaction() throws HibernateException {  
    if (hibernateTransaction==null) {  
       hibernateTransaction = owner.getFactory().getSettings()  
              .getTransactionFactory().createTransaction( this, owner );  
    }  
    return hibernateTransaction;  
}  
TransactionFactory有很多实现类:

选择最基本的org.hibernate.transaction.JDBCTransactionFactory观察一下:
public Transaction createTransaction(JDBCContext jdbcContext, Context transactionContext)throws HibernateException {  
    return new JDBCTransaction( jdbcContext, transactionContext );  
}  
org.hibernate.transaction.JDBCTransaction类的说明:
Transaction implementation based on transaction management through a JDBC Connection.  
This the Hibernate's default transaction strategy.  
事务开始时,会禁用自动提交:
public void begin() throws HibernateException {  
    if (begun) {  
        return;  
    }  
    if (commitFailed) {  
        throw new TransactionException("cannot re-start transaction after failed commit");  
    }  
  
    log.debug("begin");  
  
    try {  
        toggleAutoCommit = jdbcContext.connection().getAutoCommit();  
        if ( log.isDebugEnabled() ) {  
            log.debug("current autocommit status: " + toggleAutoCommit);  
        }  
        if (toggleAutoCommit) {  
            log.debug("disabling autocommit");  
            jdbcContext.connection().setAutoCommit(false);//关闭事务自动提交  
        }  
    }  
    catch (SQLException e) {  
        log.error("JDBC begin failed", e);  
        throw new TransactionException("JDBC begin failed: ", e);  
    }  
  
    callback = jdbcContext.registerCallbackIfNecessary();  
  
    begun = true;  
    committed = false;  
    rolledBack = false;  
  
    if ( timeout>0 ) {  
        jdbcContext.getConnectionManager().getBatcher().setTransactionTimeout(timeout);  
    }  
  
    jdbcContext.afterTransactionBegin(this);  
} 
打开log日志也能看出很多端倪:

[2013-08-09 16:37:55] DEBUG  -> begin  
[2013-08-09 16:37:55] DEBUG  -> opening JDBC connection  
[2013-08-09 16:37:55] DEBUG  -> current autocommit status: false  
[2013-08-09 16:37:55] DEBUG  -> generated identifier: 1, using strategy: org.hibernate.id.Assigned  
[2013-08-09 16:37:55] DEBUG  -> commit  
6. 说明二 不需要显式的调用flush()方法,事务提交时会根据session的FlushMode自动触发session的flush


还是通过最基本的JDBCTransaction类看一下:

事务提交完成之后又恢复了事务的自动提交

public void commit() throws HibernateException {  
    if (!begun) {  
        throw new TransactionException("Transaction not successfully started");  
    }  
  
    log.debug("commit");  
  
    if ( !transactionContext.isFlushModeNever() && callback ) {  
        transactionContext.managedFlush(); //根据FlushMode(通常为AUTO)刷新Session  
  
    notifySynchronizationsBeforeTransactionCompletion();  
    if ( callback ) {  
        jdbcContext.beforeTransactionCompletion( this );  
    }  
  
    try {  
        commitAndResetAutoCommit();//在该方法中重新开启了事务自动提交  
        log.debug("committed JDBC Connection");  
        committed = true;  
        if ( callback ) {  
            jdbcContext.afterTransactionCompletion( true, this );  
        }  
        notifySynchronizationsAfterTransactionCompletion( Status.STATUS_COMMITTED );  
    }  
    catch (SQLException e) {  
        log.error("JDBC commit failed", e);  
        commitFailed = true;  
        if ( callback ) {  
            jdbcContext.afterTransactionCompletion( false, this );  
        }  
        notifySynchronizationsAfterTransactionCompletion( Status.STATUS_UNKNOWN );  
        throw new TransactionException("JDBC commit failed", e);  
    }  
    finally {  
        closeIfRequired();  
    }  
}  
  
private void commitAndResetAutoCommit() throws SQLException {  
    try {  
        jdbcContext.connection().commit();  
    }  
    finally {  
        toggleAutoCommit();  
    }  
}  
  
private void toggleAutoCommit() {  
    try {  
        if (toggleAutoCommit) {  
            log.debug("re-enabling autocommit");  
            jdbcContext.connection().setAutoCommit( true );//重新开启事务自动提交  
        }  
    }  
    catch (Exception sqle) {  
        log.error("Could not toggle autocommit", sqle);  
        //swallow it (the transaction _was_ successful or successfully rolled back)  
    }  
}
JDBC事务默认自动提交,但是如果Hibernate的事务策略使用JDBC,在事务开始之前,Hibernate会关闭事务自动提交,在事务结束之后,重新开启事务自动提交

7.事务的隔离级别

为了解决多个事务并发会引发的问题。数据库系统提供了四种事务隔离级别供用户选择。
o Serializable:串行化。隔离级别最高
o Repeatable Read:可重复读。
o Read Committed:读已提交数据。
o Read Uncommitted:读未提交数据。隔离级别最差。
数据库系统采用不同的锁类型来实现以上四种隔离级别,具体的实现过程对用户是透明的。用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。
每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。 JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
Read Uncommitted: 1
Read Committed: 2
Repeatable Read: 4
Serializable: 8
在hibernate.cfg.xml中设置隔离级别如下:
    <session-factory>
<!-- 设置JDBC的隔离级别 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
设置之后,在开始一个事务之前,Hibernate将为从连接池中获得的JDBC连接设置级别。需要注意的是,在受管理环境中, 如果Hibernate使用的数据库连接来自于应用服务器提供的数据源,Hibernate不会改变这些连接的事务隔离级别。在这种情况下,应该通过修改应用服务器的数据源配置来修改隔离级别。


三.spring事务管理

    Spring配置文件中关于事务配置总是由三个组成部分,分别是DataSource、TransactionManager和代理机制这三部分,无论哪种配置方式,一般变化的只是代理机制这部分。

    DataSource、TransactionManager这两部分只是会根据数据访问方式有所变化,比如使用hibernate进行数据访问时,DataSource实际为SessionFactory,TransactionManager的实现为HibernateTransactionManager。具体如下图:


    根据代理机制的不同,总结了五种Spring事务的配置方式,配置文件如下:

    第一种方式:每个Bean都有一个代理

<?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:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="
http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-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/context 
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
	<!-- 配置数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
		<property name="url" value="jdbc:sqlserver://172.25.6.146:1433;DatabaseName=xsjdd;SelectMethod=cursor;" />
		<property name="username" value="sa" />
		<property name="password" value="cosnet" />
	</bean>

	<!-- 配置sessionFactory -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="hibernateProperties">
			<props>
				<!-- web项目启动时是否更新表结构 -->
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<!-- 系统使用的数据库方言,也就是使用的数据库类型 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
				<!-- 是否打印Hibernate生成的SQL到控制台 -->
				<prop key="hibernate.show_sql">true</prop>
				<!-- 是否格式化打印出来的SQL -->
				<prop key="hibernate.format_sql">true</prop>
			</props>
		</property>
		<!-- 自动扫描注解方式配置的hibernate类文件 -->
		<property name="packagesToScan">
			<list>
				<value>com.cosconet.model</value>
			</list>
		</property>
	</bean>

	<!-- 配置DAO -->
	<bean id="userDao" class="com.cosconet.dao.impl.UserDaoImpl">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
	
	<!-- 配置service -->
	<bean id="userServiceTarget" class="com.cosconet.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao" />
	</bean>

	<!-- 配置事务管理器 (声明式的事务)-->
	<bean name="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<bean id="userService"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
		<!-- 配置事务管理器 -->
		<property name="transactionManager" ref="transactionManager" />
		<!-- 配置代理类 -->
		<property name="target" ref="userServiceTarget" />
		<!-- 配置事务属性 -->
		<property name="transactionAttributes">
			<props>
<span style="white-space:pre">				</span><prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
<span style="white-space:pre">				</span><prop key="delete*">PROPAGATION_REQUIRED</prop>
<span style="white-space:pre">				</span><prop key="update*">PROPAGATION_REQUIRED</prop>
<span style="white-space:pre">				</span><prop key="add*">PROPAGATION_REQUIRED</prop>
<span style="white-space:pre">				</span><prop key="save*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
</beans>

第二种方式:所有Bean共享一个代理基类

<?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:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-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/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
	<!-- 配置数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
		<property name="url" value="jdbc:sqlserver://172.25.6.146:1433;DatabaseName=xsjdd;SelectMethod=cursor;" />
		<property name="username" value="sa" />
		<property name="password" value="cosnet" />
	</bean>

	<!-- 配置sessionFactory -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="hibernateProperties">
			<props>
				<!-- web项目启动时是否更新表结构 -->
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<!-- 系统使用的数据库方言,也就是使用的数据库类型 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
				<!-- 是否打印Hibernate生成的SQL到控制台 -->
				<prop key="hibernate.show_sql">true</prop>
				<!-- 是否格式化打印出来的SQL -->
				<prop key="hibernate.format_sql">true</prop>
			</props>
		</property>
		<!-- 自动扫描注解方式配置的hibernate类文件 -->
		<property name="packagesToScan">
			<list>
				<value>com.cosconet.model</value>
			</list>
		</property>
	</bean>

	<!-- 配置事务管理器 (声明式的事务)-->
	<bean name="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<!-- 代码基类 -->
	<bean id="transactionBase"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
		lazy-init="true" abstract="true">
		<!-- 配置事务管理器 -->
		<property name="transactionManager" ref="transactionManager" />
		<!-- 配置事务属性 -->
		<property name="transactionAttributes">
			<props>
<span style="white-space:pre">				</span><prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
<span style="white-space:pre">				</span><prop key="delete*">PROPAGATION_REQUIRED</prop>
<span style="white-space:pre">				</span><prop key="update*">PROPAGATION_REQUIRED</prop>
<span style="white-space:pre">				</span><prop key="add*">PROPAGATION_REQUIRED</prop>
<span style="white-space:pre">				</span><prop key="save*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	
	<!-- 配置DAO -->
	<bean id="userDao" class="com.cosconet.dao.impl.UserDaoImpl">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
	
	<!-- 配置service -->
	<bean id="userServiceTarget" class="com.cosconet.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao" />
	</bean>
	
	<!-- 配置代理-->
	<bean id="userService" parent="transactionBase">
		<!-- 配置代理类 -->
		<property name="target" ref="userServiceTarget" />
	</bean>
</beans>


第三种方式:使用拦截器

<?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:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-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/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
	<!-- 配置数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
		<property name="url" value="jdbc:sqlserver://172.25.6.146:1433;DatabaseName=xsjdd;SelectMethod=cursor;" />
		<property name="username" value="sa" />
		<property name="password" value="cosnet" />
	</bean>

	<!-- 配置sessionFactory -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="hibernateProperties">
			<props>
				<!-- web项目启动时是否更新表结构 -->
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<!-- 系统使用的数据库方言,也就是使用的数据库类型 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
				<!-- 是否打印Hibernate生成的SQL到控制台 -->
				<prop key="hibernate.show_sql">true</prop>
				<!-- 是否格式化打印出来的SQL -->
				<prop key="hibernate.format_sql">true</prop>
				<prop key="current_session_context_class">thread</prop>
			</props>
		</property>
		<!-- 自动扫描注解方式配置的hibernate类文件 -->
		<property name="packagesToScan">
			<list>
				<value>com.cosconet.model</value>
			</list>
		</property>
	</bean>

	<!-- 配置事务管理器 (声明式的事务)-->
	<bean name="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<!-- 代码基类 -->
	<bean id="transactionBase"
		class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
		lazy-init="true" abstract="true">
		<!-- 配置事务管理器 -->
		<property name="transactionManager" ref="transactionManager" />
		<!-- 配置事务属性 -->
		<property name="transactionAttributes">
			<props>
				<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="delete*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="add*">PROPAGATION_REQUIRED</prop>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	
	<bean id="transactionInterceptor"
		class="org.springframework.transaction.interceptor.TransactionInterceptor">
		<property name="transactionManager" ref="transactionManager" />
		<!-- 配置事务属性 -->
		<property name="transactionAttributes">
			<props>
				<prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
				<prop key="delete*">PROPAGATION_REQUIRED</prop>
				<prop key="update*">PROPAGATION_REQUIRED</prop>
				<prop key="add*">PROPAGATION_REQUIRED</prop>
				<prop key="save*">PROPAGATION_REQUIRED</prop>
			</props>
		</property>
	</bean>
	<bean id="txProxy"
		class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<list>
				<value>*Service</value>
			</list>
		</property>
		<property name="interceptorNames">
			<list>
				<value>transactionInterceptor</value>
			</list>
		</property>
	</bean>
	
	<!-- 配置DAO -->
	<bean id="userDao" class="com.cosconet.dao.impl.UserDaoImpl">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
	
	<!-- 配置service -->
	<bean id="userService" class="com.cosconet.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao" />
	</bean>
</beans>

第四种方式:使用tx标签配置的拦截器

<?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:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" 
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-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/context 
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
	<!-- 配置数据源 -->
	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
		<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
		<property name="url" value="jdbc:sqlserver://172.25.6.146:1433;DatabaseName=xsjdd;SelectMethod=cursor;" />
		<property name="username" value="sa" />
		<property name="password" value="cosnet" />
	</bean>

	<!-- 配置sessionFactory -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="hibernateProperties">
			<props>
				<!-- web项目启动时是否更新表结构 -->
				<prop key="hibernate.hbm2ddl.auto">update</prop>
				<!-- 系统使用的数据库方言,也就是使用的数据库类型 -->
				<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
				<!-- 是否打印Hibernate生成的SQL到控制台 -->
				<prop key="hibernate.show_sql">true</prop>
				<!-- 是否格式化打印出来的SQL -->
				<prop key="hibernate.format_sql">true</prop>
				<prop key="current_session_context_class">thread</prop>
			</props>
		</property>
		<!-- 自动扫描注解方式配置的hibernate类文件 -->
		<property name="packagesToScan">
			<list>
				<value>com.cosconet.model</value>
			</list>
		</property>
	</bean>

	<!-- 配置事务管理器 (声明式的事务)-->
	<bean name="transactionManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="*" propagation="REQUIRED" read-only="true"/>
			<tx:method name="delete*" propagation="REQUIRED"/>
			<tx:method name="update*" propagation="REQUIRED"/>
			<tx:method name="add*" propagation="REQUIRED"/>
			<tx:method name="save*" propagation="REQUIRED"/>
		</tx:attributes>
	</tx:advice>
	<aop:config>
		<aop:pointcut id="interceptorPointCuts"	expression="execution(* com.cosconet.service.*.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts" />
	</aop:config>
	
	<!-- 配置DAO -->
	<bean id="userDao" class="com.cosconet.dao.impl.UserDaoImpl">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
	
	<!-- 配置service -->
	<bean id="userService" class="com.cosconet.service.impl.UserServiceImpl">
		<property name="userDao" ref="userDao" />
	</bean>
</beans>
第五种方式:全注解




报错:org.hibernate.HibernateException: No Session found for current thread
使用spring管理事务后在dao中不再需要调用beginTransaction和commit,也不需要调用session.close(),使用API sessionFactory.getCurrentSession()来替代sessionFactory.openSession()。
采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()创建的session则不会。
采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()创建的session必须手动关闭。
集成hibernate4之后,最小事务级别必须是Required,如果是以下的级别,或者没有开启事务的话,无法得到当前的Session。Java代码:sessionFactory.getCurrentSession();这方法必须在事务控制范围内,否则执行这行代码,会抛出No Session found for current thread。需要把之前一些方法的事务从NOT_SUPPORT提升到required,readonly=true。
<prop key="find*">PROPAGATION_NOT_SUPPORTED,readOnly</prop>改为<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
read-only="true":只读状态时不使用事务






  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值