소스 검색

使用jta 分布式事务Atomikos ok

NorthLan 7 년 전
부모
커밋
1e0b0ec798

+ 6 - 1
.gitignore

@@ -150,4 +150,9 @@ logs/
 
 
 # bus
-transaction-logs/
+transaction-logs/
+*.epoch
+*.lck
+
+/*.epoch
+/*.lck

BIN
transaction-logs/192.168.1.204.tm0.epoch


+ 0 - 0
transaction-logs/tmlog.lck


+ 1 - 0
zen-api/build.gradle

@@ -1,5 +1,6 @@
 dependencies {
     compile project(":zen-umps")
+    compile project(":zen-orm")
 }
 
 jar{

+ 5 - 5
zen-api/src/main/kotlin/com/gxzc/zen/api/bus/service/impl/MgrFondsServiceImpl.kt

@@ -1,15 +1,14 @@
 package com.gxzc.zen.api.bus.service.impl
 
-import com.gxzc.zen.api.bus.model.MgrFonds
+import com.baomidou.mybatisplus.service.impl.ServiceImpl
 import com.gxzc.zen.api.bus.mapper.MgrFondsMapper
+import com.gxzc.zen.api.bus.model.MgrFonds
 import com.gxzc.zen.api.bus.service.IMgrFondsService
-import com.baomidou.mybatisplus.service.impl.ServiceImpl
 import com.gxzc.zen.api.sys.model.SysParam
 import com.gxzc.zen.api.sys.service.ISysParamService
+import com.gxzc.zen.orm.annotation.MultiTransactional
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.stereotype.Service
-import org.springframework.transaction.annotation.Propagation
-import org.springframework.transaction.annotation.Transactional
 
 /**
  * <p>
@@ -25,7 +24,8 @@ class MgrFondsServiceImpl : ServiceImpl<MgrFondsMapper, MgrFonds>(), IMgrFondsSe
     @Autowired
     private lateinit var sysParamService: ISysParamService
 
-    @Transactional(propagation = Propagation.NESTED)
+
+    @MultiTransactional(noRollbackFor = [RuntimeException::class])
     override fun testTransaction() {
         baseMapper.insert(MgrFonds().also {
             it.fondsName = "2333"

+ 0 - 1
zen-orm/build.gradle

@@ -1,4 +1,3 @@
 dependencies {
     compile project(":zen-common")
-    compile project(":zen-api")
 }

+ 1 - 4
zen-orm/src/main/kotlin/com/gxzc/zen/orm/annotation/DynamicDataSource.kt

@@ -1,12 +1,9 @@
 package com.gxzc.zen.orm.annotation
 
-import org.springframework.core.annotation.AliasFor
-
 /**
  *
  * @author NorthLan at 2018/1/29
  */
 @Retention(AnnotationRetention.RUNTIME)
 @Target(AnnotationTarget.FUNCTION, AnnotationTarget.TYPE)
-annotation class DynamicDataSource(@get:AliasFor("dataSource") val value: String = "",
-                                   @get:AliasFor("value") val dataSource: String = "")
+annotation class DynamicDataSource(val value: String = "")

+ 17 - 0
zen-orm/src/main/kotlin/com/gxzc/zen/orm/annotation/MultiTransactional.kt

@@ -0,0 +1,17 @@
+package com.gxzc.zen.orm.annotation
+
+import java.lang.annotation.Inherited
+import kotlin.reflect.KClass
+
+/**
+ *
+ * @author NorthLan
+ * @date 2018/2/3
+ * @url https://noahlan.com
+ */
+@Target(AnnotationTarget.FUNCTION)
+@Retention(AnnotationRetention.RUNTIME)
+@Inherited
+annotation class MultiTransactional(val value: String = "",
+                                    val rollbackFor: Array<KClass<out Throwable>> = [],
+                                    val noRollbackFor: Array<KClass<out Throwable>> = [])

+ 10 - 0
zen-orm/src/main/kotlin/com/gxzc/zen/orm/annotation/Test.java

@@ -0,0 +1,10 @@
+package com.gxzc.zen.orm.annotation;
+
+/**
+ * @author NorthLan
+ * @date 2018/2/3
+ * @url https://noahlan.com
+ */
+public @interface Test {
+    Class<? extends Throwable>[] rollbackFor() default {};
+}

+ 57 - 6
zen-orm/src/main/kotlin/com/gxzc/zen/orm/aop/DataSourceSwitchAspect.kt

@@ -1,7 +1,9 @@
 package com.gxzc.zen.orm.aop
 
+import com.gxzc.zen.common.util.SpringContextHolder
 import com.gxzc.zen.orm.DynamicMultipleDataSource
 import com.gxzc.zen.orm.annotation.DynamicDataSource
+import com.gxzc.zen.orm.annotation.MultiTransactional
 import com.gxzc.zen.orm.contants.DSKey
 import org.aspectj.lang.JoinPoint
 import org.aspectj.lang.ProceedingJoinPoint
@@ -10,7 +12,10 @@ import org.aspectj.lang.reflect.MethodSignature
 import org.slf4j.LoggerFactory
 import org.springframework.core.annotation.Order
 import org.springframework.stereotype.Component
+import org.springframework.transaction.jta.JtaTransactionManager
 import java.lang.reflect.Method
+import kotlin.reflect.KClass
+
 
 /**
  *
@@ -21,13 +26,14 @@ import java.lang.reflect.Method
 @Order(-1) // 保证先于事务执行
 @Component
 class DataSourceSwitchAspect {
-    init {
-        logger.debug("${this::class.java.simpleName} initialized...")
-    }
     companion object {
         private val logger = LoggerFactory.getLogger(DataSourceSwitchAspect::class.java)
     }
 
+    init {
+        logger.debug("${this::class.java.simpleName} initialized...")
+    }
+
     private var isAnnotationAspect = false
 
     @Pointcut("execution(* com.gxzc.zen.api..*Service.*(..))")
@@ -46,11 +52,56 @@ class DataSourceSwitchAspect {
     fun mpMapperPointCut() {
     }
 
-    @Pointcut("@annotation(com.gxzc.zen.orm.annotation.DynamicDataSource)")
-    fun annotationCut() {
+    /**
+     * 一致性事务切面解决方案
+     */
+    @Around("@annotation(com.gxzc.zen.orm.annotation.MultiTransactional)")
+    fun multiTransactionAround(joinPoint: ProceedingJoinPoint): Any? {
+        logger.info("@MultiTransactional aspect...")
+        val methodName = joinPoint.signature.name
+        val parameterTypes = (joinPoint.signature as MethodSignature).method.parameterTypes
+        val method = joinPoint.target::class.java.getMethod(methodName, *parameterTypes)
+
+        if (method.isAnnotationPresent(MultiTransactional::class.java)) {
+            val multiTransaction = method.getAnnotation(MultiTransactional::class.java)
+            val transactionManager = SpringContextHolder.getBean(JtaTransactionManager::class.java)
+            val userTransaction = transactionManager?.userTransaction
+            return try {
+                userTransaction?.begin()
+                val r = joinPoint.proceed()
+                userTransaction?.commit()
+                return r
+            } catch (e: Throwable) {
+                val rollbackExceptions = multiTransaction.rollbackFor
+                val noRollbackExceptions = multiTransaction.noRollbackFor
+
+                val isRollbackExceptionPresent = isPresent(e, rollbackExceptions)
+                val isNoRollbackExceptionPresent = isPresent(e, noRollbackExceptions)
+
+                // rollbackFor回滚 noRollbackFor不回滚
+                if (isRollbackExceptionPresent || !isNoRollbackExceptionPresent) {
+                    userTransaction?.rollback()
+                } else {
+                    userTransaction?.commit()
+                }
+            }
+        } else {
+            return joinPoint.proceed()
+        }
+    }
+
+    /**
+     * 判断指定类型是否存在于注解中
+     * @param e 指定抛出类型
+     * @param exceptions 注解定义的类型列表
+     */
+    private fun isPresent(e: Throwable, exceptions: Array<KClass<out Throwable>>): Boolean {
+        return exceptions.find {
+            e::class.java.isAssignableFrom(it.java) || e::class.java == it::java
+        } != null
     }
 
-    @Around("annotationCut()")
+    @Around("@annotation(com.gxzc.zen.orm.annotation.DynamicDataSource)")
     fun annotationAround(joinPoint: ProceedingJoinPoint): Any? {
         logger.debug("@DynamicDatasource aspect...")
         isAnnotationAspect = true

+ 14 - 4
zen-orm/src/main/kotlin/com/gxzc/zen/orm/config/MultipleDataSourceConfig.kt

@@ -1,6 +1,8 @@
 package com.gxzc.zen.orm.config
 
 import com.alibaba.druid.pool.xa.DruidXADataSource
+import com.atomikos.icatch.jta.UserTransactionImp
+import com.atomikos.icatch.jta.UserTransactionManager
 import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean
 import com.baomidou.mybatisplus.spring.boot.starter.MybatisPlusProperties
 import com.baomidou.mybatisplus.spring.boot.starter.SpringBootVFS
@@ -15,11 +17,11 @@ import org.springframework.context.annotation.Bean
 import org.springframework.context.annotation.Configuration
 import org.springframework.context.annotation.DependsOn
 import org.springframework.context.annotation.Primary
-import org.springframework.jdbc.datasource.DataSourceTransactionManager
+import org.springframework.transaction.PlatformTransactionManager
 import org.springframework.transaction.jta.JtaTransactionManager
 import javax.sql.DataSource
 import javax.sql.XADataSource
-import javax.transaction.TransactionManager
+
 
 /**
  *
@@ -72,9 +74,17 @@ class MultipleDataSourceConfig {
         }
     }
 
+//    @Bean("tx1")
+//    fun platformTransactionManager(): PlatformTransactionManager {
+//        return JtaTransactionManager().also {
+//            it.userTransaction = UserTransactionImp()
+//            it.transactionManager = UserTransactionManager()
+//        }
+//    }
+
 //    @Bean
-//    fun transactionManager(dynamicMultipleDataSource: DynamicMultipleDataSource): JtaTransactionManager {
-//        return JtaTransactionManager(DataSourceTransactionManager(dynamicMultipleDataSource) as TransactionManager)
+//    fun transactionManager(dynamicMultipleDataSource: DynamicMultipleDataSource): DataSourceTransactionManager {
+//        return DataSourceTransactionManager(dynamicMultipleDataSource)
 //    }
 
     @Bean

+ 1 - 1
zen-web/build.gradle

@@ -1,7 +1,7 @@
 apply plugin: 'war'
 
 dependencies {
-    compile project(":zen-orm")
+//    compile project(":zen-orm")
     compile project(":zen-api")
     compile project(":zen-umps")
     compile project(":zen-mq")

+ 1 - 1
zen-web/src/main/resources/application.yml

@@ -6,7 +6,7 @@ server:
 spring:
   profiles:
     active: dev
-    include: orm-local,mq
+    include: orm,mq
 #  redis:
 #    host: localhost
 #    port: 6379