简体   繁体   English

使用Spring和Hibernate进行事务管理会导致非活动事务

[英]Transaction management with Spring and Hibernate make inactive transactions

I'm managing a Java Web Application with Spring and Hibernate. 我正在使用Spring和Hibernate管理Java Web应用程序。 I use Spring and Hibernate tools to handle the persistence level, so I don't need to commit\\rollback my transactions. 我使用Spring和Hibernate工具来处理持久性级别,所以我不需要提交\\ rollback我的事务。 The application is concurrent, so the users can modify the same records and I decided to use Read Committed as isolation level. 应用程序是并发的,因此用户可以修改相同的记录,我决定使用Read Committed作为隔离级别。

The problem is sometimes I find JDBC errors in the log, and all the next requests go in the same error, blocking the application behaviour. 问题是有时我在日志中发现JDBC错误,并且所有下一个请求都出现相同的错误,阻止了应用程序行为。

These are the components involved in the transaction management: 这些是事务管理中涉及的组件:

@Bean
    public SpringLocalSessionFactoryBean sessionFactory(DataSource dataSource){
        SpringLocalSessionFactoryBean bean = new SpringLocalSessionFactoryBean();
        bean.setConfigLocation(new ClassPathResource("hibernate.cfg.xml"));
        bean.setDataSource(dataSource);
        return bean;
    }

    @Bean
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory){
        HibernateTransactionManager tm = new HibernateTransactionManager();
        tm.setSessionFactory(sessionFactory);
        return tm;
    }

In the db session monitor, when this stuff happens, I got an INACTIVE transaction. 在db session监视器中,当这个东西发生时,我得到了一个INACTIVE事务。

The error I get is the following: 我得到的错误如下:

WARN  - (SqlExceptionHelper.java:144) - SQL Error: 0, SQLState: null
14/03/2016 15:46:06 - ERROR - (SqlExceptionHelper.java:146) - Connection oracle.jdbc.driver.T4CConnection@1a6d7ad6 is closed.
14/03/2016 15:46:06 - ERROR - (AutoCompleterController.java:73) - could not prepare statement
org.hibernate.exception.GenericJDBCException: could not prepare statement
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:126)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:196)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:160)
    at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1885)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1862)
    at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1839)
    at org.hibernate.loader.Loader.doQuery(Loader.java:910)
Caused by: java.sql.SQLException: Connection oracle.jdbc.driver.T4CConnection@1a6d7ad6 is closed.
    at org.apache.tomcat.dbcp.dbcp.DelegatingConnection.checkOpen(DelegatingConnection.java:398)
    at org.apache.tomcat.dbcp.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:279)
    at org.apache.tomcat.dbcp.dbcp.PoolingDataSource$PoolGuardConnectionWrapper.prepareStatement(PoolingDataSource.java:313)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:162)
    at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:186)
    ... 97 more

The problem is the transactions and the connections should be automatically opened and closed... And I expect that transactions that should fail for concurrent modification to get a rollback... But it seems they get inactive. 问题是事务和连接应该自动打开和关闭......我希望并发修改失败的事务得到回滚......但似乎它们变得不活跃。

I attach my hibernate config. 我附上了我的hibernate配置。

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

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>

<!--        <property name="hibernate.hbm2ddl.auto">update</property> -->
        <property name="hibernate.connection.isolation">2</property>

        <!-- Disable the second-level cache -->
        <property name="hibernate.cache.use_second_level_cache">false</property>
        <property name="hibernate.id.new_generator_mappings">true</property>
        <property name="hibernate.connection.autocommit">false</property>

        <!-- Show and print nice SQL on stdout -->
        <property name="hibernate.show_sql">false</property>
        <property name="hibernate.format_sql">false</property>
        <property name="hibernate.use_sql_comments">false</property>
        <property name="hibernate.generate_statistics">false</property>

    </session-factory>
</hibernate-configuration>

As connection library I use ojdbc. 作为连接库,我使用ojdbc。 Any help will be appreciated. 任何帮助将不胜感激。 I don't know where to check anymore. 我不知道在哪里检查。

PS: I add that this error spawns like once every 2 days. PS:我补充一点,这个错误每2天产生一次。

EDIT: Just another integration, this is what I have on my server.xml, could it be related to something here? 编辑:只是另一个集成,这是我在我的server.xml上,它可能与这里的东西有关?

  <Resource name="jdbc/ToolSfDB" global="jdbc/ToolSfDB" auth="Container" type="javax.sql.DataSource"
      driverClassName="oracle.jdbc.OracleDriver"
      url="jdbc:oracle:thin:@//oracle01-internal.local:1521/orcl01"
      username="tools"
      password="mypwd"
      maxActive="10"
      maxIdle="2"
      minIdle="1"
      suspectTimeout="60"
      timeBetweenEvictionRunsMillis="30000"
      minEvictableIdleTimeMillis="60000"
      validationQuery="select 1 from dual"
      validationInterval="30000"
      testOnBorrow="true"
      removeAbandoned="true"
      removeAbandonedTimeout="60"
      abandonWhenPercentageFull="10"
      maxWait="10000"
      maxAge="60000"/>

It seems that the problem of transaction happens because it failed to open connection with oracle . 似乎交易问题发生了,因为它无法打开与oracle的连接 If you are using oracle 10g as you have configured in hibernate.cfg.xml 如果您正在使用oracle 10g,就像在hibernate.cfg.xml中配置的一样

    <session-factory>
      <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>

And You are using oracle thin driver : 你正在使用oracle瘦驱动程序

 <Resource name="jdbc/ToolSfDB" global="jdbc/ToolSfDB" auth="Container" type="javax.sql.DataSource"
      driverClassName="oracle.jdbc.OracleDriver"
      url="jdbc:oracle:thin:@//oracle01-internal.local:1521/orcl01"

The driver class might not be configured properly. 可能未正确配置驱动程序类

Use oracle.jdbc.driver.OracleDriver instead of oracle.jdbc.OracleDriver . 使用oracle.jdbc.driver.OracleDriver而不是oracle.jdbc.OracleDriver

  <Resource name="jdbc/ToolSfDB" global="jdbc/ToolSfDB" auth="Container" type="javax.sql.DataSource"
          driverClassName="oracle.jdbc.driver.OracleDriver"
          url="jdbc:oracle:thin:@//oracle01-internal.local:1521/orcl01"

Notes: Make sure of the oracle jar version. 注意:确保oracle jar版本。 it will work for ojdbc6.jar . 它适用于ojdbc6.jar

References: 参考文献:

  1. hibernate cfg xml settings for derby oracle and h2 用于derby oracle和h2的hibernate cfg xml设置
  2. difference between oracle jdbc driver classes oracle jdbc驱动程序类之间的区别
  3. configuring jdbc pool high concurrency 配置jdbc池高并发性

At first, I want to give you couple of suggestions. 首先,我想给你几个建议。

  1. Please check version of oracle driver . 请检查oracle driver版本。 If not same then use correct version of oracle driver . 如果不相同则使用正确版本的oracle驱动程序 As you are using oracle 11, so download ojdbc6.jar file and use it. 在使用oracle 11时,请下载ojdbc6.jar文件并使用它。
  2. Sometimes ORACLE_HOME was not set. 有时ORACLE_HOME没有设置。 So when the java application accessing the database, it causes the following error. 因此,当java应用程序访问数据库时,会导致以下错误。 So check that ORACLE_HOME is set or not. 因此,请检查是否设置了ORACLE_HOME

Caused by: java.sql.SQLException: Connection oracle.jdbc.driver.T4CConnection@1a6d7ad6 is closed. 引起:java.sql.SQLException:连接oracle.jdbc.driver.T4CConnection@1a6d7ad6已关闭。

  1. From the error , 从错误

it is defined that It means the connection was successfully established at some point, but when you try to commit right there, the connection was no longer open. 它被定义为表示连接已在某个时刻成功建立,但是当您尝试在那里提交时,连接不再打开。 The parameters you mentioned sound like connection pool settings . 您提到的参数听起来像连接池设置 In your hibernate.cfg.xml file add 在你的hibernate.cfg.xml文件中添加

<property name="hibernate.connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.min_size">5</property> 
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.timeout">1800</property>
<property name="hibernate.c3p0.max_statements">50</property>

Related Link: 相关链接:

  1. hibernate connection pool configuration with c3p0 example 使用c3p0示例的hibernate连接池配置
  2. docs 文档

If you want to add pool size in properties file , then follow this tutorial. 如果要在properties file添加池大小,请遵循教程。

4. Are you using oracle 10g ? 你在使用oracle 10g吗? if yes then it's ok otherwise Oracle10gDialect need to be changed for lower version . 如果是,则可以,否则Oracle10gDialect需要更改为lower version

<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
  1. Use hibernate.hbm2ddl.auto = validate mode. 使用hibernate.hbm2ddl.auto = validate模式。 It is used in oracle 11g . 它用于oracle 11g

UPDATE: 更新:

  1. As you are not using c3p0 pooling, then configure the pool by setting in properties file 由于您没有使用c3p0池,因此可以通过在属性文件中进行设置来配置池

    accessToUnderlyingConnectionAllowed = true accessToUnderlyingConnectionAllowed = true

and then it may work. 然后它可能会起作用。

Default is false, it is a potential dangerous operation and misbehaving programs can do harmful things. 默认是假的,这是一个潜在的危险操作,行为不端的程序可以做有害的事情。 (closing the underlying or continue using it when the guarded connection is already closed) Be careful and only use when you need direct access to driver specific extensions (在保护连接已经关闭时关闭底层或继续使用它)小心并且仅在需要直接访问驱动程序特定扩展时使用

  1. In your server.xml please change 在您的server.xml请更改

     initialSize="10" maxActive="100" maxIdle="50" minIdle="10" 

The initialSize=10 is the number of connections that will be established when the connection pool is created initialSize=10是创建连接池时将建立的连接数

The maxActive=100 is the maximum number of established connections to the database. maxActive=100是与数据库建立的最大连接数。

The minIdle=10 is the minimum number of connections always established after the connection pool has reached this size. minIdle=10是连接池达到此大小后始终建立的最小连接数。

The maxIdle attribute is a little bit trickier. maxIdle属性有点棘手。 It behaves differently depending on if the pool sweeper is enabled. 它的行为会有所不同,具体取决于池清除程序是否已启用。

Please study configuring-jdbc-pool-high-concurrency tutorial for better understanding to configure server.xml . 请学习配置-jdbc-pool-high-concurrency教程,以便更好地理解配置server.xml If you study this tutorial, I hope you can solve it by yours. 如果你学习本教程,我希望你能解决它。

you said that I add that this error spawns like once every 2 days. 你说I add that this error spawns like once every 2 days. if your database trafic hight, I think manage connection pools for example use C3P0 and manage total connections,timeouts ... etc 如果您的数据库交通高,我认为管理连接池例如使用C3P0并管理总连接,超时等

for example 例如

<property name="hibernate.c3p0.timeout">500</property>

this idle connection is removed from the pool (500 second) 从池中删除此空闲连接(500秒)

and more knowledge here . 这里有更多的知识。

I'm investigating further more, and I suspect a scenario that could cause this issue. 我正在进一步调查,我怀疑可能导致此问题的情况。

Suppose I have a transactional method in the service layer. 假设我在服务层中有一个事务方法。 This method can call different objects on the DAO layer, each of them having his own connections. 此方法可以调用DAO层上的不同对象,每个对象都有自己的连接。

Suppose the first call to DAO1 goes well, and updates a record. 假设第一次调用DAO1运行良好,并更新记录。

Now another user make some other operations, and when my transactional method calls for DAO2 operation, it finds no connections available, causing the issue and leaving the transaction inactive after a timeout. 现在另一个用户进行了一些其他操作,当我的事务方法调用DAO2操作时,它找不到可用的连接,导致问题并在超时后使事务处于非活动状态。

Could it be the issue? 这可能是问题吗?

If so, I found out that Tomcat Jdbc configuration has other parameters that I cound add: 如果是这样,我发现Tomcat Jdbc配置有其他参数我要添加:

rollbackOnReturn    
(boolean) If autoCommit==false then the pool can terminate the transaction by calling rollback on the connection as it is returned to the pool Default value is false.

commitOnReturn  
(boolean) If autoCommit==false then the pool can complete the transaction by calling commit on the connection as it is returned to the pool If rollbackOnReturn==true then this attribute is ignored. Default value is false.

At this point, could the first parameter set to true be the solution? 此时,第一个参数设置为true是解决方案吗?

I ran into similar issue, After tweaking removeAbandonedTimeout got it working. 我遇到了类似的问题,经过调整removeAbandonedTimeout让它工作。 Here is how my configuration looks now. 以下是我的配置现在的样子。

    maxActive="60"
    maxIdle="30"

    maxWait="12000"
    validationQuery="select 1"
    validationInterval="30000"
    testOnBorrow="true"
    testOnReturn="false"
    testWhileIdle="true"
    timeBetweenEvictionRunsMillis="30000"
    minEvictableIdleTimeMillis="600000"

    logAbandoned="true"
    removeAbandoned="true" 
    removeAbandonedTimeout="180"

Explanation: Earlier my removeAbandonedTimeout is configured as 60. But some of my queries are taking more that 60 seconds to execute, So while the query is being executed the connection is closed by the pool as the abandoned timeout is reached. 说明:之前我的removeAbandonedTimeout配置为60.但是我的一些查询执行时间超过60秒。因此,在执行查询时,池会在达到放弃超时时关闭连接。 After query execution, spring transaction tries to commit that connection which is failing because the connection has been already closed. 查询执行后,spring transaction尝试提交失败的连接,因为连接已经关闭。

For now i increased the removeAbandonedTimeout to 180, while we are trying optimize the query that is taking more time. 现在我将removeAbandonedTimeout增加到180,而我们正在尝试优化需要更多时间的查询。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM