最近在搭建TX-LCN分布式事务时遇到不少坑,为了这些坑浪费了很长时间,为了别的小伙伴不在和我似的在这些坑上遇到相同的麻烦特把我的搭建过程整理出来,给大家参考
官方说明:http://www.txlcn.org/zh-cn/docs/demo/env.html
前期准备工作:
Mysql数据库、Redis缓存、Eureka注册服务。
1、新建SpringBoot项目
截止到发文前springboot官网版本是2.1.5,因此创建完成后,需要修改版本信息,降低版本号。TX-LCN项目中已经集成了redis和数据库连接,因此这里不需要加入数据库和redis相关的依赖。只加入eureka 客户端的依赖即可。
2、修改pom.xml文件,修改版本号信息及,增加相关的依赖信息,如图:
生成的pom.xml文件内容如下:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.6.RELEASE
com.manager
tc-manager
0.0.1-SNAPSHOT
tc-manager
Demo project for Spring Boot
1.8
Finchley.SR2
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.boot
spring-boot-starter-test
test
com.codingapi.txlcn
txlcn-tm
5.0.2.RELEASE
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
3、修改application.properties文件,增加tm相关的配置信息,如redis和数据库等。
注意:tx-lcn.manager.port=8070 这个配置,它用于配置LCN的监听端口,我们在下面配置客户端服务里需要用到这个端口号。
server.port=7970
spring.application.name=TransactionManager
eureka.client.service-url.defaultZone=http://admin:admin@localhost:8761/eureka
eureka.instance.appname=transaction-manager
eureka.instance.prefer-ip-address=true
#JDBC 数据库配置
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://10.115.132.12:3306/tx?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
#数据库方言
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
# 第一次运行可以设置为: create, 为TM创建持久化数据库表
#spring.jpa.hibernate.ddl-auto=validate
spring.jpa.hibernate.ddl-auto=update
# TM监听IP. 默认为 127.0.0.1
tx-lcn.manager.host=127.0.0.1
# TM监听Socket端口. 默认为 ${server.port} - 100
tx-lcn.manager.port=8070
# 心跳检测时间(ms). 默认为 300000
tx-lcn.manager.heart-time=300000
# 分布式事务执行总时间(ms). 默认为36000
tx-lcn.manager.dtx-time=8000
# 参数延迟删除时间单位ms 默认为dtx-time值
tx-lcn.message.netty.attr-delay-time=${tx-lcn.manager.dtx-time}
# 事务处理并发等级. 默认为机器逻辑核心数5倍
tx-lcn.manager.concurrent-level=160
# TM后台登陆密码,默认值为codingapi
tx-lcn.manager.admin-key=codingapi
# 分布式事务锁超时时间 默认为-1,当-1时会用tx-lcn.manager.dtx-time的时间
tx-lcn.manager.dtx-lock-time=${tx-lcn.manager.dtx-time}
# 雪花算法的sequence位长度,默认为12位.
tx-lcn.manager.seq-len=12
# 异常回调开关。开启时请制定ex-url
tx-lcn.manager.ex-url-enabled=false
# 事务异常通知(任何http协议地址。未指定协议时,为TM提供内置功能接口)。默认是邮件通知
tx-lcn.manager.ex-url=/provider/email-to/***@**.com
# 开启日志,默认为false
tx-lcn.logger.driver-class-name=${spring.datasource.driver-class-name}
tx-lcn.logger.jdbc-url=${spring.datasource.url}
tx-lcn.logger.username=${spring.datasource.username}
tx-lcn.logger.password=${spring.datasource.password}
# redis 的设置信息. 线上请用Redis Cluster
spring.redis.host=10.115.132.12
spring.redis.port=6379
spring.redis.password=123456
4、修改启动文件,增加TX-LCN的注解@EnableTransactionManagerServer。代码如下:
package com.manager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import com.codingapi.txlcn.tm.config.EnableTransactionManagerServer;
@SpringBootApplication
@EnableDiscoveryClient
@EnableTransactionManagerServer
public class TcManagerApplication {
public static void main(String[] args) {
SpringApplication.run(TcManagerApplication.class, args);
}
}
5、创建完成后就可以启动服务了。控制台出现如下信息表示TX-LCN的服务端搭建完成。
2019-06-09 18:18:30.544 INFO 14812 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@2b662a77: startup date [Sun Jun 09 18:18:30 CST 2019]; root of context hierarchy
2019-06-09 18:18:30.716 INFO 14812 --- [ main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2019-06-09 18:18:30.737 INFO 14812 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'configurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$d2cfd437] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.0.6.RELEASE)
2019-06-09 18:18:30.878 INFO 14812 --- [ main] com.manager.TcManagerApplication : No active profile set, falling back to default profiles: default
2019-06-09 18:18:30.878 INFO 14812 --- [ main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@67b9b51a: startup date [Sun Jun 09 18:18:30 CST 2019]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@2b662a77
2019-06-09 18:18:31.347 INFO 14812 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2019-06-09 18:18:31.662 INFO 14812 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Multiple Spring Data modules found, entering strict repository configuration mode!
2019-06-09 18:18:31.678 INFO 14812 --- [ main] .RepositoryConfigurationExtensionSupport : Spring Data Redis - Could not safely identify store assignment for repository candidate interface com.codingapi.txlcn.tm.support.db.jpa.TxExceptionRepository.
2019-06-09 18:18:31.806 INFO 14812 --- [ main] o.s.b.f.s.DefaultListableBeanFactory : Overriding bean definition for bean 'dataSource' with a different definition: replacing [Root bean: class [null]; scope=refresh; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=false; primary=false; factoryBeanName=org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Hikari; factoryMethodName=dataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]] with [Root bean: class [org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in BeanDefinition defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]]
2019-06-09 18:18:31.958 INFO 14812 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=0df06d89-18ce-38e7-9c32-fa4e5efaeac5
2019-06-09 18:18:31.977 INFO 14812 --- [ main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2019-06-09 18:18:32.070 INFO 14812 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$b6b5d13a] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-06-09 18:18:32.105 INFO 14812 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration' of type [org.springframework.cloud.autoconfigure.ConfigurationPropertiesRebinderAutoConfiguration$$EnhancerBySpringCGLIB$$d2cfd437] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2019-06-09 18:18:32.491 INFO 14812 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 7970 (http)
2019-06-09 18:18:32.516 INFO 14812 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2019-06-09 18:18:32.516 INFO 14812 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet Engine: Apache Tomcat/8.5.34
2019-06-09 18:18:32.524 INFO 14812 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jre1.8.0_201\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:/Program Files/Java/jre1.8.0_201/bin/server;C:/Program Files/Java/jre1.8.0_201/bin;C:/Program Files/Java/jre1.8.0_201/lib/amd64;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\iCLS\;C:\Program Files\Intel\Intel(R) Management Engine Components\iCLS\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\TortoiseSVN\bin;C:\Users\lenovo\AppData\Local\Microsoft\WindowsApps;;E:\sts-3.9.0.RELEASE;;.]
2019-06-09 18:18:32.684 INFO 14812 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-06-09 18:18:32.684 INFO 14812 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1806 ms
2019-06-09 18:18:32.856 WARN 14812 --- [ost-startStop-1] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2019-06-09 18:18:32.856 INFO 14812 --- [ost-startStop-1] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2019-06-09 18:18:32.863 INFO 14812 --- [ost-startStop-1] c.netflix.config.DynamicPropertyFactory : DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@521808b8
2019-06-09 18:18:34.071 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2019-06-09 18:18:34.072 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'webMvcMetricsFilter' to: [/*]
2019-06-09 18:18:34.072 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2019-06-09 18:18:34.072 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2019-06-09 18:18:34.072 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
2019-06-09 18:18:34.072 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpTraceFilter' to: [/*]
2019-06-09 18:18:34.072 INFO 14812 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Servlet dispatcherServlet mapped to [/]
2019-06-09 18:18:34.157 INFO 14812 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2019-06-09 18:18:34.424 INFO 14812 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2019-06-09 18:18:34.471 INFO 14812 --- [ main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2019-06-09 18:18:34.471 INFO 14812 --- [ main] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [
name: default
...]
2019-06-09 18:18:34.549 INFO 14812 --- [ main] org.hibernate.Version : HHH000412: Hibernate Core {5.2.17.Final}
2019-06-09 18:18:34.549 INFO 14812 --- [ main] org.hibernate.cfg.Environment : HHH000206: hibernate.properties not found
2019-06-09 18:18:34.596 INFO 14812 --- [ main] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2019-06-09 18:18:34.706 INFO 14812 --- [ main] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5InnoDBDialect
2019-06-09 18:18:35.368 INFO 14812 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2019-06-09 18:18:36.133 WARN 14812 --- [ main] c.n.c.sources.URLConfigurationSource : No URLs will be polled as dynamic configuration sources.
2019-06-09 18:18:36.133 INFO 14812 --- [ main] c.n.c.sources.URLConfigurationSource : To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
2019-06-09 18:18:36.196 INFO 14812 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2019-06-09 18:18:36.289 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@67b9b51a: startup date [Sun Jun 09 18:18:30 CST 2019]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@2b662a77
2019-06-09 18:18:36.336 WARN 14812 --- [ main] aWebConfiguration$JpaWebMvcConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2019-06-09 18:18:36.367 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/provider/email-to/{email}],methods=[POST]}" onto public boolean com.codingapi.txlcn.tm.support.txex.provider.DefaultExUrlProvider.email(java.lang.String,com.codingapi.txlcn.tm.support.db.domain.TxException)
2019-06-09 18:18:36.367 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/]}" onto public java.lang.String com.codingapi.txlcn.tm.support.restapi.RedirectController.index()
2019-06-09 18:18:36.383 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/login],methods=[POST]}" onto public com.codingapi.txlcn.tm.support.restapi.vo.Token com.codingapi.txlcn.tm.support.restapi.AdminController.login(java.lang.String) throws com.codingapi.txlcn.common.exception.TxManagerException
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/logs/{page} || /admin/logs/{page}/{limit} || /admin/logs],methods=[GET]}" onto public com.codingapi.txlcn.tm.support.restapi.vo.TxLogList com.codingapi.txlcn.tm.support.restapi.AdminController.txLogList(java.lang.Integer,java.lang.Integer,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.Integer) throws com.codingapi.txlcn.common.exception.TxManagerException
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/tx-manager],methods=[GET]}" onto public com.codingapi.txlcn.tm.support.restapi.vo.TxManagerInfo com.codingapi.txlcn.tm.support.restapi.AdminController.getTxManagerInfo()
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/app-mods/{page} || /admin/app-mods/{page}/{limit} || /admin/app-mods],methods=[GET]}" onto public com.codingapi.txlcn.tm.support.restapi.vo.ListAppMods com.codingapi.txlcn.tm.support.restapi.AdminController.listAppMods(java.lang.Integer,java.lang.Integer)
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/exceptions/{page} || /admin/exceptions || /admin/exceptions/{page}/{limit}],methods=[GET]}" onto public com.codingapi.txlcn.tm.support.restapi.vo.ExceptionList com.codingapi.txlcn.tm.support.restapi.AdminController.exceptionList(java.lang.Integer,java.lang.Integer,java.lang.Integer,java.lang.Integer)
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/exceptions],methods=[POST]}" onto public boolean com.codingapi.txlcn.tm.support.restapi.AdminController.deleteExceptions(com.codingapi.txlcn.tm.support.restapi.vo.DeleteExceptions) throws com.codingapi.txlcn.common.exception.TxManagerException
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/logs],methods=[DELETE]}" onto public boolean com.codingapi.txlcn.tm.support.restapi.AdminController.deleteLogs(com.codingapi.txlcn.tm.support.restapi.vo.DeleteLogsReq) throws com.codingapi.txlcn.common.exception.TxManagerException
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/tm-cluster],methods=[GET]}" onto public java.util.List com.codingapi.txlcn.tm.support.restapi.AdminController.tmList() throws com.codingapi.txlcn.common.exception.FastStorageException
2019-06-09 18:18:36.387 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/log/transaction-info],methods=[GET]}" onto public com.alibaba.fastjson.JSONObject com.codingapi.txlcn.tm.support.restapi.AdminController.transactionInfo(java.lang.String,java.lang.String) throws com.codingapi.txlcn.common.exception.TxManagerException
2019-06-09 18:18:36.388 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/admin/transaction-info],methods=[DELETE]}" onto public boolean com.codingapi.txlcn.tm.support.restapi.AdminController.deleteTransactionInfo(java.lang.String,java.lang.String,java.lang.String) throws com.codingapi.txlcn.common.exception.TxManagerException
2019-06-09 18:18:36.388 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/manager/refresh],methods=[POST]}" onto public boolean com.codingapi.txlcn.tm.support.restapi.TxManagerController.refresh(com.codingapi.txlcn.txmsg.params.NotifyConnectParams) throws com.codingapi.txlcn.txmsg.exception.RpcException
2019-06-09 18:18:36.388 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2019-06-09 18:18:36.388 INFO 14812 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2019-06-09 18:18:36.404 INFO 14812 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2019-06-09 18:18:36.404 INFO 14812 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2019-06-09 18:18:36.960 INFO 14812 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2019-06-09 18:18:36.970 INFO 14812 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map)
2019-06-09 18:18:36.970 INFO 14812 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map)
2019-06-09 18:18:36.971 INFO 14812 --- [ main] s.b.a.e.w.s.WebMvcEndpointHandlerMapping : Mapped "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto protected java.util.Map> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2019-06-09 18:18:37.008 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2019-06-09 18:18:37.009 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'logDbProperties' has been autodetected for JMX exposure
2019-06-09 18:18:37.010 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'dataSource' has been autodetected for JMX exposure
2019-06-09 18:18:37.018 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'environmentManager' has been autodetected for JMX exposure
2019-06-09 18:18:37.019 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'refreshScope' has been autodetected for JMX exposure
2019-06-09 18:18:37.020 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'configurationPropertiesRebinder' has been autodetected for JMX exposure
2019-06-09 18:18:37.023 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'environmentManager': registering with JMX server as MBean [org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager]
2019-06-09 18:18:37.029 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'refreshScope': registering with JMX server as MBean [org.springframework.cloud.context.scope.refresh:name=refreshScope,type=RefreshScope]
2019-06-09 18:18:37.037 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'logDbProperties': registering with JMX server as MBean [com.codingapi.txlcn.logger.db:name=logDbProperties,type=LogDbProperties]
2019-06-09 18:18:37.039 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'configurationPropertiesRebinder': registering with JMX server as MBean [org.springframework.cloud.context.properties:name=configurationPropertiesRebinder,context=67b9b51a,type=ConfigurationPropertiesRebinder]
2019-06-09 18:18:37.043 INFO 14812 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located MBean 'dataSource': registering with JMX server as MBean [com.zaxxer.hikari:name=dataSource,type=HikariDataSource]
2019-06-09 18:18:37.048 INFO 14812 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2019-06-09 18:18:37.059 INFO 14812 --- [ main] o.s.c.n.eureka.InstanceInfoFactory : Setting initial instance status as: STARTING
2019-06-09 18:18:37.095 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Initializing Eureka in region us-east-1
2019-06-09 18:18:37.139 INFO 14812 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using JSON encoding codec LegacyJacksonJson
2019-06-09 18:18:37.140 INFO 14812 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using JSON decoding codec LegacyJacksonJson
2019-06-09 18:18:37.241 INFO 14812 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML encoding codec XStreamXml
2019-06-09 18:18:37.241 INFO 14812 --- [ main] c.n.d.provider.DiscoveryJerseyProvider : Using XML decoding codec XStreamXml
2019-06-09 18:18:37.423 INFO 14812 --- [ main] c.n.d.s.r.aws.ConfigClusterResolver : Resolving eureka endpoints via configuration
2019-06-09 18:18:37.464 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Disable delta property : false
2019-06-09 18:18:37.465 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
2019-06-09 18:18:37.465 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
2019-06-09 18:18:37.465 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Application is null : false
2019-06-09 18:18:37.465 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true
2019-06-09 18:18:37.465 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Application version is -1: true
2019-06-09 18:18:37.465 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
2019-06-09 18:18:37.606 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : The response status is 200
2019-06-09 18:18:37.621 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Starting heartbeat executor: renew interval is: 30
2019-06-09 18:18:37.621 INFO 14812 --- [ main] c.n.discovery.InstanceInfoReplicator : InstanceInfoReplicator onDemand update allowed rate per min is 4
2019-06-09 18:18:37.621 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Discovery Client initialized at timestamp 1560075517621 with initial instances count: 2
2019-06-09 18:18:37.621 INFO 14812 --- [ main] o.s.c.n.e.s.EurekaServiceRegistry : Registering application TRANSACTION-MANAGER with eureka with status UP
2019-06-09 18:18:37.621 INFO 14812 --- [ main] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1560075517621, current=UP, previous=STARTING]
2019-06-09 18:18:37.621 INFO 14812 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_TRANSACTION-MANAGER/DESKTOP-242V863:TransactionManager:7970: registering service...
2019-06-09 18:18:37.668 INFO 14812 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 7970 (http) with context path ''
2019-06-09 18:18:37.668 INFO 14812 --- [ main] .s.c.n.e.s.EurekaAutoServiceRegistration : Updating port to 7970
2019-06-09 18:18:37.668 INFO 14812 --- [ main] com.manager.TcManagerApplication : Started TcManagerApplication in 7.483 seconds (JVM running for 7.935)
2019-06-09 18:18:37.668 INFO 14812 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_TRANSACTION-MANAGER/DESKTOP-242V863:TransactionManager:7970 - registration status: 204
2019-06-09 18:18:37.778 INFO 14812 --- [ main] c.c.t.t.n.i.NettyRpcServerInitializer : Socket started on 127.0.0.1:8070
2019-06-09 18:18:37.793 INFO 14812 --- [ntLoopGroup-4-1] io.netty.handler.logging.LoggingHandler : [id: 0xd80096dd] REGISTERED
2019-06-09 18:18:37.793 INFO 14812 --- [ntLoopGroup-4-1] io.netty.handler.logging.LoggingHandler : [id: 0xd80096dd] BIND: /127.0.0.1:8070
2019-06-09 18:18:37.793 INFO 14812 --- [ntLoopGroup-4-1] io.netty.handler.logging.LoggingHandler : [id: 0xd80096dd, L:/127.0.0.1:8070] ACTIVE
2019-06-09 18:18:37.871 INFO 14812 --- [ main] io.lettuce.core.EpollProvider : Starting without optional epoll library
2019-06-09 18:18:37.871 INFO 14812 --- [ main] io.lettuce.core.KqueueProvider : Starting without optional kqueue library
2019-06-09 18:18:38.043 INFO 14812 --- [ main] c.c.t.t.s.s.impl.ManagerServiceImpl : Acquired machine id 40, max machine id is: 2251799813685246
二、TX-LCN的服务端搭建完成后,下一步我们就可以针对我们自己的项目设置分布式事务了。配置过程如下:
1、第一步我们先创建我们自己的微服务。如果有现成的微服务也可以在原有的微服务的基础上改造。为了测试方便,我这里创建了两个最简单的微服务。分别叫tc-client-1和tc-client-2。由于只是测试分布式事务,因此这两个项目我建设的完全一样。只有名称不一样。
2、项目创建后,修改依赖信息形成的pom.xml文件内容如下:
4.0.0
org.springframework.boot
spring-boot-starter-parent
2.0.6.RELEASE
com.client
tc-client-1
0.0.1-SNAPSHOT
tc-client-1
Demo project for Spring Boot
1.8
Finchley.SR2
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-web
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.4
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
org.springframework.cloud
spring-cloud-starter-netflix-hystrix
org.springframework.cloud
spring-cloud-starter-openfeign
mysql
mysql-connector-java
runtime
org.springframework.boot
spring-boot-starter-test
test
com.alibaba
druid-spring-boot-starter
1.1.9
com.codingapi.txlcn
txlcn-tc
5.0.2.RELEASE
com.codingapi.txlcn
txlcn-txmsg-netty
5.0.2.RELEASE
org.springframework.cloud
spring-cloud-dependencies
${spring-cloud.version}
pom
import
org.springframework.boot
spring-boot-maven-plugin
3、修改application.properties文件,我这里将application.properties文件改名为application.yml文件,因此格式是yml格式。
注意:
tx-lcn:
client:
manager-address: 127.0.0.1:8070
这个配置信息是服务器端的监听端口,在服务器端通过tx-lcn.manager.port,tx-lcn.manager.host这两个属性进行的配置
tc-client-1项目的配置代码如下:
server:
port: 10002
spring:
application:
name: client1
eureka:
instance:
appname: client1
prefer-ip-address: true
client:
service-url:
defaultZone: http://admin:admin@localhost:8761/eureka
---
spring:
datasource:
password: 123456
username: root
url: jdbc:mysql://10.115.132.12:3306/tx?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
validation-query: select '*'
initial-size: 1
max-active: 20
max-wait: 1000
filters: stat
pool-prepared-statements: false
redis:
port: 6379
host: 10.115.132.12
database: 0
jedis:
pool:
max-idle: 20
max-active: 20
max-wait: -1
min-idle: 0
timeout: 1000
transaction:
rollback-on-commit-failure: true
mybatis:
mapper-locations: classpath*:com/client/dao/xml/*.xml
type-aliases-package: com.client.dao.mapper
tx-lcn:
client:
manager-address: 127.0.0.1:8070
feign:
client:
config:
default:
connect-timeout: 10000
read-timeout: 20000
service-test:
connect-timeout: 10000
read-timeout: 20000
hystrix:
enabled: true
management:
endpoints:
web:
exposure:
include:
"*"
endpoint:
health:
show-details: always
tc-client-2项目的配置代码为:
server:
port: 10003
spring:
application:
name: client2
eureka:
instance:
appname: client2
prefer-ip-address: true
client:
service-url:
defaultZone: http://admin:admin@localhost:8761/eureka
---
spring:
datasource:
password: 123456
username: root
url: jdbc:mysql://10.115.132.12:3306/tx?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
validation-query: select '*'
initial-size: 1
max-active: 20
max-wait: 1000
filters: stat
pool-prepared-statements: false
redis:
port: 6379
host: 10.115.132.12
database: 0
jedis:
pool:
max-idle: 20
max-active: 20
max-wait: -1
min-idle: 0
timeout: 1000
transaction:
rollback-on-commit-failure: true
mybatis:
mapper-locations: classpath*:com/client/dao/xml/*.xml
type-aliases-package: com.client.dao.mapper
tx-lcn:
client:
manager-address: 127.0.0.1:8070
feign:
client:
config:
default:
connect-timeout: 10000
read-timeout: 20000
service-test:
connect-timeout: 10000
read-timeout: 20000
hystrix:
enabled: true
management:
endpoints:
web:
exposure:
include:
"*"
endpoint:
health:
show-details: always
4、在tx这个数据库中创建我们要操作的表test_1和test_2。这两个表的类型必须为innodb。MYISAM格式是不支持事务的。结构如下图:
5、开始编整合事务。
tc-client-1 项目的结构如下:
其中TcClient1Application作为启动类,需要加入@EnableDistributedTransaction和@EnableTransactionManagement这两个注解。生成的代码如下:
package com.client;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableDiscoveryClient
@ComponentScan("com.client.service")
@MapperScan("com.client.dao")
@EnableDistributedTransaction
@EnableTransactionManagement
public class TcClient1Application {
public static void main(String[] args) {
SpringApplication.run(TcClient1Application.class, args);
}
}
TestService作用事务的处理类也需要加入事务注解, @LcnTransaction(propagation = DTXPropagation.SUPPORTS)
@Transactional 。由于这个是被作用被调用者使用的,因此需要在注解中加入propagation = DTXPropagation.SUPPORTS配置。形成的代码如下:
package com.client.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.client.dao.mapper.TestMapper;
import com.client.model.TestModel;
import com.codingapi.txlcn.tc.annotation.DTXPropagation;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
@Service
public class TestService {
@Autowired
private TestMapper mapper;
@LcnTransaction(propagation = DTXPropagation.SUPPORTS)
@Transactional
public int insert() throws Exception{
TestModel test = new TestModel();
test.setId("1");
test.setName("name");
test.setType(1);
return mapper.insert(test);
}
}
其他model类,dao层的数据库操作方法大概按原来的方式写即可。没有特别需要注意的。
6、下一步就是修改tc-client-2项目了,这个项目是需要调用tc-client-1这个微服务的。它的结构如下:
从两个结构图中可以看出,这个项目多了一个ClientService类用于调用tc-client-1这个项目。它的代码如下:
package com.client.service;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
@FeignClient(name="client1")
public interface ClientService {
@RequestMapping("/test")
public int insertTest() throws Exception;
}
这个项目的启动类也是TcClient1Application,它的代码和tc-client-1项目没有任何区别,都是在原有项目的基础上增加了@EnableDistributedTransaction
@EnableTransactionManagement
这两个注解。
package com.client;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.codingapi.txlcn.tc.config.EnableDistributedTransaction;
@SpringBootApplication
@EnableFeignClients
@EnableCircuitBreaker
@EnableDiscoveryClient
@ComponentScan("com.client.service")
@MapperScan("com.client.dao")
@EnableDistributedTransaction
@EnableTransactionManagement
public class TcClient1Application {
public static void main(String[] args) {
SpringApplication.run(TcClient1Application.class, args);
}
}
这个项目中的TestService服务调用类有一点不同,代码如下:
package com.client.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.client.dao.mapper.TestMapper;
import com.client.model.TestModel;
import com.codingapi.txlcn.tc.annotation.DTXPropagation;
import com.codingapi.txlcn.tc.annotation.LcnTransaction;
@Service
public class TestService {
@Autowired
private TestMapper mapper;
@Autowired
private ClientService client;
@LcnTransaction
@Transactional
public int insert() throws Exception{
client.insertTest();
TestModel test = new TestModel();
test.setId("1");
test.setName("name");
test.setType(1);
return mapper.insert(test);
}
}
它虽然也加了@LcnTransaction这个注解,但由于这里是调用其他服务的,因此这个注解中不能配置其他属性。
这个项目中dao层和Model层相关的代码如tc-client-1完全相同,小伙伴们按照自己喜欢的方式写就可以了。
到这里就大功告成了。小伙伴们可以自己修改一个数据库结构让其中一个数据插入不成功,看看成果。