--- /dev/null
+-- MySQL dump 10.13 Distrib 5.5.35, for debian-linux-gnu (x86_64)
+--
+-- Host: localhost Database: example
+-- ------------------------------------------------------
+-- Server version 5.5.35-0+wheezy1-log
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `children`
+--
+
+DROP TABLE IF EXISTS `children`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `children` (
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(500) COLLATE utf8_unicode_ci NOT NULL,
+ `parent_id` bigint(20) unsigned NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `parent_id` (`parent_id`),
+ CONSTRAINT `children_ibfk_1` FOREIGN KEY (`parent_id`) REFERENCES `parents` (`id`) ON DELETE CASCADE
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `children`
+--
+
+LOCK TABLES `children` WRITE;
+/*!40000 ALTER TABLE `children` DISABLE KEYS */;
+INSERT INTO `children` VALUES (1,'Peter',1),(2,'Mary',2);
+/*!40000 ALTER TABLE `children` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `parents`
+--
+
+DROP TABLE IF EXISTS `parents`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!40101 SET character_set_client = utf8 */;
+CREATE TABLE `parents` (
+ `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(500) COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `parents`
+--
+
+LOCK TABLES `parents` WRITE;
+/*!40000 ALTER TABLE `parents` DISABLE KEYS */;
+INSERT INTO `parents` VALUES (1,'John'),(2,'Foo');
+/*!40000 ALTER TABLE `parents` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2014-10-09 11:35:50
package de.example.sql.deadlocks;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import de.example.sql.deadlocks.example.CustomAnnotationExample;
+import de.example.sql.deadlocks.example.FirstTransaction;
+import de.example.sql.deadlocks.example.SecondTransaction;
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();
+
+ final FutureTask<Void> taskFirst = new FutureTask<Void>
+ (
+ new Runnable(){
+
+ @Override
+ public void run() {
+ final FirstTransaction first = (FirstTransaction) SpringContextLocator.getInstance().getBean("firstTransaction");
+ first.doTransaction();
+ }
+ },
+ null
+ );
+ new Thread(taskFirst).start();
+
+ final FutureTask<Void> taskSecond = new FutureTask<Void>
+ (
+ new Runnable(){
+
+ @Override
+ public void run() {
+ final SecondTransaction second = (SecondTransaction) SpringContextLocator.getInstance().getBean("secondTransaction");
+ second.doTransaction();
+ }
+ },
+ null
+ );
+ new Thread(taskSecond).start();
+
+ // Wait for end.
+ try {
+ taskFirst.get();
+ taskSecond.get();
+ } catch (final InterruptedException e) {
+ logger.error("Error", e);
+ } catch (final ExecutionException e) {
+ logger.error("Error", e);
+ }
+
+
logger.info("End application");
}
}
*
* @return interval in milliseconds
*/
- int interval() default 1000;
+ long interval() default 1000;
}
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.core.Ordered;
import com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException;
*
*/
@Aspect
-public class DeadlockRetryAspect {
+public class DeadlockRetryAspect implements Ordered {
private static final Logger logger = LoggerFactory.getLogger(DeadlockRetryAspect.class);
+ private static final int ORDER = 99;
- @Around(value = "@annotation(de.example.sql.deadlocks.annotation.DeadlockRetry)", argNames = "deadlockRetry")
+ @Around(value = "@annotation(deadlockRetry)", argNames = "deadlockRetry")
public Object doAround(final ProceedingJoinPoint pjp, final DeadlockRetry deadlockRetry) throws Throwable {
- logger.info("GUSUSUSUUS");
- final Integer maxTries = deadlockRetry.maxTries();
+
+ final int maxTries = deadlockRetry.maxTries();
final long interval = deadlockRetry.interval();
final Object target = pjp.getTarget();
}
}
}
- } while (count <= maxTries);
+ } while (count < maxTries);
throw new RuntimeException("DeadlockRetry failed, deadlock in all retry attempts.", deadLockException);
}
+ @Override
+ public int getOrder() {
+ return ORDER;
+ }
private boolean isDeadLock(Throwable ex) {
do {
+++ /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
+package de.example.sql.deadlocks.example;
+
+import javax.sql.DataSource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcOperations;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.transaction.annotation.Transactional;
+
+import de.example.sql.deadlocks.annotation.DeadlockRetry;
+
+@Transactional
+public class FirstTransaction {
+ private static final Logger logger = LoggerFactory.getLogger(FirstTransaction.class);
+ private DataSource dataSource;
+
+ @DeadlockRetry(maxTries = 10, interval = 5000)
+ public void doTransaction() {
+ logger.info("Running doTransaction");
+
+ final JdbcOperations jdbcTemplate = new JdbcTemplate(dataSource);
+ jdbcTemplate.execute("UPDATE children SET name='Bilbo', parent_id='2' WHERE id='1'");
+ jdbcTemplate.execute("UPDATE parents SET name='Smith' WHERE id='1'");
+
+ try {
+ Thread.sleep(100000);
+ } catch (final InterruptedException e) {
+ logger.warn("First transaction thread interrupt");
+
+ // Restore interrupt status.
+ Thread.currentThread().interrupt();
+ }
+
+ logger.info("Running endTransaction");
+ }
+
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+}
--- /dev/null
+package de.example.sql.deadlocks.example;
+
+import javax.sql.DataSource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcOperations;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.transaction.annotation.Transactional;
+
+import de.example.sql.deadlocks.annotation.DeadlockRetry;
+
+@Transactional
+public class SecondTransaction {
+ private static final Logger logger = LoggerFactory.getLogger(SecondTransaction.class);
+ private DataSource dataSource;
+
+ @DeadlockRetry(maxTries = 10, interval = 5000)
+ public void doTransaction() {
+ logger.info("Running doTransaction");
+
+ final JdbcOperations jdbcTemplate = new JdbcTemplate(dataSource);
+ jdbcTemplate.execute("UPDATE children SET name='Frodo', parent_id='2' WHERE id='2'");
+ jdbcTemplate.execute("UPDATE parents SET name='Smith' WHERE id='1'");
+
+ logger.info("Running endTransaction");
+ }
+
+ public void setDataSource(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+}
<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
@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.
+ I do not really need the component-scan thing but I hope, it will improve performance (not sure)
-->
<context:component-scan base-package="de.example.sql.deadlocks" use-default-filters="false">
<context:include-filter
-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="user" value="root"/>
- <property name="password" value=""/>
+ <property name="password" value="root"/>
<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"/>
- <bean id="customAnnotation" class="de.example.sql.deadlocks.example.CustomAnnotationExample" >
+ <bean id="firstTransaction" class="de.example.sql.deadlocks.example.FirstTransaction" >
+ <property name="dataSource" ref="dataSource"/>
+ </bean>
+
+ <bean id="secondTransaction" class="de.example.sql.deadlocks.example.SecondTransaction" >
+ <property name="dataSource" ref="dataSource"/>
</bean>
</beans>