一.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":只读状态时不使用事务