Mybatis分布式事物

springboot实现mybatis分布式事务(atomikos) 背景:项目中使用了两个mysql数据源,有一个功能是同时修改两个库里的表数据,需要进行事务控制。项目框架为springcloud+mybatis。 项目结构如下 增加maven依赖 <!--分布式事务支持--> <dependency> <groupId>org.springframework.boot</groupId> ... 阅读详情

SpringMVC+MyBatis 相信已经是现在企业开发中常用技术了。 
因为一些需求,我们需要集成JMS(我使用的是ActiveMQ),大家应该都知道,MQ也可以认为是一个数据源,数据也是数据源。这种情况下,如果我们在一个方法内操作JMS和数据库,我们就需要保证这个方法执行需要满足原子性。 
这也就意味这一个问题,我们要多个数据源在同一个事务中。这里不枚举市面上的所有解决方案,其实atomikos JTA 是一个比较不错分布式事务管理器。
当然如果没有使用到JMS,在需要多数据源(也就是需要连接多个数据库)的情况同样适用。

下面将项目的主要配置贴出来共享: 
1、applicationContext.xml

<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:amq="http://activemq.apache.org/schema/core"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.13.0.xsd">

     <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>

     <!-- 配置扫描路径 -->
     <context:component-scan base-package="com.hvgroup.zhuhai10086.jms">
        <!-- 只扫描Service,也可以添加Repostory,但是要把Controller排除在外,Controller由spring-mvc.xml去加载 -->
        <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> -->
        <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> -->
        <!-- <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
     </context:component-scan>

    <!-- 读取环境变量(自定义扩展)  -->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:config/config.properties</value>
            </list>
        </property>
    </bean>

    <import resource="classpath:spring/applicationContext-Service.xml" />

</beans>  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

2、applicationContext-Service.xml

<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.1.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    <!-- JDBC连接数据库数据源 -->
    <!-- <bean id="dataSource" -->
    <!-- class="org.springframework.jdbc.datasource.DriverManagerDataSource"> -->
    <!-- <property name="driverClassName" value="${jdbc.driverClassName}" /> -->
    <!-- <property name="url" value="${jdbc.url}" /> -->
    <!-- <property name="username" value="${jdbc.username}" /> -->
    <!-- <property name="password" value="${jdbc.password}" /> -->
    <!-- </bean> -->

    <!-- DBCP连接池 -->
<!--    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" -->
<!--        destroy-method="close"> -->
<!--        <property name="driverClassName" value="${jdbc.driverClassName}" /> -->
<!--        <property name="url" value="${jdbc.url}" /> -->
<!--        <property name="username" value="${jdbc.username}" /> -->
<!--        <property name="password" value="${jdbc.password}" /> -->
<!--        <property name="initialSize" value="20" /> -->
<!--        <property name="maxActive" value="80" /> -->
<!--        <property name="maxIdle" value="100" /> -->
<!--        <property name="minIdle" value="20" /> -->
<!--        <property name="validationQuery" value="SELECT COUNT(*) FROM DUAL"></property> -->
<!--        <property name="testOnBorrow" value="true"></property> -->
<!--        <property name="testOnReturn" value="true"></property> -->
<!--        <property name="testWhileIdle" value="true"></property> -->
<!--    </bean> -->

    <bean id="dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
        init-method="init" destroy-method="close">
        <property name="uniqueResourceName" value="ds1" />
<!--        <property name="xaDataSourceClassName" value="${jdbc.driverClassName}" /> -->
        <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
        <property name="xaProperties">
            <props>
                <prop key="URL">${jdbc.url}</prop>
                <prop key="user">${jdbc.username}</prop>
                <prop key="password">${jdbc.password}</prop>
            </props>
        </property>
<!--        #连接池中保留的最小连接数 -->
        <property name="minPoolSize" value="5" />
<!--        #连接池中保留的最大连接数  -->
        <property name="maxPoolSize" value="20" />
<!--        #最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default:  -->
        <property name="maxIdleTime" value="60" />
        <property name="testQuery">
            <value>select 1</value>
        </property>
    </bean>


    <!-- JNDI连接池 -->
    <!-- <bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean"> -->
    <!-- <property name="jndiName"> -->
    <!-- <value>java:comp/env/jdbc/huiyzl</value> -->
    <!-- </property> -->
    <!-- </bean> -->

    <!-- 配置SqlSessionFactoryBean -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!-- mapper和resultmap配置路径 -->
        <property name="mapperLocations">
            <list>
                <!-- 注意classpath后面的星号不可省略,否则不能加载jar包中的xml文件 -->
                <value>classpath*:com/hvgroup/zhuhai10086/jms/**/sql/mysql/*Mapper.xml
                </value>
            </list>
        </property>
        <property name="plugins">
            <array>
                <!-- 关于分页插件的使用说明:http://git.oschina.net/free/Mybatis_PageHelper/blob/master/wikis/HowToUse.markdown -->
                <bean class="com.github.pagehelper.PageHelper">
                    <property name="properties">
                        <value>
                            offsetAsPageNum=true
                            rowBoundsWithCount=true
                            reasonable=true
                        </value>
                    </property>
                </bean>
            </array>
        </property>
    </bean>

        <!-- 事务管理 --> 
<!--    <bean id="transactionManager" -->
<!--        class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> -->
<!--        <property name="dataSource" ref="dataSource" /> -->
<!--    </bean> -->

    <!-- MapperScanner配置,Spring 自动去搜索mapper里的对象,并注入。指定markerInterface表示只有继承SqlMapper接口的接口,才会被扫描映射 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.hvgroup.zhuhai10086.jms.**.mapper" />
        <property name="markerInterface" value="com.hvgroup.zhuhai10086.jms.mapper.SqlMapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>


    <bean id="userTransactionService" class="com.atomikos.icatch.config.UserTransactionServiceImp" 
            init-method="init" destroy-method="shutdownForce">
        <constructor-arg>
            <props>
                <prop key="com.atomikos.icatch.service">com.atomikos.icatch.standalone.UserTransactionServiceFactory</prop>
            </props>
        </constructor-arg>
    </bean>

    <bean id="atomikosTransactionManager"  
          class="com.atomikos.icatch.jta.UserTransactionManager"  
          depends-on="userTransactionService"
          init-method="init" destroy-method="close" >  
        <property name="forceShutdown" value="false"/>
    </bean>

    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" >  
        <property name="transactionTimeout" value="300"/>  
    </bean>

    <!-- 分布式事务 -->
    <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">  
        <property name="transactionManager" ref="atomikosTransactionManager"/>  
        <property name="userTransaction" ref="atomikosUserTransaction"/>  
    </bean>

<!--    <tx:jta-transaction-manager /> -->
    <!-- 可通过注解控制事务,也可以配置拦截器方式配置事务 -->
    <tx:annotation-driven transaction-manager="jtaTransactionManager" />

</beans>

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141

3、ActiveMQ-XA.xml

<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:amq="http://activemq.apache.org/schema/core"
    xmlns:jms="http://www.springframework.org/schema/jms"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.1.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/jms
        http://www.springframework.org/schema/jms/spring-jms-4.1.xsd
        http://activemq.apache.org/schema/core
        http://activemq.apache.org/schema/core/activemq-core-5.13.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">

    <!-- 重发策略:最多重发次数=maximumRedeliveries -->
    <amq:redeliveryPolicy id="redeliveryPolicy"
        maximumRedeliveries="6" />

    <!-- 抓取策略 -->
    <amq:prefetchPolicy id="prefetchPolicy" queuePrefetch="5" topicPrefetch="5" />

    <!-- activeMQ连接信息,XA事务 -->
    <amq:xaConnectionFactory id="jmsXaConnectionFactory"
        brokerURL="${activemq.brokerURL}" 
        userName="${activemq.username}" 
        password="${activemq.password}"
        redeliveryPolicy="#redeliveryPolicy"
        alwaysSessionAsync="false"
        alwaysSyncSend="true" 
        prefetchPolicy="#prefetchPolicy"/>



    <bean id="amqConnectionFactory"  
          class="com.atomikos.jms.AtomikosConnectionFactoryBean" init-method="init" destroy-method="close">  
        <property name="uniqueResourceName" value="XAactiveMQ"/>  
        <property name="xaConnectionFactory" ref="jmsXaConnectionFactory"/>  
        <property name="poolSize" value="100"/>
    </bean>

    <!-- ====Producer side start==== -->

    <!-- 定义JmsTemplate的Queue类型 -->
    <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
        <constructor-arg ref="amqConnectionFactory" />
        <!-- 非pub/sub模型(发布/订阅),即队列模式 -->
        <property name="pubSubDomain" value="false" />
    </bean>

    <!-- 定义JmsTemplate的Topic类型 -->
    <bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
        <constructor-arg ref="amqConnectionFactory" />
        <!-- pub/sub模型(发布/订阅) --> 
        <property name="pubSubDomain" value="true" />
    </bean>

    <!-- ====Producer side end==== -->

    <!-- ====Consumer side start==== -->

    <!--这个是sessionAwareQueue目的地(响应消息)-->  
    <amq:queue id="queueReceiver2ResponseDestination"  physicalName="test.queue2.response" />

    <!-- 定义Queue监听器(无事务) -->
    <jms:listener-container
        destination-type="queue" 
        container-type="default" 
        connection-factory="amqConnectionFactory" 
        error-handler="jmsErrorHandler"
        acknowledge="auto">
        <jms:listener destination="xinge.queue.push" ref="xgMessageReceiver"  concurrency="5-100" />
        <jms:listener destination="xinge.queue.push.device.multiple" ref="xgMessageReceiverMultiple"  concurrency="5-100" />
    </jms:listener-container>

    <!-- 定义Queue监听器(有事务) -->
    <jms:listener-container
        destination-type="queue" 
        container-type="default" 
        connection-factory="amqConnectionFactory" 
        transaction-manager="jtaTransactionManager"
        error-handler="jmsErrorHandler"
        acknowledge="transacted">
        <jms:listener destination="xinge.queue.push.invokelog" ref="xgMessageReceiverInvokeLog"  concurrency="5-100" />
<!--        <jms:listener destination="test.queue" ref="queueReceiver"  concurrency="10-100" /> -->
<!--        <jms:listener destination="test.queue2" ref="queueReceiver2"  concurrency="2-10"/> -->
<!--        <jms:listener destination="test.queue2.response" ref="queueReceiver2Response" concurrency="2-10" /> -->
    </jms:listener-container>

    <!-- 定义Topic监听器 -->
<!--    <jms:listener-container  -->
<!--        destination-type="topic"   -->
<!--        container-type="default"  -->
<!--        connection-factory="amqConnectionFactory" -->
<!--        transaction-manager="jtaTransactionManager" -->
<!--        error-handler="jmsErrorHandler" -->
<!--        acknowledge="transacted" > -->
<!--        <jms:listener destination="test.topic" ref="topicReceiver" /> -->
<!--        <jms:listener destination="test.topic" ref="topicReceiver2" /> -->
<!--    </jms:listener-container> -->

    <!-- ====Consumer side end==== -->

    <bean id="xingeApp" class="com.tencent.xinge.XingeApp">
        <constructor-arg index="0" value="2100170086"/><!-- accessId -->
        <constructor-arg index="1" value="2d257b10220bc3849743ffe0e9bd233a"/><!-- secretKey -->
    </bean>

</beans>  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

4、spring-mvc.xml

<?xml version="1.0" encoding="GBK"?>  
<beans xmlns="http://www.springframework.org/schema/beans"   
       xmlns:aop="http://www.springframework.org/schema/aop"   
       xmlns:context="http://www.springframework.org/schema/context"  
       xmlns:mvc="http://www.springframework.org/schema/mvc"   
       xmlns:tx="http://www.springframework.org/schema/tx"   
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/aop   
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd   
        http://www.springframework.org/schema/beans   
        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd   
        http://www.springframework.org/schema/context   
        http://www.springframework.org/schema/context/spring-context-4.0.xsd   
        http://www.springframework.org/schema/mvc   
        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd   
        http://www.springframework.org/schema/tx   
        http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">  

    <!-- 启用MVC注解 -->
    <mvc:annotation-driven />

    <!-- 静态资源文件,不会被Spring MVC拦截 -->
    <mvc:resources location="/resources/" mapping="/resources/**"/>

    <!-- 指定Sping组件扫描的基本包路径 -->
    <context:component-scan base-package="com.hvgroup.zhuhai10086.jms" >
        <!-- 这里只扫描Controller,不可重复加载Service -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- JSP视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/views/" />  
        <property name="suffix" value=".jsp" />
        <property name="order" value="1" />
    </bean>

</beans>  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

5、config.properties

jdbc.url=jdbc:mysql://localhost:3306/xgmessage?useUnicode=true&amp;characterEncoding=utf-8&amp;relaxAutoCommit=true
jdbc.username=root
jdbc.password=123456

activemq.brokerURL=tcp://localhost:61616
activemq.username=admin
activemq.password=admin
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6、web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:web="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">
    <display-name>zhuhai10086-jms</display-name>
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>zhuhai10086-jms</param-value>
    </context-param>
    <!-- Log4j配置 -->
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:log4j/log4j.xml</param-value>
    </context-param>
    <!-- 加载log4j配置文件 -->
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    <filter>
        <filter-name>characterEncoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>characterEncoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/applicationContext.xml,classpath*:activemq/ActiveMQ-XA.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring/spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>SpringMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57

7、把log4j.xml 也贴出来吧,兴许有的同学能用上

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration PUBLIC "-//LOGGER" "log4j.dtd">
<log4j:configuration debug="true" xmlns:log4j="http://jakarta.apache.org/log4j/">

    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d][%p][%13F:%L] %m%n" />
        </layout>
    </appender>
    <appender name="DEBUG" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="File" value="${log4j.logfile.path}" />
        <param name="Encoding" value="UTF-8" />
        <param name="DatePattern" value="'.'yyyy-MM-dd" />
        <param name="ImmediateFlush" value="true" />
        <param name="Append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="[%d][%p] %m%n" />
        </layout>
    </appender>

    <logger name="java.sql.Connection">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="java.sql.PreparedStatement">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="java.sql.Statement">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="java.sql.ResultSet">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="org.mybatis">
        <level value="DEBUG" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="org.springframework">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>   
    <logger name="org.apache.ibatis">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="org.apache.xbean.spring">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="com.atomikos">
        <level value="ERROR" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>
    <logger name="org.apache.activemq">
        <level value="INFO" />
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>

    <logger name="com.hvgroup">
        <level value="DEBUG"/>
        <appender-ref ref="DEBUG" />
        <appender-ref ref="CONSOLE" />
    </logger>

    <!-- Root Logger -->
    <root>
        <level value="DEBUG"/>
    </root>

</log4j:configuration>

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84

对需要使用数据库数据源的方法使用 @Transactional 注解即可,在配置上,JMS的事务我们已经在配置文件中指定了。如下代码中指定的 transaction-manager=”jtaTransactionManager”:

    <!-- 定义Queue监听器(有事务) -->
    <jms:listener-container
        destination-type="queue" 
        container-type="default" 
        connection-factory="amqConnectionFactory" 
        transaction-manager="jtaTransactionManager"
        error-handler="jmsErrorHandler"
        acknowledge="transacted">
        <jms:listener destination="xinge.queue.push.invokelog" ref="xgMessageReceiverInvokeLog"  concurrency="5-100" />
    </jms:listener-container>
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

最后贴上工程代码的结构图: 
工程结构图

springboot+atomikos+mybatis+druid实现配置化atomikos分布式事物管理 最近工作中遇到需要管理多个数据源,因此使用了atomikos写了一个小模块,采用了注释实现了灵活配置多数据源。使用的项目只需要在启动类上使用@EnableFreeagerAtomikos加上配置文件的配置项就可以了。(gitee代码:https://gitee.com/freeager/springboot-atomikos,包括了测试代码,数据库看mapper自己建哦) ... 阅读详情

相关推荐

sprng boot多个sqlserver数据库或者mysql数据库 数据源配置及事物处理

1.新建spring boot项目,sqlserver数据库的话,依赖可能无法下载,需要手动下载并且引入的maven项目中,其他数据库类型,直接在pom中引入即可。 2.项目结构 3.配置文件application.properties: server.port=8894 #主库的配置 spring.datasource.config.jdbc-url=jdbc:sqlserver://127....

Z__Sheng的博客 1137

SpringMVC+MyBatis+JMS+JTA(分布式事务)

SpringMVC+MyBatis 相信已经是现在企业开发中常用技术了。 因为一些需求,我们需要集成JMS(我使用的是ActiveMQ),大家应该都知道,MQ也可以认为是一个数据源,数据也是数据源。这种情况下,如果我们在一个方法内操作JMS和数据库,我们就需要保证这个方法执行需要满足原子性。 这也就意味这一个问题,我们要多个数据源在...

weixin_34378969的博客 356

Java高端培训蚂蚁课堂(每特学院)系列项目实战

教程目录:1-多线程快速入门第一节.进程与线程的区别第二节.使用继承Thread类创建线程第三节.疑问解答第四节.实现Runnable创建线程第五节.使用匿名内部类创建线程第六节.sleep方法介绍第七节.获取对象名称第八节.多线程运行状态第九节.使用多线程分批发送短信2-多线程之间实现同步第一节.线程安全介绍第二节.证明同步方法是this锁第三节.静态同步代码块第四节.多线程死锁3-多线程之间通...

f123124的博客 2273

【133】Spring Boot 1 + MyBatis 多数据源分布式事务(一)

本文源代码位置:https://gitee.com/zhangchao19890805/csdnBlog.git 仓库中的 blog133 文件夹就是项目文件夹。 使用 Spring Boot 和 Spring Cloud 做分布式微服务系统,难免会碰到跨数据库的事务。众所周知的CAP原则,即一致性(C)、可用性(A)和分区容错性(P)只能做到其中两个比较强,剩下一个较弱。Spring Clou...

zhangchao19890805的专栏 590

Spring+Mybatis+Mysql搭建分布式数据库访问框架的方法

主要介绍了Spring+Mybatis+Mysql搭建分布式数据库访问框架的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下

Redis+Unity 数据库搭建

游戏中需要存放排行榜等数据,而且是实时存放,所以就涉及到数据库的问题。这里找服务器大神了解到可以用Redis来做存储,免费的效率极高。

chaixinke的专栏 879

SpringBoot+MyBatis(动态数据源/分布式事务XA(Atomikos))

快速集成工具,欢迎打脸 说明 适用环境:SpringBoot / MyBatis / Atomickos 特性: 多数据源,动态切换 多数据源,XA分布式事务支持(需引入Atomickos) 仅支持Mybatis,采用AbstractRoutingDataSource实现数据源动态切换。 引入Atomickos分布式事务,可支持多数据源动态切换分布式事务。 使用方法 引入jar包依...

t0m的专栏 2372

华为iTrustee实战:5分钟搞定TrustZone环境搭建(附BoostKit配置技巧)

本文提供了一份华为iTrustee与ARM TrustZone环境的5分钟快速搭建实战指南。详细介绍了在TaiShan服务器上利用鲲鹏BoostKit套件部署可信执行环境(TEE)的完整流程,包括环境检查、驱动安装、首个可信应用(TA)的编译与运行,并分享了关键的BoostKit配置技巧与深度排错方法,助力开发者快速为业务注入硬件级安全能力。

yoga7的博客 968

MyBatis的多数据源与分布式事务

1.背景介绍 MyBatis是一款流行的Java数据访问框架,它可以简化数据库操作并提高开发效率。在实际应用中,我们经常需要处理多数据源和分布式事务。在本文中,我们将讨论MyBatis的多数据源与分布式事务,并提供一些最佳实践和技巧。 1.背景介绍 在现代应用中,我们经常需要处理多个数据源,以实现高性能和高可用性。同时,分布式事务是一种在多个数据源之间实现原子性的方法。MyBatis提供了一...

AI天才研究院 1184

基于ROS2系统开发机器人

以上是基于ROS 2开发机器人的基本流程和一个简单的发布者-订阅者示例。通过这个流程,你可以逐步扩展和优化你的机器人系统,实现更复杂的功能。

xuweilin的博客 1495

stm32H743基于CubeMX配置为双ADC多通道DMA规则采样

stm32H743的ADC支持的最大频率为36MHz,有相关资料上说是可以超频,具体技术细节不多讨论。 需求: 使用stm32H743的ADC采集5路ovrc

xtqbp的博客 4363

基于SpringBoot+Mybatis+Atomikos 多数据于分布式事物平台搭建

SpringBoot+Mybatis+Atomikos 多数据于分布式事物平台搭建POM文件配置文件关健代码 POM文件 <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/xsd/mav

weixin_43505928的博客 165

【纯实战】C#基于TCP/IP实现三菱PLC MC协议完整通信(含完整源码+通信原理+避坑指南)

MC协议是三菱电机为旗下MELSEC系列PLC量身定制的以太网专用通信协议,本质是一套基于TCP/IP的应用层协议规范,专门用于实现上位机(PC/工控机)与PLC之间的双向数据交互,支持对PLC的软元件(X/Y/M/D/W/T/C等)进行读、写、批量读写等核心操作,同时支持PLC状态查询、程序启停等控制指令。重要:三菱PLC的MC协议默认基于TCP 4999端口通信,部分新版本FX5U/Q系列也支持TCP 5000端口,核心通信逻辑一致。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 895

Maven Mybatis JTA SprintBoot分布式事物管理,拦截器管理事物

如果要源码参考请访问:https://download.youkuaiyun.com/download/liqi_q/10445505java中分布式事物JTA是比较常用的第三方服务,下面我是使用的Atomikos ,分布式事物主要是2.5之前和之后使用上有明显的区别,Springboot项目在配置数据源的时候多数据源的情况下项目启动要指定一个默认的数据源及@Primary,2.5版本之前使用的时候如果说处理...

liqi_q的博客 374

一文搞定离线环境下的RAG引擎部署

在人工智能浪潮下,技术已成为构建智能问答、文档分析和代码助手等应用的核心。然而,在许多企业场景中,出于数据安全和性能的考虑,服务器往往部署在中,并要求极致的推理效率。这给依赖外部资源的应用部署带来了巨大挑战。如何在这种严苛的环境下,完整、可靠地部署一套包含向量数据库、**高性能推理服务(vLLM)**和Python后台的复杂RAG系统呢?本文将为你提供一个,手把手教你如何使用 Docker 技术,将一套基于 Weaviate 和的 Python RAG 应用完整打包,并在离线环境中一键部署。

木鱼时刻的专栏 1242

ROS2入门到精通—— 2-9 ROS2实战:Nav2常见的工程问题(参考3D视觉工坊)

本文介绍了Nav2常见的工程问题,还有调试DWB的一些经验,以及DWB的一些缺点

BigDavid123的博客 1068

spring+mybatis+atomikos实现分布式事物管理

spring版本4.3.10,mybatis版本3.2.0,atomikos版本4.0.4,整合atomikos,需要额外引入以下两个jar包 com.atomikos transactions-jdbc 4.0.4 javax.transaction jta 1.1 配置文件定义: <beans xmlns="http:

qq_30881357的博客 383

SAP SLT DMIS 2018_1_752 究竟是什么意思?

把读懂,并不需要背太多编号。你只要记住:它就是DMIS 2018发行线里、面向的那一档组件版本,承载SLT 3.0的功能集。面向项目落地,要点就是三件事:看清平台基线、对齐DMIS支持包、走官方安装与补丁路径。如此,S/4到HANA,抑或S/4到BigQuery的复制链路,都会变得既稳定又可维护。DMIS 2018是新技术发行,基于,覆盖SLT全场景(SAP Learning)。DMIS_2018的安装与下载路径、通过SAINT安装的官方步骤(Installation Guide PDF)。源系统与。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 224

springboot+ mybatis + Druid+ Atomikos 多数据源,支持分布式事物

springboot + mybatis + druid 多数据源配置 看了别人的配置,还是觉得自己配置的比较简单。。直接看代码 springboot 启动类 package com; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.i...

walle167的博客 1040

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Spring boot 入门教程-集成Mybatis-Plus,2024年最新java分布式事物面试

看完美团、字节、腾讯这三家的面试问题,是不是感觉问的特别多,可能咱们又得开启面试造火箭、工作拧螺丝的模式去准备下一次的面试了。开篇有提及我可是足足背下了1000道题目,多少还是有点用的呢,我看了下,上面这些问题大部分都能从我背的题里找到的,所以今天给大家分享一下互联网工程师必备的面试1000题。注意不论是我说的互联网面试1000题,还是后面提及的算法与数据结构、设计模式以及更多的Java学习笔记等,皆可分享给各位朋友互联网工程师必备的面试1000题而且从上面三家来看,算法与数据结构是必备不可少的。

2401_84435578的博客 1119

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

2018-01-08 学习随笔 SpirngBoot整合Mybatis进行主从数据库的动态切换,以及一些数据库层面和分布式事物的解决方案...

先大概介绍一下主从数据库是什么?其实就是两个或N个数据库,一个或几个主负责写(当然也可以读),另一个或几个从只负责读.从数据库要记录主数据库的具体url以及BigLOG(二进制日志文件)的参数.原理就是在定时的从主数据库的BigLOG文件中获取相应的日志记录,并转换成相应的sql语句进行同步. SpringBoot整合Mybatis怎么自动化的区分主从数据库进行读写,并且保证其线程安全性;创建一...

weixin_30758821的博客 141

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

SpringBoot02

热部署,就是在应用正在运行的时候升级软件(增加业务/修改bug),却不需要重新启动应用大家都知道在项目开发过程中,常常会改动页面数据或者修改数据结构,为了显示改动效果,往往需要重启应用查看改变效果,其实就是重新编译生成了新的 Class 文件,这个文件里记录着和代码等对应的各种信息,然后 Class 文件将被虚拟机的 ClassLoader 加载。

KKTT01的博客 1004

SpringBoot分布式事物管理

新增配置文件信息 &lt;dependency&gt; &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt; &lt;artifactId&gt;spring-boot-starter-jta-atomikos&lt;/artifactId&gt; &lt;/dependency&gt; 新增配置文件信息 # Mysql 1...

qq_41988225的博客 256

Spring Boot 分布式事物管理

Spring Boot 分布式事物管理 前言 事务是为了保证数据的一致性而产生的。那么分布式事务,顾名思义,就是我们要保证分布在不同数据库、不同服务器、不同应用之间的数据一致性。 在单体项目下数据是存放在一个数据库上的,采用数据库的事务就能满足我们的要求。 但随着业务的不断扩张,数据的不断增加,单一数据库已经到达了一个瓶颈,因此我们需要对数据库进行分库分表。为了保证数据的一致性,可能需要不同的数据...

. 748

SSM之MyBatis_03_02_mybatis整合ehcache缓存、什么叫分布式、二级缓存应用场景、局限性

系列文章目录 文章目录系列文章目录mybatis整合ehcache缓存前言什么是分布式mybatis整合ehcache缓存测试:用上面二级缓存例子即可二级缓存应用场景局限性 mybatis整合ehcache缓存 前言 我们在使用hibernate的时候,可以知道,hibernate就是使用ehcache来实现二级缓存的 为什么我们要用ehcache来实现缓存而不用mybatis自带的perpetualCache 因为 Mybatis本身是一个持久层框架,它不是专门的缓存框架,所以它对缓存的实现不够好,不能支

小良的博客 228

SpringBoot多数据源+分布式事物配置

SpringBoot多数据源+分布式事物 SpringBoot多数据源 application.properties #多数据源配置 spring.datasource.db1.url = jdbc:mysql://localhost:3306/db1? useUnicode=true&characterEncoding=utf-8 spring.datasource.db1.username = db1 spring.datasource.db1.password = 123456 spring

小毕超博客 2570
上一篇: java多线程的使用与原理
下一篇: Tomcat内存设置详解
CookSjg
博客等级 码龄10年 1粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值