Data base deadlocks. How to deal with them (retries)
authorgu.martinm@gmail.com <gu.martinm@gmail.com>
Wed, 8 Oct 2014 19:53:18 +0000 (21:53 +0200)
committergu.martinm@gmail.com <gu.martinm@gmail.com>
Wed, 8 Oct 2014 19:53:18 +0000 (21:53 +0200)
SpringJava/DeadLocksSQL/pom.xml [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/Main.java [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/SpringContextLocator.java [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/annotation/DeadlockRetry.java [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/aspect/DeadlockRetryAspect.java [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/java/de/example/sql/deadlocks/example/CustomAnnotationExample.java [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/resources/log4j2.xml [new file with mode: 0644]
SpringJava/DeadLocksSQL/src/main/resources/spring-config.xml [new file with mode: 0644]

diff --git a/SpringJava/DeadLocksSQL/pom.xml b/SpringJava/DeadLocksSQL/pom.xml
new file mode 100644 (file)
index 0000000..57d311e
--- /dev/null
@@ -0,0 +1,187 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>de.example.sql.deadlocks</groupId>
+  <artifactId>sql-deadlocks-retry</artifactId>
+  <packaging>jar</packaging>
+  <version>1.0-SNAPSHOT</version>
+  <name>sql-deadlocks-retry</name>
+  <url>http://gumartinm.name</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <spring.version>3.1.1.RELEASE</spring.version>
+    <spring.batch.version>2.0.4.RELEASE</spring.batch.version>
+  </properties>
+  <dependencies>
+    <!--
+    **************************************************************************************************************************
+        1. LOGBACK: SLF4J NATIVE IMPLEMENTATION. See: http://logback.qos.ch/
+    **************************************************************************************************************************
+    -->
+    <!--
+        1/1 Required dependency for native implementation (nothing else is required)
+
+        Native implementation. There are also SLF4J bindings external to the SLF4J project, e.g. logback which implements
+        SLF4Jnatively. Logback's ch.qos.logback.classic.Logger class is a direct implementation of SLF4J's org.slf4j.Logger
+        interface. Thus, using SLF4J in conjunction with logback involves strictly zero memory and computational overhead.
+        see: http://www.slf4j.org/manual.html
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>1.1.2</version>
+    </dependency>
+    -->
+    <!--
+    **************************************************************************************************************************
+        2. SLF4J AND LOG4J 2. See: http://logging.apache.org/log4j/2.x/
+    **************************************************************************************************************************
+    -->
+    <!--
+        1/2 Required dependency for log4j 2 with slf4j: binding
+    -->
+    <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-slf4j-impl</artifactId>
+        <version>2.0-rc1</version>
+    </dependency>
+    <!--
+        2/2 Required dependency for log4j 2 with slf4j: log4j 2 maven plugin
+    -->
+    <dependency>
+        <groupId>org.apache.logging.log4j</groupId>
+        <artifactId>log4j-core</artifactId>
+        <version>2.0-rc1</version>
+    </dependency>
+    <!--
+        LMAX Disruptor technology for LOG4J 2. I am not using it, but it is declared in my log4j2.xml file (just for fun)
+    -->
+    <dependency>
+      <groupId>com.lmax</groupId>
+      <artifactId>disruptor</artifactId>
+      <version>3.2.1</version>
+    </dependency>
+
+       
+    <!--
+        Spring dependencies
+    -->
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-context</artifactId>
+        <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-jdbc</artifactId>
+        <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-beans</artifactId>
+        <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-beans</artifactId>
+        <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-tx</artifactId>
+        <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework</groupId>
+        <artifactId>spring-aop</artifactId>
+        <version>${spring.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework.batch</groupId>
+        <artifactId>spring-batch-core</artifactId>
+        <version>${spring.batch.version}</version>
+    </dependency>
+    <dependency>
+        <groupId>org.springframework.batch</groupId>
+        <artifactId>spring-batch-infrastructure</artifactId>
+        <version>${spring.batch.version}</version>
+    </dependency>
+
+
+    <!--
+        AOP AspectJ
+    -->
+    <dependency>
+        <groupId>org.aspectj</groupId>
+        <artifactId>aspectjrt</artifactId>
+        <version>1.6.5</version>
+    </dependency>
+    <dependency>
+        <groupId>org.aspectj</groupId>
+        <artifactId>aspectjweaver</artifactId>
+        <version>1.6.5</version>
+    </dependency>
+
+
+    <dependency>
+        <groupId>com.mchange</groupId>
+        <artifactId>c3p0</artifactId>
+        <version>0.9.2.1</version>
+    </dependency>
+    <dependency>
+        <groupId>mysql</groupId>
+        <artifactId>mysql-connector-java</artifactId>
+        <version>5.1.6</version>
+    </dependency>
+    <dependency>
+      <groupId>cglib</groupId>
+      <artifactId>cglib</artifactId>
+      <version>2.2.2</version>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+        <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <version>2.0.2</version>
+            <configuration>
+                <source>1.6</source>
+                <target>1.6</target>
+                <encoding>${project.build.sourceEncoding}</encoding>
+            </configuration>
+        </plugin>
+        <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-resources-plugin</artifactId>
+            <version>2.6</version>
+            <configuration>
+                <encoding>${project.build.sourceEncoding}</encoding>
+            </configuration>
+        </plugin>
+        <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jar-plugin</artifactId>
+            <version>2.3.1</version>
+            <configuration>
+                <archive>
+                    <manifestEntries>
+                        <Specification-Title>${project.description}</Specification-Title>
+                        <Specification-Version>${project.version}</Specification-Version>
+                        <Specification-Vendor>${project.organization.name}</Specification-Vendor>
+                        <Implementation-Title>${project.description}</Implementation-Title>
+                        <Implementation-Version>${project.version}</Implementation-Version>
+                        <Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                        <Implementation-Build>${BUILD_TAG}</Implementation-Build>
+                        <Implementation-Build-id>${BUILD_ID}</Implementation-Build-id>
+                        <Implementation-Build-number>${BUILD_NUMBER}</Implementation-Build-number>
+                        <scm-committed-revision>${prefix.committedRevision}</scm-committed-revision>
+                        <scm-repository>${prefix.repository}</scm-repository>
+                        <scm-path>${prefix.path}</scm-path>
+                    </manifestEntries>
+                </archive>
+            </configuration>
+        </plugin>
+    </plugins>
+  </build>
+</project>
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 (file)
index 0000000..b545307
--- /dev/null
@@ -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 (file)
index 0000000..36bdda1
--- /dev/null
@@ -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 (file)
index 0000000..ba8cc7d
--- /dev/null
@@ -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 (file)
index 0000000..96c9ed2
--- /dev/null
@@ -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 (file)
index 0000000..9eef75a
--- /dev/null
@@ -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 (file)
index 0000000..067a6f0
--- /dev/null
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    * name: The name of the configuration.
+    * dest: Either "err", which will send output to stderr, or a file path or URL.
+    * status: The level of internal Log4j events that should be logged to the console. Valid values for this attribute are "trace",
+      "debug", "info", "warn", "error" and "fatal". Log4j will log details about initialization, rollover and other internal
+      actions to the status logger.
+    * strict: Enables the use of the strict XML format. Not supported in JSON configurations.
+    * monitorInterval: If the monitorInterval attribute is specified on the configuration element and is set to a non-zero value
+      then the file will be checked the next time a log event is evaluated and/or logged and the monitorInterval has elapsed
+      since the last check.
+    * packages: A comma separated list of package names to search for plugins. Plugins are only loaded once per classloader so
+      changing this value may not have any effect upon reconfiguration.
+-->
+<Configuration name="XMLConfigTest" dest="err" status="trace" strict="true" monitorInterval="30" packages="org.apache.logging.log4j.test">
+    <!--
+        Log4j 2 supports the ability to specify tokens in the configuration as references to properties defined elsewhere. Some of
+        these properties will be resolved when the configuration file is interpreted while others may be passed to components
+        where they will be evaluated at runtime.
+    -->
+    <Properties>
+        <Property name="filename">target/fileappender.log</Property>
+        <Property name="filerandomname">target/filerandomappender.log</Property>
+    </Properties>
+
+    <!--
+         Filters may be configured in one of four locations:
+
+        Context-wide Filters are configured directly in the configuration. Events that are rejected by these filters
+        will not be passed to loggers for further processing. Once an event has been accepted by a Context-wide filter
+        it will not be evaluated by any other Context-wide Filters nor will the Logger's Level be used to filter the event.
+        The event will be evaluated by Logger and Appender Filters however.
+        Logger Filters are configured on a specified Logger. These are evaluated after the Context-wide Filters and the Log Level
+        for the Logger. Events that are rejected by these filters will be discarded and the event will not be passed to a parent
+        Logger regardless of the additivity setting.
+
+        Appender Filters are used to determine if a specific Appender should handle the formatting and publication of the event.
+        Appender Reference Filters are used to determine if a Logger should route the event to an appender.
+
+    <Filter type="ThresholdFilter" level="debug"/>
+    -->
+    
+    <Appenders>
+        <Appender type="Console" name="STDOUT">
+            <!--
+            <ThresholdFilter level="ERROR" onMatch="ACCEPT" onMismatch="DENY"/>
+            -->
+            <Filter type="ThresholdFilter" level="trace"/>
+            <!--
+            <Layout type="PatternLayout" pattern="%d{ABSOLUTE} %5p %c{1}:%L %m%n"/>
+            -->
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx - %X{id} %X{name} %X{surname}%n"/>
+            <!--  
+            <Filters>
+                See: FlowTracingExample class in this project.
+                <Filter type="MarkerFilter" marker="FLOW" onMatch="ENTER" onMismatch="NEUTRAL"/>
+                <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="CATCHING" onMismatch="ACCEPT"/>
+                
+                See: MarkersExample class in this project.
+                ¿Cómo usar esto cuando hago logger.debug(QUERY_MARKER, "SELECT * FROM {}", table);?
+                ¿Sería marker="DEBUG"?
+                <Filter type="MarkerFilter" marker="FLOW" onMatch="SQL_UPDATE" onMismatch="NEUTRAL"/>
+                <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="SQL_QUERY" onMismatch="ACCEPT"/>
+            </Filters>
+            -->
+        </Appender>
+        <Appender type="Console" name="FLOW">
+            <Layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/><!-- class and line number -->
+            <Filters>
+                <Filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
+                <Filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
+            </Filters>
+        </Appender>
+        <!--
+            ¿Puedo mezclar bufferedIO=true con immediateFlush=true?
+            JUGAR CON ESOS 2 VALORES A VER QUE TAL... :/
+        -->
+        <Appender type="File" name="FileAppender" fileName="${filename}" bufferedIO="false" immediateFlush="true" append="true">
+            <Layout type="PatternLayout">
+                <!--
+                <Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
+                -->
+                <Pattern>"%d{yyyyMMddHHmmssSSS} - %-5p - [%t] - %m%n"</Pattern>
+                <Charset>UTF-8</Charset> 
+            </Layout>
+        </Appender>
+         <!--
+           * Asynchronous Loggers are a new addition to Log4j 2. Their aim is to return from the call to Logger.log to the application
+             as soon as possible. You can choose between making all Loggers asynchronous or using a mixture of synchronous and asynchronous
+             Loggers. Making all Loggers asynchronous will give the best performance, while mixing gives you more flexibility.
+           * LMAX Disruptor technology. Asynchronous Loggers internally use the Disruptor, a lock-free inter-thread communication library,
+             instead of queues, resulting in higher throughput and lower latency.
+           * Asynchronous Appenders already existed in Log4j 1.x, but have been enhanced to flush to disk at the end of a batch
+             (when the queue is empty). This produces the same result as configuring "immediateFlush=true", that is, all received log events
+             are always available on disk, but is more efficient because it does not need to touch the disk on each and every log event.
+             (Async Appenders use ArrayBlockingQueue internally and do not need the disruptor jar on the classpath.)
+           * (For synchronous and asynchronous use) Random Access File Appenders are an alternative to Buffered File Appenders. Under the hood,
+             these new appenders use a ByteBuffer + RandomAccessFile instead of a BufferedOutputStream. In our testing this was about 20-200%
+             faster. These appenders can also be used with synchronous loggers and will give the same performance benefits. Random Access
+             File Appenders do not need the disruptor jar on the classpath.
+        -->
+        <!-- El random access file siempre es con buffer!!!
+             When set to true - the default, each write will be followed by a flush. This will guarantee the data is written
+             to disk but could impact performance.
+
+             Flushing after every write is only useful when using this appender with synchronous loggers. Asynchronous loggers
+             and appenders will automatically flush at the end of a batch of events, even if immediateFlush is set to false.
+             This also guarantees the data is written to disk but is more efficient. 
+        -->
+        <Appender type="RandomAccessFile" name="RandomAccessFileAppender" fileName="${filerandomname}" immediateFlush="true" append="true">
+            <Layout type="PatternLayout">
+                <Pattern>"%d{yyyyMMddHHmmssSSS} - %-5p - [%t] - %m%n"</Pattern>
+                <Charset>UTF-8</Charset> 
+            </Layout>
+        </Appender>
+        <!--
+            El AsyncAppender siempre es bufferado y hace siempre un immediateFlush ¿independientemente del appender ref? SÍ, mira:
+
+            Mejor usar includeLocation=false proque el AsyncAppender siempre debe hacer la localización del log (nombre de clase, método y línea)
+            independientemente de si luego se va a loguear o no (porque haya filtros por ejemplo) Esto es así porque el asyncappender
+            debe generar toda la info necesaria antes de pasar esta info a la cola. Una vez en la cola asíncrona esa info ya no puede
+            ser generada. Por tanto, aunque ese log finalmente no se use, siempre se pone en la cola asíncrona con todos sus datos.
+
+            Extracting location is an expensive operation (it can make logging 5 - 20 times slower). To improve performance, location
+            is not included by default when adding a log event to the queue. You can change this by setting includeLocation="true".
+            Para extraer la localización al parecer hay que recorrer el stacktrace por eso es una operacion pesada.
+        -->
+        <Appender type="Async" name="AsyncAppender" blocking="true" bufferSize="128" errorRef="FileAppender" ignoreExceptions="false" includeLocation="false">
+                <!--
+                Probar las dos configuraciones
+                <AppenderRef ref="RandomAccessFileAppender"/>
+                -->
+                <AppenderRef ref="FileAppender"/>
+        </Appender>
+
+    </Appenders>
+     
+    <Loggers>
+        <!--
+        <Logger name="de.loggers.test" level="debug" additivity="false">
+            <Filter type="ThreadContextMapFilter">
+                <KeyValuePair key="test" value="123"/>
+            </Filter>
+            <AppenderRef ref="STDOUT"/>
+        </Logger>
+        -->
+    
+        <!-- 
+        <Logger name="de.loggers.test" level="debug" additivity="false">
+            <AppenderRef ref="File"/>
+        </Logger>
+        -->
+
+        <Logger name="de.loggers.test.simple" level="TRACE">
+            <!--
+              * Because THIS logger has additivity="true" by default THIS logger will use the same appender as its parent's logger,
+                which in this case is the logger Root.
+              * Because THIS logger has additivity="true" by default if we use this AppenderRef we will see for
+                classes in de.loggers.test.simple the same messages twice. One from this logger and one from its parent's logger,
+                which in this case is the logger Root.
+            <AppenderRef ref="STDOUT"/>
+            -->
+        </Logger>
+        <Logger name="de.loggers.test.formatter" level="TRACE" additivity="false">
+            <!--
+              * Because THIS logger has additivity="false" THIS logger will not use the same appender as its parent's logger.
+            -->
+            <AppenderRef ref="STDOUT"/>
+        </Logger>
+        <!--
+            By default, location is not passed to the I/O thread by asynchronous loggers. If one of your layouts or custom
+            filters needs location information, you need to set "includeLocation=true" in the configuration of all relevant loggers,
+            including the root logger.
+        -->
+
+
+
+        <!--
+           * Asynchronous Loggers are a new addition to Log4j 2. Their aim is to return from the call to Logger.log to the application
+             as soon as possible. You can choose between making all Loggers asynchronous or using a mixture of synchronous and asynchronous
+             Loggers. Making all Loggers asynchronous will give the best performance, while mixing gives you more flexibility.
+           * LMAX Disruptor technology. Asynchronous Loggers internally use the Disruptor, a lock-free inter-thread communication library,
+             instead of queues, resulting in higher throughput and lower latency.
+           * Asynchronous Appenders already existed in Log4j 1.x, but have been enhanced to flush to disk at the end of a batch
+             (when the queue is empty). This produces the same result as configuring "immediateFlush=true", that is, all received log events
+             are always available on disk, but is more efficient because it does not need to touch the disk on each and every log event.
+             (Async Appenders use ArrayBlockingQueue internally and do not need the disruptor jar on the classpath.)
+           * (For synchronous and asynchronous use) Random Access File Appenders are an alternative to Buffered File Appenders. Under the hood,
+             these new appenders use a ByteBuffer + RandomAccessFile instead of a BufferedOutputStream. In our testing this was about 20-200%
+             faster. These appenders can also be used with synchronous loggers and will give the same performance benefits. Random Access
+             File Appenders do not need the disruptor jar on the classpath.
+        -->
+        <AsyncLogger name="de.loggers.test.loggernames" level="TRACE" includeLocation="false">
+            <AppenderRef ref="RandomAccessFileAppender"/>
+        </AsyncLogger>
+        <Root level="TRACE">
+            <AppenderRef ref="STDOUT"/>
+        </Root>
+    </Loggers>
+     
+</Configuration>
diff --git a/SpringJava/DeadLocksSQL/src/main/resources/spring-config.xml b/SpringJava/DeadLocksSQL/src/main/resources/spring-config.xml
new file mode 100644 (file)
index 0000000..7fc8b38
--- /dev/null
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xmlns:tx="http://www.springframework.org/schema/tx"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans 
+                                                  http://www.springframework.org/schema/beans/spring-beans.xsd
+                                                  http://www.springframework.org/schema/context 
+                                                  http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/aop 
+                           http://www.springframework.org/schema/aop/spring-aop.xsd
+                           http://www.springframework.org/schema/tx
+                           http://www.springframework.org/schema/tx/spring-tx.xsd">
+          
+    <!-- 
+        ************* WE HAVE TO ENABLE THE ASPECTJ SUPPORT!!!!!! ************* 
+        Otherwise the @Aspect annotation (defines @AspectJ aspects) will not work
+        It relies on the Java 5 specific AspectJ reflection APIs. You can not use it
+        on JDK 1.4 and below.
+            
+            
+        We could force here the use of CGLIB.
+        See: http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/aop.html#aop-proxying
+        Spring detects if the bean has an interface implementation. If it has one,
+        Spring will use J2SE (J2SE needs classes with interfaces) in other case it
+        will use CGLIB. We could force the CGLIB use in classes with interfaces.
+    -->
+    <aop:aspectj-autoproxy/>
+
+
+    <!--
+        Spring makes the nasty work for us (it searches the annotations) 
+        See: http://static.springsource.org/spring/docs/3.1.0.RC1/spring-framework-reference/html/beans.html#beans-annotation-config
+
+        With filters we can narrow down the targets and hopefully improve the 
+        performance while searching annotations in the Spring context. 
+        Besides we disable automatic detection of classes annotated with 
+        @Component, @Repository, @Service, or @Controller because we do not
+        need here that feature.
+
+        NOTA: VER SI ASPECTJ REALMENTE NECESITA ESTO. YO CREO, QUE NO!!!! PROBAR A BORRAR ESTO Y VER QUE PASA.
+    -->
+    <context:component-scan base-package="de.example.sql.deadlocks" use-default-filters="false">
+        <context:include-filter 
+        type="annotation" 
+        expression="de.example.sql.deadlocks.annotation.DeadlockRetry" />
+    </context:component-scan>
+
+    <bean id="deadlockRetryAspect" class="de.example.sql.deadlocks.aspect.DeadlockRetryAspect">
+    </bean>
+
+
+
+
+
+    <!-- enables configuration of transactional behavior based on annotations -->
+    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
+    <!--
+        Not required, just for fun.
+    -->
+       <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
+                <property name="user" value="root"/>
+                <property name="password" value=""/>
+                <property name="driverClass" value="com.mysql.jdbc.Driver"/>
+                <property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/example?autoReconnect=true"/>
+                <property name="initialPoolSize" value="5"/>
+                <property name="maxPoolSize" value="20"/>
+                <property name="minPoolSize" value="10"/>
+                <property name="acquireIncrement" value="1"/>
+                <property name="acquireRetryAttempts" value="5"/>
+                <property name="acquireRetryDelay" value="1000"/>
+                <property name="automaticTestTable" value="con_test"/>
+                <property name="checkoutTimeout" value="5000"/>
+    </bean>
+
+    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+        <property name="dataSource" ref="dataSource"/>
+    </bean>
+
+
+
+
+    <bean id="customAnnotation" class="de.example.sql.deadlocks.example.CustomAnnotationExample" >
+    </bean>
+</beans>