From: gu.martinm@gmail.com Date: Wed, 8 Oct 2014 19:53:18 +0000 (+0200) Subject: Data base deadlocks. How to deal with them (retries) X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=562338f73131e9ccc6dbba1c2dfc7ac8765db0d2;p=JavaForFun Data base deadlocks. How to deal with them (retries) --- diff --git a/SpringJava/DeadLocksSQL/pom.xml b/SpringJava/DeadLocksSQL/pom.xml new file mode 100644 index 0000000..57d311e --- /dev/null +++ b/SpringJava/DeadLocksSQL/pom.xml @@ -0,0 +1,187 @@ + + 4.0.0 + de.example.sql.deadlocks + sql-deadlocks-retry + jar + 1.0-SNAPSHOT + sql-deadlocks-retry + http://gumartinm.name + + UTF-8 + 3.1.1.RELEASE + 2.0.4.RELEASE + + + + + + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.0-rc1 + + + + org.apache.logging.log4j + log4j-core + 2.0-rc1 + + + + com.lmax + disruptor + 3.2.1 + + + + + + org.springframework + spring-context + ${spring.version} + + + org.springframework + spring-jdbc + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-beans + ${spring.version} + + + org.springframework + spring-tx + ${spring.version} + + + org.springframework + spring-aop + ${spring.version} + + + org.springframework.batch + spring-batch-core + ${spring.batch.version} + + + org.springframework.batch + spring-batch-infrastructure + ${spring.batch.version} + + + + + + org.aspectj + aspectjrt + 1.6.5 + + + org.aspectj + aspectjweaver + 1.6.5 + + + + + com.mchange + c3p0 + 0.9.2.1 + + + mysql + mysql-connector-java + 5.1.6 + + + cglib + cglib + 2.2.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + 1.6 + 1.6 + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-resources-plugin + 2.6 + + ${project.build.sourceEncoding} + + + + org.apache.maven.plugins + maven-jar-plugin + 2.3.1 + + + + ${project.description} + ${project.version} + ${project.organization.name} + ${project.description} + ${project.version} + ${project.organization.name} + ${BUILD_TAG} + ${BUILD_ID} + ${BUILD_NUMBER} + ${prefix.committedRevision} + ${prefix.repository} + ${prefix.path} + + + + + + + diff --git a/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/Main.java b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/Main.java new file mode 100644 index 0000000..b545307 --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/Main.java @@ -0,0 +1,23 @@ +package de.example.sql.deadlocks; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.example.sql.deadlocks.example.CustomAnnotationExample; + + +public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + + /** + * @param args + */ + public static void main(String[] args) { + logger.info("Starting application"); + + CustomAnnotationExample customAnnotation = + (CustomAnnotationExample) SpringContextLocator.getInstance().getBean("customAnnotation"); + customAnnotation.doCustomAnnotationExample(); + logger.info("End application"); + } +} diff --git a/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/SpringContextLocator.java b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/SpringContextLocator.java new file mode 100644 index 0000000..36bdda1 --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/SpringContextLocator.java @@ -0,0 +1,37 @@ +package de.example.sql.deadlocks; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + + +public final class SpringContextLocator { + private static final Logger logger = LoggerFactory.getLogger(SpringContextLocator.class); + // Spring Context + private static final String SPRING_CONFIG_CONTEXT="/spring-config.xml"; + // Spring ApplicationContext + private final ApplicationContext context; + + + private SpringContextLocator() { + logger.info("Loading context files: " + SpringContextLocator.SPRING_CONFIG_CONTEXT); + + final String[] factoryFiles = new String[] { SPRING_CONFIG_CONTEXT }; + context = new ClassPathXmlApplicationContext(factoryFiles); + + logger.info("The context has been loaded successfully!! "); + } + + private static class SingletonHolder { + private static final SpringContextLocator INSTANCE = new SpringContextLocator(); + } + + public static SpringContextLocator getInstance() { + return SingletonHolder.INSTANCE; + } + + public Object getBean(final String name) { + return context.getBean(name); + } +} diff --git a/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/annotation/DeadlockRetry.java b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/annotation/DeadlockRetry.java new file mode 100644 index 0000000..ba8cc7d --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/annotation/DeadlockRetry.java @@ -0,0 +1,26 @@ +package de.example.sql.deadlocks.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface DeadlockRetry { + + /** + * Tries max number. Default value 3. + * + * @return tries max number. + */ + int maxTries() default 3; + + /** + * Interval in milliseconds between subsequent repeats. Default value 1000. + * + * @return interval in milliseconds + */ + int interval() default 1000; +} diff --git a/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/aspect/DeadlockRetryAspect.java b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/aspect/DeadlockRetryAspect.java new file mode 100644 index 0000000..96c9ed2 --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/aspect/DeadlockRetryAspect.java @@ -0,0 +1,79 @@ +package de.example.sql.deadlocks.aspect; + +import java.lang.reflect.Method; + +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException; + +import de.example.sql.deadlocks.annotation.DeadlockRetry; + +/** + * Following example from: http://java-success.blogspot.com.es/2013/08/deadlock-retry-with-spring-aop-using.html + * + */ +@Aspect +public class DeadlockRetryAspect { + private static final Logger logger = LoggerFactory.getLogger(DeadlockRetryAspect.class); + + @Around(value = "@annotation(de.example.sql.deadlocks.annotation.DeadlockRetry)", argNames = "deadlockRetry") + public Object doAround(final ProceedingJoinPoint pjp, final DeadlockRetry deadlockRetry) throws Throwable { + logger.info("GUSUSUSUUS"); + final Integer maxTries = deadlockRetry.maxTries(); + final long interval = deadlockRetry.interval(); + + final Object target = pjp.getTarget(); + final MethodSignature signature = (MethodSignature) pjp.getSignature(); + final Method method = signature.getMethod(); + + int count = 0; + Throwable deadLockException = null; + do { + try { + count++; + + logger.info("Attempting to invoke method " + method.getName() + " on " + target.getClass() + " count " + count); + //Calling real method + Object result = pjp.proceed(); + logger.info("Completed invocation of method " + method.getName() + " on " + target.getClass()); + + return result; + } catch (final Throwable e1) { + + if (!isDeadLock(e1)) { + throw e1; + } + + deadLockException = e1; + if (interval > 0) { + try { + Thread.sleep(interval); + } catch (final InterruptedException e2) { + logger.warn("Deadlock retry thread interrupt", e2); + + // Restore interrupt status. + Thread.currentThread().interrupt(); + } + } + } + } while (count <= maxTries); + + throw new RuntimeException("DeadlockRetry failed, deadlock in all retry attempts.", deadLockException); + } + + + private boolean isDeadLock(Throwable ex) { + do { + if (ex instanceof MySQLTransactionRollbackException) { + return true; + } + } while ((ex = ex.getCause()) != null); + + return false; + } +} diff --git a/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/example/CustomAnnotationExample.java b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/example/CustomAnnotationExample.java new file mode 100644 index 0000000..9eef75a --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/example/CustomAnnotationExample.java @@ -0,0 +1,17 @@ +package de.example.sql.deadlocks.example; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.transaction.annotation.Transactional; + +import de.example.sql.deadlocks.annotation.DeadlockRetry; + +//@Transactional +public class CustomAnnotationExample { + private static final Logger logger = LoggerFactory.getLogger(CustomAnnotationExample.class); + + @DeadlockRetry(maxTries = 10, interval = 5000) + public void doCustomAnnotationExample() { + logger.info("Running doCustomAnnotationExample"); + } +} diff --git a/SpringJava/DeadLocksSQL/src/main/resources/log4j2.xml b/SpringJava/DeadLocksSQL/src/main/resources/log4j2.xml new file mode 100644 index 0000000..067a6f0 --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/resources/log4j2.xml @@ -0,0 +1,201 @@ + + + + + + target/fileappender.log + target/filerandomappender.log + + + + + + + + + + + + + + + + + + + + + + + + "%d{yyyyMMddHHmmssSSS} - %-5p - [%t] - %m%n" + UTF-8 + + + + + + + "%d{yyyyMMddHHmmssSSS} - %-5p - [%t] - %m%n" + UTF-8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SpringJava/DeadLocksSQL/src/main/resources/spring-config.xml b/SpringJava/DeadLocksSQL/src/main/resources/spring-config.xml new file mode 100644 index 0000000..7fc8b38 --- /dev/null +++ b/SpringJava/DeadLocksSQL/src/main/resources/spring-config.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +