--- /dev/null
+<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>
--- /dev/null
+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");
+ }
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+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");
+ }
+}
--- /dev/null
+<?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>
--- /dev/null
+<?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>