记录 JDBC/Hibernate/JPA 事务隔离级别

发布于 2024-09-11 12:01:38 字数 1707 浏览 9 评论 0原文

我正在开发一个连接到 Microsoft SQL Server 数据库的 Flex/BlazeDS/Spring/JPA/Hibernate Web 应用程序。它似乎过于激进地锁定表格。根据我的研究,使用快照隔离策略似乎是最好的选择。

我已经这样设置了:

  <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
    <property name="persistenceUnitName" value="OrderManagerPersistenceUnit" />
    <property name="dataSource" ref="dataSource"/>
     <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
     </property>
    <property name="jpaProperties">
      <props>
        <prop key="hibernate.jdbc.batch_size">${db.main.hibernate.jdbc.batch_size}</prop>
        <prop key="hibernate.hbm2ddl.auto">${db.main.hbm2ddl.auto}</prop>
        <prop key="hibernate.search.default.indexBase">${db.main.search.default.indexBase}</prop>
        <prop key="hibernate.search.autoregister_listeners">${db.main.search.autoregister_listeners}</prop>
          <prop key="hibernate.show_sql">${db.main.show_sql}</prop>
          <prop key="hibernate.dialect">${db.main.dialect}</prop>
          <prop key="hibernate.connection.isolation">${db.main.isolation}</prop>
          <prop key="hibernate.ejb.naming_strategy">com.herffjones.zebra.db.ZebraNamingStrategy</prop>
      </props>
    </property>
  </bean>

但是,我不相信它实际上使用了 hibernate.connection.isolation。看来我还必须在 JDBC 数据源上设置一些属性。

我想验证当前是否使用 4096 作为查询的事务隔离级别。

我可以将哪些包和日志级别添加到 logback.xml 文件中,以清楚地查看特定查询正在使用的隔离级别?

谢谢!

I'm working on a Flex/BlazeDS/Spring/JPA/Hibernate web application hooked up to a Microsoft SQL Server database. It seems to be locking the tables too aggresively. From my research, it looks like using the snapshot isolation policy is the best bet.

I've set things up as such:

  <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true">
    <property name="persistenceUnitName" value="OrderManagerPersistenceUnit" />
    <property name="dataSource" ref="dataSource"/>
     <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
     </property>
    <property name="jpaProperties">
      <props>
        <prop key="hibernate.jdbc.batch_size">${db.main.hibernate.jdbc.batch_size}</prop>
        <prop key="hibernate.hbm2ddl.auto">${db.main.hbm2ddl.auto}</prop>
        <prop key="hibernate.search.default.indexBase">${db.main.search.default.indexBase}</prop>
        <prop key="hibernate.search.autoregister_listeners">${db.main.search.autoregister_listeners}</prop>
          <prop key="hibernate.show_sql">${db.main.show_sql}</prop>
          <prop key="hibernate.dialect">${db.main.dialect}</prop>
          <prop key="hibernate.connection.isolation">${db.main.isolation}</prop>
          <prop key="hibernate.ejb.naming_strategy">com.herffjones.zebra.db.ZebraNamingStrategy</prop>
      </props>
    </property>
  </bean>

However, I'm not convinced that it's actually using hibernate.connection.isolation. It looks like I have to set some properties on the JDBC datasource as well.

I'd like to verify whether or not it's currently using 4096 as the transaction isolation level for queries.

What packages and log levels can I add to my logback.xml file to clearly see the isolation level that a particular query is using?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

莫多说 2024-09-18 12:01:38

您应该将 hibernate 的事务隔离级别设置为 2(READ_COMMITTED 的 java.sql.Connection 常量)。

然后在 SQL Server 2005 实例(没有活动连接)中执行以下命令:

ALTER DATABASE [database_name] SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE [database_name] SET READ_COMMITTED_SNAPSHOT ON;

通过执行以下查询进行测试:

SELECT [name], snapshot_isolation_state_desc, snapshot_isolation_state, is_read_comfilled_snapshot_on
来自系统数据库
WHERE [名称] = '数据库名称';

现在,READ_COMMITTED 在 SQL Server 中将被解释为 READ_COMMITTED_SNAPSHOT。

You should set the transaction isolation level of hibernate as 2 (the java.sql.Connection constant for READ_COMMITTED.

Then execute the following in your SQL Server 2005 instance (with no active connections):

ALTER DATABASE [database_name] SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE [database_name] SET READ_COMMITTED_SNAPSHOT ON;

Test by executing this query:

SELECT [name], snapshot_isolation_state_desc, snapshot_isolation_state, is_read_committed_snapshot_on
FROM sys.databases
WHERE [name] = 'database_name';

Now a READ_COMMITTED will be interpreted as READ_COMMITTED_SNAPSHOT in SQL Server.

掩耳倾听 2024-09-18 12:01:38

我想描述一下我在 JPA/MySQL 上遇到的一个问题;它可能会激发您的调查...

  • 全局事务开始
  • 事务1)表地址上的新行
    (自动增量)
  • 事务2)一个新的
    表上的行 企业
    表地址上的外键;新的
    插入的企业链接到
    新地址#ID。
  • 全局事务结束

MYSQL 在这种情况下与 ResourceLocal / JPATransactionManager 发生死锁。

实际上,我们似乎无法打开多个嵌套事务。全局事务似乎与事务 1) 和 2) 合并。事务 2) 以死锁结束,因为无法使用尚未准备就绪的表 A 新 #Id 提供数据。

但是,我们可以使用调试器看到事务 1 和事务 2 之间的新地址 row#id。

这与您的问题类似吗?您猜想自动增量与您的死锁有关系吗?
以下是可能的解决方案...

  • 解决方案1
    更改隔离级别?
    ->怎么办?!!我没有答案...而且我不确定这会改变什么。

  • 解决方案2
    将 JPA 实体 ID 生成策略(自动或标识)替换为自定义序列表。

  • 解决方案3

检查是否无法在ManyToOne 关系上使用级联策略。

EntrepriseEntity{
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id_entreprise")
private int id;

@ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name = "id_address")
private AddressEntity address;  

然后将两行保存到单个 merge() 中:

EntrepriseEntity e=new EntrepriseEntity();
e.setAddress(new AddressEntity());
e=entityManager.merge(e);

返回的实例会返回插入的新#ids,并且魔法:不再死锁...

解决方案#3 更聪明,但需要更深入的分析并更改一些代码...

I would like to describe an issue I got on JPA/MySQL; it may inspire your investigations...

  • Global transaction begin
  • transaction 1) a new row on table Address
    (autoincrement)
  • transaction 2) a new
    row on table Entreprise with a
    foreign key on table Addres; the new
    Entreprise inserted is linked to the
    new Adress #ID.
  • End of Global transaction

MYSQL dead-locks for this case with ResourceLocal / JPATransactionManager.

Actually, it seems that we cannot open several nested transactions. The global transaction seems to be merged with transactions 1) and 2). Transaction 2) ends in deadlock because data cannot be feeded with table A new #Id that is not ready.

However, we can see with the debugger the new adresse row#id between transaction 1 and 2.

Is it similar to your issue ? Do you guess some autoincrement - relation with your deadlock?
These followings are possible solutions...

  • Solution1
    Change isolation level ?
    -> How ?!!I don't have the answer...And I'm not shure this will change anything.

  • Solution2
    Replace JPA Entities ID generation strategy (auto or identity) into a custom sequence table.

  • Solution3

Check if you cannot use cascade strategy on ManyToOne relationships.

EntrepriseEntity{
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "id_entreprise")
private int id;

@ManyToOne(fetch=FetchType.LAZY,cascade=CascadeType.ALL)
@JoinColumn(name = "id_address")
private AddressEntity address;  

And then save both rows into a single merge() :

EntrepriseEntity e=new EntrepriseEntity();
e.setAddress(new AddressEntity());
e=entityManager.merge(e);

Returned instance with give you back both new #ids inserted, and magic : no longer deadlock...

Solution#3 is smarter, but needs deeper analysis and change some code...

倒带 2024-09-18 12:01:38

每当您提供数据源时 ,Hibernate 将忽略 hibernate.connection.isolation 设置。

您需要在数据源级别设置隔离级别。大多数连接池或 XA Java EE 应用程序服务器数据源允许您设置全局事务隔离级别,因此来自该数据源的所有连接都继承相同的隔离级别。

Whenever you supply a DataSource, Hibernate is going to ignore the hibernate.connection.isolation setting.

You need to set the isolation level at the DataSource level instead. Most connection pools or XA Java EE Application Server DataSources allow you to set a global transaction isolation level, so all connections coming from that DataSource inherit the same isolation level.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文