Voj*_*ěch 12 java mysql hibernate c3p0
我在我的项目中使用hibernate,我得到随机的表观死锁,用于非常简单的数据库操作.
有一个堆栈跟踪:https://gist.github.com/knyttl/8999006 - 让我困惑的是,第一个Exception是RollbackException,然后是LockAquisition Exceptions.
问题经常出现在类似的条款中:
@Transactional
public void setLastActivity() {
User user = em.findById(...);
user.setLastActivity(new Date());
em.merge(user);
em.flush();
}
Run Code Online (Sandbox Code Playgroud)
我很困惑,因为我不知道它是Hibernate,MySQL还是C3P0的问题.
我的Hibernate配置:
<prop key="hibernate.dialect">${database.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${database.structure}</prop>
<prop key="hibernate.connection.url">${database.connection}</prop>
<prop key="hibernate.connection.username">${database.username}</prop>
<prop key="hibernate.connection.password">${database.password}</prop>
<prop key="hibernate.connection.driver_class">${database.driver}</prop>
<prop key="hibernate.connection.shutdown">true</prop>
<prop key="hibernate.connection.writedelay">0</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.charSet">UTF-8</prop>
<prop key="hibernate.show_sql">${database.show_sql}</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.ejb.metamodel.generation">disabled</prop>
<!-- Use the C3P0 connection pool provider -->
<prop key="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</prop>
<prop key="hibernate.c3p0.min_size">0</prop>
<prop key="hibernate.c3p0.max_size">50</prop>
<prop key="hibernate.c3p0.timeout">120</prop>
<prop key="hibernate.c3p0.max_statements">0</prop>
<prop key="hibernate.c3p0.max_statementsPerConnection">0</prop>
<prop key="hibernate.c3p0.maxStatementsPerConnection">0</prop>
<prop key="hibernate.c3p0.idle_test_period">120</prop>
<prop key="hibernate.c3p0.acquire_increment">1</prop>
<prop key="hibernate.c3p0.numHelperThreads">8</prop>
Run Code Online (Sandbox Code Playgroud)
EDIT1:
EDIT2:
这也发生在这些方法上 - 那些需要用@Transactional注释的NEEDS:
@Transactional
public void setLastActivity() {
em.insertNative("table")
.values(...)
.execute();
}
Run Code Online (Sandbox Code Playgroud)
Ang*_*ity 23
因为死锁频繁发生,所以看起来应用程序的某些线程长时间持有锁.
应用程序中的每个线程在访问数据库时都将使用它自己的数据库连接/连接,因此从数据库的角度来看,两个线程是两个不同的客户端,它们竞争数据库锁.
如果一个线程长时间持有锁并以某种顺序获取它们,并且第二个线程以不同的顺序获取相同的锁,则必然会发生死锁(有关此频繁死锁原因的详细信息,请参见此处)).
在读取操作中也会发生死锁,这意味着某些线程也在获取读锁定.如果线程在REPEATABLE_READ
隔离级别运行事务,则会发生这种情况SERIALIZABLE
.
为了解决这个问题,尝试搜索的用途Isolation.REPEATABLE_READ
和Isolation.SERIALIZABLE
项目,来看看这被使用.
作为替代方案,使用默认READ_COMMITTED
隔离级别并使用@Version
,使用乐观锁定来处理并发性.
还尝试识别长时间运行的事务,这有时会发生@Transactional
在错误的位置,例如在批处理的示例中处理整个文件,而不是逐行执行事务.
这是一个log4j配置,用于记录实体管理器和事务begin/commit/rollback的创建/删除:
<!-- spring entity manager and transactions -->
<logger name="org.springframework.orm.jpa" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
<logger name="org.springframework.transaction" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
Run Code Online (Sandbox Code Playgroud)
可以通过本机查询或JPQL进行更新查询.
在没有的方法中@Transactional
,查询将在它自己的实体管理器中执行,并且只返回分离的实体,因为在运行查询后会立即关闭会话.
所以没有方法的懒惰初始化异常@Transactional
是正常的.您也可以将它们设置@Transactional(readOnly=true)
为.
这是MySQL的错误。
解决和避免死锁的最简单方法是重新排序应用程序中发生的数据库操作。
当多个资源/连接试图以相反的顺序获取多个锁时,死锁通常会发生,如下所示:
connection 1: locks key(1), locks key(2);
connection 2: locks key(2), locks key(1);
Run Code Online (Sandbox Code Playgroud)
在两个连接同时执行的情况下,连接1将获得对键(1)的锁定,而连接2将获得对键(2)的锁定。之后,两个连接都将等待其他连接释放钥匙上的锁。这导致死锁。
但是,在事务顺序上稍作调整,就可以避免死锁。
connection 1: locks key(1), locks key(2);
connection 2: locks key(1), locks key(2);
Run Code Online (Sandbox Code Playgroud)
上面的重新排序可以证明死锁。
避免死锁的其他方法是具有事务管理机制。Spring的事务管理几乎是即插即用的。此外,您可以制定死锁重试策略。通过Spring AOP一个有趣的死锁重试,可以发现在这里。这样,您只需将注释添加到要在出现死锁的情况下重试的方法。
有关死锁的更多调试日志,以找出哪些语句可疑,请尝试运行“ show engine innodb status”诊断。另外,您还可以查看如何应付死锁。
更新:事务性数据库操作中出现死锁的情况。
在事务数据库中,当两个进程各自在其自己的事务中更新两行信息但顺序相反时,就会发生死锁。例如,进程A在确切的时间范围内先更新第1行,然后更新第2行,进程B更新第2行,然后更新第1行。直到进程B完成,进程A才能完成对行2的更新,但是直到进程B完成后,它才能完成对行1的更新。完成。无论允许经过多少时间,这种情况都永远不会解决,并且由于这种数据库管理系统通常会终止完成最少工作量的流程的事务。
希希尔
归档时间: |
|
查看次数: |
28217 次 |
最近记录: |