mysql - Jboss 7.2 txn 管理到 Spring 托管 PlatformTransactionManager - 锁定表
问题描述
从 JBoss 容器管理的 TransactionManagement 迁移到 Spring 管理的事务管理器 - (死)在插入表时锁定表并且不关闭 txn/session 并且从应用程序跟踪 txns 也会得到相同的错误。此行为仅在使用之后PlatformTransactionManager
,并且在一个 jvm/appserver 以 0s 间隔在此表上选择而另一个 jvm/appserver 在同一个表上运行 insert 并且 insert txn 挂起的情况下。我必须杀死 txnshow full PROCESSLIST; kill <pid>;
才能释放锁,以便下一个 sql 可以继续。
已锁定表的 MySQL 查询状态为“发送到客户端”
发送给客户
服务器正在向客户端写入数据包。
任何帮助/提示表示赞赏。
Caused by: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction
at com.mysql@8.0.16//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:123)
at com.mysql@8.0.16//com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql@8.0.16//com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
at com.mysql@8.0.16//com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:955)
at com.mysql@8.0.16//com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1094)
at com.mysql@8.0.16//com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1042)
at com.mysql@8.0.16//com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1345)
at com.mysql@8.0.16//com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdate(ClientPreparedStatement.java:1027)
at org.jboss.ironjacamar.jdbcadapters@1.4.11.Final-redhat-00001//org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.executeUpdate(WrappedPreparedStatement.java:537)
at org.hibernate@5.3.7.Final-redhat-00001//org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
数据源:
<datasource jndi-name="java:jboss/datasources/my-ds" pool-name="my-ds" enabled="true" use-ccm="true" statistics-enabled="true">
<connection-url>jdbc:mysql://XXXXXXXXXXXX:3306/dbName?useSSL=false&characterEncoding=UTF-8&serverTimezone=US/Eastern</connection-url>
<driver>mysql</driver>
<pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>10</max-pool-size>
<flush-strategy>FailingConnectionOnly</flush-strategy>
</pool>
<security>
<user-name>user</user-name>
<password>password</password>
</security>
<validation>
<valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"/>
<check-valid-connection-sql>select 1 from dual</check-valid-connection-sql>
<validate-on-match>false</validate-on-match>
<background-validation>true</background-validation>
<background-validation-millis>30000</background-validation-millis>
<use-fast-fail>false</use-fast-fail>
<exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"/>
</validation>
<timeout>
<set-tx-query-timeout>false</set-tx-query-timeout>
<idle-timeout-minutes>10</idle-timeout-minutes>
<query-timeout>0</query-timeout>
<allocation-retry>3</allocation-retry>
<allocation-retry-wait-millis>2500</allocation-retry-wait-millis>
</timeout>
</datasource>
<drivers>
<driver name="oracle" module="com.oracle">
<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
</driver>
<driver name="mysql" module="com.mysql">
<xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class>
</driver>
</drivers>
持久性.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
version="2.2">
<persistence-unit name="unitName" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<non-jta-data-source>java:jboss/datasources/my-ds</non-jta-data-source>
<class>com.company.entity1</class>
<class>com.company.entity2</class>
<class>com.company.entity3</class>
...
<properties>
<property name="jboss.as.jpa.managed" value="false"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.generate_statistics" value="false"/>
<property name="hibernate.id.new_generator_mapping" value="true"/>
<property name="org.hibernate.envers.audit_table_suffix" value="_history"/>
<property name="org.hibernate.envers.revision_field_name" value="history_info_id"/>
<property name="org.hibernate.envers.revision_type_field_name" value="history_info_type"/>
</properties>
</persistence-unit>
@Configuration
public class JpaConfig {
@Bean
public PersistenceUnitManager persistenceUnitManager() {
DefaultPersistenceUnitManager persistenceUnitManager = new DefaultPersistenceUnitManager();
persistenceUnitManager.setPersistenceXmlLocations("classpath*:META-INF/persistence.xml");
persistenceUnitManager.setDataSourceLookup(new JndiDataSourceLookup());
return persistenceUnitManager;
}
@Primary
@Bean("someEntityManagerFactory")
public EntityManagerFactory somentityManagerFactory(PersistenceUnitManager persistenceUnitManager) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setPersistenceXmlLocation("classpath*:META-INF/persistence.xml");
entityManagerFactoryBean.setPersistenceUnitManager(persistenceUnitManager);
entityManagerFactoryBean.setPersistenceUnitName("unitName");
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
entityManagerFactoryBean.afterPropertiesSet();
return entityManagerFactoryBean.getObject();
}
@Bean("someJpaTransactionManager")
public PlatformTransactionManager someJpaTransactionManager(
@Qualifier("someEntityManagerFactory") EntityManagerFactory entityManagerFactory){
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
jpaTransactionManager.afterPropertiesSet();
return jpaTransactionManager;
}
交易状态:
public static TransactionStatus getTransactionStatus(PlatformTransactionManager platformTransactionManager){
DefaultTransactionDefinition txDef = new DefaultTransactionDefinition(PROPAGATION_REQUIRES_NEW);
txDef.setTimeout(transactionTimeout.get().intValue());
return platformTransactionManager.getTransaction(txDef);
}
//Usage: jpaTransactionManager.commit(txnStatus);
标签:spring-tx, PlatformTransactionManager, spring-5.1.5
解决方案
这可能会有所帮助
注释类型启用事务管理
@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
@Import(value=TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement 启用 Spring 的注解驱动事务管理功能,类似于 Spring 的 XML 命名空间中的支持。用于@Configuration 类,如下所示:
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public FooRepository fooRepository() {
// configure and return a class having @Transactional methods
return new JdbcFooRepository(dataSource());
}
@Bean
public DataSource dataSource() {
// configure and return the necessary JDBC DataSource
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
}
作为参考,可以将上面的示例与以下 Spring XML 配置进行比较:
<beans>
<tx:annotation-driven/>
<bean id="fooRepository" class="com.foo.JdbcFooRepository">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.vendor.VendorDataSource"/>
<bean id="transactionManager" class="org.sfwk...DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
</beans>
在上述两种情况下,@EnableTransactionManagement 和负责注册必要的 Spring 组件,这些组件为注释驱动的事务管理提供支持,例如 TransactionInterceptor 和基于代理或 AspectJ 的建议,当 JdbcFooRepository 的 @ 时将拦截器编织到调用堆栈中调用事务方法。两个示例之间的细微差别在于 PlatformTransactionManager bean 的命名:在 @Bean 的情况下,名称是“txManager”(根据方法的名称);在 XML 的情况下,名称是“transactionManager”。默认情况下查找名为“transactionManager”的bean是硬连线的,但是@EnableTransactionManagement更灵活;它将回退到容器中任何 PlatformTransactionManager bean 的按类型查找。
对于那些希望在 @EnableTransactionManagement 和要使用的确切事务管理器 bean 之间建立更直接关系的人,可以实现 TransactionManagementConfigurer 回调接口 - 请注意下面的 implements 子句和 @Override 注释方法:
@Configuration
@EnableTransactionManagement
public class AppConfig implements TransactionManagementConfigurer {
@Bean
public FooRepository fooRepository() {
// configure and return a class having @Transactional methods
return new JdbcFooRepository(dataSource());
}
@Bean
public DataSource dataSource() {
// configure and return the necessary JDBC DataSource
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return txManager();
}
}
这种方法可能是可取的,因为它更明确,或者为了区分同一容器中存在的两个 PlatformTransactionManager bean 可能是必要的。顾名思义,annotationDrivenTransactionManager() 将用于处理@Transactional 方法。有关详细信息,请参阅 TransactionManagementConfigurer Javadoc。mode() 属性控制如何应用建议:如果模式是 AdviceMode.PROXY(默认),那么其他属性控制代理的行为。请注意,代理模式只允许通过代理拦截呼叫;同一类中的本地调用不能以这种方式被拦截。
请注意,如果 mode() 设置为 AdviceMode.ASPECTJ,则 proxyTargetClass() 属性的值将被忽略。另请注意,在这种情况下,spring-aspects 模块 JAR 必须存在于类路径中,编译时编织或加载时编织将方面应用于受影响的类。这种情况下不涉及代理;本地电话也将被拦截。
推荐阅读
- angularjs - Http Post Angularjs通过Web API导致内部服务器错误
- tensorflow - 为什么我的结果仍然无法重现?
- sql - 在集合中查找缺失的子集
- swift - 如何判断 EKEvent 实例是否被拒绝?
- javascript - 加载资源失败:服务器响应状态为 409
- android - 如何观察 LiveData
在 kotlin 中使用 android 分页 - java - 在 org.elasticsearch.client.RestHighLevelClient 中获取没有 id 的结果
- r - 如何根据条件组合长度不等的数据帧
- .net - 在不使用样式的情况下设置自定义控件的默认控件模板
- javascript - 在 TypeScript 文件中的光标下键入