使用Spring 4.0和;休眠4.2.8
我们正在用Spring 4.0.0、Hibernate 4.2.8和Ms SQL Server 8开发一个应用程序,它使用一个自定义序列,该序列由DB表支持,并映射到Hibernate VO(CustomSequence) 此序列在服务调用中被访问:使用Spring 4.0和;休眠4.2.8,spring,hibernate,transactions,sequence,isolation,Spring,Hibernate,Transactions,Sequence,Isolation,我们正在用Spring 4.0.0、Hibernate 4.2.8和Ms SQL Server 8开发一个应用程序,它使用一个自定义序列,该序列由DB表支持,并映射到Hibernate VO(CustomSequence) 此序列在服务调用中被访问: 主服务启动自己的事务 执行代码,做一些事情,查询 为序列值调用序列服务(SequenceService) SequenceService启动自己的事务(需要新的) SequenceService查找对象,返回值并保存下一个值 主服务获取值,在业务
- 主服务启动自己的事务
- 执行代码,做一些事情,查询
- 为序列值调用序列服务(SequenceService)
- SequenceService启动自己的事务(需要新的)
- SequenceService查找对象,返回值并保存下一个值
- 主服务获取值,在业务对象中设置并保存(此时序列值已由内部新事务提交)
- 出口
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
@Service("sequenceService")
public class SequenceService implements ISequenceService {
@Autowired
private ISequenceDao sequenceDao;
private Integer getSequence() {
CustomSequence sequenceOut = sequenceDao.find();
final Integer nextVal = sequenceOut.getNextVal();
sequenceOut.setNextVal(nextVal + 1);
sequenceDao.save(sequenceOut);
return nextVal;
}
}
我们的问题是serializable属性被完全忽略,所以两个并发线程访问getSequence方法并获得相同的值
如果我们使用TransactionSynchronizationManager检查隔离,该值对于serializable(值=8)似乎是正确的:
我们的spring xml文件如下所示:
<context:annotation-config />
<context:component-scan base-package="dev.app"/>
<tx:annotation-driven />
<bean name="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/appDatasource"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" lazy-init="false" >
<property name="dataSource"> <ref bean="dataSource" /></property>
<property name="packagesToScan" value="dev.app.model"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<!-- Disable LOB creation as connection -->
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
</bean>
有什么线索吗?我在网上读了很多信息,但都没有用
非常感谢 根据
HibernateTransactionManager
的代码,这可能是因为将事务管理器的prepareConnection标志设置为false:
/**
* Set whether to prepare the underlying JDBC Connection of a transactional
* Hibernate Session, that is, whether to apply a transaction-specific
* isolation level and/or the transaction's read-only flag to the underlying
* JDBC Connection.
* <p>Default is "true". If you turn this flag off, the transaction manager
* will not support per-transaction isolation levels anymore. ...
*/
public void setPrepareConnection(boolean prepareConnection) {
this.prepareConnection = prepareConnection;
}
isSameConnectionForEntireSession
表示:
/**
* Return whether the given Hibernate Session will always hold the same
* JDBC Connection. This is used to check whether the transaction manager
* can safely prepare and clean up the JDBC Connection used for a transaction.
* <p>The default implementation checks the Session's connection release mode
* to be "on_close".
*/
protected boolean isSameConnectionForEntireSession(Session session) ...
/**
*返回给定的Hibernate会话是否始终保持不变
*JDBC连接。这用于检查事务管理器
*可以安全地准备和清理用于事务的JDBC连接。
*默认实现检查会话的连接释放模式
*要“接近”。
*/
受保护的布尔值isSameConnectionForEntireSession(会话会话)。。。
这意味着只有在以下情况下才能应用自定义隔离级别:在事务管理器上启用了执行此操作的标志,并且保证相同的数据库连接将始终用于相同的hibernate会话
如果不是这样,则事务管理器不会更改隔离设置,因为如果一个会话可以使用多个会话进行不同的查询,事务管理器将不知道会话何时被发送回池
这基本上意味着,如果事务管理器能够保证在将会话发送到池之前清除相同的设置,则它只能更改数据库会话的隔离设置。谢谢您的回答。我已经调试了这个类,看起来一切正常,从某种意义上说,标志从未更改过(真值),isSameConnectionForEntireSession(会话)值也是真的。它进入DataSourceUtils.prepareConnectionForTransaction(con,definition)并将当前隔离设置为8(以前的隔离为2)。内部事务结束后,执行“doCleanupAfterCompletion”,恢复以前的隔离值(2)。我只是不知道这里出了什么问题。我想问题和服务器有关。在新服务器中重新部署,从零开始解决了问题。。。
/**
* Set whether to prepare the underlying JDBC Connection of a transactional
* Hibernate Session, that is, whether to apply a transaction-specific
* isolation level and/or the transaction's read-only flag to the underlying
* JDBC Connection.
* <p>Default is "true". If you turn this flag off, the transaction manager
* will not support per-transaction isolation levels anymore. ...
*/
public void setPrepareConnection(boolean prepareConnection) {
this.prepareConnection = prepareConnection;
}
if (this.prepareConnection && isSameConnectionForEntireSession(session)) {
....
}
/**
* Return whether the given Hibernate Session will always hold the same
* JDBC Connection. This is used to check whether the transaction manager
* can safely prepare and clean up the JDBC Connection used for a transaction.
* <p>The default implementation checks the Session's connection release mode
* to be "on_close".
*/
protected boolean isSameConnectionForEntireSession(Session session) ...