分布式事务-TCC(Hmily)[通俗易懂]

分布式事务-TCC(Hmily)[通俗易懂]TCC是什么:TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认Confirm、撤销Cancel。Try操作做业务检查及资源预留,Confirm做业务确认操作,Cancel实现一个与Try相反的操作即回滚操作。TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作,若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel操作若

大家好,又见面了,我是你们的朋友全栈君。

TCC是什么:
TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作:预处理Try、确认 Confirm、撤销Cancel。Try操作做业务检查及资源预留,Confirm做业务确认操作,Cancel实现一个与Try相反的 操作即回滚操作。TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所 有分支事务的Cancel操作,若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel 操作若执行失败,TM会进行重试。
分布式事务执行成功:
在这里插入图片描述
这边try执行成功后,没有异常会直接进入Confirm确认提交阶段。

分布式执行失败:
在这里插入图片描述
这边try执行失败后,执行成功一方的资源会进行事务回滚。

TCC分为三个阶段:
1:Try 阶段是做业务检查(一致性)及资源预留(隔离),此阶段仅是一个初步操作,它和后续的Confirm 一起才能 真正构成一个完整的业务逻辑。
2. Confirm 阶段是做确认提交,Try阶段所有分支事务执行成功后开始执行 Confirm。通常情况下,采用TCC则 认为 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。若Confirm阶段真的出错了,需引 入重试机制或人工处理。
3. Cancel 阶段是在业务执行错误需要回滚的状态下执行分支事务的业务取消,预留资源释放。通常情况下,采 用TCC则认为Cancel阶段也是一定成功的。若Cancel阶段真的出错了,需引入重试机制或人工处理。
4. TM事务管理器 TM事务管理器可以实现为独立的服务,也可以让全局事务发起方充当TM的角色,TM独立出来是为了成为公 用组件,是为了考虑系统结构和软件复用。TM在发起全局事务时生成全局事务记录,全局事务ID贯穿整个分布式事务调用链条,用来记录事务上下文, 追踪和记录状态,由于Confirm 和cancel失败需进行重试,因此需要实现为幂等,幂等性是指同一个操作无论请求 多少次,其结果都相同。

Hmily:
Hmily是一个高性能分布式事务TCC开源框架。基于Java语言来开发(JDK1.8),支持Dubbo,Spring Cloud等 RPC框架进行分布式事务。Hmily实现的TCC服务与普通的服务一样,只需要暴露一个接口,也就是它的Try业务。Confirm/Cancel业务 逻辑,只是因为全局事务提交/回滚的需要才提供的,因此Confirm/Cancel业务只需要被Hmily TCC事务框架 发现即可,不需要被调用它的其他业务服务所感知。
官网介绍:https://dromara.org/website/zh-cn/docs/hmily/index.html

Hmily环境构建:
首先导入hmily:

  <dependency>
            <groupId>org.dromara</groupId>
            <artifactId>hmily-springcloud</artifactId>
            <version>2.0.4-RELEASE</version>
        </dependency>

添加hmily数据库日志:

package com.study1.conf;

import com.alibaba.druid.pool.DruidDataSource;
import org.dromara.hmily.common.config.HmilyConfig;
import org.dromara.hmily.common.config.HmilyDbConfig;
import org.dromara.hmily.core.bootstrap.HmilyTransactionBootstrap;
import org.dromara.hmily.core.service.HmilyInitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.env.Environment;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass=true)
public class DatabaseHmliyConfiguration { 
   

    private final ApplicationContext applicationContext;

    @Autowired
    private Environment env;

    public DatabaseHmliyConfiguration(ApplicationContext applicationContext) { 
   
        this.applicationContext = applicationContext;
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DruidDataSource ds0() { 
   
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }

    @Bean
    public HmilyTransactionBootstrap hmilyTransactionBootstrap(HmilyInitService hmilyInitService){ 
   
        HmilyTransactionBootstrap hmilyTransactionBootstrap = new HmilyTransactionBootstrap(hmilyInitService);
        hmilyTransactionBootstrap.setSerializer(env.getProperty("org.dromara.hmily.serializer"));
        hmilyTransactionBootstrap.setRecoverDelayTime(Integer.parseInt(env.getProperty("org.dromara.hmily.recoverDelayTime")));
        hmilyTransactionBootstrap.setRetryMax(Integer.parseInt(env.getProperty("org.dromara.hmily.retryMax")));
        hmilyTransactionBootstrap.setScheduledDelay(Integer.parseInt(env.getProperty("org.dromara.hmily.scheduledDelay")));
        hmilyTransactionBootstrap.setScheduledThreadMax(Integer.parseInt(env.getProperty("org.dromara.hmily.scheduledThreadMax")));
        hmilyTransactionBootstrap.setRepositorySupport(env.getProperty("org.dromara.hmily.repositorySupport"));
        hmilyTransactionBootstrap.setStarted(Boolean.parseBoolean(env.getProperty("org.dromara.hmily.started")));
        HmilyDbConfig hmilyDbConfig = new HmilyDbConfig();
        hmilyDbConfig.setDriverClassName(env.getProperty("org.dromara.hmily.hmilyDbConfig.driverClassName"));
        hmilyDbConfig.setUrl(env.getProperty("org.dromara.hmily.hmilyDbConfig.url"));
        hmilyDbConfig.setUsername(env.getProperty("org.dromara.hmily.hmilyDbConfig.username"));
        hmilyDbConfig.setPassword(env.getProperty("org.dromara.hmily.hmilyDbConfig.password"));
        hmilyTransactionBootstrap.setHmilyDbConfig(hmilyDbConfig);
        return hmilyTransactionBootstrap;
    }

}

添加yml配置:

org:
  dromara:
    hmily:
      serializer: kryo
      recoverDelayTime: 30
      retryMax: 30
      scheduledDelay: 30
      scheduledThreadMax:  10
      repositorySupport: db
      started: true
      hmilyDbConfig:
        driverClassName: com.mysql.jdbc.Driver
        url:  jdbc:mysql://localhost:3306/bank1?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
        username: root
        password: 123

添加扫描:

@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients //使用@feign
//@EnableHystrix //使用hystrix
@ComponentScan({ 
   "com.study1","org.dromara.hmily"})
@MapperScan("com.study1.mapper")
public class ServceBank1Application { 
   
    public static void main(String[] args) { 
   
        SpringApplication.run(ServceBank1Application.class, args);
    }
}

第二个服务同上
这边数据库采用bank1,bank2
bank1实现用户扣款功能:

 //--------------Hmily------------------
    //只要标记@Hmily就是try方法,在注解中指定confirm、cancel两个方法的名字
    @Override
    @Transactional
    @Hmily(confirmMethod = "commit", cancelMethod = "rollback")
    public boolean reduceHmilyAmount(int amount) { 
   
        //预处理->扣款 张三扣款成功
        if (bankMapper.reduceAmount(amount) > 0) { 
   
            System.out.println("开始调用远程服务");
            //李四添加金额
            bankFeignService.addAmount(amount);
            return true;
        } else { 
   
            return false;
        }
    }

    @Transactional
    public void commit(int amount) { 
   
        System.out.println("成功处理事务");
    }

    @Transactional
    public void rollback(int amount) { 
   
        System.out.println("失败处理事务");
    }

bank2实现用户添加余额的功能:

//--------------Hmily------------------
    //只要标记@Hmily就是try方法,在注解中指定confirm、cancel两个方法的名字
    @Override
    @Transactional
    @Hmily(confirmMethod = "commit", cancelMethod = "rollback")
    public void addAmount(Integer amount) { 
   
        //预处理->扣款 张三扣款成功
        bankMapper.addAmount(amount);
        System.out.println("调用完成");
        int y = 3 / 0;
        System.out.println("执行其他业务");
    }

    @Transactional
    public void commit(int amount) { 
   
        System.out.println("bank2成功处理事务");
    }

    @Transactional
    public void rollback(int amount) { 
   
        System.out.println("---------------------失败处理事务------------------------");
        System.out.println("---------------------失败处理事务------------------------");
        System.out.println("---------------------失败处理事务------------------------");
        System.out.println("---------------------失败处理事务------------------------");
    }

feign服务调用:

//可以捕获错误日志
@FeignClient(value = "bank2", fallback = BankFeignServiceImpl.class)
public interface BankFeignService { 
   

    @GetMapping("/bank2/addAmount")
    @Hmily
    public boolean addAmount(@RequestParam("amount") Integer amount);
}

采用的是feign进行微服务调用,测试调用bank2报错,bank1执行回调方法:
在这里插入图片描述

开始调用远程服务
feign.FeignException: status 500 reading BankFeignService#addAmount(Integer)
	at feign.FeignException.errorStatus(FeignException.java:78)
	at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:93)
	at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149)
	at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78)
	at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
	at com.sun.proxy.$Proxy133.addAmount(Unknown Source)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
	at org.dromara.hmily.core.service.handler.ConsumeHmilyTransactionHandler.handler(ConsumeHmilyTransactionHandler.java:35)
	at org.dromara.hmily.core.service.impl.HmilyTransactionAspectServiceImpl.invoke(HmilyTransactionAspectServiceImpl.java:63)
	at org.dromara.hmily.springcloud.interceptor.SpringCloudHmilyTransactionInterceptor.interceptor(SpringCloudHmilyTransactionInterceptor.java:78)
	at org.dromara.hmily.core.interceptor.AbstractHmilyTransactionAspect.interceptTccMethod(AbstractHmilyTransactionAspect.java:61)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
	at org.dromara.hmily.springcloud.feign.HmilyFeignHandler.invoke(HmilyFeignHandler.java:62)
	at com.sun.proxy.$Proxy134.addAmount(Unknown Source)
	at com.study1.service.impl.BankServiceImpl.reduceHmilyAmount(BankServiceImpl.java:52)
	at com.study1.service.impl.BankServiceImpl$$FastClassBySpringCGLIB$$b1ddc6fd.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:294)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
	at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
	at org.dromara.hmily.core.service.handler.StarterHmilyTransactionHandler.handler(StarterHmilyTransactionHandler.java:70)
	at org.dromara.hmily.core.service.impl.HmilyTransactionAspectServiceImpl.invoke(HmilyTransactionAspectServiceImpl.java:63)
	at org.dromara.hmily.springcloud.interceptor.SpringCloudHmilyTransactionInterceptor.interceptor(SpringCloudHmilyTransactionInterceptor.java:78)
	at org.dromara.hmily.core.interceptor.AbstractHmilyTransactionAspect.interceptTccMethod(AbstractHmilyTransactionAspect.java:61)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
	at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
	at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
	at com.study1.service.impl.BankServiceImpl$$EnhancerBySpringCGLIB$$e3476692.reduceHmilyAmount(<generated>)
	at com.study1.controller.BankController.reduceAmount(BankController.java:19)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at com.alibaba.druid.support.http.WebStatFilter.doFilter(WebStatFilter.java:123)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117)
	at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)
	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415)
	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
失败处理事务

使用Hmily注意事项:
在使用Hmliy时候注意里面的try,confirm,cancel等方法都是异步线程调用,注意避免他们进行频繁调用可以在数据库中添加方法调用记录,避免重复调用导致数据不一致的情况。同时当事务处理失败未得到处理时,数据库表中有一个hmily的日志记录表,它会对日志中的记录进行定时重复调用。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143564.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • C语言游戏 双缓存解决闪屏问题 详细总结[通俗易懂]

    最近,应学校课程要求,要完成一个C语言课程设计。可以是写一个小游戏,或是写管理系统等。所以,准备做一个改版贪吃蛇:消灭小虫虫(瞎起的名字:D)。之前学过Java,所以学C语言也就比较顺利。而在刚学完C语言刚着手准备做C语言的小游戏时,却发现了一个问题——闪屏。(我在网上查找了很多关于双缓存,有关的解答很少,更少能够让一个完全不了解的小白一个明白的解释。下面我想和大家分享我使用…

  • PLSQL Developer 13 注册码

    PLSQL Developer 13 注册码PLSQLDeveloper13注册码,亲测有效!productcode:4vkjwhfeh3ufnqnmpr9brvcuyujrx3n3leserialNumber:226959password:xs374ca

  • 如何获取dropdownlist的值_mycat 数据库绑定

    如何获取dropdownlist的值_mycat 数据库绑定这几天遇到再DropDownList中,如何将数据库中的内容与DropDownList下拉框中的值关联起来,步骤如下:(1)建立要关联的数据库(在本例中假设为dept);要定义一个数据表用来取得这个表中的内容,代码如下:publicDataTableReaderSelectDept(){DataTableReaderdr=null;try{RunSQL

  • unable to access android sdk add-on list解决方案[通俗易懂]

    unable to access android sdk add-on list解决方案[通俗易懂]AndroidStudio报错unabletoaccessandroidsdkadd-onlist解决方案问题原因解决方案1.配置Proxy2.跳过检测在AndroidStudio的安装目录下,找到\bin\idea.properties在尾行添加disable.android.first.run=true,表示初次启动不检测SDK跳过后设置AndroidStuido模式下载SDK总结问题更新AndroidStudio4.2版本,启动后报错如下原因AS启动之后,会检查默

  • 深入理解Java虚拟机:垃圾收集

    深入理解Java虚拟机:垃圾收集概述    GC即垃圾回收,是指jvm用于释放那些不再使用的对象所占用的内存。    垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。两种常用的方法是引用计数和对象引用遍历。JVM的GC触发原理    JVM的GC主要是对堆内存的回收,一般把新生代的GC称为minorGC,把老年代的GC成为fullGC,所谓fullgc会先出发一次minor

  • 工业超纯水机:EDI超纯水设备技术介绍

    EDI超纯水设备技术是国际上20世纪90年代开始逐渐发展起来的新型纯水、超纯水制备技术。该技术巧妙地将电渗析技术和离子交换技术相融合,通过阴、阳离子的选择性透过作用与离子交换树脂对离子的交换作用,在直流电场的作用下实现离子的定向迁移,从而完成水的深度除盐,同事水电离解产生的氢离子和氧根离子对离子交换树脂进行再生,因此不需酸碱化学再生而能连续制取超纯水。  EDI设备特点  EDI系统运

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号